Spelen met code: een efficiënte wendbare aanpak (Nederlands (Dutch))

Spelen met code: een efficiënte wendbare aanpak

Sunday, 23 November 2025

//

20 minute read

Waarom het behandelen van uw tak als een zandbak... en spelen als legitiem werk... leidt tot betere software met minder stress.

Warme opname: De meeste ontwikkelaars proberen perfect te zijn in elke fase van ontwikkeling, en het doodt zowel hun creativiteit als hun productiviteit. Hier is een betere manier.

Inleiding

Ik heb software professioneel gebouwd voor... Nou, laten we zeggen dat ik me herinner toen "Agile" een nieuw idee was en niet een bedrijfsbuzzword die door projectmanagers werd bewapend om meer stand-ups te rechtvaardigen.

In de loop der jaren heb ik iets gemerkt: de beste code die ik ooit geschreven heb kwam uit projecten waar ik me voelde toestemming om af te spelen. De slechtste code kwam van projecten waar elke toetsaanslag voelde alsof het werd gecontroleerd, waar ik probeerde te schrijven "productie-klaar" code vanaf minuut één.

Dit is niet toevallig. Creativiteit en druk mengen zich niet goed.

Dus ik heb een aanpak ontwikkeld die de rommelige, creatieve exploratie scheidt van de gepolijste, productie-ready levering. Ik noem het "Laat het werken, maak het mooi, sluit het af." - maar eigenlijk gaat het erom dat je jezelf toestemming geeft om te experimenteren zonder het gewicht van perfectie boven je te hangen.

De drie fasen

Laat me eerlijk zijn: dit gaat niet over slordig zijn of discipline vermijden. toepassing van de juiste discipline op het juiste moment.

graph LR
    subgraph "Phase 1: Make It Work"
        A[New Requirement] --> B[Explore & Experiment]
        B --> C{Does It Work?}
        C -->|No| D[Try Different Approach]
        D --> B
        C -->|Yes| E[Basic Solution]
    end

    subgraph "Phase 2: Make It Pretty"
        E --> F[Refactor & Clean]
        F --> G[Apply SOLID Pragmatically]
        G --> H[Get Stakeholder Feedback]
        H --> I[Polished Solution]
    end

    subgraph "Phase 3: Lock It Down"
        I --> J[Add Tests]
        J --> K[Security Review]
        K --> L[Add Monitoring]
        L --> M[Production Ready]
    end

    style A stroke:#f59e0b,stroke-width:3px
    style E stroke:#0ea5e9,stroke-width:3px
    style I stroke:#8b5cf6,stroke-width:3px
    style M stroke:#10b981,stroke-width:4px

Fase 1: Laat het werken

De mantra: Speel eerst, bevestig je veronderstellingen.

Dit is de fase waarin uw tak is een zandbak. Messy code is prima. Dode uiteinden zijn prima. Beginnend over drie keer is boeteJe bouwt hier geen kathedraal, je schetst op een servet.

Wat je probeert uit te zoeken:

  • Gedraagt deze API zich eigenlijk zoals de docs beweren? (Spoiler: het doet het zelden)
  • Kan ik dit probleem oplossen met het gereedschap dat ik heb?
  • Wat zijn de werkelijke eisen, niet degene die op het ticket staan?
  • Is dit een probleem van twee uur of twee weken?

Het kritische inzicht: Totdat je een PR verhoogt, is je branch De jouwe.. Het is uw experimentele laboratorium. Niemand hoeft te zien uw valse starts, uw commentaar-out debugging code, uw "TODO: dit is verschrikkelijk, fix later" opmerkingen. Maar check in OFTEN alle keer dat je iets dat werkt, commit en push. Haak in uw CI-pijpleiding; een goede pijplijn zal u meer informatie (integratie testen, breken veranderingen elders, enz.). Het is fijn om in te checken lelijk, nauwelijks aan elkaar gestikt franken-code. Dat is het punt. Zelfs als een drie-decade veteraan, Ik doe dit nog steeds. Het bevrijdt mijn geest.

