MiSikora / laboratory

Feature flags for multi-module Kotlin Android projects
https://mehow.io/laboratory/
Apache License 2.0
82 stars 3 forks source link

Multi-module: providing sources without feature factories #309

Closed AlexKrupa closed 5 months ago

AlexKrupa commented 1 year ago

Problem

Feature sources from library modules can't be provided through dependency without also providing their factories.

Context

Sources can be provided to app with dependency(...). This way the app's sourced storage builder knows that it needs to configure a remote storage.

However, depending on a project also pulls in feature factories and option factories, which get merged into app's ones.

  1. For option factories it shouldn't matter whether all options are in app's option factory or split into separate ones and then combined manually. I'd argue the former is easier because I don't have to combine them myself.
  2. For feature factories it does matter because they're UI-facing through the inspector module. Depending on a library's flags adds them to the app's feature factory, so they all land in the same inspector tab.

Workarounds

1) Dependencies-only

  1. All modules with feature flags added through dependency(...)
  2. No combined feature or option factories, only app's "monolithic" one (con: all flags lumped into one inspector tab)

2) No dependencies + dummy sourced flag in app

  1. No dependencies defined in Gradle (no dependency(...) calls)
  2. Dummy feature flag in app that defines a source named "Remote" to force plugin to generate sourced storage builder step (con: unnecessary flag)
  3. Feature factories combined manually during inspector configuration
  4. Option factories combined manually during remote source configuration

3) No dependencies + stringly-typed remote source

Ignore the Gradle plugin here and use FeatureStorage.sourced that accepts a Map<String, FeatureStorage>. Con: referring to "Remote" source by string.


Any other ideas? Maybe I'm misusing the library? If not, can anything be done/changed in laboratory to accommodate this use case?

MiSikora commented 1 year ago

Ok, let me try to rephrase the problem. You want to keep generation of namespace safe FeatureStorage.sourcedBuilder() but not to generate an aggregate for all options or features? Is that correct?

Also, my wild guess, but is the main motivation that keeping safe builder results in a single inspector tab, which is hard to use?

AlexKrupa commented 1 year ago

Correct. I want the safe builder without adding pulled features to the inspector tab. I could imagine fine-grained variants of dependency API that would let me do that…

a single inspector tab, which is hard to use?

… but maybe the solution lies in the inspector UI? Both a single tab and multiple tabs are a bit cumbersome to use with many flags/features.

MiSikora commented 1 year ago

I could imagine fine-grained variants of dependency API that would let me do that…

Yeah, I'm open to a change like this.

laboratory {
  dependency(project(":lib-a")) // An overload that contributes to all mechanisms.
  dependency(project(":lib-b"), contributesTo: [FeatureFactory, FeatureSourceFactory, SourcedStorage, OptionFactory])
}

but maybe the solution lies in the inspector UI? Both a single tab and multiple tabs are a bit cumbersome to use with many flags/features.

Honestly, I realize it can get annoying to use when a project uses a lot of flags. I'm open to the UI design changes if you have a good idea on how to handle dozens of flags.

AlexKrupa commented 5 months ago

I'm open to the UI design changes if you have a good idea on how to handle dozens of flags.

A Chips-based filter UI seems like a good fit here.

MiSikora commented 5 months ago

I'm not sure I understand. How would it look like in the UI?

AlexKrupa commented 5 months ago

I'd see the UI as a flat list, with the filter chips on top. The filters could be collapsed by default to make space (e.g. single, scrollable line), but with an option to expand them into a multi-line flow layout.

While it's not exactly it, here's an example from Material.

image

MiSikora commented 5 months ago

Aren't tabs above the view pager just simpler and easier to navigate? How many features and tabs do you have that it is not sufficient?

AlexKrupa commented 5 months ago

12 tabs, so no. It's not a deal-breaker, but I'd personally prefer a flat list with sections (collapsible?).

(I'm aware that I can achieve a flat list by combining factories.)