# Jouer avec Code: Une approche agile efficace

<datetime class="hidden">2025-11-23T10:00</datetime>

<!-- category -- Software Development, Agile, Best Practices, Craftsmanship -->
**Pourquoi traiter votre succursale comme une boîte de sable—et jouer comme un travail légitimeM SK1produce un meilleur logiciel avec moins de stress.**

> **Prise chaude:** La plupart des développeurs essaient d’être parfaits à chaque étape du développement.

## Introduction

J’ai construit des logiciels de façon professionnelle pour ..., bien que ,, laissez-moi dire que je me souviens d’un moment où "Agile" était une nouvelle idée et non un mot couramment utilisé par les gestionnaires de projet pour justifier davantage de standups.

Au fil des ans, le meilleur code que j’ai jamais écrit provient de projets où je me suis senti *permission de jouer*. Le pire code provenait de projets où chaque touche de clé semblait être contrôlée.

Ce n’est pas accidentel **Creativity and pressure don't mix wellM SK1**

C’est pourquoi j’ai mis au point une approche qui sépare l’exploration créative messy de la production polissée.[Faire fonctionner, faire beau, enfermer](/blog/makeitworkthenmakeitpretty)Il s’agit de donner à vous-même la permission d’expérimenter sans que le poids de la perfection ne vous empiète sur vous.

[TOC]

## Les trois phases

Permettez-moi de vous dire tout à l’avance. *appliquer la bonne discipline au bon moment*.

```mermaid
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
```

### Phase 1: Faire fonctionner

**Le mantra:** Play first. Confirmer vos hypothèsesM SK1 Faire quelque chose fonctionner.

Il s’agit de la phase où votre succursale est une boîte à sable. Le code messagerie est bon . Les extrémités mortes sont bonnes. La période qui commence trois fois est *de l’eau potable*. Vous'Vous ne construisez pas une cathédrale ici ; vousM SK3vous dessinez sur un serviette.

Que tentez-vous de comprendre?

- Cette API se comporte-t-elle réellement comme le prétendent les dossiers?
- Puis-je même résoudre ce problème avec les outils que j'ai?
- Quelles sont les exigences réelles, non celles qui figurent dans le billetM SK1
- Est-ce un problème de deux heures ou d’une semaine?

**Le point de vue critique:** Jusqu’à ce que vous augmentez un PR, votre succursale est *de votres*. C’est votre laboratoire expérimental . personne n’a besoin de voir vos démarrages faux , les commentaires que vous avez faits MSC4 le code de débugging out M SK5 les remarques que vous faites MRK6 les tâches à accomplir MNK7 c’est terrible MMK8 corriger ultérieurement

**Avantages secondaires:** Les engagements fréquemment sont un battement cardiaque.

Cette liberté psychologique est essentielle. Lorsque vous savez que vous pouvez jeter tout de côté et commencer à prendre de nouvelles décisions, vous faites des décisions plus audacieuses . vous essayez cette approche étrange qui peut-être remporter la victoireM SK3 elle ne fonctionne pasMSC4 elle fonctionne parfois brilliantementMST5 vous devez parfois lire un article MST6 regarder un vidéo sur YouTubeM ST7 réfléchir pendant une certaine périodeM st8 vous rappelezMst9 votre travail consiste à fournir de bons logiciels et de bonnes décisions **N'EST PAS UN TYPIST**.

```csharp
// 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 };
}
```

Est-ce que ce code de production? Dieu non. est-il utileM SK2 Absolutement . Il vous indique si votre approche est même viable avant d’investir des heures à polir quelque chose qui gagneMST4 ne fonctionne pasM ST5

**Note sur la rétroaction:** Vous pouvez obtenir des commentaires à *Toute* point dans la phase 1—la clé choisit *qui* Le but est de bâtir la meilleure caractéristique, ne pas suivre un processus rigide .

Construire une API que l’autre équipe utilisera? Faire en sorte qu’ils soient impliqués tôt . Une approche rapide " cette forme a-t-elle un sens? *aperçus* plutôt que de savoir si *ouvrages*. Qu’ils donnent une rétroaction en phase 's fineM SK2

