In mijn vorige post schreef ik over vijf principes voor effectief samenwerken met AI. Het eerste principe — eerst denken, dan coderen — verdient een eigen verhaal.
De meeste developers openen Claude Code, typen een prompt, en laten het bouwen. Voor een klein utilitybestandje werkt dat prima. Maar zodra je een feature van enige omvang vraagt, krijg je code die technisch klopt maar niet past. Verkeerde patronen, andere naamgeving, een structuur die niemand in je team herkent. Je bent meer tijd kwijt aan corrigeren dan je hebt bespaard.
Het probleem is niet dat de AI slecht codeert. Het probleem is dat je hem laat rennen voordat hij weet waar hij naartoe moet. Plan Mode draait dat om. In deze modus leest Claude Code eerst je codebase, analyseert de bestaande patronen, en stelt een aanpak voor — voordat het ook maar één regel code schrijft. Het verschil: je krijgt geen code die werkt, je krijgt code die past.
Elke keer dat een AI code schrijft, neemt hij tientallen beslissingen. Welk pattern gebruik ik? Maak ik een nieuwe tabel of breid ik een bestaande uit? Polling of events? Controller of Minimal API? Zonder plan zijn die keuzes onzichtbaar — ze zitten verstopt in de code die hij oplevert. Je ontdekt ze pas als je de pull request opent. En dan is bijsturen duur: code weggooien, opnieuw beginnen, of — erger — het maar laten staan.
Plan Mode verandert niet of de AI aannames maakt. Het verandert wanneer je ze ziet. In een plan staan die aannames zwart op wit als voorstellen. “Ik wil een nieuwe tabel aanmaken.” “Ik gebruik een controller.” Dat zijn momenten waarop jij kunt zeggen: nee, wij doen dat anders. Bijsturen in een plan kost seconden. Bijsturen in code kost uren.
Zonder plan
Stel: je team bouwt een bestelplatform in ASP.NET Core. Er komt een verzoek binnen: gebruikers willen meldingen krijgen als de status van hun order verandert. Je opent Claude Code en typt:
“Bouw een notificatiesysteem voor statuswijzigingen van orders.”
Claude Code gaat meteen aan de slag. Geen vragen, geen analyse — het levert werkende code op. Maar kijk eens wat het oplevert:
- Het maakt een standalone
NotificationServiceaan met eigen logica — terwijl jullie MediatR gebruiken voor command/query separation en alles via handlers loopt. - Het creëert een nieuwe
Notifications-tabel met eigen migratie — terwijl jullie bestaandeAuditLogal events bijhoudt en uitgebreid kan worden. - Het implementeert een polling-mechanisme dat elke 30 seconden de database checkt — terwijl jullie een event-based architectuur hebben met
IEventHandler<T>.
En dan de structuur. Jullie hele API is gebouwd met Minimal APIs. Geen controllers, geen [Route]-attributen. Maar Claude levert dit:
[ApiController]
[Route("api/[controller]")]
public class NotificationsController : ControllerBase
{
private readonly NotificationService _service;
public NotificationsController(NotificationService service)
{
_service = service;
}
[HttpGet("{userId}")]
public async Task<IActionResult> GetNotifications(int userId)
{
var notifications = await _service.PollForUpdates(userId);
return Ok(notifications);
}
}
Technisch correct. Compileert. Doet wat je vroeg. Maar het past in geen enkel opzicht bij je project. Een collega die dit in een pull request ziet, denkt dat het uit een ander project is gekopieerd.
Het probleem is niet dat Claude het fout doet — het weet niet wat “goed” betekent in jouw project. Zonder plan mist het de context om de juiste keuzes te maken.
Met plan
Zelfde scenario, zelfde feature — maar een andere aanpak. Dit keer geef je Claude context en vraag je het om eerst na te denken.
Plan Mode activeren
Je opent Claude Code en geeft een prompt die richting geeft:
“We willen een notificatiesysteem bij statuswijzigingen. Ga in plan mode en analyseer eerst hoe we events afhandelen in /Application/EventHandlers. Kijk naar onze bestaande architectuur voordat je iets voorstelt.”
Claude Code schakelt naar Plan Mode — het leest en analyseert voordat het ook maar iets schrijft.
Explore
Claude duikt in je codebase en komt terug met bevindingen:
Ik heb de codebase geanalyseerd. Dit valt op:
- In
Application/EventHandlers/vind ik een consistentIEventHandler<T>-patroon. Alle domeinevents worden via deze interface afgehandeld.- MediatR wordt gebruikt voor command/query separation — commands gaan via
IRequestHandler, queries viaIRequestHandler<TRequest, TResponse>.- In de data layer staat een
AuditLog-entity die al events bijhoudt met velden alsEntityId,TypeenMessage. Dit wordt project-breed gebruikt voor traceability.
De kern: Claude begrijpt je patronen voordat het iets voorstelt. Het heeft gelezen, niet gegist.
Het plan
Op basis van die analyse komt Claude met een plan:
- Nieuw
OrderStatusChangedEventdat past in het bestaande event-patroon- Een
NotificationHandlerdieIEventHandler<OrderStatusChangedEvent>implementeert- De bestaande
AuditLog-entity uitbreiden met notificatievelden — geen nieuwe tabel- Een Minimal API-endpoint voor het ophalen van notificaties, via een MediatR query
Geen nieuw systeem, maar een uitbreiding die past bij wat er al staat.
Het resultaat
Je keurt het plan goed. Claude implementeert.
De event handler:
public class NotificationHandler : IEventHandler<OrderStatusChangedEvent>
{
private readonly IMediator _mediator;
public NotificationHandler(IMediator mediator)
{
_mediator = mediator;
}
public async Task Handle(OrderStatusChangedEvent @event)
{
await _mediator.Send(new CreateAuditLogCommand
{
EntityId = @event.OrderId,
Type = "notification",
Message = $"Order status changed to {@event.NewStatus}"
});
}
}
Het API-endpoint:
app.MapGet("/api/notifications/{userId}", async (int userId, IMediator mediator) =>
{
var result = await mediator.Send(new GetNotificationsQuery(userId));
return Results.Ok(result);
})
.WithName("GetNotifications")
.WithTags("Notifications");
Geen controller, geen polling, geen losstaande service. Dezelfde feature als in het vorige voorbeeld — maar nu gebouwd alsof het door je eigen team is geschreven.
Claude draait dotnet build en dotnet test — alles groen.
Niet voor alles
Plan Mode is niet voor alles. Een bugfix met een duidelijke stacktrace, een typo, een config-wijziging — daar heb je geen plan voor nodig. Dat is overhead zonder meerwaarde.
Vuistregel: als je het resultaat al voor je ziet, heb je geen plan nodig. Als je twijfelt over de aanpak, wel.
Eerst denken
De AI gaat altijd keuzes maken. De vraag is niet of, maar wanneer je ze ziet. In een plan lees je: “Ik maak een nieuwe NotificationService aan.” Dan kun je zeggen: nee, gebruik onze bestaande handlers. In code lees je datzelfde besluit pas terug als een complete implementatie die je moet weggooien.
De beste code is code die eruitziet alsof je team het zelf heeft geschreven. Plan Mode is hoe je daar komt — niet door meer te typen, maar door de aannames zichtbaar te maken voordat ze in je codebase terechtkomen.
De volgende keer dat je een feature bouwt, begin met: “Ga in plan mode en analyseer eerst hoe we dit doen in de bestaande codebase.” Je zult het verschil merken.