Elke Asana-implementatie heeft een beheerdersconsole. Hier configureren IT-beheerders hoe hun bedrijf Asana gebruikt, zoals het aanpassen van wachtwoordvereisten, rollen en toestemmingen, of bestanden vanuit Dropbox kunnen worden bijgevoegd en wie standaard een nieuw project kan zien.
Naarmate Asana groeide, verzamelde de beheerdersconsole jarenlange aangepaste logica en eenmalige lapmiddelen, waardoor het steeds duurder werd om beheermogelijkheden te bouwen en te onderhouden. Neem één administratieve instelling: de standaard privacy voor nieuwe projecten. Een beheerder kiest of een nieuw project in eerste instantie zichtbaar is voor de hele organisatie, zichtbaar is voor het team, of privé is voor uitgenodigde leden. Eenvoudig te beschrijven, maar er schuilt veel complexiteit achter:
Zit deze functie in het abonnement van de klant?
Betaalden ze er vroeger voor, stopten ze ermee en zitten ze nu vast aan een instelling die ze niet meer kunnen wijzigen?
Zijn ze een HIPAA- of FedRAMP-klant, waar alleen rollen met verhoogde rechten dit kunnen bewerken?
Wordt een keuze onbeschikbaar gemaakt door een andere instelling?
Moet er een infobanner worden getoond om de huidige beperkingen te beschrijven?
Elk team dat een besturing voor beheerders wilde toevoegen, moest dat allemaal goed doen. De meesten besloten dat het de moeite niet waard was, en na verloop van tijd werd de kloof tussen wat Asana kon doen en wat een beheerder kon beheren groter. Dit wordt geïllustreerd door het feit dat sommige instellingen alleen op bedrijfsbreed niveau kunnen worden geconfigureerd, waardoor het voor IT-beheerders moeilijk is om de instelling alleen toe te passen op een subset van hun gebruikers.
Hier is een fragment voor het dialoogvenster met de privacyinstellingen van het project, dat wordt gebruikt om te bepalen of het moet worden uitgeschakeld en of er een banner moet worden weergegeven:
Er moet daar veel logica worden geanalyseerd - licenties voor functies, beheer, overschrijvingen vanwege de implementatiestructuur en gebruikersrollen, vooral voor beoordelaars. Om zorgvuldig te zijn, zou je de testmatrix in je hoofd moeten reconstrueren om te bepalen of deze correct is.
En dat is nog maar het dialoogvenster. Of de rij überhaupt op de instellingenpagina wordt weergegeven, is ergens anders beslist, en ook nog eens inconsistent:
Drie rijen, drie mechanismen, en de gating staat niet altijd in hetzelfde bestand. Dus om de vraag te beantwoorden "welke instellingen ziet deze klant eigenlijk?" moest je niet alleen elke rij lezen, maar ook elk onderdeel scannen. Die vraag komt vrij vaak voor: klantondersteuning die probeert uit te leggen waarom een instelling voor een klant is verdwenen, een PM die een duidelijk antwoord wil op de vraag of een nieuwe bediening een snelle wijziging is of een wijziging van twee weken, een nieuwe medewerker die probeert de ene plek te vinden die bepaalt wat een specifieke gebruiker kan zien.
In vogelvlucht waren er vier dingen die het werken in de beheerdersconsole duur maakten:
Duur om te controleren. Logica bevond zich overal waar de auteur ze plaatste, dus een PR kon speciaal gedrag introduceren zonder dat dit voor een reviewer duidelijk was, en juistheid was niet iets wat je gemakkelijk kon verifiëren door alleen maar te lezen.
Gebrek aan standaardisatie maskeerde bugs. We hadden al lang bestaande bugs die moeilijk op te sporen waren. Vele waren te wijten aan afwijkingen tussen productspecificatie en implementatie, veroorzaakt door een dichte verspreiding van op maat gemaakte implementaties. Teams namen willekeurige beslissingen, waardoor elk bedieningselement zijn eigen eigenaardigheden had.
Duur om te veranderen. Om één wijziging voor de eindgebruiker door te voeren, moest je elke plek vinden waar een regel was gecodeerd, en er was zelden één enkel definitiepunt.
Duur om te testen. Het opzetten van tests vereiste diepgaande kennis van de backend-statussen, en uitgebreide handmatige tests van eindimplementaties waren onhaalbaar vanwege het aantal interagerende dimensies.
We hebben een declaratief raamwerk voor administratieve controles gemaakt om te dienen als de bron van waarheid in de codebase. Een controle geeft nu aan wat het is:
Elk veld hier komt overeen met een tak van het bovenstaande dialoogvenster: requiredAdminRole is de HIPAA/super-admin-controle, upsellBehavior zijn de twee upsell-takken, en churnBehavior is het geval van de vertrokken klant, waardoor ze de standaardinstellingen kunnen herstellen en niets anders.
Als onderdeel hiervan stelt het raamwerk hooks bloot die engineers gebruiken om de berekende status van de controle af te leiden. Kijk eens hoe hetzelfde dialoogvenster over projectprivacy er nu uitziet:
De if-keten van de banner is samengevallen tot één gedeeld component dat wordt aangestuurd door een gecentraliseerde hook. Het raamwerk behandelt de combinatorische logica van alle verschillende scenario's, en de SME's die verantwoordelijk zijn voor het onderhoud ervan, die het administratieproduct grondig begrijpen, kunnen met vertrouwen ingrijpende wijzigingen doorvoeren. Nu gebruiken we strikte typen om implementeerders te helpen bij het invullen van de verplichte informatie die nodig is om hun instelling in alle mogelijke scenario's correct weer te geven. Cruciaal is dat ze de fijne kneepjes van die scenario's niet hoeven te begrijpen, of hoe ze met elkaar in wisselwerking staan.
Deze instellingen zijn toegankelijk via rijen in de gebruikersinterface van de beheerdersconsole. De zichtbaarheid van die rijen kreeg dezelfde behandeling, en hier komt het tweede raamwerk om de hoek kijken. Een rij in het instellingenregister beschrijft niet zijn eigen zichtbaarheidsregels, maar koppelt deze in plaats daarvan aan de besturingselementen die deze vertegenwoordigen:
De array met besturingselementen is de toegevoegde waarde. Het bevat hetzelfde ProjectDefaultPrivacy-object dat het dialoogvenster doorgeeft aan useAdminConsoleControl, en het register voert het uit via dezelfde bron van waarheid, zodat de pagina en het dialoogvenster niet met elkaar in strijd kunnen zijn. Vroeger werd dit afzonderlijk berekend, waardoor discrepanties tot twee storingsscenario's konden leiden: een rij die zichtbaar is, maar een dialoogvenster opent dat je niet kunt gebruiken, en een instelling waar een klant voor betaalt, maar waarvoor geen rij is om deze te bereiken. Door het te centraliseren, werd deze categorie bugs geëlimineerd.
Tests die de gecentraliseerde raamwerken hebben overgenomen, hebben de ervaring van PR-reviewers aanzienlijk verbeterd. Neem bijvoorbeeld het testen van de zichtbaarheid van rijen, wat antwoord geeft op de vraag "welke instellingen ziet deze klant eigenlijk?" vraag van eerder. In plaats van testcode is een scenario gewoon data: een persona, een domeinstatus en de pagina's waarop het wordt weergegeven.
En een rij geeft alleen aan in welke genoemde scenario's deze moet voorkomen:
Er is geen render-aanroep of bewering om te schrijven. Een dynamische testsuite leest de catalogus en controleert elke rij aan de hand van elk scenario waarin deze wordt genoemd. De catalogus is nu de enige plek die aangeeft wat een klant ziet, gecontroleerd door een machine. Niet meer afhankelijk zijn van een zorgvuldige codereviewer of de auteur om hun eigen testcases correct te identificeren en te schrijven.
We zijn eind 2025 met dit werk begonnen, omdat we anticipeerden op de behoefte om engineers die geen SME zijn in staat te stellen om vol vertrouwen te bouwen in de beheerdersconsole. In die tijd was het doel niet om te optimaliseren voor LLM-prestaties, maar zoals blijkt, doet het standaardiseren en stroomlijnen van de ervaring voor engineers hetzelfde voor AI-agenten.
Voordat we deze raamwerken bouwden, hebben we AI op dit migratieprobleem losgelaten, wat technisch gezien werkte. Het probleem was dat noch de agent, noch de beoordelaar kon zeggen of de tests daadwerkelijk correct waren, wat leidde tot vals vertrouwen en onopgemerkte hiaten. AI lost het gebrek aan structuur niet op, het produceert gewoon meer code, sneller, bovenop de structuur die er al is. Google maakte een vergelijkbaar argument voor het typesysteem van Go in AI-ondersteunde ontwikkeling: statische types fungeren als een geautomatiseerd vangnet, omdat LLM's vatbaar zijn voor het hallucineren van eigenschappen en het niet-overeenkomen van types in verschillende bestanden. TypeScript is niet statisch strikt zoals Go, maar een raamwerk kan er dezelfde garantie bovenop bouwen: definieer het type van de control één keer op raamwerkniveau, en elke implementatie moet er op het gebruikspunt bij passen.
Zodra de raamwerken klaar waren, begonnen we ons voor te bereiden op het delegeren en paralleliseren. Ik gebruikte onze nieuwe spec-gestuurde ontwikkelingstool [link placeholder: eng blog post on spec driven development: Asana Eng Blog - Spec-gestuurde ontwikkeling: De goede punten om een vaardigheid te bouwen die de taak van begin tot eind uitvoert. Het codeert de hele conversie: het definiëren van het besturingselement, het aanroepen van de hook, het vervangen van de banners, het bijwerken van de fragmenten, het toevoegen van de nieuwe declaratieve tests, plus een zelfbijwerkende checklist en een logboek van randgevallen uit eerdere conversies. Van alle ~150 migraties had 91% geen revisie nodig na beoordeling.
Het vergt niet veel inzet om een agent te laten starten met het schrijven van een PR, en het beoordelen van die PR ook niet. Aangezien alles op een voorspelbare manier wordt gedeclareerd, hoeven beoordelaars geen SME's in administratie te zijn om te controleren of de implementatie overeenkomt met de productspecificatie. Cruciaal is dat dit de pool van in aanmerking komende reviewers openstelt voor een veel bredere groep engineers, wat de snelheid meer verhoogt dan alleen een bredere trechter bovenaan die PR's creëert. We zijn niet de enigen die de review voor dit tijdperk opnieuw bekijken: GitHub heeft de eigen reviewagent van Copilot opnieuw opgebouwd rond gestructureerd PR-bewijs om menselijke reviewers te helpen sneller tot de juiste vragen te komen, waardoor hun reviewkosten met ongeveer 20% worden verlaagd.
De oorspronkelijke migratie van ~150 items over meerdere raamwerken werd van begin tot eind beschouwd als handmatig, eenmalig technisch werk. Door eerst de raamwerken te bouwen en vervolgens de migratie te delegeren aan engineers die daarna toezicht houden op agents, konden we de hele inzet meer dan een maand eerder opleveren dan het oorspronkelijke plan vereiste.
Het bouwen van deze raamwerken was nooit een project op zich. Het kwam voort uit noodzaak, uit een roadmap die parallel moest worden uitgevoerd en geschaald, met beperkte en wisselende personeelsbezetting onderweg, en zonder dat elke bijdrager eerst een domeinexpert hoefde te zijn. We hebben al gezien dat het werkt buiten het team dat het heeft gebouwd: 18 van de 66 controles in het raamwerk van vandaag zijn geschreven door ingenieurs van 8 verschillende teams.
Nu zijn we op zoek naar de volgende plek om dit soort investeringen te doen. Sterker nog, de argumenten zijn nu sterker dan voordat we begonnen: een goed ontworpen, declaratief raamwerk maakt niet alleen de beoordeling gemakkelijker, maar bepaalt ook of een agent iets betrouwbaars produceert, of alleen iets snels. Het is ook wat autonome beoordeling plausibel kan maken: Cloudflare heeft een systeem gebouwd waarin een AI-beoordelaar schone code goedkeurt en zelfstandig echte problemen blokkeert, en dat werkt alleen omdat hun inputs gestructureerd genoeg zijn om de beoordelaar te laten vertrouwen. Of de onze voldoende gestructureerd zijn om hetzelfde te proberen, is een goede volgende vraag.
Leo Zhang is een software-ingenieur in het Admin Foundations-team, dat IT-beheerders in staat stelt hun organisaties te beheren. Momenteel verbetert hij de ontwikkelingservaring van andere productengineers in de beheerdersconsole door te investeren in de technische raamwerken die ons product ondersteunen.
Het ontwerpen, implementeren, testen en socialiseren van deze wijzigingen was een enorme teaminzet. Dit werd mogelijk gemaakt door de bijdragen van andere engineers van het Admin Foundations-team: Yunus Rahbar, Maryam Booshehrian, Saverio Castelli, Bronwyn Damm, Cindy Yu, Calvin Norton en Jaxsun McCarthy Huggan. Walter Li van het Agent Success Tiger-team heeft enorm geholpen bij het opzetten van de juiste AI-tools voor deze migraties.
Lan Cheng, Emerson Murphy-Hill, Mark Canning, Ciera Jaspan, Collin Green, Andrea Knight, Nan Zhang en Elizabeth Kammer, "What Improves Developer Productivity at Google? Code Quality," ESEC/FSE '22, november 2022. https://doi.org/10.1145/3540250.3558940
"Orchestrating AI Code Review at Scale," Cloudflare Blog, april 2026. https://blog.cloudflare.com/ai-code-review/
Napalys Klicius, "Betere hulpmiddelen maakten de codereview van Copilot slechter. Zo hebben we het daadwerkelijk verbeterd," The GitHub Blog, juli 2026. https://github.blog/ai-and-ml/github-copilot/better-tools-made-copilot-code-review-worse-heres-how-we-actually-improved-it/
"Why Go is an Ideal Language for AI-Assisted Software Engineering," Google Developers Blog, augustus 2026. https://developers.googleblog.com/why-go-is-an-ideal-language-for-ai-assisted-software-engineering/