Wat kost een app laten maken? Wat het bedrag niet zegt
Hoeveel budget hebt u nodig om een app te laten maken? Het bedrag alleen zegt te weinig: stuur op een doel in plaats van een lijst, met gebruikers vanaf de eerste maand.
13 min leestijd
Sébastien Nobour
Oprichter van DEVEDANOS
Een feature flag, of feature toggle, is een schakelaar in de code. Afhankelijk van de waarde ervan volgt de applicatie het ene of het andere pad. DORA definieert het als een voorwaardelijke instructie op basis van configuratie-instellingen (“Working in small batches”).
Het instrument is eenvoudig. De fouten die ermee worden gemaakt, zijn dat minder: ze laten in productie combinaties draaien die niemand heeft getest. Pete Hodgson zegt het al in de inleiding van zijn artikel over het onderwerp: toggles brengen complexiteit met zich mee, en je moet proberen hun aantal te beperken (“Feature Toggles (aka Feature Flags)”, 2017).
Hodgson deelt toggles in vier categorieën in, op basis van twee criteria: hoe lang ze bestaan, en hoe vaak hun beslissing verandert.
Weten tot welke categorie een toggle behoort, zegt hoe lang hij mag blijven bestaan. Hodgson voegt eraan toe dat verstandige teams hun toggles behandelen als voorraad die kosten met zich meebrengt, en die voorraad zo laag mogelijk proberen te houden.
Martin Fowler maakt er een regel van: release toggles zijn de laatste keuze om een functionaliteit in productie te krijgen. De eerste keuze is haar op te knippen, zodat de stukken zonder risico in productie kunnen worden genomen (“Feature Flag”, 2010).
Eerste techniek: als laatste aansluiten. Je bouwt alles wat achter de interface zit, integreert het in de trunk en deployt het, maar niets leidt ernaartoe. De laatste commit voegt het toegangspunt toe, de link of de knop, en maakt de functionaliteit zichtbaar. Humble en Farley beschrijven een nieuwe interface die werd ontwikkeld onder een adres waar geen enkele link naartoe wees, en daarna stuk voor stuk op de bestaande navigatie werd aangesloten. De applicatie bleef al die tijd werken (Continuous Delivery, 2010, p. 348). Fowler noemt dat laatste stuk de keystone interface (“Keystone Interface”, 2020).
Tweede techniek, om bestaand gedrag te wijzigen: branch by abstraction. Je zet een abstractielaag voor het deel dat moet veranderen, bouwt de nieuwe implementatie naast de oude, haalt daarna de oude weg, en soms ook de abstractie zelf (p. 349).
Dan blijft het geval over waarin iemand de functionaliteit in productie moet zien vóór alle anderen, om haar te testen en goed te keuren. Dan is een toggle gerechtvaardigd. Zelfs dan raadt Fowler aan hem alleen op de gebruikersinterface te zetten, zodat de toggle points niet door de hele code verspreid raken.
Waarom je met deze technieken elke dag onafgemaakte code kunt committen, leggen we uit in ons artikel over trunk-based development.
“Aan op de acceptatieomgeving, uit in productie.” De code ziet er zo uit:
// Anti-pattern: de beslissing hangt af van de naam van de omgeving.
if (process.env.APP_ENV === "staging") {
showInvoiceExport();
}
Het probleem past in één zin: productie draait een combinatie die de pipeline nooit heeft getest. De acceptatietests draaiden met de schakelaar aan; productie draait met de schakelaar uit.
MinimumCD beschrijft het gevolg. Codepaden die alleen voor productie bedoeld zijn, worden nooit door de testsuite uitgevoerd, en als productie andere logica draait, is de validatie op de acceptatieomgeving per definitie onvolledig (“Hard-Coded Environment Assumptions”). Hodgson zegt hetzelfde: elke omgevingsspecifieke override gaat in tegen het ideaal van Continuous Delivery, dat deployable units en hun configuratie zo onafhankelijk mogelijk van de omgeving wil houden. Humble en Farley legden het principe al vast: overal dezelfde binaries deployen, zodat wat je in productie zet ook is wat je hebt getest (Continuous Delivery, p. 42).
In plaats daarvan: de toestand van de toggle hoort bij de configuratie van de applicatie, wordt met het artefact meegeleverd en is in elke omgeving gelijk. Wat varieert, is de doelgroep, die per request wordt bepaald. Daar komen we verderop op terug.
Om tijd te besparen wordt er getest met “alles aan”. Dat is de configuratie van morgen. Het is niet de configuratie die het publiek vandaag krijgt.
Hodgson is duidelijk. Het belangrijkste is de toggleconfiguratie te testen die in productie actief zal zijn. Het is verstandig ook de fallbackconfiguratie te testen. En veel teams voegen tests toe met alle toggles aan, om verrassende regressies bij de volgende release te voorkomen.
In plaats daarvan: minstens twee geteste configuraties, die van productie en die waarin alles aan staat.
Een release toggle dient om onafgemaakt werk te verbergen. Volgens Hodgson hoort hij in de regel niet veel langer dan een à twee weken te blijven staan. Een toggle die maanden bestaat, verbergt geen onafgemaakt werk meer: hij houdt twee versies van de software in stand, en elk daarvan moet worden getest.
In plaats daarvan: een vervaldatum vanaf het moment dat hij wordt aangemaakt, en een test die faalt zodra die datum is verstreken.
Elke toggle verdubbelt het aantal mogelijke combinaties. Twee toggles geven er vier; tien geven er meer dan duizend.
Hodgson beschrijft wat teams doen die deze voorraad laag houden. Ze zetten een opruimtaak op de backlog zodra een toggle wordt aangemaakt. Ze geven elke toggle een vervaldatum. Sommige schrijven “tijdbommen”, die een test laten falen of zelfs weigeren de applicatie te starten zodra de datum is verstreken. Andere leggen een maximum vast voor het aantal toggles dat tegelijk mag bestaan. Humble en Farley gaven het advies al: houd niet te veel opties aan, en snoei ze zorgvuldig zodra ze hun werk hebben gedaan (Continuous Delivery, p. 348).
Een nieuwe pagina, een nieuwe sectie, een nieuw rapport: niets toont ze zolang er geen link naartoe leidt. Er een toggle aan toevoegen betekent de complexiteit van een schakelaar betalen voor wat de ontbrekende link al opleverde.
Fowler formuleert het zo: gebruik release toggles alleen als je niet in kleine stukken kunt releasen en ook geen keystone interface kunt gebruiken (“Feature Flag”).
In 2012 verloor een Amerikaans effectenhuis in ongeveer 45 minuten meer dan 460 miljoen dollar. De beschikking van de SEC, de Amerikaanse beurstoezichthouder, beschrijft hoe het verliep (beschikking nr. 34-70694, 2013, § 13 tot en met 17).
De nieuwe code hergebruikte een flag die vroeger diende om een oude functionaliteit te activeren. Die functionaliteit werd al jaren niet meer gebruikt, maar haar code stond er nog en kon nog worden aangeroepen. Bij de deployment kreeg een van de acht servers de nieuwe code niet. Op die server activeerden de orders met de hergebruikte flag de oude code, die niet meer goed werkte.
Twee fouten kwamen bij elkaar: een flag die van betekenis veranderde, en dode code die nooit was opgeruimd. Farley noemt hetzelfde geval voor een derde fout, handmatig deployen, server voor server (Continuous Delivery Pipelines, 2021, p. 112 en 113). Hodgson brengt het als waarschuwing voor wat er gebeurt als je je toggles slecht beheert.
In plaats daarvan: een toggle heeft één betekenis, voor één functionaliteit, en verdwijnt samen met haar. Een nieuwe behoefte krijgt een nieuwe toggle, onder een nieuwe naam. De code die de toggle vervangt, wordt tegelijk met hem verwijderd.
De toggle wordt in de browser geëvalueerd. De nieuwe sectie staat in de pagina, maar wordt verborgen door een CSS-regel of door het hidden-attribuut. De inhoud wordt toch naar elke bezoeker gestuurd.
De HTML-specificatie zegt het met zoveel woorden. Het hidden-attribuut wordt doorgaans met CSS geïmplementeerd, en kan dus door CSS worden overschreven. Verborgen elementen blijven actief: hun scripts worden uitgevoerd, hun formulieren worden verzonden (WHATWG, HTML Living Standard, “The hidden attribute”). Elke bezoeker kan via de ontwikkelaarstools van zijn browser zichtbaar maken wat verborgen was.
In plaats daarvan: op de server beslissen. Een bezoeker die niet tot de doelgroep behoort, krijgt de inhoud gewoon niet.
Achter elke toggle zitten twee vragen. In welke toestand staat hij? Wie ziet de functionaliteit? Die twee door elkaar halen is anti-pattern 1.
De toestand hoort bij de configuratie van de applicatie. MinimumCD rekent feature flags tot de interne configuratie van de applicatie, die niet per omgeving verschilt. Die configuratie wordt met het onveranderlijke artefact gedeployd en verandert niet meer zodra het artefact is gebouwd (“Application Configuration”). Hetzelfde artefact, met dezelfde toestand, doorloopt dus de acceptatie en gaat daarna naar productie.
De doelgroep wordt per request bepaald. Hodgson raadt aan het toggle point, de plek in de code waar de beslissing wordt toegepast, te scheiden van de logica die de beslissing neemt. Hij wijst ook op het risico van overrides via een cookie, een URL-parameter of een HTTP-header: een nieuwsgierige of kwaadwillende gebruiker kan dan zelf de toestand van de toggle wijzigen. De doelgroep wordt dus bepaald op basis van een identiteit die op de server is geverifieerd, nooit op basis van een parameter die de browser kan vervalsen.
Hier is een getypeerd register van toggles, geschreven voor dit artikel:
export type ToggleState = "in-progress" | "in-review";
export interface ReleaseToggle {
name: string;
state: ToggleState;
createdOn: string;
expiresOn: string;
}
export const MAX_RELEASE_TOGGLES = 3;
export const releaseToggles: readonly ReleaseToggle[] = [
{
name: "invoice-export",
state: "in-review",
createdOn: "2026-10-05",
expiresOn: "2026-10-19",
},
];
En de beslissing, gescheiden van het toggle point. De doelgroep komt van de geauthenticeerde gebruiker, nooit van de naam van de omgeving:
export type Audience = "public" | "reviewers";
export interface Viewer {
roles: readonly string[];
}
export function audienceFor(viewer: Viewer | null): Audience {
return viewer?.roles.includes("reviewer") ? "reviewers" : "public";
}
export function isVisible(toggle: ReleaseToggle, audience: Audience): boolean {
return toggle.state === "in-review" && audience === "reviewers";
}
Een toggle in in-progress is voor niemand zichtbaar. Een toggle in in-review is alleen zichtbaar voor reviewers. Er bestaat geen toestand “zichtbaar voor iedereen”: de functionaliteit voor iedereen zichtbaar maken betekent de toggle verwijderen.
Twee tests volstaan om anti-pattern 2 af te dekken. De eerste rendert de pagina zoals het publiek haar krijgt, met de configuratie die echt wordt meegeleverd. De tweede rendert haar zoals een reviewer haar krijgt, met de toggle aan. Ze zijn hier geschreven in de syntaxis die Jest en Vitest gemeen hebben; renderInvoicesPage is een fictieve functie die de pagina op de server rendert.
test("het publiek krijgt de pagina zonder de factuurexport", async () => {
const page = await renderInvoicesPage({ viewer: null });
expect(page.text).not.toContain("Facturen exporteren");
});
test("een reviewer krijgt de pagina met de factuurexport", async () => {
const page = await renderInvoicesPage({ viewer: { roles: ["reviewer"] } });
expect(page.text).toContain("Facturen exporteren");
});
De eerste test beschermt wat het publiek vandaag ziet. De tweede controleert dat de functionaliteit werkt voordat ze voor iedereen zichtbaar wordt.
Een release toggle doorloopt drie stappen. Hij ontstaat samen met de functionaliteit, voor niemand zichtbaar. Hij gaat naar de review, zichtbaar voor reviewers. Daarna verwijdert de releasecommit hem, samen met het oude pad als dat er was: de voorwaarde verdwijnt, en de nieuwe code wordt het enige pad.
Om ervoor te zorgen dat dat einde er komt, vormen twee tests de “tijdbom” die Hodgson beschrijft:
test("geen enkele release toggle is over zijn vervaldatum heen", () => {
const today = new Date().toISOString().slice(0, 10);
const expired = releaseToggles
.filter((toggle) => toggle.expiresOn < today)
.map((toggle) => toggle.name);
expect(expired).toEqual([]);
});
test("het aantal toggles blijft binnen het maximum", () => {
expect(releaseToggles.length).toBeLessThanOrEqual(MAX_RELEASE_TOGGLES);
});
De eerste test faalt op de dag dat een datum is verstreken, en de pipeline springt op rood. Het team heeft dan twee opties: de functionaliteit in productie nemen en de toggle verwijderen, of de functionaliteit verwijderen. De tweede test verhindert dat er een nieuwe toggle bijkomt zolang het maximum is bereikt.
Voor onze klanten dient een toggle om een functionaliteit in productie te testen en goed te keuren voordat ze voor iedereen zichtbaar is. Zo beschrijven we het in onze aanpak: “Zodra de functionaliteit is goedgekeurd, maken wij de nieuwe versie zichtbaar. De code is al uitgerold via onze geautomatiseerde deployment-pipeline en wacht op dat groene licht om geactiveerd te worden in productie. Geeft u het testen liever niet uit handen, dan test en keurt u elke functionaliteit zelf goed.”
Voor de ontwikkeling van software op maat werken we tegen een vast budget, aan het einde van elke maand gefactureerd voor het geleverde werk. Uw applicatie is binnen een maand bruikbaar. Uw teams gebruiken haar vanaf de eerste maand, en dat gebruik bepaalt wat we de maand erna ontwikkelen.
En om ervoor te zorgen dat wat vorige maand werkte, ook deze maand werkt, hanteren we de Nulregressiegarantie: elke regressie wordt verholpen en afgedekt door een geautomatiseerde test, zodat ze niet terugkomt, zonder meerkosten.
In onze gids vindt u de vragen die u moet stellen voordat u een offerte voor softwareontwikkeling tekent.
Wilt u software laten ontwikkelen, en wilt u dat die zo wordt gebouwd? Zullen we kennismaken?
Citaten uit het Engels zijn door ons vertaald.
Hoeveel budget hebt u nodig om een app te laten maken? Het bedrag alleen zegt te weinig: stuur op een doel in plaats van een lijst, met gebruikers vanaf de eerste maand.
Voorspellende of adaptieve aanpak? De echte scheidslijn loopt niet tussen de watervalmethode en agile, maar tussen voorspellen en je aanpassen. Wat dat betekent voor software.
Wat is een MVP in softwareontwikkeling? Niet versie 1 van een applicatie, maar de kleinste test die laat zien of een idee het ontwikkelen waard is. En wat daarna komt.