.NET & C#
Back-ends métiers, API et traitements de fond. C'est notre terrain d'origine : découpage en cas d'usage, requêtes SQL dont nous lisons le plan d'exécution, et migrations de schéma qui passent sans arrêter le service.
public sealed class CreateOrderHandler
: IRequestHandler<CreateOrder, Guid>
{
private readonly IOrderRepository _repo;
public async Task<Guid> Handle(CreateOrder cmd, CancellationToken ct)
{
var order = Order.Create(cmd.CustomerId, cmd.Lines);
await _repo.AddAsync(order, ct);
return order.Id;
}
}C'est notre terrain d'origine, et celui où nous sommes le plus difficiles à prendre en défaut. Un back-end .NET, nous en avons écrit, repris, découpé et parfois sauvé assez pour savoir où les problèmes se logent. Rarement dans le langage. Presque toujours à la frontière avec la base de données, et dans ce que l'équipe précédente a cru pouvoir remettre à plus tard.
Le choix de .NET tient à trois propriétés ennuyeuses et décisives. Les montées de version majeures se passent sans drame depuis .NET 6, ce qui n'a pas toujours été vrai. Les performances sont mesurées publiquement à chaque sortie, donc vérifiables par quelqu'un d'autre que l'éditeur. Et on trouve des développeurs à recruter, ce qui décide de la vie d'un logiciel plus sûrement que l'élégance de sa syntaxe.
Ce que nous savons en faire
Le SQL que nous lisons vraiment
Entity Framework Core rend le SQL invisible, et c'est là le piège. Une boucle qui charge des commandes puis leurs lignes une par une produit deux cent une requêtes au lieu de deux, et la page met huit secondes à s'afficher sans qu'aucune ligne de C# ne paraisse fautive. Nous lisons les requêtes générées et leur plan d'exécution, pas seulement les temps de réponse. Un temps de réponse dit qu'il y a un problème ; un plan d'exécution dit lequel.
En pratique cela veut dire savoir quand descendre en SQL écrit à la main, et l'assumer. Sur une requête de rapport avec cinq jointures et une fenêtre glissante, un ORM produit du code illisible et lent. Nous écrivons alors la requête, nous la testons, et nous la commentons. L'inverse est vrai aussi : sur les écritures courantes, EF Core fait mieux et plus sûrement que du SQL recopié dans quinze fichiers.
Les migrations de schéma sans coupure
Renommer une colonne en production casse l'application pendant le déploiement, parce que l'ancienne version du code tourne encore quand la nouvelle structure arrive. Nous procédons donc en deux temps : on ajoute la nouvelle colonne, on écrit dans les deux pendant une version, puis on retire l'ancienne à la version suivante. C'est deux fois plus de déploiements et zéro minute d'interruption.
Cette discipline a un effet secondaire qu'on mesure vite : elle rend les retours en arrière possibles. Une migration qui ne détruit rien peut être annulée en revenant à la version précédente du code, sans restauration de sauvegarde et sans réunion de crise. C'est la différence entre un incident de vingt minutes et une soirée entière.
Traitements de fond, files et idempotence
Tout ce qui est lent doit sortir du cycle de la requête HTTP : envoi de courriels, génération de documents, appels à des services tiers. La règle est simple à énoncer et souvent mal appliquée, parce qu'on oublie la suite : un traitement de fond sera rejoué. Une file de messages garantit qu'un message arrive au moins une fois, jamais exactement une fois, et un serveur qui redémarre au mauvais moment suffit à produire le doublon.
Nous écrivons donc ces traitements pour qu'un rejeu ne fasse pas de dégât : une clé d'idempotence, un état persisté, et la vérification avant l'effet plutôt qu'après. Sans cela, le client reçoit deux factures et personne ne comprend pourquoi, parce que les journaux montrent un seul appel côté métier. Ce genre de bogue coûte plusieurs jours à diagnostiquer et se prévient en une heure de conception.
Quand ce socle est le bon choix
- Votre métier a des règles écrites quelque part et il faut qu'elles soient appliquées de la même façon partout.
- Vous exposez ou consommez des API que d'autres équipes utilisent, avec des engagements de compatibilité.
- Vos volumes de données rendent la moindre requête mal écrite visible sur la facture d'infrastructure.
- Vous êtes déjà sur du .NET ancien et vous voulez avancer sans tout jeter.
L'arbitrage que nous assumons
L'écosystème .NET est plus verbeux que ses concurrents et démarre plus lentement sur les petits projets. Sur un prototype de trois écrans à sortir en trois semaines, un socle plus léger ira plus vite et nous vous le dirons. L'arbitrage s'inverse dès qu'il y a des règles métier, plusieurs développeurs, et un horizon de plus de deux ans.
Chaque socle en a un. Celui qui prétend le contraire vous le fera payer plus tard.
