Après 15 ans de missions en développement .NET, j'ai rencontré deux types de développeurs. Les premiers sont de remarquables techniciens : ils connaissent les patterns, écrivent du code propre, livrent dans les temps. Les seconds font tout ça — et en plus, ils posent des questions qui changent le sprint avant qu'il commence. Ce sont eux qui durent dans les missions, qui progressent au rôle de Lead, qui deviennent des référents. Et la différence entre les deux groupes n'est pas technique. C'est la compréhension du produit.
Feature factory vs product thinking : la vraie distinction
Le modèle de la feature factory est simple et dangereux : le ticket arrive, le développeur implémente, la PR est mergée, next. Personne ne se demande si la feature résolve vraiment le problème. Le produit s'alourdit, la base de code se complexifie, les utilisateurs boudent des fonctionnalités que personne n'utilise. Tout le monde a travaillé dur, et pourtant le résultat est décevant.
Le product thinking, c'est l'opposé : avant de toucher le clavier, on comprend pourquoi ce ticket existe. Quel problème utilisateur résout-il ? Quelle métrique améliore-t-il ? Existe-t-il une solution plus simple qui atteint le même objectif avec moins de code ? Ce n'est pas du scope creep — c'est de la rigueur intellectuelle appliquée à l'ingénierie logicielle.
Sur mes missions, je remarque systématiquement que les développeurs qui posent ces questions avant de commencer produisent un code architecturalement plus simple, plus cohérent avec le domaine, et beaucoup moins sujet à la refactorisation forcée trois sprints plus tard.
"Le pire code que j'aie jamais vu était techniquement correct. Il implémentait scrupuleusement une spécification que personne n'avait vraiment comprise — et qu'aucun utilisateur n'attendait sous cette forme."
Comment une exigence mal comprise génère du mauvais code
Voici un exemple réel, légèrement anonymisé, d'une mission sur un système de gestion de commandes B2B. Le ticket disait : "Ajouter une règle de validation : une commande ne peut pas dépasser le budget mensuel du client."
Sans context produit, le développeur implémente une validation sur la commande en cours :
// Implémentation "littérale" de la spec — techniquement correcte
// mais architecturalement fausse
public class OrderValidator
{
private readonly IOrderRepository _orders;
public async Task<bool> IsWithinBudgetAsync(Order order)
{
var monthlySpent = await _orders
.GetMonthlySpentAsync(order.ClientId, DateTime.UtcNow);
return monthlySpent + order.TotalAmount <= order.Client.MonthlyBudget;
}
}
Le code est propre. Mais en discutant avec le Product Owner, on apprend que la règle réelle est plus subtile : le budget mensuel est cumulatif par unité de gestion, non par client individuel — un client peut commander pour plusieurs entités juridiques distinctes. Et le dépassement ne doit pas bloquer la commande, il doit déclencher une demande d'approbation plutôt qu'un refus.
Résultat : le concept de "budget" n'est pas une validation de commande — c'est un processus d'approbation conditionnel. Le bon modèle DDD n'est pas un OrderValidator mais un BudgetApprovalPolicy qui émet un OrderSubmittedForApproval event. La différence architecturale est énorme. Et elle était invisible dans le ticket original.
// Modèle correct après compréhension du domaine
public class BudgetApprovalPolicy
{
public BudgetApprovalDecision Evaluate(Order order, BudgetContext context)
{
var remainingBudget = context.ManagementUnit.MonthlyBudget
- context.CurrentMonthSpent;
if(order.TotalAmount <= remainingBudget)
{
return BudgetApprovalDecision.AutoApproved();
}
return BudgetApprovalDecision.RequiresApproval(
approver: context.ManagementUnit.BudgetApprover,
overshootAmount: order.TotalAmount - remainingBudget);
}
}
// L'event qui sera traité par un process manager
public record OrderSubmittedForApproval(
OrderId OrderId,
UserId ApproverId,
decimal OvershootAmount,
DateTimeOffset SubmittedAt);
Ce second modèle n'est pas plus complexe techniquement. Il est plus juste. Et il est plus juste parce que j'ai pris 20 minutes pour comprendre le domaine avant de coder.
Event Storming et Domain Storytelling : les outils du développeur curieux
La compréhension du domaine ne vient pas de la lecture des tickets Jira. Elle vient de la conversation avec les experts métier. Deux outils que j'utilise régulièrement en démarrage de mission ou en début de sprint complexe :
Event Storming léger
Je n'ai pas toujours accès à un atelier formel d'Event Storming avec tous les stakeholders. Mais même en tête-à-tête avec un PO ou un expert métier, poser la question "quels événements se produisent dans ce processus ?" et les noter sur des post-its (physiques ou Miro) génère immédiatement une carte des domain events. Ce sont ces events qui structurent le modèle DDD : OrderPlaced, BudgetExceeded, ApprovalRequested, OrderApproved — ils sont là, dans le cerveau du métier, ils attendent juste qu'on pose la question.
Les questions à poser avant chaque feature
Avec le temps, j'ai listé les questions qui font le plus de différence. Sur mes missions, je les pose systématiquement en refinement ou en début de tâche :
- "Quel problème utilisateur ce ticket résout-il ?" — Si personne ne sait répondre, c'est un signal d'alarme.
- "Que se passe-t-il si on ne le fait pas ?" — Les tickets non-urgents révèlent souvent leur vraie priorité ici.
- "Existe-t-il un comportement existant similaire dans le système ?" — Souvent la feature demandée est une généralisation d'une règle déjà là, pas une nouvelle.
- "Qui prend la décision dans ce processus — une personne, un système, une règle automatique ?" — La réponse change radicalement l'architecture (commande vs événement vs politique).
- "À quelle fréquence ce cas se produit-il ?" — La complexité technique doit être proportionnelle à la fréquence et à l'impact réel.
"Chaque heure passée à comprendre le domaine économise entre trois et dix heures de refactorisation future. Ce n'est pas de la sur-ingénierie préventive — c'est de l'économie d'effort."
Comment l'intelligence produit façonne directement le modèle DDD
Domain-Driven Design part d'une prémisse radicale : le code doit parler le même langage que les experts métier. Pas un langage technique approximatif — exactement les mêmes mots, les mêmes concepts, les mêmes distinctions. Ce principe de l'Ubiquitous Language n'est pas une décoration méthodologique. C'est une prescription technique : quand votre code et votre domaine partagent le même langage, les nouvelles règles métier trouvent naturellement leur place dans le modèle. Les bugs liés à des interprétations erronées disparaissent.
Mais l'Ubiquitous Language ne s'acquiert pas en lisant la doc. Il s'acquiert en posant des questions, en corrigeant ses propres formulations quand l'expert métier fronce les sourcils, en participant aux démos, en lisant les contrats et les process de l'entreprise cliente. Sur les missions longues, je demande systématiquement à assister à une démonstration du produit en situation réelle — pas une démo de sprint, une vraie session utilisateur. Ce que j'y apprends sur l'usage réel vaut plus que trois sessions de refinement.
Ce que cela change concrètement en freelance
En tant que freelance, la compréhension produit est un avantage concurrentiel direct. Les entreprises ne cherchent pas un exécutant — elles cherchent quelqu'un qui peut les aider à prendre de meilleures décisions techniques sur un domaine qu'il comprend. Un freelance qui pose les bonnes questions, qui propose une simplification architecturale parce qu'il a compris que le cas d'usage réel est plus simple que la spec initiale, qui anticipe les conflits entre deux fonctionnalités parce qu'il connaît le domaine — ce profil-là renouvelle ses missions. L'autre reçoit des specs et les implémente.
Concrètement, depuis que je cultive cette posture systématiquement, j'observe trois effets sur mes missions :
- Moins de bugs fonctionnels : pas parce que j'écris moins de bugs techniques — parce que je code rarement la mauvaise chose.
- Des modèles de domaine plus stables : quand le modèle reflète vraiment le domaine, les nouvelles règles métier s'y insèrent sans chirurgie. Le code vieillit mieux.
- Des relations client plus solides : un développeur qui comprend votre métier, qui vous pose des questions précises, qui parfois vous dit "attendez, je pense que ce ticket résout un faux problème" — ça crée une confiance différente. Ça transforme une prestation en partenariat.
Par où commencer ?
Si vous cherchez un point d'entrée concret, commencez par une habitude simple : pour chaque ticket que vous prenez en main cette semaine, posez une question à votre PO avant de commencer à coder. Une seule. "Quel problème ça résout ?" ou "qui va utiliser ça ?". Notez la réponse et regardez si elle change quelque chose à votre approche.
Dans 80% des cas, elle changera quelque chose. Et dans les 20% restants, vous aurez quand même appris quelque chose sur le domaine.
Vous cherchez un Lead Dev .NET qui comprend votre produit ?
Je m'implique dans la compréhension métier dès le démarrage de la mission. Pas pour faire du scope creep — pour livrer ce qui a vraiment de la valeur. Basé à La Rochelle, disponible en remote.
✉ Me contacter