Bijwerkingen: Frequent commits zijn een hartslag. In remote/async teams, een gestaag spoor van "lelijke maar progressieve" commits verzekert iedereen die werk beweegt en zonder dat je productiviteit in Slack uit te voeren.

Deze psychologische vrijheid is essentieel. Als je weet dat je alles kunt weggooien en opnieuw kunt beginnen, maak je moedigere beslissingen. Je probeert die rare aanpak die waarschijnlijk niet zal werken. Soms werkt het briljant. Soms moet je een artikel lezen, een YouTube video bekijken, denken voor een tijdje. Onthoud: je taak is om goede software en goede beslissingen te leveren, niet om snel te typen. GEEN TYPIST.

// Phase 1 code looks like this - and THAT'S OKAY
public async Task<Result> ProcessThing(Request req)
{
    // TODO: what if this is null?
    var data = await _api.GetSomething(req.Id);

    // This probably isn't right but let's see what happens
    var transformed = data.Items
        .Where(x => x.Status != "deleted") // Is this the right filter?
        .Select(x => new Thing { Name = x.Name }); // Missing loads of fields

    // HACK: hardcoded for now
    return new Result { Items = transformed.ToList(), Total = 42 };
}

Is dit productiecode? God nee. Is het nuttig? Absoluut. Het vertelt u of uw aanpak is zelfs levensvatbaar voordat je investeert uren polijsten iets dat niet zal werken.

Een opmerking over feedback: U kunt feedback krijgen op alle punt in fase 1: de sleutel is kiezen wie Het doel is om de beste functie te bouwen, niet om een rigide proces te volgen.

Het bouwen van een API die een ander team zal consumeren? Laat ze vroeg betrokken. Een snelle "heeft deze vorm zinvol?" conversatie kan dagen van herwerken besparen. Bouwen van iets user-facing? Misschien wachten met het tonen van de zakelijke stakeholder totdat het minder ruw een aantal mensen worden opgehangen over hoe iets blikken in plaats van of het werken. Dat is prima; ze geven feedback in fase 2.

Gebruik je oordeel. Soms heb je feedback nodig om verduidelijking, niet om goed te keuren de spec al deed dat. "De spec zegt 'afhandeling fouten sierlijk' betekent dat opnieuw proberen drie keer, of faal snel en melden?" Dat is een fase 1 gesprek.

Als de input van een stakeholder kritiek is, maar ze zouden worstelen met ruwe code, bouw een triviale demo. Een hard gecodeerde happy-path dat toont dat het concept waardevolle feedback kan ontgrendelen zonder de afleiding van ontbrekende rand gevallen.

Wees pragmatisch. Het doel is het beste kenmerk, niet proceszuiverheid.

Fase 2: Maak het mooi

De mantra: Nu je weet wat je aan het bouwen bent, maak het goed.

De verkennende fase heeft zijn werk gedaan. Je hebt bevestigd dat de aanpak werkt, je begrijpt de vorm van het probleem, en je hebt waarschijnlijk ontdekt een dozijn rand gevallen de oorspronkelijke ticket niet vermeld.

Nu ruim je het op:

// Phase 2: Same logic, but actually maintainable
public async Task<ProcessingResult> ProcessItemsAsync(
    ProcessingRequest request,
    CancellationToken cancellationToken = default)
{
    ArgumentNullException.ThrowIfNull(request);

    var items = await _itemRepository.GetActiveItemsAsync(
        request.AccountId,
        cancellationToken);

    var processedItems = items
        .Where(item => item.Status != ItemStatus.Deleted)
        .Select(item => _mapper.ToProcessedItem(item))
        .ToList();

    return new ProcessingResult
    {
        Items = processedItems,
        TotalCount = processedItems.Count,
        ProcessedAt = _timeProvider.UtcNow
    };
}

Dit is waar je:

  • SOLID-beginselen toepassen pragmatisch (Ken hen, maar aanbidt hen niet)
  • Dingen juiste namen geven
  • Type hints en XML-documentatie toevoegen
  • Denk aan het API-oppervlak vanuit het perspectief van de beller
  • Behandel de edge cases die je in fase 1 ontdekte.

