AIO APEX
Works best with Claude Opus 4.8 or Sonnet 5 for large functions (context window and code reasoning matter more than raw speed here); GPT-5.4 is a solid alternative. Avoid smaller/faster models for this — risk scoring requires holding the whole function's logic in view at once.You've inherited a 400-line function that everyone on the team avoids touching because it 'works, mostly' and nobody remembers why it's structured the way it is. You need to clean it up before adding a new feature, but you don't have time to rewrite it from scratch and can't afford to break the parts that work.Developer Tools

Le Conseiller en Refactorisation de Code : Corrections Avant/Après avec un Score de Risque pour Chacune

Partager:
Le Conseiller en Refactorisation de Code : Corrections Avant/Après avec un Score de Risque pour Chacune

Why this prompt matters

Developers now spend 23-42% of their work week dealing with technical debt and bad code — the Stripe Developer Coefficient study puts the global cost at $85 billion in lost productivity a year. The failure mode isn't not knowing code is bad; it's not knowing which fix is safe to make first. A one-standard-deviation rise in an organization's debt-to-code ratio corresponds to a 31% jump in defect density — refactoring the wrong part first, or all of it at once, is how technical debt cleanup itself introduces new bugs.

What we use it for

You've inherited a 400-line function that everyone on the team avoids touching because it 'works, mostly' and nobody remembers why it's structured the way it is. You need to clean it up before adding a new feature, but you don't have time to rewrite it from scratch and can't afford to break the parts that work.

Prompt

You are a senior software engineer with expertise in refactoring legacy code without introducing regressions. You are conservative by default — you flag risk honestly rather than being falsely reassuring.

