Architecture système : des décisions, une équipe et la preuve que le changement a du sens

Un atelier pratique : quand structurer l’architecture, qui impliquer, comment décider, documenter les frontières et reprendre un système existant. Avec carte mentale, code et mini-jeu de décision.

L’article complet est disponible ci-dessous. Activez JavaScript pour les quiz et les simulations.

Un atelier d’architecture sans mise en scène

Une bonne architecture commence quand on cesse de deviner.

Avant le diagramme, le framework ou les microservices, il faut répondre à une question simple et difficile : qu’est-ce qui changera souvent, qu’est-ce qui doit rester stable et qu’est-ce qu’on ne peut pas casser au deuxième déploiement ?

Une bonne architecture permet de faire évoluer le produit sans panique. L’équipe sait où sont les responsabilités. Paiement, formulaire, espace client, e-mail et rapport ne forment pas un bloc que personne n’ose toucher avant le week-end.

Ce que fait l’architecture

Elle fixe les frontières, consigne les choix, réduit le coût des changements et décrit la réaction aux incidents.

Ce qu’elle ne fait pas

Elle ne remplace ni réflexion, ni tests, ni responsabilité, ni échanges métier. La documentation seule n’exploite pas la production.

Quand elle devient urgente

Lorsqu’une correction touche plusieurs modules sans que personne puisse prévoir ses effets secondaires.

Une définition utile en pratique

L’architecture rassemble les décisions difficiles à inverser.

On peut changer un framework, une couleur ou un endpoint. Modifier le modèle de données, les responsabilités, les paiements, les droits, le pipeline ou l’observabilité est plus difficile.

Une décision coûteuse à inverser mérite une réflexion architecturale. Une décision facilement réversible ne nécessite pas un grand comité. Cette règle protège autant du désordre sans règles que de la bureaucratie sans valeur.

Carte mentale Une bonne décision d’architecture
ProblèmeQu’est-ce qui fait réellement souffrir l’activité ?
DonnéesQuelle est la source de vérité ?
FrontièreOù s’arrête la responsabilité du module ?
PanneQue faire si le prestataire ne répond plus ?
PreuveComment vérifier le fonctionnement ?
RetourComment retrouver un état stable ?

Ce qu’il faut

Cinq éléments sans lesquels l’architecture reste un dessin.

objectif métier frontières du processus responsable de la décision preuve de fonctionnement raison du choix consignée

Le manque concerne souvent la responsabilité, pas la technologie. On sait qu’il faut une intégration, mais personne ne précise qui gère les reprises, les doublons, les erreurs, la recette et la clôture.

L’architecture doit donc être courte, lisible et liée au flux réel. Si un client paie un audit, le système doit savoir ce que signifie ce paiement, quand lancer la mesure, comment enregistrer le rapport, notifier et afficher l’échec d’une étape.

Quand une structure légère suffit-elle et quand faut-il formaliser davantage ?

Situation Socle suffisant À ne pas oublier
Site marketing Standards de composants, SEO, formulaires, analytique. Sauvegarde des contenus, sécurité des formulaires, suivi des erreurs.
Espace client Rôles, sessions, journaux et audit des changements clairs. Autorisations, rétention, réinitialisation du mot de passe, tests E2E.
Checkout et paiements Flux distinct de commande et de réception. Idempotence du webhook, signatures, remboursement, statut du paiement.
Intégrations ERP/API Contrats, files, reprises, cartographie des données. Doublons, DLQ, cohérence et versionnement.
Système réglementé ADR, revue sécurité, contrôle d’accès, piste d’audit. RGPD, sous-traitance des données, rétention, procédure d’incident.

Personnes et responsabilités

Qui doit porter l’architecture et combien de personnes impliquer ?

Deux modèles fonctionnent mal : une personne impose son architecture comme une vérité, ou douze personnes donnent un avis sans assumer la décision.

La plupart des projets nécessitent un petit groupe : responsable de l’objectif métier, propriétaire technique du backend et des données, personne du frontend ou de l’UX, exploitation et sécurité, plus un spécialiste métier si nécessaire : vente, comptabilité, logistique ou assistance.

3–4 personnespetite application, un domaine, décisions rapides
5–6 personnesespace client, paiements, intégrations, plusieurs rôles
6–8 personnesdonnées sensibles, systèmes multiples, audit et recette formelle

Davantage de personnes ne garantit pas une meilleure architecture. Cela peut ralentir les décisions et diluer les responsabilités. Préférez une petite équipe capable de choisir, expliquer et prouver.

Énigme 01

Le client paie un audit qui peut durer plusieurs minutes. Que faites-vous ?

Je lance l’audit complet dans le webhook Stripe.

J’enregistre le paiement et l’événement dans l’outbox.

J’affiche « rapport bientôt disponible » sans file.

Choisissez une décision et découvrez sa conséquence.

Exemple de production

Une petite fonction peut coûter cher si les frontières sont mauvaises.

Imaginons : URL, paiement, analyse, résultat enregistré, e-mail et rapport dans l’espace client. Simple sur une diapositive. En production : webhook Stripe reçu deux fois, e-mail échoué, audit lent, actualisation après paiement ou rapport créé mais non enregistré. Que fait le système ?

C’est exactement ici que commence l’architecture : dans le comportement face au monde réel, avant le choix d’une bibliothèque.

Du code qui alerte

Même un code court peut en faire trop.

L’exemple mélange paiement, audit, rapport, e-mail et prestataire au même endroit. Après une panne, il devient difficile de savoir ce qui s’est déjà passé.