Utilisez votre jugement. Parfois vous avez besoin de rétroaction pour **clarifier**, de ne pas approuver —la spécification a déjà fait ce qui est indiqué. "La spécifications indiquent que les erreurs doivent être gérées gracieusementM SK5 cela signifie qu'il faut essayer trois fois de nouveauMSC6 ou échouer rapidement et en notifier l'échecMSM7 QueMST8est une conversation phase MST9

Si l’entrée d’un intervenant, ', est critique mais qu’il se bat avec un code brut, MSC1, construit une démonstration triviale, ., un cheminement happy hardcoded qui montre le concept peut débloquer des rétroactions précieuses sans distraire les cas à bord manquants.

Être pragmatique. L’objectif est la meilleure caractéristique , non la pureté du procédéM SK2

### Phase 2: Make It Pretty

**Le mantra:** Maintenant que vous savez ce que vous construisez, *de la bonne qualité*.

La phase d’exploration s’est achevée.

Maintenant vous le nettoyez:

```csharp
// 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
    };
}
```

C'est là où vous êtes:

- Appliquer les principes SOLID *de façon pragmatique* (les connaissons, mais ne les croyons pas.
- Donnez aux choses des noms appropriés
- Ajouter des conseils de type et une documentation XML
- Pensez à la surface de l’API du point de vue du caller'
- Gérer les cases de bord que vous avez découvertes dans la phase 1

**De façon critique, c’est le meilleur moment pour les intervenants qui ne participent pas à l’examen de la question.** La fonctionnalité est maintenant visible et utilisable, mais vous n’avez pas't encore investi des heures de rédaction d’essais pour elleM SK2 Si ils disent MSC3 en faitMST4 nous voulions qu’elle fasse X au lieuM ST5 vous pouvez pivoter sans le fracture cardiaque de supprimer une suite exhaustive de testsM st6

### Phase 3: Fermez-le

**Le mantra:** Équilibrer la résistance à l’aéronef

Maintenant—et seulement maintenantM SK1Vous écrivez vos essais. Ajouter des vérifications de sécurité . Mettre en œuvre une gestion correcte des erreurs pour les cases à bord de la production

Pourquoi attendre jusqu’à présent? Parce **Vous savez enfin ce que vous testez.**.

Les essais écrits dans la phase 1 auraient été erronés — vous n’avez pas encore compris le problème ' vous ne comprenez pas encore le problème~ . les essais réalisés dans cette phase *correction*, parce que la mise en œuvre est stable

```csharp
[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);
}
```

Cette phase inclut également les :

- Examen de la sécurité (authentication,autorisationM SK2 validation des intrants )
- Concurrence des considérations (ce qui se passe sous la chargeM SK1
- Analyse du mode de défaillance (que se passera-t-il si la base de données est lente?Que se passerait-il s'il y avait un outage de l'API?
- Surveillance (comment nous saurons s’il y a rupture de production?

## Rétroaction Choréographie

Des personnes différentes devraient être impliquées à différents stades.

```mermaid
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
```

**Phase 1:** Les voix techniques seulement—dévs supérieursM SK1architectes. Ils peuvent voir passer le désordre jusqu’à la forme de la solution . Non–-les intervenants techniques paniqueront à l’égard du code brut et se demandent des couleurs des boutons alors que vous envisagez encore de trouver un modèle de données.

**Phase 2:** Non-Voices techniques sont bienvenuesM SK1 La fonctionnalité est utilisable, Les boutons font des choses . Faire participer maintenant les propriétaires et les concepteurs de produitsMSC4Les changements sont toujours bon marchéMST5 vous n'avez pas encore fait de testsMSP6vous n'avons pas encore écrit d'essaisMSS7

**Phase 3:** Ops et voix de sécurité. "Qu'arrivera-t-il si cela obtient un trafic 10xM SK3 | | "qu'arriverait-on si quelqu'un passe des intrants malicieuxMSC5 Ces préoccupations ne sont valables qu'une fois que la fonction fonctionne réellement

## Branches en tant que boîtes de sable

Voici ce qui a changé ma vie de développement. **jusqu’à ce que vous augmentez un PR, votre succursale est entièrement privée**.

Cela peut sembler évident, mais je vois les développeurs traiter chaque engagement comme il se doit' s’enfonçant sur leur dossier permanent . IlsM SK3 ont peur d’expérimenterMSC4 craignent de écrire un code uglyMska5 craignant de détruire des chosesMka6

Je veux que vous pensez à votre branche comme à une boîte de sable.

```mermaid
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
```

Dans la pratique, ce qui signifie

- Commettre fréquemment, même si le code ne se compile pas
- Écrire `FIXME` et `TODO` Commentaires partout
- Laissez le code de débugging en place pendant que vous explorez
- Faire plusieurs "essayer cette approche" engagements
- Ne vous inquiétez pas de transmettre les messages.

Ensuite, avant d’augmenter un PRM SK1

1. Nettoyage du code (Phase 2)
2. Ajouter des essais (Phase 3)
3. Rebase interactive pour détruire toute cette histoire meurtrière
4. Rédigez un message d'engagement approprié

Les évaluateurs de la PR voient un code professionnel propre, avec une narration claire. Ils ne voient pas les six entrées faussesM SK3 le MSC4am "comment 't-il ne fait pas ce travail sanguinaireMST7 il s’engageMst8 ou le \MST9undo undo undoMSt10 historiqueM st11

> **La boîte de sable demeure privée. Le travail poli est rendu public.**

## Pourquoi cela réduit le stress

Traditionnel "être professionnel en tout tempsM SK1 le développement est déracinant . Chaque ligne se sent permanente M SK3 Chaque décision se sent consequentielle . Cette approche élimine cette pression en réduisant le chaos **Le jeu est un travail légitime** dans la phase 1, le rétroaction arrive lorsque le pivotage est bon dans la Phase 2, et les essais sont écrits une fois correctement dans laphase 3 parce que vous savez enfin ce que vous testez

> **"Le jeu est un travail légitime."**

TDD fonctionne parfaitement lorsque le domaine est bien compris ou que vous identifiez une erreur connue.

## Pragmatique SOLID (And DRYM SK1s Dirty Secret)

Qu’est-ce que cette mentalité de trois phases, -, faite à vos principes de conception?

J’ai mentionné l’application des principes SOLID "pragmatiquement" dans la phase 2. Permettez-moi d’être précis sur ce que j’entends par .

SOLID est un bon ensemble de principes.

Voici ma héuristique.

**Appliquer SOLID lorsque:**

- Vous avez des preuves que vous aurez besoin de la souplesse
- L'abstraction rend le code plus clair
- Vous construisez quelque chose que d’autres utiliseront

**Ne pas appliquer SOLID lorsque :**

- Vous ' vous prévoyez des besoins futurs
- L'abstraction ajoute de la complexité sans clarté
- Vous construisez un code interne que vous seuls entretenez

Trois lignes de code similaires sont meilleures qu’une abstraction prématurée. Vous pouvez toujours extraire plus tard quand vous voyez clairement le modèleM SK1 Vous ne pouvez pas facilement supprimer une abstraction qui' est fondée dans votre architecture .

```csharp
// 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
    }
}
```

Si vous avez besoin de souplesse plus tard, la réfactorisation est bon marché.

### Le piège de la DRY

Et alors que nous tuons des vaches sacrées, laissez-nous parler de **DRY (en anglais seulement)** Il s’agit peut-être du principe le plus dogmatique appliqué dans notre industrie.

Le problème est le suivant: **ne sont pas tous des mêmes types de double emploi**.

Lorsque deux morceaux de code apparaissent similaires mais servent à des fins différentes, en les extrayant dans une abstraction partagée, on associe des choses qui devraient évoluer indépendamment . Maintenant que l’un d’entre eux a besoin de changer le cas d’utilisation, vousM SK3 êtes soit l’une ou l’autre

1. Ajouter des paramètres et des conditions pour traiter les deux cas (en aggravant l'abstractionM SK1
2. La rupture de l'autre cas d'utilisation
3. Copying the shared code back out and editing it (admitting DRY was wrong here)

```csharp
// "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 */ }
```

Oui, il existe'il y a quelques M SK2duplication " dans la deuxième approcheMSC4 Mais chaque méthode est

- Facile à comprendre en isolement
- Facile à modifier sans effets secondaires
- Facile à supprimer lorsque ce type d'entité disparaît
- Facile à tester avec des entrées et des sorties claires

La version DRY est un cauchemar à maintenir parce qu’elle'essaie d’être tout pour tous les appelants. Chaque changement requiert la compréhension de toutes les situations d’utilisation . Toute correction d’erreur risque de détruire quelque chose d’autre

**Mon règlement:** Tolérer le double emploi jusqu’à ce que vous *la même* 3 fois, et vous êtes convaincus qu’il représente le *la même* concept qui évoluera ensemble. Jusqu’à ce momentMSC1 un peu de copie- la pâte est fineM SK3 Celle-ci ' n’est pas une erreur moraleMST5 c’est elleM ST6 une prudence appropriéeM st7

La copie est beaucoup moins coûteuse que la mauvaise abstraction.

### Le problème de l'interface dans C#

Voici une autre vache sacrée qui a besoin d’être tuée. **la "tous les classes ont besoin d'une interface**.

Dans les premiers jours de l’injection .NET de dépendance, quelqu’un a décidé que pour rendre le code testable , vous devriez injecter des interfaces partout `IService` et `ServiceImpl`. D’un coup, chaque base de code CM SK1 était dépourvue d’interfaces de mise en œuvre uniques qui existaient uniquement pour tester.

```csharp
// 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
```

Il s’agissait de programmes cultes du fret. Nous payions une taxe de complexité pour *évaluation théorique* d'examinabilité et *évaluation théorique* flexibilité future rarement réalisée.

**C’est là le problème.**

Cadres modernes de mockerie comme [NSubstituer](https://nsubstitute.github.io/) et [Moq](https://github.com/moq/moq4) Pouvoir reproduire les classes de béton (avec des méthodes virtuelles ). Plus important encore, ASPMSC3NET CoreM SK4les contenants DI fonctionnent parfaitement avec les types de bétonsMNK5

```csharp
// 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
}
```

Aucune interface. Non `IOrderService`. Juste le service dont vous avez besoin

**" Mais que dire de la mise à l’essaiM SK1** Je l’entends crier.

Pour les essais unitaires, vous avez des options:

1. Méthodes clés `virtual` et utiliser un cadre de mockery
2. Utiliser le service réel avec une base de données d'essai (les essais d'intégration sont souvent plus utiles en tout état de cause
3. Ajouter une interface *Lorsque vous en avez besoin pour les essais*

Ce troisième point est crucial. **les outils de refactoring sont extrêmement bons à extraire des interfaces**.

Dans Rider ou Visual Studio, il' est littéralement `Ctrl+.` → "Interface d'extractionM SK2 et vous'vous êtes terminésMSC4 Chaque méthode est extraiteMST5 la classe est mise à jour pour l'appliquerM ST6et vous pouvez trouverM st7remplacer tous les usages si nécessaireMst8 Il faut quelques secondes

```csharp
// 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 { ... }
```

Mon flux de travail maintenant: **Les interfaces apparaissent dans la phase 3, et non dans la Phase 1**.

Au cours de "fait fonctionner" et "faite beauM SK3 Je n'écrive que des classesMSC4 Pas d'abstraction prématuréeMNK5 Aucune taxe sur l'interface pour tous les typesMMK6 Le code est plus simpleMRK7 plus facile à naviguer (pas de saut entre `IFoo` et `Foo`), et plus rapide à écrire

Lorsque je touche "blocagez-le " et que j’ai besoin de faire des tests, *puis* Je décide quels services ont réellement besoin d’être reproduits.

Pour les services de logique des affaires internes? La moitié du temps, je les teste directement avec des dépendances réelles. Les tests sont plus valables en tout état de cause parce qu’ils vérifient le comportement réel. *envisager* le comportement devrait être.

```csharp
// 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
```

**Le point est:** supprimer l’écriture des interfaces avant "en cas d’urgence".écrire les classes de béton . Si vous avez besoin d’une interface pour tester ou un véritable polymorphisme ultérieurementM SK3 en extrayant une, cela prend literally quelques secondes avec la modernisation de l’outil

Votre base de code sera plus simple, plus navigableM SK1 et vous gagnerez ' n’aurez pas le fardeau d’entretien de maintenir les interfaces en sync avec les mises en oeuvre sans aucun avantage

## La connectivité agile

Il est ironique que cette approche soit plus conforme à la *d'origine* Manifeste agile par rapport à la plupart des processus "AgileM SK1 Processus que j’ai rencontrés '. Travailler le logiciel rapidement

L’approche moderne "Agile" a été capturée par des adeptes du processus qui 'y ont ajouté tant de cérémonies M SK3il n’y a plus de temps à explorer . Cette approche rétablit le jeu MSC5non pas comme une indulgence MST6 mais comme une phase légitime du travail créatif MSS7

## Quand ne pas utiliser cette approche

Je dois être honnête.

**Fixes de bogues:** Lorsque vous corrigez une erreur connue, le style TDD est plus judicieux.

**Bons-problèmes comprises:** Si vous appliquez un algorithme standard ou un modèle que vous avez utilisé cent fois, vous n’avez pas besoin d’une phase d’exploration.

**Délais stricts avec des exigences connues:** Si vous savez vraiment exactement ce que vous construisez et quand il doit être expédié, vous pourriez passer par la phase de l’exploration.

**Environnements très réglementés:** Si chaque engagement a besoin d’un signe-offM SK1 le sandboxing est plus difficile. Bien que vous puissiez encore faire l’exploration locale avant de pousser

Mais pour *La plupart des* développement des fonctionnalités—où les exigences sont un peu floues , l’approche technique n’est pas'il n’y a pas d’évidenceMSC3 et vous avez besoin de place pour penserM SK4 cette approche fonctionne brilliantlyMST5

## Note pour les jeunes développeurs

Si vous êtes au début de votre carrière,, vous risquez d’avoir des pressions pour montrer le code "perfectM SK3 tout le temps. Vous n’avez pas àMSC5aucune obligationMST6 Utiliser ces trois approchesMSP7phases MST8 Soyez clair sur la phase où vous êtesMSV9vous êtes enMSS10 et terminez toujours l’emploi jusqu’à la phase MSSS11 personne ne vous reprochera pour un code d’exploration meurtrière qui mènera à une polisseMSR12examinéMSSR13productionMSSA14code prêt à la finMSA15

## Ligne inférieure

**Faire fonctionner, faire beau, enfermer**

Démarrer simple. Concevoir avec prévoyance mais pas spéculaire. Repéter rapidementM SK2 Ajouter seulement la complexité lorsque cela vaut la peineMSC3

> **"La duplication est beaucoup moins coûteuse que l’abstraction erronéeM SK1**

La phase d’exploration n’est pas un secret coupable, mais une partie définie du processus.

Cela maintient la créativité vivante , réduit le stress, et produit des systèmes qui s’élargent de façon élégante— car vous avez compris le problème avant d’être engagé à trouver une solutionM SK3

> **Cessez de tenter d’être parfait depuis le premier minute. Demandez à vous-même la permission de jouerM SK1**

---


## Lecture connexe

Si cela resonate, vous pouvez aussi profiter de ces articles connexes:

- **[Comment je crée un logiciel](/blog/makeitworkthenmakeitpretty)** - Étudie plus en profondeur la philosophie d’essai qui sous-tend cette approche, avec des exemples de code détaillés des trois phases
- **[Les stand-ups quotidiens sont bullshit (à moins qu’ils ne gagnent leur salaire)](/blog/agile-standups-ceremony-tax)** - Mon point de vue sur la raison pour laquelle les cérémonies sont imposées , et comment évaluer si vos rituels agiles gagnent leur main-d’œuvre .
- **[Agile Speccing: Écrire des spécifications de fonctions qui fonctionnent réellement](/blog/writingfeaturespecs)** - Parce que les spécifications sont des outils , non pas des bibles — et qu’en les traitant comme des documents vivants, c’est la seule façon de bâtir le bien-fondé.
- **[Travailler sur les bases de codes d'héritage](/blog/workingonlegacysystems)** - Leçons pratiques tirées des décennies de la vie d’un sous-traitant