Kritisch gezien is dit het beste moment voor niet-technische feedback van belanghebbenden. De functie is nu zichtbaar en bruikbaar, maar je hebt nog niet geïnvesteerd uren schrijven testen voor het. Als ze zeggen "Eigenlijk, we wilden dat het te doen X in plaats," kunt u draaien zonder de gebroken hart van het verwijderen van een uitgebreide test suite.

Fase 3: Sluit het af

De mantra: Verhard het, test het, maak het veerkrachtig.

Nu en alleen nu schrijf je je tests. Voeg beveiligingscontroles. Voer de juiste foutafhandeling voor de productie edge cases. Voeg monitoring en vangrails.

Waarom wachten tot nu? Je weet eindelijk wat je aan het testen bent..

Tests geschreven in Fase 1 zou verkeerd zijn geweest.Je begreep het probleem nog niet. Tests geschreven in Fase 2 zou hebben karn.Je was nog steeds het verfijnen van de API. Tests geschreven in Fase 3 zijn correct, omdat de uitvoering stabiel is.

[Theory]
[InlineData(0)]
[InlineData(1)]
[InlineData(100)]
public async Task ProcessItemsAsync_WithValidRequest_ReturnsCorrectCount(
    int itemCount)
{
    // Arrange
    var items = _fixture.CreateMany<Item>(itemCount).ToList();
    _mockRepository
        .Setup(r => r.GetActiveItemsAsync(It.IsAny<Guid>(), It.IsAny<CancellationToken>()))
        .ReturnsAsync(items);

    // Act
    var result = await _sut.ProcessItemsAsync(
        new ProcessingRequest { AccountId = Guid.NewGuid() });

    // Assert
    result.TotalCount.Should().Be(itemCount);
    result.Items.Should().HaveCount(itemCount);
}

[Fact]
public async Task ProcessItemsAsync_WithNullRequest_ThrowsArgumentNullException()
{
    // Act & Assert
    await _sut.Invoking(s => s.ProcessItemsAsync(null!))
        .Should().ThrowAsync<ArgumentNullException>();
}

[Fact]
public async Task ProcessItemsAsync_ExcludesDeletedItems()
{
    // Arrange
    var items = new[]
    {
        new Item { Status = ItemStatus.Active },
        new Item { Status = ItemStatus.Deleted },
        new Item { Status = ItemStatus.Active }
    };
    _mockRepository
        .Setup(r => r.GetActiveItemsAsync(It.IsAny<Guid>(), It.IsAny<CancellationToken>()))
        .ReturnsAsync(items);

    // Act
    var result = await _sut.ProcessItemsAsync(
        new ProcessingRequest { AccountId = Guid.NewGuid() });

    // Assert
    result.Items.Should().HaveCount(2);
}

Deze fase omvat ook:

  • Beveiligingsbeoordeling (authenticatie, autorisatie, inputvalidatie)
  • Concurrency overwegingen (wat gebeurt er onder belasting?)
  • Failure mode analyse (wat als de database traag is? Wat als de API time-out?)
  • Monitoring (hoe weten we of dit in productie breekt?)

Terugkoppeling Choreografie

Als je het mis hebt, verdrink je in wrijving.

graph TB
    subgraph "Phase 1: Technical Voices"
        P1[Make It Work] --> T1[Senior Dev Review]
        T1 --> T2["Does the approach<br/>make sense?"]
        T2 --> T3["Any obvious<br/>architectural issues?"]
    end

    subgraph "Phase 2: Non-Technical Voices"
        P2[Make It Pretty] --> N1[Product Owner Demo]
        N1 --> N2["Does it meet<br/>the requirement?"]
        N2 --> N3["Is the UX<br/>intuitive?"]
    end

    subgraph "Phase 3: Ops/Security Voices"
        P3[Lock It Down] --> O1[Security Review]
        O1 --> O2[Operations Review]
        O2 --> O3["Will it hold up<br/>in production?"]
    end

    T3 --> P2
    N3 --> P3

    style T1 stroke:#3b82f6,stroke-width:2px
    style N1 stroke:#8b5cf6,stroke-width:2px
    style O1 stroke:#ef4444,stroke-width:2px

