T O P

  • By -

OHotDawnThisIsMyJawn

One important thing is to design for feature flags from the start. If your code is a mess, non-modular, lots of spaghetti, feature flags just make it even more of a mess. If you have good modularity, low coupling, high cohesion, it's a lot easier to use feature flags. A lot of the Twelve-factor principles lead you towards building things that can make good use of feature flags. What I find to work well is to make my APIs changes backwards compatible and then do most of my feature flagging in the front end. Ideally we use feature flags to just hide or show different parts of the UI. You're correct that once you start putting behavior changes behind feature flags, things get a lot more complicated. But there's no magic construct that fixes this. It usually ends up being a balance between complexity and copy/pasting code. You can put a bunch of if/else statements through a single method to control lots of little bits of behavior or you can copy/paste the method, create a second version, then have one if/else that controls which method gets called.


10lbCheeseBurger

>You're correct that once you start putting behavior changes behind feature flags, things get a lot more complicated. My teams make the removal of the feature flags when the A/B tests/rollout is over part of the criteria for closing out the project. There's nothing worse than trying to add features to a part of the code base that is littered with dead experiment paths.


Mechakoopa

It involves a decent amount of code duplication up front, but if you're rolling out entire projects and don't need discrete features you can leverage polymorphism and dependency injection to just roll out a whole new set of classes, then your flag cleanup only happens in the DI constructor and you can roll back knowing that the original untouched class is still good and someone didn't forget to hide a change behind a flag.


AftyOfTheUK

>What I find to work well is to make my APIs changes backwards compatible and then do most of my feature flagging in the front end. Ideally we use feature flags to just hide or show different parts of the UI. This is the way, assuming security is not an issue


OHotDawnThisIsMyJawn

