Ever since frontend-plugin-framework introduced the concept of a <PluginSlot />
, whenever I run into PRs that add configuration to control UI I’ve been asking: wouldn’t it be better to make it a slot instead?
There have been a few examples of this, recently, and I’m not even counting the several instances of business-specific code we’ve asked to be made into plugins:
- feat!: footer legal links by asadali145 · Pull Request #403 · openedx/frontend-component-footer · GitHub
- Footer UI Plugin Approach by hinakhadim · Pull Request #405 · openedx/frontend-component-footer · GitHub
- feat: ability to point header logo to other locations by arora-r · Pull Request #479 · openedx/frontend-component-header · GitHub
What I’d like at this point is a temperature check on my stance, which is as follows:
1. We have too many toggles and configuration variables already
We’re adding over 20 individual variables in Redwood, and most of those just for controlling Studio UI behavior. This adds to the hundreds that already exist, some documented some not.
The point is that the more toggles you add, the worse you make it on operators, whether they’re upgrading from one release to the next or just starting from scratch. We should consider each new toggle as a detriment to adoption, to be weighed carefully against the value in optionality that it brings to the table.
2. We don’t have a unified guideline on when, where, how and configuration should be created
Some are feature flags in settings.py, some are waffle flags in the database, some are MFE-specific environment variables (which can depend on other backend configuration themselves). The latter, in turn, can either be configured via .env
files, via MFE_CONFIG
in settings.py, or via site_configuration
in the database… some of which work with actual booleans, some only with string values. Oh, and now we have env.config.js
, of course, which adds yet another configuration vehicle.
In short, it’s usually up to the developer implementing the toggle, who also decides whether or not to document it correctly. All of this compounds the adoption problem described on 1.
3. Config variables are APIs we have to support
Once a toggle exists in a release, removing it means it has to go through the DEPR process. This means that with each new configuration item we’re introducing complexity in the codebase that can’t be easily refactored away: both sides of that if()
have to be maintained for the lifetime of the toggle.
4. Some configuration strategies can make UX objectively worse
From making bundle sizes bigger (the else
needs to get bundled, too!) to requiring new requests to the server and throwing a wrench in react-router soft navigation (looking at you, course-authoring!), sometimes even resorting to configuration can make the user experience not as good as it would be otherwise.
5. Why add configuration when you can let the user create a plugin?
I don’t mean to say with 1-4 that configuration variables are always bad, or even avoidable. Sometimes, it’s just necessary to allow users to flip switches easily. But - and here’s my point - many other times a single config var is not enough for the user to achieve the level of customization they need. This is the worst possible situation, in that we as maintainers of the platform have to deal with the drawbacks of configuration, and the user still has to fork.
Enter plugins. Can they suffer from some of the same drawbacks as config vars (specially if we do them wrong - which we’re trying to avoid)? Yes. But the flip side is that they give users much more control. So much so that whenever we find that optionality is necessary, we should avoid relying on a regular configuration variable (whether feature flag, waffle flag, or environment variable), and instead attempt to present the it as something a plugin can modify.
Thoughts? Objections? At some point I intend to extract an OEP, or at least an ADR, out of the conversation. Or maybe more than one: say, one to define when-where-how to create configuration, another for plugins, and maybe even a plan to deprecate and remove old flags that have no business still existing.