Fase 1: Technische stemmen alleen senior devs, architecten. Ze kunnen voorbij de puinhoop zien naar de vorm van de oplossing. Niet-technische stakeholders zullen in paniek raken bij ruwe code en vragen naar knopkleuren wanneer je nog steeds het datamodel uitzoekt.

Fase 2: Niet-technische stemmen welkom. De functie is bruikbaar, knoppen doen dingen. Krijg producteigenaren en designers betrokken nu de veranderingen zijn nog steeds goedkoop, je hebt nog niet geschreven tests.

Fase 3: Ops en security stemmen. "Wat als dit krijgt 10x verkeer?" "Wat als iemand voorbij kwaadaardige input?" Deze zorgen zijn alleen belangrijk als de functie echt werkt.

Takken als zandbakken

Dit is het ding dat mijn ontwikkelingsleven veranderde: totdat u een PR verhoogt, is uw vestiging volledig privé.

Dat klinkt misschien voor de hand liggend, maar ik zie ontwikkelaars elke commit behandelen alsof het op hun permanente record staat. Ze zijn bang om te experimenteren. Bang om lelijke code te schrijven. Bang om dingen te breken.

Beschouw je functie als een zandbak, een speeltuin, een laboratorium waar explosies worden verwacht en niemand gewond raakt.

graph TD
    A[Feature Branch Created] --> B[Experiment Freely]
    B --> C{Did it work?}
    C -->|No| D[Try Something Else]
    D --> B
    C -->|Yes| E[Clean Up the Mess]
    E --> F[Interactive Rebase]
    F --> G[Squash to Clean Commits]
    G --> H[Raise PR]
    H --> I[Public Code Review]

    style B stroke:#f59e0b,stroke-width:3px
    style D stroke:#f59e0b,stroke-width:2px
    style H stroke:#10b981,stroke-width:3px

    subgraph "Private - Go Mental"
        B
        C
        D
        E
    end

    subgraph "Public - Be Professional"
        H
        I
    end

In de praktijk betekent dit:

  • Vaak committen, zelfs als de code niet compileert
  • Schrijven FIXME en TODO reacties overal
  • Laat de debug code op zijn plaats tijdens het verkennen
  • Meerdere "probeer deze aanpak" commits
  • Maak je geen zorgen over commit berichten (je squasht later)

Dan, voordat je een PR oproept:

  1. De code opruimen (fase 2)
  2. Tests toevoegen (fase 3)
  3. Interactieve rebase om al die rommelige geschiedenis te verpletteren
  4. Schrijf een juiste commit bericht

De PR beoordelaars zien schone, professionele code met een duidelijk verhaal. Ze zien niet de zes valse starts, de 3am "waarom niet dit bloederige werk" commits, of de "undo ongedaan maken" geschiedenis.

De zandbak blijft privé, het gepolijste werk gaat openbaar.

Waarom dit stress vermindert

Traditioneel "wees professioneel te allen tijde" ontwikkeling is verpletterend. Elke lijn voelt permanent. Elke beslissing voelt als gevolg. Deze aanpak verwijdert die druk door het inperken van de chaos: spelen is legitiem werk in fase 1, feedback komt wanneer draaien goedkoop is in fase 2, en tests zijn eenmaal correct geschreven in fase 3, omdat je eindelijk weet wat je test.

Spelen is legitiem werk.

TDD werkt briljant als het domein goed wordt begrepen of als je een bekende bug vastpint. Maar als het probleem nog steeds wazig is, betekent het schrijven van tests eerst vaak het testen van het verkeerde ding drie keer achter elkaar. Deze benadering sidesteps die: verken eerst, test wanneer stabiel.

