ExPlat: Handle local Experiment registration - #14559
Conversation
|
You can trigger optional UI/connected tests for these changes by visiting CircleCI here. |
|
You can test the changes on this Pull Request by downloading the APK here. |
| @Inject AppConfig mAppConfig; | ||
| @Inject ImageEditorFileUtils mImageEditorFileUtils; | ||
| @Inject ExPlat mExPlat; | ||
| @Inject Set<Experiment> mExperiments; |
There was a problem hiding this comment.
I'm wondering whether it would make sense to inject this directly in the ExPlat class. The reason is that it would hide this internal piece of logic in there instead of using it in the shared application class. I see it's a singleton but I wouldn't expect it to outlive the application class. WDYT?
There was a problem hiding this comment.
That would make sense, for sure. The reason I avoided doing that in the first place was because I didn't want to generate a circular dependency (ExPlat depends on Experiment that depends on ExPlat).
That said, I tried using dagger.Lazy to inject the Set<Experiment> in the ExPlat constructor and it actually ended up working pretty well and the code got cleaner, specially because we no longer need the ExPlat::start method.
You can check the changes here: 3eb27b7 – thanks for the suggestion!
| @Multibinds fun experiments(): Set<Experiment> | ||
|
|
||
| // Copy and paste the line below to add a new experiment. | ||
| // @Binds @IntoSet fun exampleExperiment(experiment: ExampleExperiment): Experiment |
There was a problem hiding this comment.
Is it viable to introduce some kind of a lint rule that would fail if there is an experiment that is not registered in the module? Maybe that's unnecessary.
There was a problem hiding this comment.
This is probably viable, although I have no experience with custom lint rules so I can't say for sure.
That said, if that's something we want to do, we should probably do it in a different PR (specially since I guess it would need to be submitted to WordPress-Lint-Android?).
planarvoid
left a comment
There was a problem hiding this comment.
It's looking good and works well, thanks for the PR! I have one comment 👍
planarvoid
left a comment
There was a problem hiding this comment.
Thanks for the changes, it's looking good 👍
This PR is a follow up to #14498 and is related to wordpress-mobile/WordPress-FluxC-Android#1970.
These changes can be divided into two parts:
Experimentregistration in theExPlatclass.Experiments to theExPlatclass for registration.I thought about splitting this PR in two, but its changes are not so big overall and I think they make sense together, but let me know what you prefer.
Part 1
In this first part, the
ExPlatclass was updated in two ways:start()method that replaces the direct call we previously made toforceRefresh()once the app started. This method accepts a set ofExperiments, maps it to a list of experiment names which is then held internally and then callsforceRefresh().forceRefresh()andrefreshIfNeeded(), we check if the list is empty and if so, we prevent any calls to the API from being made.getVariation()we check if the list contains the name of the providedExperimentand if it doesn't, we just returnControldirectly (ifBuildConfig.DEBUGistrue, we throw aIllegalArgumentExceptioninstead).Part 2
In this part, Dagger is being used to actually provide the set of
Experiments to theExPlatclass. Since ourExperimentimplementations were already being included in the dependency graph, I just created aExperimentModulewhere we can add the experiments we want to register and bind them all into aSet<Experiment>by using a combination of@Bindsand@IntoSetannotations. It also uses a@Multibindsannotation to provide an emptySetin case noExperimentis currently registered.This approach is a bit similar to the one we use to provide a
MapofViewModels to theViewModelFactoryclass and it introduces a similar extra step. To demonstrate, here's how it would work in practice to add a newExperiment:Experimentclass, and inject theExPlatdependency using Dagger, just like we did before:Experimentin theExperimentModulelike so:And that's it. I also created an
ExampleExperimentand left a commented out line inExperimentModulewith the code above as an example.👉 Note: while this approach is pretty safe to use, I don't expect it to be final. Once we start working on adding functionality to list and edit registered experiments locally (as described in #14089), I expect we should be able to replace it with something similar to what we currently have with our remote configs, where we would just need to add an annotation to our
Experimentclass and the generated code would handle the rest for us. For now, other than that extra step, I don't see any major drawbacks that would prevent us from moving forward with this, so please let me know if you do!To test
Without registered experiments
logcat, make sure you don't see any messages like:ExPlat: fetching assignments successful with result: ....Try logging in/out and restarting the app and make sure you still don't see the message.
With registered experiments
ExperimentModuleclass and restart the app.logcat, notice a message like:ExPlat: fetching assignments successful with result: ....Regression Notes
Potential unintended areas of impact
n/a
What I did to test those areas of impact (or what existing automated tests I relied on)
n/a
What automated tests I added (or what prevented me from doing so)
Added a few extra unit tests to account for new behaviors.
PR submission checklist:
RELEASE-NOTES.txtif necessary.