-
Notifications
You must be signed in to change notification settings - Fork 3.2k
Nimbus Features
A feature, in Nimbus, is a configuration that outlines a set of properties that define the experimentable aspects of a feature. Each feature should be distinct, and standalone from other features.
Nimbus works by outlining available features in the nimbus.fml.yaml file. This file has three main sections:
-
about- identifying the client for Nimbus -
channels- outlining the available channels for building/setting defaults for -
include- outlining the various features to include in the file at build time
Feature files are found in the nimbus-features directory from the root of the repo. For ease of working & maintaining features, each feature should be placed in its own file. Each feature file is composed of several sections:
| Section | Optional | Description |
|---|---|---|
features |
No | Contains the feature in the file |
objects |
Yes | Outlines the custom objects for the specific feature |
enums |
Yes | Outlines the custom enums for the specific feature |
If objects or enums don't contain anything, they may be omitted from the file.
When creating a new feature, please use the fxios utility.
For a more involved discussion of feature flags, please see Feature Flags
Some external documentation on Nimbus features can be found here. However, setting up a new feature in code is fairly simple, if these steps are followed.
- Use the
fxiosutility to add a feature - Add the feature to the feature spreadsheet (found in the Slack channel's documents tab)
- Implement a layer translating the feature from FxNimbus to what you need to use.
- Use the layer in the app appropriately.
The fxios CLI utility should be used for managing feature flags addition and removal, and is mostly self-documenting. To see your available options, try
$ fxios nimbus --help
For more info on the utility, check out the fxios repo
To edit a feature, open the respective feature's file in the nimbus-features directory, and proceed to edit the feature.
To edit a feature simply means to add or remove a variable, as well as adding or removing objects or enums as necessary.
One current drawback is that the build system knows if there's been a change to the nimbus.fml.yaml file, but doesn't know about changes in files found in the include block. If you make a change and update one of those file, to see these changes reflected in the generated FxNimbus.swift, you must clean and rebuild in Xcode.
Note: The top level feature name should not be changed unless working with a Nimbus engineer to make sure the old name is removed from the database, as this is currently a manual process. This only applies if editing a feature that is also present in the main branch. If you are working on a branch where you are adding a new feature and it has not yet been merged to main, feel free to change the feature name as much as you like.
Most features will be one of three types: a simple feature flag, a configuration for a feature, or a combination of the two.
In either case, the fxios utility is the easiest way to add a feature, regardless of what it should be.
In the case that the feature has a feature flag, the fxios utility will have already taken care of the setup for that. Most feature should have an enabled property, which will be checked by the NimbusFeatureFlagLayer and the upstream abstractions for feature flags.
In the case of a configuration for a feature, that configuration should be extracted from Nimbus through a specific <FeatureName>NimbusLayer class, that should be mockable for easy testing, which will then be used in the appropriate places in the app to access the required configuration for that feature.
When testing a feature, you're either testing the feature flag (in which case, see the Feature Flags Testing discussion), or the feature configuration. In these latter situation, there are two approaches: you can either test using a mock, or you can override the Nimbus feature directly using the FxNimbus.shared.features.<feature>.with API:
private func setupNimbusTrendingSearchesTesting(isEnabled: Bool) {
FxNimbus.shared.features.trendingSearchesFeature.with { _, _ in
return TrendingSearchesFeature(
enabled: isEnabled,
maxSuggestions: 5
)
}
}This bypasses remote config and forces the Nimbus feature to return the exact struct you provide. Use this approach when:
- You need to test a specific combination of Nimbus feature fields (not just a feature flag toggle).
- You want to verify integration with the real Nimbus plumbing end-to-end.
For most unit tests, prefer injecting a mock backend layer - it is simpler, faster, and does not couple your tests to Nimbus internals or generated config types.