-
Notifications
You must be signed in to change notification settings - Fork 199
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Introduce behavior-change configs as an alternative to feature configs #1124
base: main
Are you sure you want to change the base?
Conversation
It seems that there's some conflict between the two
|
For now I've found that duplicating code between |
Could we quickly discuss this in the community sync tomorrow? |
Good idea @dimas-b, let's plan to discuss there |
My general feeling about A typical configuration class in a Quarkus application would like like this: @ConfigMapping(prefix = "polaris.feature")
interface FeatureConfiguration {
boolean configX();
Optional<String> configY();
List<String> configZ();
} However, we currently have this: @ConfigMapping(prefix = "polaris.feature")
interface FeatureConfiguration {
Map<String, String> defaults();
} Where the map values are dynamically parsed as json, then each map entry is collated against the fields in public class PolarisConfiguration<T> {
public static final PolarisConfiguration<Boolean> CONFIG_X = ...
public static final PolarisConfiguration<String> CONFIG_Y = ...
public static final PolarisConfiguration<List<String>> CONFIG_Z = ...
} This makes the code quite brittle, as it's not possible to statically compile it against an existing method like I understand that the goal is to be able to override things on different levels, by realm for instance – and I think that's a great idea. But there are other ways to achieve that while preserving a strongly-typed configuration mechanism. Let's discuss this at the next meeting, but I would suggest to refactor this by grouping the configuration options into logical groups inside one or many configuration classes. |
@adutra I agree there. Actually, I am hoping that when we refactor FeatureConfiguration to make it more structured, we can also resolve the issue where With all that being said, I see adding a new type of config as not strictly related to these changes. Potentially, we could establish the existence of these configs here and then later refactor the |
That split is rather for technical reasons, since |
I see. Yeah, I am also open to revisiting that if it simplifies things. For now, what do you think is the best way to proceed? Should we introduce the flags with something like this change, and then try to refactor PolarisConfiguration etc. after? I'm a little worried about trying to sort out the refactor now (especially something potentially controversial like adding a Quarkus dependency in polaris-sevice-common) since other PRs like #1068 that should be gated behind a flag will be blocked. |
* | ||
* @param <T> The type of the configuration | ||
*/ | ||
public class BehaviorChangeConfiguration<T> extends PolarisConfiguration<T> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we really need different types to support this? I think probably adding a field to PolarisConfiguration
would be sufficient
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Strictly speaking we don't need a new type, but I chose to add one because I think it's valuable to separate the actual config instances from one another. Besides just having them clearly separated & organized, it means the caller is forced to recognize which type they are relying on (e.g. BehaviorChangeConfiguration.UNSTABLE_FLAG
vs FeatureConfiguration.ACTUAL_FEATURE
). It also allows us to override e.g. catalogConfig
which shouldn't be valid for these flags.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It also allows us to override e.g. catalogConfig which shouldn't be valid for these flags.
That seems reasonable, but given that we use a builder, can't we just enforce that at construction? I do like having the different config types housed in different namespaces (as in your examples BehaviorChangeConfiguration.UNSTABLE_FLAG
vs FeatureConfiguration.ACTUAL_FEATURE
)...
I guess I would just like to ensure that the call sites that are checking for config values don't need to know what type the configuration is at runtime. I can just imagine cases where someone accidentally references one type and the config field is another or someone tries to write some generic code that only works for one config type but not the other...
Polaris currently has the
PolarisConfiguration
type as a catch-all for behavior that can be altered via the application.properties. When I refactored it in #97 I imagined that we would only use these flags for "features" -- things a typical user will want to enable/disable depending on their deployment, and things that the project should support for a long time.It's becoming apparent that we'll also want to use flags to protect behavior changes that aren't strictly features. For example, a bugfix that may cause a regression for users relying on buggy behavior, or a controversial change like the one in #490 where theoretical performance concerns could cause a regression.
To better support these cases, this PR refactors
PolarisConfiguration
intoFeatureConfiguration
andBehaviorChangeConfiguration
. In the future, changes that are perceived to be high-risk or to have a high chance to cause a regression should be gated behind behavior change flags.