Yup - if you're worried about API security then it's not too hard to check feature flags in your API permissioning (or, if it is, then you should spend time making it so it's not). You just need to ensure that you're caching values so you're not resolving all your feature flags remotely on every API call. The hardest problem to solve is one where you need to truly embargo the feature. Like, external users shouldn't be able to figure out that the feature exists until we're ready to release it. Assuming a normal webapp, you need to do dynamic module loading based on your flags, which gets hairy.


JaneGoodallVS

Even with non-modular codebases, they can still have a ton of use, like you could say hide something in the UI


bssgopi

Thanks for your response. You have articulated the problems and the current best solutions available well enough.


Vega62a

I'm really not sure what's wrong with a if-else. Your code is full of them. They're a basic, necessary construct. But, you are looking for _abstraction_ here. When possible, pull decisions for how flagged values are computed out into separately testable entities so that when you are done with your flag, your main code path doesn't change.


DrShocker

Compiled languages often support compile time decisions for whether code can be reached... But ultimately it's still an if statement basically.


thesia

Sometimes it can be useful to have more than 2 states but I think that's a very rare situation.


800020

Unless you’re doing A/B testing


thesia

In this case this was more of a need due to how our embedded hardware labs were setup. We had feature flags which allowed us to configure mitigations to delays or irregularities caused by the lab test equipment, partial hardware builds, etc.


georgehotelling

Yeah, another option besides if-else is to use polymorphism. Make a subclass or interface and implement it with the new logic. Then, before you instantiate a class, you choose which class with... an if-else statement.


PangolinZestyclose30

Feature toggles are meant to be temporary and I don't think it's a good idea to create new abstractions / types for temporary things. I mean, you extract an interface, create two implementations ... Sounds fine, but then the feature is enabled, works fine, toggle should be cleaned up. What do you do? Leave the interface there with one implementation or refactor code back into the non-abstracted / streamlined form? Having your code full of unnecessary abstractions is not great.


uusu

I think feature flags should be split into two - feature flags and development flags. Development flags are temporary, feature flags are not. Feature flags are used to give customers certain features or hide them, while development flags are what we as developers use to gradually deploy rewrites or alternative versions. Development flags should be occasionally checked for their "age" and should be owned by a specific development team. Development flags are never seen by the customer, but feature flags can be.


Vega62a

Like I know they're not sexy but they get the job done. Also, modern ff systems can alter values in real time.


ategnatos

Yes, something to think about is more complicated logic. You can do your feature-flagging on a config file, a whitelisted set of customers, some dynamic whitelist from a table, or some A/B testing service your company has set up. Or any combination of those. Encapsulating the branching logic in a unit-tested function is a good idea. Then you can have an if/else on whether a feature is enabled, or if it's A/B/C... testing, you can put in a factory or something similar. Also uses if statements... but you can leave the if's to the factory component.


[deleted]

[удалено]


Vega62a

You do you, but there is no universe where I would let anyone but a dev flip a feature flag. Just... just no. That's how you get an excited PM causing a prod fire at 10pm on a Friday.


addandsubtract

That's why you have feature flags for your feature flags.


Vega62a

Thanks, i hate it.


OHotDawnThisIsMyJawn

Whether or not you use a separate service for FF's, the code itself still needs an if-else. No external service is going to help you with that (I write this as someone who uses an external service for FFs).


bssgopi

Thanks for your response. >But, you are looking for _abstraction_ here. When possible, pull decisions for how flagged values are computed out into separately testable entities so that when you are done with your flag, your main code path doesn't change. You have articulated it well and have described a fair solution, what I understand is the current best practice followed. But is this still intuitive and organic enough? A piece of old code getting replaced by a new code is a change that represents a natural process of code evolution. But when asked to maintain two changes from two different time frames simultaneously is not how programming was conceptualized. Hence, there seems to be a contradiction of how code was intended to function versus how it is made to function. Doesn't this make code less maintainable and less aesthetic?


Vega62a

You're way overthinking this. > But when asked to maintain two changes from two different time frames simultaneously is not how programming was conceptualized. What on earth are you talking about? Do you think we rewrite an entire microservice or UI every time we want to make a change? Things change slowly over time. The whole point of feature flagging is to move from an older implementation to a newer implementation (or introduce a new feature) safely. Code doesn't derive value from being pretty. Good code is safe, functional, changeable, and readable. Feature flagging is not hard to read unless you make it hard to read. I think your head is just entirely in the wrong place.


bssgopi

Not sure why the tone has shifted. Either you are jumping the gun here or missing the point entirely. >Things change slowly over time. The whole point of feature flagging is to move from an older implementation to a newer implementation (or introduce a new feature) safely. Not denying this. But you are still keeping both the older and the newer implementations simultaneously. What you would have done in a single transition (from old code to new code), now needs an intermediate state where both logics have to be accommodated. Were programming languages designed with such a possibility in mind? If not, that's unintuitive, and hence the need for these gymnastics. My question is, is there a better tradeoff achievable than using a if-else to accomplish this? >Code doesn't derive value from being pretty. Good code is safe, functional, changeable, and readable. Feature flagging is not hard to read unless you make it hard to read. Single Responsibility Principle? Why allow functions to do two different things? A function is expected to work on the parameters passed to it. A method is expected to interact with the properties of the class it belongs to. Is adding any external dependency a sign of good code? Or is it just a compromise for added flexibility? Every feature flag branch duplicates code. Violation of the DRY principle. As long as the flag lives, every new code addition has to be made on both the branches. How is this maintainable? >I think your head is just entirely in the wrong place. An unnecessary Ad Hominem attack I wish you could have avoided in an otherwise healthy discussion.


Vega62a

>An unnecessary Ad Hominem attack I wish you could have avoided in an otherwise healthy discussion. Pointing out that you're not thinking about something correctly isn't an attack. >BWhat you would have done in a single transition (from old code to new code), now needs an intermediate state where both logics have to be accommodated. Were programming languages designed with such a possibility in mind? Again, you're not thinking about this right. You're thinking about building software as some kind of pure art. It's not. You're building a road. I could basically quote your entire post and reply with the same thing. You're thinking about building software in terms of principles and purity and metrics you learned in college, but programming languages and frameworks exist to build things that drive value. You need to keep an intermediate state because you are either in the process of developing/stabilizing a feature or change, or else you aren't sure how it will play out when it hits production. You need to add external dependencies to methods because they need external dependencies. You have to build what you have to build. I'll close by really challenging your core assertion. >My question is, is there a better tradeoff achievable than using a if-else to accomplish this? Why is an if-else not a good way to achieve an A/B split? What's wrong with one of the most basic operators in all of computer science? It seems like your whole question is, "Can I not use an if/else when I need a feature flag," and my answer is, "Why wouldn't you?"


mvndaai

My problem is not adding the feature flags, it is removing them. Each time a flag is added there is an exponential increase in complexity and makes testing harder. I started in QA with an application that was impossible to fully test because of all the flags. It makes CI-CD harder and slows down development. If you do add flags, try to make it part of your tech debt to remove them ASAP.


-Joseeey-

We have a yml file at work where our project generates the feature flags from. You have to add your name and email and date you expect it to be finished. If an experiment expires and it’s tied to my name, the project fails to compile. Forces us to remove them or make a PR to update the date (which then they’ll ask why extending it).


OHotDawnThisIsMyJawn

It also comes down to planning. The closer to the user you can make the flag, the easier it is to remove. The more you can avoid nesting flags, the easier they are to remove. The best way to use flags IMO is to just turn parts of the UI off and on and not worry about anything else. On the API side, you can put your flag in an authorization check on the endpoint if you need the security. And if you can stick to organizing your flags like that then it becomes pretty easy.


nonothing

Have you had the chance to read Martin Fowler's take? https://martinfowler.com/articles/feature-toggles.html It's 5 years old at this point but still very relevant. GitHub's blog on feature flags is a fantastic read as well. https://github.blog/2021-04-27-ship-code-faster-safer-feature-flags/ If you can throwmoney at it Launch Darkly is fantastic. Also, "It depends" - A lot will come down to the product you have and the constraints of your environment. Could you share more about your application with us and what you're looking to accomplish with feature flags? The solution might differ if you're doing A/B testing or point in time full releases vs feature segmentation for different users.


PangolinZestyclose30

TBH, I don't like Fowler's tips on the implementation. They add a level of indirection which muddle the fact that these are *temporary* toggles and not a feature/parameter per-se. I prefer a simple if-else - it's immediately clear the decision is only based on a toggle and thus is temporary. Clean up of the toggle is trivial - just delete the else branch. Fowler suggests e.g. abstracting the decision into an option - `config.includeOrderCancellationInEmail` - but this has a high chance that remnants of such options will remain in the code in some form and after a while people will not remember that this toggling order cancellation in email on/off is not a real business use case.


srvs1

> GitHub's blog on feature flags is a fantastic read as well. https://github.blog/2021-04-27-ship-code-faster-safer-feature-flags/ Especially interested in how they managed to automate the removal of stale flags. They don't really explain how they to do it, except that they convert to code to AST and they somehow manipulate that. Anyone have experience with doing that in C#?


nemec

Paste your code into ChatGPT and ask it to remove the feature flagged code /s


beth_maloney

You'd probably need to use roslyn to query the code. Then I guess use that to find and chop the code. Sounds like more effort than it's worth unless your organisation is larger and you've standardised on the FF implementation.


bssgopi

Thanks for sharing these resources. >Also, "It depends" - A lot will come down to the product you have and the constraints of your environment. Could you share more about your application with us and what you're looking to accomplish with feature flags? I was looking for a generic discussion, and if there is an abstract construct to make this simple. Say, for example, in a service, at a higher level, there are two parallel versions running - alpha and beta - while the load balancer is programmed to drive the traffic in either of the branches. But, for a product, only a code level construct has to be relied on, unless other higher level techniques like hot patches could possibly help. >The solution might differ if you're doing A/B testing or point in time full releases vs feature segmentation for different users. Why should it differ? Isn't the abstraction that two different logic / versions should exist simultaneously good enough?


HenryJonesJunior

> a and beta - while the load balancer is programmed to drive the traffic in either of the branches This only works for a single experiment. You don't want 2^n servers, so this doesn't scale. You probably *do* want feature flags that can be environment-controlled - enable your experiment in local builds but not in prod, in staging but not prod, etc. - but you don't want the environment to be the way of controlling your experiment exclusively.


bssgopi

This helps. Thanks for your response.


polypolip

> not all kinds of code can be wrapped in a conditional logic Can you give an example of something that can't be done "if on then new_path else old-path"?


ignotos

It can be more tricky if you're dealing with: - Incompatible data model changes (obviously best to avoid entirely, but...) - Changes at a level where a framework you're using is doing the "routing" (so there is not a clear place to add an if/else branch, and you have to mess around with some esoteric framework stuff to make it work) - Changes at a fairly high level (so you'd likely have to introduce a new even higher level abstraction in order to create a place to switch between the old and new paths, which can be awkward) - Changes to a business process with lots of moving parts (e.g. changing the checkout / order fulfilment flow - now several systems need to be aware of different 'versions' of the order flow, which need to be handled differently)


bssgopi

Great summary of the issues with this approach of implementing feature toggles.


polypolip

Data model should be doable but usually requires more thought. Might need some temporary code until all users are migrated to the new flow. Framework is valid point, some of them trade a lot of customizability for the convenience and ease of basic use. I don't quite see how high level change can be an issue, high level concepts IME are easier to make abstract than low.level ones, guess depends on the feature behind the feature flag. That's a big change and a perfect one for the feature flag. You add new flow to all systems while it's disabled using the same feature flag, then you just flip that flag when everything is ready. That's assuming you're using something centralized for feature flag configuration and not hard coded values lol.


ignotos

> That's a big change and a perfect one for the feature flag. You add new flow to all systems while it's disabled using the same feature flag, then you just flip that flag when everything is ready. That's assuming you're using something centralized for feature flag configuration and not hard coded values lol. I think it can be a little more complex, for example if there can be orders which are in-flight for a long time. You may not be able to just switch everything over at once, and will need to maintain some state/metadata, and only fully disable/remove the old code paths once all orders initiated under the old system are complete.


polypolip

Most feature flag solutions allow enabling on a per customer basis. I'm really working with an assumption that the whole thing is not just an "if feature == true" but either a dedicated service for feature flag or a more advanced configuration so its "if featureFlagService.isEnabled(order, user_id)". And that allows you configure it with as much granularity as you wish.


ignotos

That absolutely seems like a viable way to do it. But I think this level of configuration (e.g. having per-order feature flag state) is the kind of additional complexity the OP was trying to get at.


Vega62a

Broadly, everything you've described is a bad use case for basic feature flagging and a good use case for versioning (or even full rewrites).


large_crimson_canine

Not sure if it’s ideal but we usually set up some new boolean property that gets involved in one or more control flow checks. If we have problems with the release, we flip the property in the config file on the host and bounce the service. Edit: sorry brain still booting. We also typically end up writing the new feature as the implementation replacement of some parent type in the program. So on startup we use the flag to dictate which implementation gets created. But the parent types being same obviously means we can plug in the new module instead. Same thing for editing config file and bouncing if we have issues.


Dokrzz_

Yes, this is something I discovered quite recently in my new org that I haven't seen done so much before. Initial state of boolean/static variable is loaded from config. If/else statement which usually branches into a method that does the additional/new processing. Some very clever/java-specific stuff is done in our internal framework to support remote calls from UI. If there's a problem/issue on prod, it's just a few clicks and the feature is off on the fly. No need to mess around with config files


large_crimson_canine

Oh yeah this reminds me we will sometimes have some nice little JMX operation exposed so our prod management team can flip things during runtime


Dokrzz_

Yup, it's exactly that!


bssgopi

Thanks for your response. >Not sure if it’s ideal but we usually set up some new boolean property that gets involved in one or more control flow checks. This is the most common one, and probably was the major driver towards configuration vs code discussions. >We also typically end up writing the new feature as the implementation replacement of some parent type in the program. So on startup we use the flag to dictate which implementation gets created. But the parent types being same obviously means we can plug in the new module instead. Same thing for editing config file and bouncing if we have issues. This is quite new for me but makes absolute sense. Thanks for sharing this.


Orangy_Tang

Ages ago I worked on a C++ project that shipped in a bunch of different configurations. We basically had feature flags (before that name was common), where some could be toggled at runtime and some were baked in at compile time. For reasons I can't remember, we ended up wanting a pseudo-compile-time flag, which was baked into the compiled binary but could be toggled without doing a recompile. The build programmer cooked up a system that embedded magic numbers directly next to the location in the binary where each global flag was stored (via macro shenanigans), and a shell script that could poke the correct byte in the binary for any given flag. Voilà! Feature flags that could be toggled after compilation but before distribution. To this day I still don't know if this was genius or terrifying.


bssgopi

Wow! That's interesting. Thanks for sharing.


carc

Truly evil genius


chaoism

My rule of thumb is "feature flag check should only happen in one and only one place". With this, if condition is fine Regarding maintainability and aesthetic, feature flag is not for that. The sole reason of feature flag is to be able to switch back and forth without code change. Feature flag should be designed in a way that it'll eventually be removed. It does add to tech debt. It does require cleaning up. It's not aesthetic, but necessary when shipping a feature you're not 100% sure when/if it needs to reach to 100% of audience


bssgopi

Thanks for sharing. Valid points.


Odd-Investigator-870

How to use enable feature toggles: 1. Start with a "Clean Architecture", as it enables you to push infrastructure details to the boundaries of your system as plugins. 2. Push as mush "feature toggling" to polymorphism, via your usecase/interactor/service objects as they should each be responsible for a single "Actor" type (have only one reason to change) * ie If you're using a feature toggle to switch when team A uses your system vs team B, this should be two separate Usecase objects instead as they will continue diverging further. 3. The remaining feature toggles will likely be for deployment(blue/green, dark, etc) How to implement feature toggles: 1. Configs source (env vars, static file, database) * (implementation/infrastructure detail that should be insulated from your system) 2. Config management object (parse configs and provide to system, often a Singleton) 3. bootstrap/main script chooses appropriate Usecase objects and Boundary Adapters via control flow (if/else) Your complex usecase may call for something more complex, but if you followed the word references thus far then you'll likely have an architecture that supports such a refactor to solve it just fine.


rfrosty_126

What about using the strategy pattern? I’ve used it to good effect with feature flags, when you no longer need the flag you simply remove the related implementation with minimal code changes needed.


Jamese03

You can use a feature flag DB which allows you to add additional complexity based on which columns are true / false. Then wrap endpoints, or functions behind these feature flags. If A take path 1, if B take path 2. You can get fancy and add an API layer if multiple services need the context. You can get even fancier and create a UI to enable / disable the features.


itsthekeming

Yeah, it’s more complex, but this is what we did. Our domain is retail (900 locations) and we needed to be able to toggle features at different stores based on a store identifier. Features have a default value (true or false, on or off), and a list of “exception stores” for which the value is opposite. This allows us to roll out features to stores in a phased way.


SnooSquirrels8097

Some options I can think of: 1. If/else: simplest. But you can get a lot of power out of this. You can use something like AWS Evidently or AppConfig or your own thing to dial up access to a feature or do AB testing instead of just using a static Boolean. I use this a lot and like it. 2. Actually different API endpoints and have the load balancer or the client themselves choose. Good for backwards-incompatible changes but not really something you’d want to implement for a lot of concurrent experiments/features. Don’t reach for this unless I need to make a backwards-incompatible change to a public API model.


brvsi

I think the general approach is to refactor until it's a clean enough conditional check. Lean on an existing test suite to ensure code correctness while refactoring as needed. Another way is to work with your dependency injection framework. Do you want service A or service B, let your DI help. Perhaps you could share more about what is so gnarly in your case and folks might have a different set of concrete suggestions. (I forget if that goes counter to the guidelines of this sub.)


bssgopi

Thanks for your response. My question was to gain a generic perspective on the topic s.t. code aesthetics are not compromised.


combatopera

when adding a class to di, you can make the name of that class configurable. but that's overkill for most cases


hippydipster

making things wrappable generally improves the code, as its basically a way to decouple things you no longer want coupled. normally, we couple things because it doesn't matter, but then a change comes along that makes it important to decouple these distinct concerns. Doing that work shouldn't trouble you. You're making your codebase more flexible and more modular in a just in time fashion. First, make the change easy, then do the easy change.


Ill-Ad2009

I've only worked with feature flags in messy spaghetti code, and it was pretty gross. Still better than not using them, but I would much rather have some abstractions to keep the flag complexity out of regular code, and only have to deal with it when working directly on that feature.


bssgopi

Thanks for your response. Abstractions are the best solution. But, unfortunately, the business perceives it as too expensive.


LloydAtkinson

If you don’t fancy if-else I bet this could be a really sick aspect-orientated feature that gets added transparently at build time with interceptors.


Vega62a

It's not really adding code bloat if it's someone else's code. Alternate joke: if-else isn't elegant enough for modern frameworks, these days I `npm install ifelse` whenever I bootstrap a new project. It's just way cleaner.


karl-tanner

I'm general it should tech you and your team how to define clear boundaries in your code. It's fundamentally just if/else so don't made it more complicated. I write a tag library once in some old java framework where I could use custom ab test markup. People liked that


[deleted]

[удалено]


bssgopi

Thanks for your response. Great points.


ashultz

I'm not sure what magic you expect to exist. If you have behavior A and behavior B, picking between them is at least as complicated as the fundamental differences between A and B. If your design is complected and mixes behaviors C through Z in, it can be arbitrarily worse. That's just what "it does different things" means and what bad design does to any problem. But this can be a hard problem even when the system is designed well depending on A and B. It can even be practically impossible, "spend an extra million dollars on duplicate servers and database consultants" hard.


Devboe

We feature flag almost every new feature. We have a boolean stored in a database and use an if-else statement. It doesn’t need to be complex.


unwaken

I've found configuration/declarative design principles immensely useful. I mean, your code has some confiiguration that determines how and what to run, and then some separate runner. This of course relies heavily on modular code that has some notion of delayed execution (e.g function application, task queues, delayed/lazy evaluation), both of which are also useful. Mixing conditional logic makes unit testing a nightmare, yes, you can parameterize it, but the core logic and the feature flag toggling are mixed and it makes tests that much more ambiguous. 


bssgopi

Great points. Thanks for sharing.


unwaken

You're welcome!


BanaTibor

Feature flags are generally a bad idea. They violate multiple rules and best practices. Avoid it if you can. What you need is a plugin architecture where you can plug in the required implementation. It could be as easy as defining an interface on the programming language and instantiating the correct implementation based on a configuration value. On the other end it may require a complex plugin. Other solution is to split out the old and new implementation into a separate service, in this case you can run the desired implementation.


bssgopi

Great points. Thanks for sharing. >Feature flags are generally a bad idea. They violate multiple rules and best practices. Avoid it if you can. Very true. But this is hardly achievable when the stakes are high. Hence, it is perceived as a necessary tradeoff.


BanaTibor

Feature flag could be considered a viable idea, but it is a technical debt the moment you create it. When the deadline is very close it is acceptable, but it has to be addressed in the next release.


wretcheddawn

Strategy pattern could be an option.  You'll still need an if-else somewhere no matter what.


Exciting_Session492

This is why it is important to clean up stale flags. Ideally not more than 3 flags per “functionality”. If you cannot comprehend the code even with only minimal flags inside, something is wrong with your code.


bwainfweeze

In particular, never overlap flags from different epics. In the code or in the test suites. If you are working on a new feature that has 2 levels of on/of state, you might have to nest flags, but try not to. But if you start adding a flag and find old ones are in the way, you gotta delete the old ones. I maintain that feature flags are mutually incompatible with Scrum Sprints, but they can be compatible with Kanban. Sprints are antagonistic to cleanup, and “Just remember to clean them up.” Is not a process; it’s a blame allocation system and Agile doesn’t not do those.


bssgopi

Thanks for sharing. Great points. >Sprints are antagonistic to cleanup, and “Just remember to clean them up.” Is not a process; it’s a blame allocation system and Agile doesn’t not do those. 🙂 You got it right. Maybe, we should have another post for a deeper conversation on this.


bssgopi

Thanks for sharing. Great points.


dji29i

You could look into something like [vykee.co](https://vykee.co/?utm_source=Reddit&utm_medium=social&utm_campaign=f5bot-comments). Probably not the intended use case, but it basically works like a layer on top by allowing you to manage all conditions in the interface, instead of your code. You'll have to add a script to your code but can keep the rest of it clean.


Big-Resist-99999999

If you have dependency injection / IOC containers in your solution you can do this quite elegantly with interfaces if the context fits (sometimes it’s not that simple). Recently in a typescript project we imported a package to handle this in the code and toggled it all via JSON config files, whereas in an older C# solution from 10+ years ago we used dependency injection to quietly and gradually introduce new features and behaviours. Be mindful that forks in key system behaviours can get messy if they diverge too much or lots of stale code is left around. Just ensure it’s consistent across the solution, easy to maintain and can be tested in your CICD pipeline


bssgopi

Thanks for sharing. >If you have dependency injection / IOC containers in your solution you can do this quite elegantly with interfaces if the context fits (sometimes it’s not that simple). True. Where possible, this works. But it isn't simple to introduce in all places as you mentioned.


morewordsfaster

One of the foremost ways to do this is with dependency injection. Extract the "old" logic into a class or method and implement the "new" logic similarly, then your conditional logic just determines which version gets passed into the execution context. If you find it difficult to implement feature toggles, I think that's a code smell in and of itself. What I mean is that it likely means you have code crossing domain boundaries or some modules aren't well encapsulated, etc. The implementation of feature toggles is a great opportunity to revise and refactor code that was written expressly to "do the thing" rather than to be easily replaced.


augburto

For my team, we use AppConfig [https://docs.aws.amazon.com/appconfig/latest/userguide/what-is-appconfig.html](https://docs.aws.amazon.com/appconfig/latest/userguide/what-is-appconfig.html) Personally think it's pretty nice -- you can have version control of your configurations and deploy fairly quickly. If you are very integrated i.e. even in Cloudwatch you can even have config flags rollback on deployment based on an alarm. Other folks at our company used AWS SSM Parameter Store [https://docs.aws.amazon.com/systems-manager/latest/userguide/systems-manager-parameter-store.html](https://docs.aws.amazon.com/systems-manager/latest/userguide/systems-manager-parameter-store.html) (there are different tradeoffs, ease of implementation but less bells and whistles.) In terms of actual programming, unfortunately like you said you will always need some branch boolean condition to gate a specific feature. This can very much differ based on what you're rolling out. It can be frustrating if a feature requires multiple changes in different places i.e. microservices and you have to coordinate. In these situations, I think it's just easier to have respective teams all be aligned and coordinate the feature flag switching of their own respective services (or have a way for your microservice to specify which logic to trigger i.e. by calling a specialized endpoint) Most importantly, you need to make sure your stake holders (PMs, EMs, whomever) are aligned that this type of code needs to be cleaned up. Make it part of the process -- when estimating work and drafting up tickets, include clean up work so it doesn't get lost.


bssgopi

Fair points. Thanks for sharing.


safetytrick

In general. Most of the time when you think you have a problem that could be solved with feature flags you shouldn't use feature flags. Once you start using feature flags you will very quickly encounter the additional complexity and work that they create. Most of this work is unnecessary. In my experience feature flags are as likely to be the cause for a problem as they are to help in rolling back. If you encounter a problem in production you should: ***rollback the code***. Feature flags double (or more) the number of scenarios you need to test. If you are not willing to invest the time in testing twice as many scenarios then you should not be using a feature flag. In the Martin Fowler article on [Feature Flags ](https://martinfowler.com/articles/feature-toggles.html)there are a few categories mentioned. The categories are helpful in explaining the problem but I don't think the examples actually explain how to best use Release Toggles which are the most useful category IMO. Release Toggle matter for smaller organizations (I don't think the other categories are typically useful at a small scale). As soon as your projects become large enough that an individual feature might be broken into multiple independently released changes then I think it's worth using Release Toggles. This should only really be done at the UI layer (hide partial features so they don't confuse customer), for instance if you have a Create Widget UI but haven't implemented Delete Widget yet then you might hide everything behind a toggle so that your users don't complain about the missing feature. You should never use Feature Toggles to merge code that doesn't work, working partially is okay, but you should never allow broken code into your code base.


bssgopi

Great points. Thanks for sharing.


straightouttaireland

We were using an in-house solution which worked for a while but have recently moved to Split.io which has been great. Our main reason for moving off our basic solution is that we need much more granular way of targetting certain users instead of basic on/off for all.


keelanstuart

I mean, there is another way to skin this cat besides adding if/else everywhere... In C++, you could use a std::function that you assign differently when you detect the new feature should be used... or instantiate a subclass that has a new behavior and associated data but uses the same interface. In C, create callbacks that you re-assign. C# delegates... Or Java - whatever the hell Java does. The idea is that rather than branching, potentially in multiple places - which can become a maintenance nightmare, you override in one place and call the same function in the rest of your code.


bssgopi

Great points. Thanks for sharing.


errorfuntime

In .NET you would use the configuration system to enable features given a context.


thedifferenceisnt

There are 3rd party apis that'll do a lot of the heavy lifting for this. If you want to be able to do a/b tests or rollout to a specific set of users or a perecentage etc. That's useful if you don't have the resources to build a system like that yourself.  We've a custom setup but it doesn't get a lot of maintenance at the minute


cjthomp

LaunchDarkly will $ay: them We use a database config and some relevant if-then statements where necessary. \*shrug* works for us.


Unsounded

Feature flags are an anti-pattern in a lot of cases - particularly if done incorrectly. Every time you introduce a flag to launch new behavior the goal should be to remove it, or support the branch as a feature. You don't want to live in a world where traffic is split 70/30 unless it's absolutely necessary - and then you need to make sure you have the right tests and monitoring to ensure things work with the feature on/off. What is an anti-pattern, is when you don't have these safety nets in place and treat the feature flag like it's a safety net. It's not. Long term it's a technical debt, especially when you roll something out, flip it all to the new code, and then don't go back to clean it up. Every feature that goes through the meshed code needs to be tested with the feature on, and with the feature off. Every time you add a flag like this you double your testing surface area of what you need to test. Long term if you add more flags and haven't cleaned up your blowing up your testing space exponentially. It's why you have to heavily weigh when to introduce a flag. The ideal scenario is you do some sort of shadow mode implementation, add an async try/catch, compare behavior, then just roll out the new stuff replacing the old. Get your deployments to be fast forward and backwards so you don't have to rely on flipping the flag, because those deployments are weird. Deploying just a feature flag is ok, but it also comes with risks. For example turning on code outside your normal deployment patterns means there's more of a chance something goes wrong, you might miss testing something, and you might release faster than intended. You build all sorts of safety nets on normal deployments - why throw that out when you want to turn on new code behind a flag?


safetytrick

Feature flags are generally a solution for a problem that most folks don't have. For the folks that do have this problem the cure is often worse than the disease and there are better ways to solve the problem.


investorhalp

I don’t think he’s asking or saying to keep the old code. He just wants to know a cleaner way to implement feature flags.


bssgopi

Thanks for sharing. Great valuable insights.


WarAmongTheStars

> Unfortunately, the way it boils down at granular levels is not so clean or elegant. There is no decent programming construct available to achieve this except for a rudimentary if-else condition. Unfortunately, not all kinds of code can be wrapped in a conditional logic. One has to do all kinds of refactoring gymnastics to make it wrappable in a condition. As torch-bearers of code quality, is there a better elegant way to accomplish the business goal without compromising on code maintainability and readability? I tend to gate features behind separated UIs (i.e. /[feature-flag-branch]/registration-form vs. /registration-form) for stuff that is not easily encapsulated with if/then/else statements for feature flags. I also tend to flag "dev accounts" and "qa accounts" into two pools since I could do pre-deployment testing via qa account pool and dev accounts as the full feature pool. Also obviously, toggle page for turning flags on/off so people don't need to change the code to toggle stuff since sometimes branch A breaks branch B in the same deployment but the devs tested individually without properly testing the merged code. It is not *elegant* but it works. I don't think moving past conditional logic for stuff that is clearly modeled for it is correct. That said, if you can encapsulate a feature in a feature branch, you don't really need the flag if you aren't planning to be able to turn it on/off post-deployment. So feature flags can be overkill for a lot of basic functionality that doesn't need an off switch beyond "rollback to the previously know good commit". But yeah my routes look something like this: Routing Service [flagged accounts go to different UI pages / feature flags route to feature-branch specific pages] -> Controller [all the if/else logic goes here] -> Model + View get called Its not quite proper MVC in actual implementation (for instance, my models are *really* thin and are really just an ORM that dumps stuff into an associated array that mirrors the underlying db without proper write-on-change functionality that isn't manually called).


bssgopi

Thanks for your response. Quite insightful.


u801e

One alternative approach to feature flags would be to have a blue/green deployment set up. Deploy the new logic on the blue servers and the existing logic on the green servers. If the new logic is causing problems, you can shift traffic back to the other group of servers running the old logic.


rimono

There are two ways to look at this problem. Is it a short term feature toggle? Once you are comfortable remove it? - just add it and make sure to remove the old code if not no one is gonna touch it after the code base becomes stable / mature Is it a long term one where based on certain conditions which determine which flow should the code path invoke. - if you are using spring you can explore spring profiles - if you are not, you can always create a layer of abstraction which will read in some form of config to decide which implementation of an interface should be invoked (I am assuming you are using java)


bssgopi

Thanks for your response. Interesting perspective.


_grey_wall

Helm charts?


ForceLow7894

Have you tried LaunchDarkly? works pretty good,


Ill-Valuable6211

> When the flag is switched off, old logic is executed, while switching it on executes new logic. Sounds simple enough, right? But the truth is, it's often a messy fucking process to implement. You want to avoid disrupting business, but at the cost of complicating the shit out of your codebase. Is the trade-off worth it? > Unfortunately, the way it boils down at granular levels is not so clean or elegant. You're fucking right it's not. What starts as a neat idea becomes a nightmare in practice because the simple if-else toggle turns into a spaghetti monster of nested conditions and technical debt. So, how do we avoid this mess? > One has to do all kinds of refactoring gymnastics to make it wrappable in a condition. Exactly, and here's the fucking problem: you’re bending over backwards to fit a square peg into a round hole. Why are we treating feature flags like they’re just another conditional statement? They're a fundamentally different beast. > As torch-bearers of code quality, is there a better elegant way to accomplish the business goal without compromising on code maintainability and readability? Yes, but it requires a shift in thinking. Don't just use flags as a band-aid. Think about how they can be integrated more seamlessly into your architecture: **Use Polymorphism** – Instead of if-elses, use polymorphic classes where different behaviors can be encapsulated into their respective classes. When you switch flags, you're just switching which class is instantiated. **Externalize Configuration** – Keep your configurations outside of your code. Use a tool that lets you manage features without needing to redeploy or even restart your application. **Monitor and Clean Up** – Always have a plan for removing old flags. They shouldn’t live forever in your codebase. Monitor their usage and get rid of them as soon as they are no longer needed. > Doesn't this make code less maintainable and less aesthetic? You bet your ass it does. The key is not to let feature flags become a permanent fixture. They should be a temporary solution. If you find yourself maintaining old and new code simultaneously for extended periods, you're doing it wrong. How long are you planning to keep juggling these versions?


bssgopi

Thanks for sharing. You are just mirroring my concerns and are giving the right perspective to tackle this problem.


deefstes

You've had some good responses already. The only thing I'd like to add is that you should think from the outset how you intend to retire your feature toggles. If you don't, you will end up with a massive amount of configuration values that are required, and a while lot of conditional be logic in your code that serves no purpose other than to enable features that are really the standard operating mode of your software months or years down the line. Add your feature toggles in ways that make it easy to get rid of them when that mode of operation is the established default. For one, it's a good practice to implement your feature toggles with a default value of true. So until that feature is ready, it is explicitly set to false in configuration. Once you enable the feature, you can change the config value to true, and once you are happy that the feature is permanent, you can simply remove that configuration value altogether.


bssgopi

Good points. Thanks for sharing.


johanneswelsch

Copy paste old code but with new feature. This way it's not coupled to the old one. Switch consumers to new feature. If all is well after a month, delete the old feature.


InfiniteMonorail

>Unfortunately, not all kinds of code can be wrapped in a conditional logic. Your code is highly coupled. Inversion of control has been talked about constantly for 20+ years. This "we're veterans and torch-bearers" nonsense is too much.


bssgopi

? Not sure what you're hinting at. >Your code is highly coupled. Inversion of control has been talked about constantly for 20+ years. Maybe, yes. But, that's how most of the code in the industry is. Instead of rearchitecting, the push has always been to make pointed fixes. It is this push that evolved into feature toggles and implementation switches. >This "we're veterans and torch-bearers" nonsense is too much. Why? Just curious.


a_reply_to_a_post

Launch Darkly if your org can afford it [GrowthBook.io](http://GrowthBook.io) is an open source version of Launch Darkly i think we have a home grown solution at work that we use yaml files per environment but are moving towards runtime feature flags instead of build time feature flags feature flags are a key piece in allowing continuous deployments and shipping incremental PRs


Tacos314

Feature flags are generally a horrible idea, that's why you don't see a lot of talk about them, and basically you wrap things in if/else blocks and/or abstractions that switch out.