Du code jetable au code durable : Notre approche de la dette technique
"On fera propre plus tard, là il faut livrer vite." Cette phrase, nous l'avons tous entendue. Le problème ? "Plus tard" n'arrive jamais. Et le code "temporaire" devient permanent.
La dette technique : Le tueur silencieux
📉 Les chiffres qui font peur
Coût de la dette technique
- 10-25% du budget projet : Temps passé à corriger des problèmes évitables
- 3-4x plus cher de corriger : Un bug en production vs en développement
- 40% de productivité perdue : Dans les projets avec dette technique élevée
Impact sur les équipes
- Démotivation : "On passe notre temps à réparer au lieu d'innover"
- Turnover : Les bons développeurs fuient le code pourri
- Burnout : Le stress de travailler sur du code fragile
🎭 Les symptômes de la dette technique
Signes visibles
- Bugs récurrents : Même zone du code, problèmes différents
- Lenteur d'évolution : "Pourquoi ça prend autant de temps pour si peu ?"
- Peur de toucher au code : "On ne sait pas ce que ça va casser"
- Documentation inexistante : "Il faut demander à Jean, lui seul comprend"
Signes techniques
// Code smell #1 : Fonctions géantes
function handleUserAction(user, action, data) {
// 500 lignes de code
// Tout est mélangé : validation, métier, persistance
}
// Code smell #2 : Duplication
function calculatePriceForUser(user) { /* 50 lignes */ }
function calculatePriceForCompany(company) { /* 50 lignes quasi identiques */ }
// Code smell #3 : Couplage fort
class UserService {
constructor() {
this.database = new PostgresDatabase(); // Impossible de tester
this.emailService = new SendGridService(); // Dépendances hardcodées
}
}Pourquoi la dette technique s'accumule
🏃 La pression du time-to-market
Le cercle vicieux
- Pression : "Il faut livrer vite"
- Compromis : "On fait vite et mal"
- Dette : Le code devient difficile à maintenir
- Ralentissement : Les évolutions prennent de plus en plus de temps
- Plus de pression : "Pourquoi vous êtes si lents ?"
- Retour au point 2
💸 Les mauvaises incitations économiques
En régie
- Plus de dette = plus d'heures : Le prestataire gagne plus
- Pas de responsabilité long terme : "Pas mon problème après livraison"
- Développeurs interchangeables : Pas de continuité
En forfait mal géré
- Économies à court terme : "On rogne sur la qualité pour respecter le budget"
- Absence de prévoyance : "On paiera la dette plus tard"
Notre approche : La qualité dès le premier jour
🎯 Principe fondamental : Le code maintenable coûte moins cher
Paradoxe apparent : Prendre le temps de bien faire ralentit à court terme mais accélère à long terme.
Comparaison sur un projet de 6 mois
Approche "quick & dirty"
- Mois 1-2 : 100% de vélocité
- Mois 3-4 : 60% de vélocité (bugs, difficulté d'évolution)
- Mois 5-6 : 30% de vélocité (dette technique écrasante)
- Fonctionnalités livrées : 60%
Approche "clean & sustainable"
- Mois 1-2 : 80% de vélocité (temps investi dans la qualité)
- Mois 3-4 : 90% de vélocité (bases solides)
- Mois 5-6 : 95% de vélocité (code maintenable)
- Fonctionnalités livrées : 85%
🏗️ Architecture solide dès le départ
Principes SOLID appliqués
// ❌ Mauvais : Tout dans une classe
class UserManager {
createUser() { /* ... */ }
sendEmail() { /* ... */ }
saveToDatabase() { /* ... */ }
generatePDF() { /* ... */ }
}
// ✅ Bon : Responsabilités séparées
class UserService {
constructor(
private repository: UserRepository,
private emailService: EmailService,
private pdfGenerator: PDFGenerator
) {}
async createUser(data: CreateUserDto): Promise<User> {
const user = await this.repository.create(data);
await this.emailService.sendWelcome(user);
return user;
}
}Avantages concrets
- Testabilité : Chaque composant testé indépendamment
- Évolutivité : Changer un composant sans tout casser
- Compréhension : Code lisible et prévisible
- Réutilisation : Composants réutilisables dans d'autres projets
🧪 Tests automatisés non négociables
Notre règle : 80% de couverture minimum
// Test unitaire
describe('UserService', () => {
it('should create user and send welcome email', async () => {
const mockRepo = { create: jest.fn().mockResolvedValue(mockUser) };
const mockEmail = { sendWelcome: jest.fn() };
const service = new UserService(mockRepo, mockEmail);
const result = await service.createUser(userData);
expect(mockRepo.create).toHaveBeenCalledWith(userData);
expect(mockEmail.sendWelcome).toHaveBeenCalledWith(mockUser);
expect(result).toEqual(mockUser);
});
});
// Test d'intégration
describe('User Registration Flow', () => {
it('should register user end-to-end', async () => {
const response = await request(app)
.post('/api/users/register')
.send(userData);
expect(response.status).toBe(201);
expect(response.body.user.email).toBe(userData.email);
// Vérifier que l'email a été envoyé
const emails = await getTestEmails();
expect(emails).toContainEmail(userData.email);
});
});Les bénéfices
- Confiance : Refactorer sans crainte
- Documentation : Les tests documentent le comportement
- Régression : Détection immédiate des bugs
- Vélocité : Moins de temps en debugging
📚 Documentation vivante
Documentation au bon niveau
Code auto-documenté
// ❌ Mauvais : Commentaires qui disent ce que fait le code
// Incrémente le compteur
counter++;
// ✅ Bon : Code qui se lit comme du français
function incrementFailedLoginAttempts(user: User): void {
user.failedLoginAttempts++;
if (user.hasReachedMaxLoginAttempts()) {
this.lockUserAccount(user);
this.notifySecurityTeam(user);
}
}Architecture documentée
- README : Vue d'ensemble du projet
- Architecture Decision Records (ADR) : Pourquoi on a fait tel choix
- API Documentation : Swagger/OpenAPI générée automatiquement
- Diagrammes : Architecture système, flux de données
Documentation automatisée
/**
* Crée un nouvel utilisateur dans le système
*
* @param data - Les données de l'utilisateur à créer
* @returns L'utilisateur créé avec son ID
* @throws {ValidationError} Si les données sont invalides
* @throws {DuplicateEmailError} Si l'email existe déjà
*
* @example
* ```ts
* const user = await userService.createUser({
* email: 'john@example.com',
* name: 'John Doe'
* });
* ```
*/
async createUser(data: CreateUserDto): Promise<User> {
// ...
}🔍 Code Review systématique
Notre process de review
- Aucun code en production sans review
- Review par au moins un autre développeur
- Checklist de review
- Tests présents et pertinents
- Code lisible et maintenable
- Pas de duplication
- Gestion d'erreurs appropriée
- Performance acceptable
- Sécurité vérifiée
Exemple de feedback constructif
// Code proposé
function getUsers() {
return db.query('SELECT * FROM users');
}
// Commentaire review
// 🔴 Problème :
// - SELECT * est coûteux et expose potentiellement des données sensibles
// - Pas de pagination, problème de performance si beaucoup d'utilisateurs
// - Pas de gestion d'erreur
//
// ✅ Suggestion :
async function getUsers(page: number = 1, limit: number = 20): Promise<PaginatedUsers> {
try {
const offset = (page - 1) * limit;
const users = await db.query(
'SELECT id, email, name, created_at FROM users LIMIT ? OFFSET ?',
[limit, offset]
);
const total = await db.query('SELECT COUNT(*) as count FROM users');
return {
data: users,
pagination: {
page,
limit,
total: total[0].count,
totalPages: Math.ceil(total[0].count / limit)
}
};
} catch (error) {
logger.error('Failed to fetch users', error);
throw new DatabaseError('Unable to retrieve users');
}
}Gérer la dette existante
🔧 Audit et cartographie
Notre méthode d'audit
- Analyse statique : SonarQube, ESLint, outils de complexité
- Identification des hotspots : Zones les plus problématiques
- Priorisation : Impact business vs effort de correction
- Plan de remédiation : Roadmap de réduction de dette
Exemple de cartographie
Zone critique : Module de paiement
- Complexité cyclomatique : 45 (critique, devrait être < 10)
- Couverture tests : 20% (insuffisant)
- Duplication : 40%
- Impact business : CRITIQUE (revenus)
→ Priorité 1 : Refactoring immédiat
Zone problématique : Dashboard admin
- Complexité : 15 (élevée)
- Couverture tests : 60%
- Performance : Lente (2s de chargement)
- Impact business : MOYEN (outil interne)
→ Priorité 2 : Amélioration progressive🎯 Stratégie du Boy Scout
"Laissez le code dans un meilleur état que vous ne l'avez trouvé"
// Lors d'une intervention sur une fonctionnalité
// Avant
function calculate(a, b, c) { // Noms peu clairs
return a * b + c; // Formule opaque
}
// Après intervention sur une feature adjacente
function calculateTotalPrice(
unitPrice: number,
quantity: number,
shippingCost: number
): number {
const subtotal = unitPrice * quantity;
const total = subtotal + shippingCost;
return total;
}
// On a amélioré le code en passant, sans projet de refactoring complet🔄 Refactoring incrémental
Principe : Petits pas, livraison continue
❌ Mauvaise approche : Big Bang Rewrite
- Arrêter les features pendant 3 mois
- Réécrire tout from scratch
- Risque énorme de régression
- Clients mécontents de l'absence d'évolution
✅ Bonne approche : Étrangleur Pattern
Ancien système → Façade → Nouveau système
↓ ↓ ↑
Module A Routing Module A' (nouveau)
Module B → Module B (ancien, encore)
Module C → Module C (ancien, encore)
// Progressivement, on migre module par module
// Le système reste fonctionnel à tout momentMesurer et suivre la qualité
📊 Métriques de qualité
Métriques objectives
- Couverture de tests : Minimum 80%
- Complexité cyclomatique : < 10 par fonction
- Duplication : < 5%
- Temps de build : < 5 minutes
- Taux de bugs en production : < 1 par semaine
Métriques subjectives
- Satisfaction développeurs : Enquêtes trimestrielles
- Temps d'onboarding : Nouveau dev autonome en combien de temps ?
- Vélocité d'évolution : Tendance sur 6 mois
📈 Tableau de bord qualité
Projet: E-commerce Platform
Date: 2025-01-20
Code Quality Score: 87/100 (🟢 Excellent)
Couverture tests: ████████░░ 82% 🟢
Complexité: ████████░░ 8.5/10 🟢
Duplication: ██████████ 3% 🟢
Dette technique: ███████░░░ 12 jours 🟡
Performance: ████████░░ 85/100 🟢
Tendance 3 mois: 📈 +5 points
Actions prioritaires:
1. Refactorer module paiement (dette: 5 jours)
2. Optimiser requêtes dashboard (perf: -15 pts)
3. Ajouter tests module reporting (couv: 60%)L'impact business de la qualité
💰 ROI de la qualité
Projet e-commerce : Comparaison 2 ans
Avec dette technique (ancien prestataire)
- Année 1 : 100k€ développement initial
- Année 2 : 80k€ corrections + évolutions lentes
- Total : 180k€
- Fonctionnalités livrées : 15
- Bugs en production : ~50/an
Sans dette technique (notre approche)
- Année 1 : 120k€ développement initial (+20% pour qualité)
- Année 2 : 40k€ évolutions rapides
- Total : 160k€
- Fonctionnalités livrées : 25 (+67%)
- Bugs en production : ~10/an (-80%)
ROI : 20k€ d'économie + 10 fonctions en plus
🚀 Vélocité maintenue dans le temps
Vélocité (story points / sprint)
Code de qualité:
Sprint 1-5: ████████░░ 40 pts
Sprint 6-10: █████████░ 45 pts ↗
Sprint 11-15: ██████████ 50 pts ↗
Code avec dette:
Sprint 1-5: ██████████ 50 pts
Sprint 6-10: ███████░░░ 35 pts ↘
Sprint 11-15: ████░░░░░░ 20 pts ↘↘
La qualité paye ses dividendes sur la duréeNotre engagement qualité
✅ Dans nos forfaits
Inclus systématiquement :
- Architecture solide : Design patterns et SOLID
- Tests automatisés : 80% de couverture minimum
- Code review : 100% du code reviewé
- Documentation : Technique et utilisateur
- Monitoring : Logs et métriques dès le jour 1
- CI/CD : Déploiement automatisé et sécurisé
🎯 Garantie anti-dette
Engagement sur 3 mois post-livraison :
- Correction gratuite : De tout bug ou problème de qualité
- Refactoring inclus : Si une zone s'avère problématique
- Support technique : Aide à la maintenance
Conclusion : La qualité est un investissement
Le code de qualité n'est pas un luxe, c'est un investissement rentable.
Notre conviction
Chez craftsquad.io, nous refusons de livrer du code dont nous ne serions pas fiers. Parce que nous savons que :
- Votre projet va évoluer : Le code doit être maintenable
- Votre business va grandir : Le code doit être scalable
- Vos utilisateurs sont exigeants : Le code doit être fiable
Le code jetable coûte moins cher aujourd'hui mais beaucoup plus cher demain. Le code durable coûte un peu plus aujourd'hui mais beaucoup moins cher sur la durée.
C'est ce deuxième chemin que nous avons choisi.
Vous voulez un code qui ne se transforme pas en cauchemar de maintenance ? [Parlons de votre projet](/#contact).