« Clouer » et « hardcoder » sont des termes d'argot qui désignent la fixation rigide de valeurs directement dans le code du programme, au lieu de les placer dans des paramètres ou une configuration. Le hardcode est l'un des anti-patrons les plus connus en développement, car il réduit la flexibilité et la réutilisabilité du code. Selon Refactoring Guru, le hardcode complique les tests, la maintenance et l'adaptation de l'application à différents environnements. L'utilisation consciente de constantes au lieu de hardcode est un signe d'architecture mature.
Points essentiels
Hardcoder (clouer) — intégrer une valeur spécifique dans le code du programme de sorte que sa modification nécessite d'éditer le code source et de recompiler l'application. La métaphore « clouer » reflète exactement l'essence : la valeur est fixée de manière permanente, et on ne peut l'arracher du code qu'avec effort.
Exemple de hardcode — une URL de serveur écrite comme chaîne directement dans le corps d'une fonction. Si le serveur change d'adresse, le développeur doit trouver la chaîne dans le code, la modifier, reconstruire l'application et déployer une nouvelle version. Dans une application avec une architecture correcte, cette URL serait placée dans un fichier de configuration, une variable d'environnement ou un service de configuration.
Le terme « clouer » est plus chargé émotionnellement : il souligne que la valeur est insérée de manière permanente, sans possibilité de remplacement rapide. Dans l'environnement russophone, les deux expressions sont utilisées comme des synonymes complets avec une connotation négative. Parfois, le hardcode est ironiquement appelé « constante extraite dans une constante séparée d'une constante ».
Hardcode — un anti-patron car il viole les principes de maintenabilité, de testabilité et d'extensibilité du code. Dans un code où les valeurs sont « clouées », toute modification d'environnement, de design ou de logique exige une recherche et un remplacement manuels dans les sources. Cela augmente le risque d'erreurs et ralentit le développement.
Considérons les conséquences spécifiques du hardcode en prenant l'exemple d'une application mobile typique. Si la marge de tous les boutons est définie par un nombre dans le code, et non par une ressource — un changement de design nécessitera de trouver toutes les occurrences et de les remplacer. Si l'URL du point d'accès est fixée rigidement — le passage entre les environnements (dev, stage, prod) est impossible sans reconstruction.
| Conséquence | Description | Niveau de criticité |
|---|---|---|
| Difficulté de maintenance | La modification exige une recherche dans tout le code | Élevé |
| Erreurs lors de la copie | Toutes les occurrences ne sont pas trouvées et remplacées | Élevé |
| Impossibilité de tester | Impossible de substituer des données de test | Moyen |
| Problèmes de localisation | Les textes dans le code ne sont pas traduits | Moyen |
| Complexité de la revue de code | Le relecteur doit se souvenir de tous les contextes | Faible |
Une fonction qui utilise des nombres magiques et des chaînes fixées — l'exemple classique de hardcode. Un mois plus tard, l'auteur ne se souviendra plus de ce que signifient 18, 0.07 et 2.5. Un an plus tard — personne dans l'équipe n'osera modifier ces nombres, de peur de casser la logique. Extraire les valeurs dans des constantes nommées rend le code auto-documenté.
// Mauvais : nombres magiques et chaînes
fun calculatePrice(base: Double): Double {
val tax = base * 0.07
val tip = base * 0.15
val discount = if (base > 100) 10 else 0
return base + tax + tip - discount
}
Une URL de base de données hardcodée ne permettra pas d'exécuter des tests sur une base de données locale in-memory. Le développeur devra démarrer un serveur complet ou modifier le code avant les tests. Extraire la configuration du code résout le problème : les tests utilisent des paramètres de test, la production utilise des paramètres réels, et le code reste inchangé.
Le hardcode est un anti-patron, mais il existe des exceptions légitimes où une valeur fixée est non seulement acceptable, mais aussi préférable. La limite suit l'axe de mutabilité : si la valeur ne change jamais ou presque jamais au cours du cycle de vie de l'application, elle peut être hardcodée. Si elle peut potentiellement changer — placez-la dans la configuration.
Les constantes mathématiques et physiques — Pi, accélération de la pesanteur, nombre de millisecondes dans une seconde — sont sûres pour le hardcode. Elles sont définies par la nature ou les normes et ne changeront pas. Les tailles de tableaux constants définies par spécification peuvent aussi être fixées, mais avec un commentaire sur l'origine du nombre.
Le nombre de millisecondes dans une seconde est une constante stable définie par la norme de temps. Il n'y a pas de sens à la placer dans une configuration, car elle ne changera jamais. Cependant, même ces constantes, il est préférable de les déclarer avec un nom explicite, pour que le code ne contienne pas de « nombres magiques » : au lieu de 1000, écrivez MILLISECONDS_IN_SECOND.
// Hardcode justifié : constantes stables
private const val MILLIS_IN_SECOND = 1000
private const val LOGIN_TIMEOUT_SECONDS = 30
fun formatDuration(ms: Long): String {
val seconds = ms / MILLIS_IN_SECOND
return "${seconds} sec."
}
Il existe plusieurs façons éprouvées d'éviter le hardcode, chacune adaptée à son type de valeur. Le choix de l'alternative dépend de la fréquence de changement de la valeur et de qui la modifie : développeur, devops ou utilisateur final.
Pour les URL de serveurs, les clés API et les feature flags, utilisez des fichiers de configuration aux formats JSON, YAML ou TOML. Sur Android, c'est build.gradle avec buildConfigField ou res/values/config.xml. Sur iOS — Info.plist ou xcconfig. Les configurations sont compilées avec l'application, mais peuvent être différentes pour différents schémas de build.
Pour les secrets (tokens, mots de passe) et les paramètres d'environnement, utilisez des variables d'environnement. Elles n'entrent pas dans le dépôt et peuvent différer sur les serveurs dev, stage et prod. En développement mobile, les variables d'environnement sont souvent émulées via les schémas de build Xcode ou les build flavors dans Gradle.
Les chaînes, couleurs, tailles, images doivent être placées dans des fichiers de ressources : strings.xml sur Android, Localizable.strings sur iOS, fichiers ARB dans Flutter. Cela facilite la localisation, l'adaptation à différents écrans et le thème sombre. Modifier une chaîne dans les ressources ne nécessite pas de réécrire le code.
<!-- Android: res/values/strings.xml -->
<resources>
<string name="app_name">MyApp</string>
<string name="api_base_url">https://api.example.com</string>
</resources>
Pour les services et fournisseurs, utilisez l'injection de dépendances avec Dagger, Hilt ou Koin sur Android, Swinject sur iOS. Les frameworks DI permettent de remplacer les implémentations à la volée — pour les tests, pour différents environnements, pour différents utilisateurs. C'est le plus haut niveau d'abstraction, où le « clouage » de la valeur est remplacé par une injection externe.
Le refactoring du hardcode est le processus d'extraction des valeurs fixées vers la configuration ou les ressources. C'est l'une des opérations de refactoring les plus sûres, si elle est faite méthodiquement. La séquence décrite ci-dessous convient à tout langage et plateforme.
La recherche peut être effectuée via l'IDE (Search in Project) ou un script. Cherchez des chaînes, URL, littéraux numériques, tailles, timeouts. Une attention particulière — aux valeurs répétées : si le même nombre apparaît à cinq endroits, c'est un candidat à devenir une constante. Utilisez grep ou la recherche intégrée d'IDEA / Xcode.
Pour chaque valeur trouvée, créez une constante avec un nom significatif. Regroupez les constantes par modules ou classes. Le nom doit expliquer ce que signifie la valeur, pas comment elle est utilisée : API_TIMEOUT, pas TIMEOUT_30. Après le remplacement, aucun nombre dans le code ne doit rester sans explication.
// Avant : nombre magique 0.4
let cardHeight = screenHeight * 0.4
// Après : constante nommée
private let cardHeightRatio: CGFloat = 0.4
let cardHeight = screenHeight * cardHeightRatio
Si la valeur peut varier entre les builds ou les environnements — placez-la dans un fichier de configuration ou les ressources de l'application. Pour les chaînes, utilisez des fichiers de localisation. Pour les URL — build config ou xcconfig. Pour les tailles — fichiers de ressources (dimens.xml sur Android). Vérifiez que l'application se compile et fonctionne correctement après l'extraction.
Après le refactoring, écrivez un test qui vérifie que la configuration est chargée correctement et que les valeurs correspondent aux attendues. Si quelqu'un modifie la configuration à l'avenir, le test signalera la divergence. Un test de configuration est un moyen rapide et fiable de prévenir la régression.
Après l'extraction dans la configuration, vérifiez que tous les endroits qui utilisaient l'ancienne valeur référencent la source unique. Supprimez le code commenté et les anciennes constantes qui ne sont plus utilisées. Finalisez le refactoring par un commit dont le message décrit quelles valeurs ont été extraites et où.
Questions fréquentes
Hardcoder — écrire une valeur directement dans le code source au lieu de la placer dans la configuration ou les ressources. Cela rend le code moins flexible et plus difficile à maintenir.
Hardcode complique la modification du comportement de l'application, entrave les tests, crée de la duplication et augmente le risque d'erreurs lors de la copie. Modifier une valeur hardcodée nécessite une recompilation et une nouvelle publication de l'application.
Acceptable pour les constantes mathématiques, les valeurs stables qui ne changent pas dans le cycle de vie de l'application et pour les prototypes temporaires. En production, même les constantes devraient être extraites dans des variables nommées.
Trouvez tous les nombres magiques par recherche, remplacez-les par des constantes nommées ou extrayez-les dans un fichier de configuration. Écrivez un test vérifiant le chargement de la configuration. Supprimez les doublons et faites un commit avec une description des modifications.
Constante — une valeur nommée dans le code, modifiable à un seul endroit. Hardcode — des valeurs sans nom dispersées dans le code. Bonne pratique : toujours utiliser des constantes nommées avec des noms significatifs.
Résumé
Nous développerons une application mobile clé en main
IT Sectr crée des applications iOS et Android pour les startups et les entreprises depuis 2017. Nous vous conseillerons et vous proposerons la meilleure solution.
Lisez aussi