Pragmatic SOLID (And DRY's Dirty Secret)

Dus wat doet deze drie-fase mindset met uw ontwerp principes? Kortom: het doodt dogma. Hier is hoe het verandert mijn denken over SOLID, DRY, en interfaces in C#.

Ik heb het gehad over de toepassing van de SOLID-beginselen "pragmatisch" in fase 2.

SOLID is een goede set van principes. Ik leer ze. Ik gebruik ze. Maar ik heb gezien teams verdwijnen abstractie konijnen gaten in de naam van Single Responsibility of Open/Closed, het creëren van systemen zo flexibel ze zijn onbegrijpelijk.

Hier is mijn heuristische:

SOLID toepassen als:

  • Je hebt bewijs dat je de flexibiliteit nodig hebt.
  • De abstractie maakt de code duidelijker
  • Je bouwt iets wat anderen zullen gebruiken.

SOLID niet toepassen wanneer:

  • Je speculeert over toekomstige behoeften.
  • De abstractie voegt complexiteit toe zonder duidelijkheid
  • Je bouwt interne code die alleen jij behoudt.

Drie gelijkaardige regels code zijn beter dan een premature abstractie. Je kunt altijd later extraheren als je het patroon duidelijk ziet. Je kunt niet gemakkelijk een abstractie ongedaan maken die in je architectuur wordt gebakken.

// Over-engineered SOLID worship
public interface IThingProcessor { }
public interface IThingProcessorFactory { }
public class ThingProcessorFactory : IThingProcessorFactory { }
public class ThingProcessor : IThingProcessor { }
public class ThingProcessorDecorator : IThingProcessor { }
public class ThingProcessorValidationDecorator : IThingProcessor { }

// What you probably actually need
public class ThingProcessor
{
    public async Task<Result> ProcessAsync(Thing thing)
    {
        // Just do the thing
    }
}

Als je later de flexibiliteit nodig hebt, refactoring is goedkoop. Over-engineering vooraf is duur omdat je abstractie lagen die niet verdienen hun houden.

De DRY Trap

En terwijl we heilige koeien doden, laten we praten over DRY Het is misschien wel het meest dogmatisch toegepaste principe in onze industrie, en wanneer toegepast zonder nadenken, veroorzaakt het meer schade dan goed.

Het probleem is dit: Niet alle duplicatie is hetzelfde soort duplicatie.

Als twee stukjes code op elkaar lijken maar verschillende doeleinden dienen, en ze extraheren in een gedeelde abstractie paren dingen die onafhankelijk moeten evolueren. Nu wanneer een use case moet veranderen, ben je ofwel:

  1. Het toevoegen van parameters en voorwaarden om beide gevallen te behandelen (het verergeren van de abstractie)
  2. Breek de andere use case
  3. Kopiëren van de gedeelde code terug en bewerken (het toevoegen van DRY was hier fout)
// "DRY" solution - looks clever, causes pain
public async Task<Result> ProcessEntity<T>(
    T entity,
    bool validateFirst = true,
    bool sendNotification = false,
    Func<T, bool>? customFilter = null,
    Action<T>? preProcess = null,
    Action<T>? postProcess = null) where T : IEntity
{
    // 50 lines of conditional spaghetti trying to handle
    // "processing" for Users, Orders, and Products
    // because they all had 3 similar lines once
}

// What you probably actually need
public async Task<Result> ProcessUser(User user) { /* 15 clear lines */ }
public async Task<Result> ProcessOrder(Order order) { /* 15 clear lines */ }
public async Task<Result> ProcessProduct(Product product) { /* 15 clear lines */ }

Ja, er is wat "duplicatie" in de tweede benadering, maar elke methode is:

  • Gemakkelijk te begrijpen in afzondering
  • Gemakkelijk aan te passen zonder bijwerkingen
  • Eenvoudig te verwijderen wanneer dat type entiteit verdwijnt
  • Eenvoudig te testen met duidelijke ingangen en uitgangen

De DRY versie is een nachtmerrie te handhaven omdat het probeert om alle dingen te zijn voor alle bellers. Elke verandering vereist begrip van alle use cases. Elke bug repareert risico's breken van iets anders.

Mijn regel: Duplicatie tolereren tot je het hebt gezien. hetzelfde Drie keer en je bent er zeker van dat het de hetzelfde Tot die tijd is een beetje kopieerpasta prima. Het is geen morele mislukking; het is gepaste voorzichtigheid.

Duplicatie is veel goedkoper dan de verkeerde abstractie. Je kunt altijd later dedupliceren als het patroon duidelijk is. Je kunt niet gemakkelijk een slechte abstractie ongedaan maken die door je codebase is geweven.

Het interfaceprobleem in C#

Hier is nog een heilige koe die geslacht moet worden: het "elke klasse heeft een interface" patroon nodig.

In de vroege dagen van .NET afhankelijkheid injectie, iemand besloten dat om code testbaar te maken, je nodig hebt om interfaces overal te injecteren. De logica was: je kunt niet spotten met een betonnen klasse, dus elke dienst moet IService en ServiceImpl. Plotseling was elke C# codebase bezaaid met enkele-implementatie interfaces die uitsluitend bestond voor het testen.

// The interface tax - early 2010s style
public interface IUserService { }
public interface IOrderService { }
public interface IEmailService { }
public interface INotificationService { }
public interface IPaymentProcessor { }
public interface IInventoryManager { }

// Each with exactly ONE implementation
public class UserService : IUserService { }
public class OrderService : IOrderService { }
// ... you get the idea

Dit was cargo cult programmering. We betaalden een complexiteit belasting voor theoretisch testbaarheid en theoretisch de toekomstige flexibiliteit die zelden tot stand kwam.

Het zit zo: je hebt dit niet meer nodig.

Moderne bespotte kaders zoals N Plaatsvervanger en Moq kan bespot beton klassen (met virtuele methoden). Belangrijker, ASP.NET Core DI container werkt perfect goed met concrete types:

// Modern approach - just register the concrete type
services.AddScoped<UserService>();
services.AddScoped<OrderService>();
services.AddScoped<EmailService>();

// In your controller or service
public class OrderController(OrderService orderService, UserService userService)
{
    // Primary constructor injection - clean and simple
}

Geen interfaces. IOrderService. Precies de dienst die u nodig hebt, rechtstreeks geïnjecteerd.

"Maar hoe zit het met testen?" Ik hoor je huilen.

Voor unit testen, heb je opties:

  1. Belangrijke methoden maken virtual en gebruik maken van een bespottelijk kader
  2. Gebruik de echte service met een testdatabase (integratietests zijn in ieder geval vaak waardevoller)
  3. Een interface toevoegen wanneer je het echt nodig hebt om te testen

Dat derde punt is van cruciaal belang: refactoring tools zijn buitengewoon goed in het extraheren van interfaces.

In Rider of Visual Studio, het is letterlijk Ctrl+. → "Extract Interface" en je bent klaar. Elke methode wordt eruit gehaald, de klasse wordt bijgewerkt om het te implementeren, en je kunt vinden / vervangen alle toepassingen indien nodig. Het duurt seconden.

// Phase 1 & 2: Just write the class
public class OrderService
{
    public async Task<Order> CreateOrderAsync(CreateOrderRequest request) { ... }
    public async Task<Order?> GetOrderAsync(int orderId) { ... }
    public async Task CancelOrderAsync(int orderId) { ... }
}

// Phase 3: Need to mock it for testing? Extract interface in 2 seconds
public interface IOrderService
{
    Task<Order> CreateOrderAsync(CreateOrderRequest request);
    Task<Order?> GetOrderAsync(int orderId);
    Task CancelOrderAsync(int orderId);
}

public class OrderService : IOrderService { ... }

Mijn workflow nu: interfaces zijn te vinden in fase 3, niet in fase 1.

Tijdens "make it work" en "make it pretty," schrijf ik gewoon klassen. Geen premature abstractie. Geen interface belasting op elk type. De code is eenvoudiger, gemakkelijker te navigeren (geen springen tussen IFoo en Foo), en sneller te schrijven.

Als ik op "lock it down" druk en tests moet schrijven, dan Ik beslis welke diensten eigenlijk moeten spotten. Meestal is het minder dan je zou denken dat het vaak gewoon externe integraties zoals HTTP-clients, databases, en bericht wachtrijen.

Voor interne bedrijfslogica diensten? De helft van de tijd test ik ze direct met echte afhankelijkheden. De tests zijn toch waardevoller omdat ze het feitelijke gedrag testen, niet een spot van wat ik Denk na. het gedrag zou moeten zijn.

// Services I typically DO extract interfaces for (external boundaries)
public interface IPaymentGateway { }      // Third-party API
public interface IEmailSender { }         // External service
public interface IBlobStorage { }         // Cloud storage

// Services I typically DON'T need interfaces for (internal logic)
public class OrderValidator { }           // Pure logic, test directly
public class PriceCalculator { }          // Pure logic, test directly
public class OrderService { }             // Test with real repo + in-memory DB

Het punt is: Stop met het schrijven van interfaces vooraf "voor het geval." Schrijf beton klassen. Als u een interface nodig hebt voor het testen of echte polymorfisme later, het extraheren van een duurt letterlijk seconden met moderne tooling.

Je codebase zal eenvoudiger zijn, bevaarbaarder, en je zult niet de onderhoudslast hebben om interfaces op één lijn te houden met implementaties zonder voordeel.

De wendbare verbinding

Ironisch genoeg is deze benadering meer afgestemd op de origineel Behendig manifest dan de meeste "Agile" processen die ik heb ondervonden. Werk software snel (fase 1). Reageren op verandering (fase 1-2). Klantsamenwerking wanneer de functie aantoonbaar is (fase 2). Geen sprintpunten, geen snelheid volgen, geen bloedige burndown grafieken.

Moderne "Agile" is gevangen genomen door proces liefhebbers die hebben toegevoegd zo veel ceremonies er is geen tijd meer voor exploratie. Deze aanpak brengt spel terug niet als een verwennerij, maar als een legitieme fase van creatief werk.

When NOT to use this approach

Ik moet eerlijk zijn: dit is niet altijd de juiste aanpak.

Bugfixes: Als je een bekende bug repareert, is TDD stijl logischer. Schrijf een test die de bug reproduceert, repareer het, klaar.

Begrepen problemen: Als je een standaard algoritme implementeert of een patroon dat je al honderd keer hebt gebruikt, heb je geen exploratiefase nodig.

Strakke deadlines met bekende eisen: Als je echt precies weet wat je aan het bouwen bent en wanneer het moet verschepen, kun je fase 1 verkenning overslaan.

Zeer gereguleerde omgevingen: Als elke commit afmelden nodig heeft, is sandboxen moeilijker. Hoewel je nog steeds de exploratie lokaal kunt doen voordat je duwt.

Maar voor de meeste feature development. Waar eisen zijn een beetje wazig, de technische aanpak is niet voor de hand liggend, en je hebt ruimte nodig om te denken deze aanpak werkt briljant.

A Note for Junior Developers

Als je vroeg in je carrière, je zou kunnen voelen druk om te laten zien "perfecte" code de hele tijd. Je hoeft niet te. Gebruik deze drie-fase aanpak gewoon duidelijk over welke fase je in, en altijd het werk helemaal tot fase 3 af te maken. Niemand zal je de schuld voor rommelige exploratie code als het leidt tot gepolijst, getest, productie-klaar code aan het einde.

Onderste regel

Laat het werken, maak het mooi, sluit het af.

Start eenvoudig. Ontwerp met vooruitziendheid, maar niet speculatie. Itereer snel. Voeg alleen complexiteit wanneer het loont.

"Duplicatie is veel goedkoper dan de verkeerde abstractie."

De exploratiefase is geen schuldig geheim.Het is een gedefinieerd onderdeel van het proces. Je vestiging is je sandbox totdat je een PR verhoogt. Technische feedback komt vroeg, niet-technische feedback komt midden, ops en security feedback komt te laat.

Dit houdt creativiteit in leven, vermindert stress, en produceert systemen die elegant schalen omdat u het probleem begreep voordat u zich inzette voor de oplossing.

Geef jezelf toestemming om te spelen.


Gerelateerd lezen

Als dit resoneert, kunt u ook genieten van deze gerelateerde berichten:

Finding related posts...
logo

© 2026 Scott Galloway — Unlicense — All content and source code on this site is free to use, copy, modify, and sell.