public async Task CompleteOrder(Guid orderId)
{
    var order = await db.Orders.FindAsync(orderId);
    order.Status = "Paid";

    var audit = await crawler.Run(order.TargetUrl);
    order.ReportJson = JsonSerializer.Serialize(audit);

    await email.Send(order.Email, "Raport gotowy", audit.Summary);
    await stripe.MarkProcessed(order.PaymentIntentId);
    await db.SaveChangesAsync();
}

Une meilleure frontière

La décision d’abord, puis les effets secondaires.

La transaction enregistre un fait et l’intention de poursuivre. Audit, e-mail et intégrations peuvent ensuite avancer séparément avec reprises, supervision et statut clair.

public sealed record ConfirmAuditPayment(
    Guid OrderId,
    string PaymentIntentId,
    DateTimeOffset ConfirmedAt);

public sealed class ConfirmAuditPaymentHandler
{
    public async Task Handle(ConfirmAuditPayment command)
    {
        var order = await orders.Get(command.OrderId);

        order.MarkAsPaid(command.PaymentIntentId, command.ConfirmedAt);
        outbox.Add(new AuditRequested(order.Id, order.TargetUrl));
        outbox.Add(new CustomerNotificationRequested(order.Id));

        await unitOfWork.SaveChanges();
    }
}

SOLID sans dogme

Les principes doivent aider, pas masquer l’absence de décisions.

Single Responsibility : si changer l’e-mail casse le paiement, les responsabilités sont mêlées. Open/Closed : si chaque prestataire oblige à modifier la moitié du système, il manque un contrat. Dependency Inversion : si le domaine dépend du détail technique, ce détail gouverne le produit.

Commencez simplement par des contrats qui tiennent leurs promesses :

public interface AuditReportStore
{
    Task Save(AuditReport report, CancellationToken cancellationToken);
}

public interface AuditNotifier
{
    Task NotifyReportReady(Guid orderId, CancellationToken cancellationToken);
}

public sealed class CompleteAuditHandler
{
    public async Task Handle(AuditCompleted completed, CancellationToken ct)
    {
        await reports.Save(completed.Report, ct);
        await notifier.NotifyReportReady(completed.OrderId, ct);
    }
}

Mini-jeu

Reconstituez le parcours de la décision d’architecture.

0/6

Plan de panne et de reprises

Objectif métier

Tests, supervision et rollback

Modèle de données et source de vérité

Frontières du processus

Contrat d’intégration

Remettez les étapes dans l’ordre. Partez de l’objectif, pas de la technologie.

Effacer les réponses

Reprendre un système existant

Avant de refactoriser, comprenez ce qui ne doit pas être cassé.

Reprendre du code n’est ni chercher un coupable ni chasser les classes laides. C’est enquêter sur les flux critiques, données sources, intégrations, décideurs et endroits où un test manquant peut coûter de l’argent au client.

Lancez l’application en local Repérez connexion, paiements, formulaires et intégrations Dessinez la carte des données Ajoutez un test de caractérisation Fixez les critères de recette avant la modification

Le test de caractérisation ne dit pas que l’ancien code est beau. Il dit : « Voici le comportement actuel à ne pas modifier par accident. »

[Fact]
public async Task Paid_order_requests_audit_only_once_for_duplicate_webhook()
{
    var paymentIntentId = "pi_123";

    await app.HandleStripeWebhook(paymentIntentId);
    await app.HandleStripeWebhook(paymentIntentId);

    var order = await app.FindOrderByPayment(paymentIntentId);

    Assert.Equal(OrderStatus.Paid, order.Status);
    Assert.Single(await app.Outbox.EventsOfType<AuditRequested>(order.Id));
}
Énigme 02

Vous reprenez un module sans tests. Que faites-vous le premier jour ?

Je refactorise immédiatement la classe la plus laide.

J’écris un test de caractérisation du flux critique.

Je lis le README en supposant qu’il est à jour.

Choisissez et découvrez la conséquence pour la maintenance.

L’ADR en pratique

Une décision exige une raison, des conséquences et une preuve.

Nous la consignons pour comprendre dans trois mois pourquoi le système fonctionne ainsi, pas pour produire de la documentation pour elle-même.

ADR-004 : lancer l’audit de manière asynchrone après le paiement

Contexte :
L’audit d’un site peut durer de quelques dizaines de secondes à plusieurs minutes.
Le checkout doit se terminer rapidement.

Décision :
Après le webhook Stripe, nous enregistrons la commande comme payée
et plaçons l’événement AuditRequested dans l’outbox.

Conséquences :
Le tableau de bord affiche le statut "en attente".
Le worker peut relancer l’audit après une erreur.
Il faut surveiller la file et les tâches en échec définitif.

Preuves :
Test d’un webhook en double, test de redémarrage du worker,
log de corrélation orderId.

Lancer le preflight de la décision

Prêt à vérifier. Cliquez pour contrôler la traçabilité de la décision.

Questions de contrôle

Sans réponse, l’architecture n’est pas encore prête.

01Quel événement métier déclenche le processus ?
02Quelles données font autorité ?
03Qui peut approuver une décision coûteuse ?
04Que se passe-t-il avec une requête dupliquée ?
05Comment le client verra-t-il le statut du travail ?
06Quel test clôture la recette ?

Conclusion

Une bonne architecture se voit surtout quand quelque chose échoue.

Si le système affiche un statut clair, répète sans danger, conserve les données, alerte, revient en arrière et laisse l’humain décider au bon endroit, l’architecture commence à rentabiliser son coût.

Elle réduit le désordre et permet de livrer sans peur ; c’est cela qui compte, pas la mode.

Résultat des décisions de cet atelier 0/2

Commencez par une décision. Une bonne architecture doit se défendre dans un scénario réel, pas seulement sur un diagramme.

Réinitialiser l’atelier