Feature flags: best practices, and seven anti-patterns to avoid
What is a feature flag? Four types of toggles, what to try before adding one, and seven anti-patterns that end up running code nobody has tested.
14 min read
Sébastien Nobour
Founder of DEVEDANOS
Fixed price or time and materials: the question comes up as soon as you have software built. Most answers compare two ways of billing, and they assume that a fixed price locks in both the price and the feature list. Yet there are two kinds of fixed price. A fixed price with fixed scope puts a price on a written specification. A fixed-budget, flexible-scope contract fixes the budget and the problem to solve, and lets the features that address it evolve.
Fixed scope and time and materials have one thing in common: both rest on a prediction. The first predicts the cost of a feature list. The second predicts a number of days. And that prediction is put to the test by one question: when requirements change along the way, who pays?
Because requirements do change. When Microsoft measures the effect of its ideas through controlled experiments, only one in three improves the target metric. One third has no effect, one third makes it worse (Kohavi and Thomke, Harvard Business Review, 2017). Nobody knows in advance which ones. You find out through use.
Under a fixed price with fixed scope, the provider commits to delivering a list of features, described in a written specification, for a price set at signing.
Under time and materials, the provider supplies people and bills the time they spend, by the day. What is set at signing is the day rate.
Under a fixed-budget, flexible-scope contract, the price is set, and so is the problem to solve. What stays flexible is how it gets solved: the features that are developed.
So a fixed-scope contract locks in the total price and the list. Time and materials sets only the day rate. A fixed-budget contract locks in the budget and the problem, not the list. To see who carries the risk, you have to look at how each one arrives at its numbers.
Everything starts from the specification. The provider breaks the list down into tasks, then estimates each task in days of work. They add it all up. They multiply by their rate. Out comes a price.
That price rests entirely on estimates. And an estimate is still a guess about work that has not been done yet. In NoEstimates (ch. 1), Vasco Duarte reports data he collected at one company between 2001 and 2003, across seventeen projects. The average delay against the estimate was 62%. A project planned for three months took nearly five.
A provider who commits to a price knows this risk, and builds it into the figure. Evan Leybourn, in How Much Does It Cost? A Guide to Agile Contracts (section “Fixed contracts”), says it plainly: when price and scope are both fixed, the contingency goes up before the quote goes out. Tomas Rybing, in Applied Capacity Planning With NoEstimates (pp. 4-5), describes the same practice from the inside: a gut-feel multiplier applied to the estimate, to allow for the obstacles you know you will hit without knowing which ones. He mentions values such as 30%, or doubling it.
Duarte (ch. 2) shows where this stops working. A margin that is too wide makes the bid more expensive than the competition’s. And once the time is granted, work tends to expand to fill it: that is Parkinson’s law.
The schedule follows the same logic as the price. The estimated tasks are put in order, often in a Gantt chart, and grouped into milestones. Each milestone has its date. Acceptance testing comes at the end, once everything has been delivered.
This schedule is detailed, and that is what makes it hard to change. Duarte (ch. 7) points this out: changing the order of the work in a detailed plan means reworking all of it, the sequence of tasks, their content, who does them. The simpler the plan, the more easily it absorbs change.
Yet the list is written before the software exists, on the day you know least about how your teams will use it. Along the way, requirements shift. A planned feature is no longer needed. Another one, which nobody had thought of, becomes urgent. Each of these discoveries falls outside the signed list. It goes through a change request, priced separately. It becomes a change order, and the client pays for it.
The gaps can be large. Across 4,677 IT projects, the actual cost averages 1.8 times the estimated cost, or 80% more (Flyvbjerg et al., JMIS 2022). That average is pulled up by a minority of projects with extreme overruns: in the same sample, the median overrun is close to zero. But nobody knows, on the day they sign, which side their project will fall on.
So a fixed price with fixed scope covers estimation error, within the limits of the signed list. It does not cover changing requirements. Leybourn goes further for the case where price, scope and date are all fixed: in his view, such a project is unlikely to succeed without some degree of flexibility.
Under time and materials, the price of a day is known. The number of days is not.
The starting budget is still built the same way as for a fixed-scope contract: someone estimates the number of days needed and multiplies it by the rate. The difference is that this figure commits no one. It is a provisional budget. The invoice follows the days actually worked, backed each month by a timesheet.
If the work takes twice as long as planned, it costs twice as much. The estimation risk sits entirely with the client.
Leybourn (section “Time and material contracts”) nonetheless sees it as the most flexible contract. The client can stop as soon as what the rest would cost exceeds what it would bring in. To limit spending, he describes a capped variant, where the cap has to stay high enough for the investment to remain worthwhile. The budget becomes a limit again, but a limit that was, once more, estimated.
This is the strength of time and materials: the list stays open to change. The client changes priorities whenever they like, with no change order. Many teams then work in short iterations, two weeks for example. They estimate each item in story points, measure how many points they complete per iteration, and work out a date from that.
Duarte (ch. 2) points out the flaw in this mechanism: as the team understands the work better, it re-estimates what is left, and the average used for forecasting keeps moving.
He proposes something else (ch. 5). Stop estimating the size of items, and slice them small enough that they look alike. Count how many are finished each week. Extend that pace to forecast what comes next. He adds that work discovered along the way is not scope creep: it is value discovered. And he argues for a principle that turns the fixed-scope contract upside down (ch. 2): fix the time and the cost, and let the list vary.
Rybing applies this idea under the name capacity planning (pp. 2-6). Every Friday, his team counts the tasks finished on its board, which takes less than five minutes. The average gives a capacity: 18 tasks a week in his example. From there, a simple division: 213 defects to fix, 18 a week, so 12 weeks, twice the 6 weeks in the schedule. Or, within those 6 weeks, about half of the fixes.
Duarte himself no longer talks about estimating; he talks about forecasting. These tools are the best available when you are forced to predict. They limit the damage, and they push towards a flexible scope. But they still rest on a form of estimation: they assume that the past pace holds for what comes next. A guess about the future has been swapped for an extrapolation from the past.
Lastly, what time and materials sells is days. Nothing in the model requires usable software to be in your teams’ hands each month. And the provider has to keep authority over the people it supplies. When the client directs their work day to day, the arrangement can be reclassified as unlawful labour hire under French law: the French Labour Code prohibits any for-profit operation whose sole purpose is the supply of labour (article L8241-1).
For Leybourn, a contract is defined first of all by the level of risk each party agrees to carry. Fixed scope and time and materials present themselves as opposites. Yet they start from the same move: estimating the work before doing it. The fixed-scope contract turns that estimate into a price. Time and materials turns it into a provisional budget, then tries to keep visibility: timesheets, tracking of the days used, a recalculated end date.
Why do we cling to these forecasts? In his training course “Un retour à l’essence de l’Agilité”, Frédéric Leguédois categorises the needs estimates serve. Providing visibility and reassurance are among them. And in his talk “Éloge de la simplicité” (Devoxx France, in French), he describes the schedule as a reassuring mental picture in the face of uncertainty: “A schedule is an organisational comfort blanket” (our translation).
A comfort blanket soothes. It protects against nothing. A schedule recalculated every week gives the impression of steering the budget. The budget itself keeps following what the work actually costs.
The fixed price as such is not the problem. The problem is fixing the budget and the feature list at the same time. Fixing both puts all the risk of uncertainty on one of the parties, and nobody can adapt any more. Fixing nothing, on the other hand, lets the budget drift.
That leaves one combination neither of them offers: fix the budget and the problem to solve, leave the scope that addresses it flexible, and stop predicting what cannot be predicted.
Leybourn describes a related form: a price fixed per week or per iteration, a fixed date, a flexible feature list. The price no longer comes from an estimate: “The cost is effectively budgeted, instead of estimated”. He still measures the rate at which items are accepted, though, to forecast how many will fit in the time available. That is still a prediction.
This is where our model parts ways with it. It is a fixed price: a fixed monthly budget, with no end date to forecast and no pace to extend. What is fixed is the budget and the problem to solve. What stays flexible is the scope, that is, the features that address the problem. Each one is an experiment testing the same question.
How the budget is set. The monthly budget is built with you, from your figures and your goals, at a second meeting. It does not start from a feature list to price. It starts from the time you decide to invest in your software, weighed against what going without it costs you. The contract covers 15 working days per month per team member. We develop your custom application on a fixed budget, invoiced at the end of each month for the work done.
How the work is planned. There is no Gantt chart, no dated milestones, no pace extended to forecast an end date. The approach predicts what is predictable: the monthly budget and the development days per month. It does not try to predict the unpredictable: what your users will do with a feature before they have it in their hands. It belongs to what Leguédois calls working without projection. And it meets the need for visibility and reassurance in another way: Leguédois proposes meeting it with fine-grained slicing, fast releases to production and automated regression tests. In his view, these are what build trust. And it asks a single question: what is the most useful thing to do now?
Your application is usable within a month. Usable does not mean finished: your teams use it from the first month. When their use of a feature teaches us something, we apply it the same day. Every day, you see the application move forward on your staging environment.
What happens when requirements change. The problem stays the same. What changes is how it is solved, and nothing has to be renegotiated. The feature that is no longer needed comes off the list. The one that becomes urgent moves to the front. The budget does not move. What we develop, on the other hand, follows what your teams learn by using it.
That does not make it time and materials. What you receive each month is not a timesheet. It is software your teams use.
It is a fixed price, but not a fixed-scope one. Your budget buys ongoing work to ease this problem, starting on the first day of development. We aim to solve it completely, but we cannot guarantee that or put a date on it. You do not wait for that day for the problem to start easing. Each month you see what comes out of it, and you decide whether to continue. You can terminate the contract in writing at any time, without justification.
A results guarantee is there to protect a client who cannot leave. Here, you can leave every month.
So that what worked last month still works this month, we apply the Zero-Regression Guarantee: every regression is fixed and covered by an automated test so that it does not come back, at no extra cost.
Under a fixed price with fixed scope, the provider carries the estimation error on the signed list. The client carries changing requirements, one change order after another.
Under time and materials, the client carries both. A change needs no change order, but every extra day is added to the invoice.
Under a fixed-budget, flexible-scope contract, there is no estimate left to overrun. The budget is known before work starts, and it holds, because nothing depends on a prediction. Changing requirements change what gets developed, not what gets paid. And each month, the client keeps the decision to continue. So their technical partner has every reason to do the work well, so that the client does not end the contract the following month. Each useful month gives the client a reason to continue, and gives their technical partner a reason to take care over the next one: a virtuous circle.
A fixed price with fixed scope still suits a need that will not change. Work you repeat the same way every time becomes predictable. Software, by contrast, is always built for the first time.
Why a price set by adding up estimates so often exceeds the planned budget: that is the subject of our article on budget overruns.
Our guide covers these sources in detail. You will also find the questions to ask before signing a software development quote.
Do you need software built, or do you have a tool that no longer keeps up with your business? Shall we talk?
What is a feature flag? Four types of toggles, what to try before adding one, and seven anti-patterns that end up running code nobody has tested.
How much should you budget to build an app? The figure alone is not enough: aim for a goal rather than a feature list, with users from the first month.
Predictive or adaptive approach? The real dividing line is not between waterfall and agile. It runs between predicting and adapting. What that means for software.