CONTEXT:
Language/framework: [YOUR LANGUAGE, e.g. "TypeScript, Node.js, Express"]
What this code does: [ONE-SENTENCE DESCRIPTION OF THE FUNCTION'S PURPOSE]
Known problems (if any): [WHAT YOU ALREADY SUSPECT IS WRONG, e.g. "deeply nested conditionals, unclear variable names, does three unrelated things"]
Test coverage: [DESCRIBE CURRENT TESTS, e.g. "one integration test covering the happy path only" or "none"]
Constraints: [ANYTHING THAT CANNOT CHANGE, e.g. "the public function signature must stay identical, this is called from 40+ places"]

TASK:
Review the code below and identify 3-6 specific, independent refactoring opportunities. For EACH one:
1. Name the problem (e.g. "duplicated validation logic", "mixed abstraction levels", "unclear boolean flag parameter").
2. Show the BEFORE code snippet (just the relevant lines, not the whole function).
3. Show the AFTER code snippet with the fix applied.
4. Assign a Risk Score (Low/Medium/High) based on: how much of the function's behavior the change touches, whether existing tests would catch a regression, and whether the change is purely structural (safe) or alters logic/behavior (riskier).
5. State what you'd want to verify manually or via a new test before merging this specific change.

CONSTRAINTS:
- Do NOT rewrite the entire function in one pass. Each refactor must be independently applicable — I need to be able to accept refactor #2 without necessarily taking #4.
- Order your suggestions from LOWEST risk to HIGHEST risk, so I can bank easy wins first.
- If the function is doing more than one job, say so explicitly and suggest a split — but still give me the low-risk internal cleanups first, since a full split is inherently higher-risk.
- Do not suggest changes that alter the function's observable behavior unless you flag it as Medium or High risk with a clear explanation of what changes.
- If test coverage is described as weak or absent, recommend which specific test(s) to write BEFORE attempting the Medium/High risk refactors, not after.

OUTPUT FORMAT:
## Refactor 1: [Problem name] — Risk: [Low/Medium/High]
**Before:**
```
[code]
```
**After:**
```
[code]
```
**Verify before merging:** [what to check or test]

[repeat for each refactor, low to high risk]

## Summary
[One paragraph: overall assessment of the function's health, and the recommended order of operations]

CODE TO REVIEW:
[PASTE YOUR FUNCTION OR CODE BLOCK HERE]

Result

Refactor 1: Duplicated validation logic — Risk: Low

Before:

if (!user.email || user.email.length === 0) { throw new Error('Email required'); }
if (!user.name || user.name.length === 0) { throw new Error('Name required'); }
if (!user.phone || user.phone.length === 0) { throw new Error('Phone required'); }

After:

const requiredFields = ['email', 'name', 'phone'];
for (const field of requiredFields) {
  if (!user[field]?.length) throw new Error(`${field} required`);
}

Verify before merging: Confirm error message format isn't parsed elsewhere by exact string match — the field name capitalization changed slightly.

Refactor 2: Unclear boolean flag parameter — Risk: Low

Before:

function processOrder(order, flag) {
  if (flag) { applyDiscount(order); }
  ...
}

After:

function processOrder(order, { applyLoyaltyDiscount }) {
  if (applyLoyaltyDiscount) { applyDiscount(order); }
  ...
}

Verify before merging: Update all 6 call sites to pass a named object instead of a positional boolean — purely mechanical, no behavior change, but touches every caller.

Refactor 3: Deeply nested conditionals — Risk: Medium

Before:

if (user.active) {
  if (user.subscription) {
    if (user.subscription.tier === 'pro') {
      // 15 more lines
    }
  }
}

After:

if (!user.active) return;
if (!user.subscription) return;
if (user.subscription.tier !== 'pro') return;
// 15 more lines, now unindented

Verify before merging: Early returns change control flow if there's an else branch further down handling the negative case elsewhere in the original function — check for one before applying. Write a test for the non-pro-tier path specifically, since current coverage doesn't exercise it.

Refactor 4: Function does three unrelated things — Risk: High

Before: Single 400-line function handles validation, discount calculation, and email notification in sequence.

After: Split into validateOrder(), calculateDiscount(), and notifyCustomer(), called in sequence from a thin orchestrator function.

Verify before merging: This changes the function's shape enough that any code relying on partial execution (e.g. catching an error mid-function and still sending a notification) will behave differently. Do NOT attempt this split until Refactors 1-3 are merged and you have integration test coverage for all three code paths — this should be its own PR, reviewed separately.

Summary

This function is moderately unhealthy but not unsalvageable. Refactors 1-2 are safe, mechanical wins you can ship today. Refactor 3 needs one new test first but is still low-stakes. Refactor 4 (the actual split) is the real fix but should wait until the others are merged and stable — attempting all four at once is how a cleanup PR turns into a production incident.

La plupart des prompts de refactorisation produisent une réécriture géante de votre fonction et espèrent qu'elle est correcte. C'est l'inverse pour du code de production réel — une réécriture unique et massive est exactement le genre de changement le plus difficile à réviser, le plus difficile à tester, et le plus susceptible de cacher une régression dans un diff trop grand pour que quiconque puisse le vérifier correctement. Ce prompt fait l'inverse : il divise le nettoyage en morceaux indépendants et fusionnables individuellement, et les classe selon leur capacité à casser quelque chose.

Pourquoi le score de risque prime sur le score de qualité du code

Une refactorisation qui améliore la lisibilité mais ne change aucun comportement observable est fondamentalement différente de celle qui touche à la logique réelle, même si les deux semblent être des diffs de taille similaire. Le prompt impose cette distinction en demandant un Score de Risque basé sur trois facteurs spécifiques : à quel point le changement touche le comportement, si les tests existants détecteraient une régression, et si le changement est purement structurel ou modifie la logique. Cela transforme une vague impression de "cela semble risqué" en une décision reproductible que le modèle doit justifier.

Pourquoi les corrections à faible risque viennent en premier

Classer les suggestions du risque le plus faible au plus élevé n'est pas seulement une question de sécurité — c'est une question de dynamique. Les équipes qui évitent une mauvaise fonction l'évitent souvent complètement, y compris les parties qui sont trivialement sûres à corriger. Obtenir quelques victoires à faible risque en premier (variables renommées, validation dédoublonnée, remplacement de booléens par des paramètres nommés) renforce la confiance et réduit le fichier avant que quelqu'un doive prendre une décision plus difficile sur les changements structurels plus risqués.

Pourquoi il demande une couverture de tests avant de suggérer les choses risquées

La façon la plus courante dont la refactorisation tourne mal est de sauter directement à la partie satisfaisante — diviser une fonction gonflée en morceaux propres et bien nommés — sans vérifier que les tests actuels exercent réellement les chemins de code modifiés. Ce prompt vérifie explicitement votre couverture de tests déclarée et, si elle est faible, vous indique quel test écrire avant de tenter les refactorisations à plus haut risque plutôt qu'après qu'un problème survienne en production.

Pourquoi la division de la fonction est marquée comme son propre PR

Diviser une fonction aux multiples responsabilités en fonctions séparées est généralement la « vraie » correction que tout le monde souhaite, mais c'est aussi le changement le plus susceptible d'altérer des comportements subtils — chemins de gestion d'erreurs, états d'exécution partiels, ordre des effets secondaires. Le prompt traite délibérément cela comme une refactorisation distincte à plus haut risque, à réaliser seulement une fois que les nettoyages plus sûrs sont fusionnés et stables, plutôt que de le regrouper dans le même changement que les victoires faciles.

Comment l'adapter

Soyez précis sur vos contraintes — une fonction appelée depuis 40 endroits se comporte très différemment sous pression de refactorisation qu'une fonction appelée depuis un seul fichier de test. Si vous n'avez réellement aucune couverture de tests, attendez-vous à ce que le modèle recommande d'écrire des tests avant de toucher quoi que ce soit au-delà des un ou deux premiers éléments à faible risque, et traitez cette recommandation comme la réponse réelle, pas comme une formalité à ignorer.

prompt-engineeringcode reviewdeveloper-productivitycode-refactoringtechnical-debt
Partager: