Logo ConstructiCat
CodeBust.
Parcourir la section ▾

Codage en dur.

Le codage en dur intègre des chemins, des identifiants ou des taux dans le code source : les modifier impose d’éditer et de recompiler le programme.

Le codage en dur est la pratique de développement logiciel consistant à intégrer des données directement dans le code source d'un programme ou d'un autre objet exécutable, au lieu de les obtenir à partir de sources externes ou de les générer à l'exécution.

Les données codées en dur ne peuvent généralement être modifiées qu'en éditant le code source et en recompilant l'exécutable, même si elles peuvent être modifiées en mémoire ou sur le disque à l'aide d'un débogueur ou d'un éditeur hexadécimal.

Les données codées en dur conviennent le mieux à des informations immuables, telles que les constantes physiques, les numéros de version et les éléments de texte statiques.

Les données à codage souple, en revanche, encodent des informations arbitraires via les saisies utilisateur, les fichiers texte, les fichiers INI, les réponses de serveur HTTP, les fichiers de configuration, les bases de données, les arguments de ligne de commande, et sont déterminées à l'exécution. Les macros de préprocesseur et les constantes placées dans un en-tête ou un module séparé ne relèvent pas du codage souple en ce sens : elles donnent à la valeur un nom et un emplacement unique, mais celle-ci reste fixée à la compilation, et la modifier impose de recompiler.

Vue d'ensemble

Le codage en dur impose de modifier le code source du programme chaque fois que les données d'entrée ou le format souhaité changent, alors qu'il pourrait être plus pratique pour l'utilisateur final de modifier ce détail par un moyen extérieur au programme.

Le codage en dur est souvent nécessaire, mais peut aussi être considéré comme un anti-patron. Les programmeurs n'ont peut-être pas encore mis au point de solution d'interface utilisateur dynamique pour l'utilisateur final, mais doivent tout de même livrer la fonctionnalité ou publier le programme. Cela est généralement temporaire, mais résout, à court terme, la pression liée à la livraison du code. Plus tard, le codage souple est mis en place pour permettre à un utilisateur de transmettre des paramètres qui donnent à l'utilisateur final un moyen de modifier les résultats ou l'issue.

Le terme « codé en dur » a d'abord été utilisé par analogie avec le câblage en dur des circuits, et visait à exprimer le manque de souplesse qui résulte de son usage dans la conception et l'implémentation logicielles. Dans le contexte des environnements de développement collaboratifs extensibles à l'exécution tels que les MUD, le codage en dur désigne aussi le développement du moteur central du système chargé des tâches de bas niveau et de l'exécution des scripts, par opposition au codage souple qui consiste à développer les scripts de haut niveau interprétés par le système à l'exécution, avec des valeurs provenant de sources externes, telles que les fichiers texte, les fichiers INI, les bases de données, les arguments de ligne de commande, les réponses de serveur HTTP, les fichiers de configuration et les saisies utilisateur. Dans ce cas, le terme n'est pas péjoratif et désigne le développement en général, plutôt que l'intégration spécifique de données de sortie.

Portes dérobées

Coder en dur des identifiants est un moyen répandu de créer une porte dérobée. Les identifiants codés en dur ne sont généralement pas visibles dans les fichiers de configuration ni dans la sortie des commandes d'énumération de comptes, et ne peuvent être facilement modifiés ou contournés par les utilisateurs. Si elle est découverte, un utilisateur peut désactiver une telle porte dérobée en modifiant et en reconstruisant le programme à partir de son code source (si la source est disponible publiquement), en le décompilant, ou en faisant de la rétro-ingénierie du logiciel, en éditant directement le code binaire du programme, ou en instaurant un contrôle d'intégrité (tel que des signatures numériques, des protections anti-altération et anti-triche) pour empêcher l'accès inattendu, mais de telles actions sont souvent interdites par un contrat de licence utilisateur final.

Chemin d'installation fixe

Si un programme Windows est conçu en supposant qu'il est toujours installé dans C:\Program Files\Appname et que quelqu'un tente de l'installer sur un autre lecteur pour des raisons d'espace ou d'organisation, il peut échouer à s'installer ou à s'exécuter après l'installation. Ce problème peut ne pas être repéré au cours du processus de test, car l'utilisateur moyen installe sur le lecteur et le répertoire par défaut, et les tests peuvent ne pas inclure l'option de changer le répertoire d'installation. Il est toutefois conseillé aux programmeurs et aux développeurs de ne pas figer le chemin d'installation d'un programme, car le chemin d'installation par défaut dépend du système d'exploitation, de sa version et des décisions de l'administrateur système. Par exemple, de nombreuses installations de Microsoft Windows utilisent le lecteur C: comme disque dur principal, mais cela n'est pas garanti.

Dossiers spéciaux

Certains systèmes d'exploitation Windows possèdent ce que l'on appelle des dossiers spéciaux qui organisent logiquement les fichiers sur le disque dur. Le codage en dur peut y poser des problèmes :

Chemin du profil

Certains programmes Windows codent en dur le chemin du profil vers des emplacements définis par le développeur, tels que C:\Documents and Settings\Username, l'emplacement par défaut sous Windows 2000 et Windows XP, ou C:\Users\Username, l'emplacement par défaut depuis Windows Vista. Un tel chemin cesse de fonctionner lorsque le programme s'exécute sur une autre version de Windows ou lorsque le profil est stocké sur un réseau ou déplacé d'une autre manière. La bonne façon de l'obtenir est d'appeler la fonction GetUserProfileDirectory ou de résoudre la variable d'environnement %userprofile%. Une autre supposition que font souvent les développeurs est que le profil se trouve sur un disque dur local.

Chemin du dossier Mes documents

Certains programmes Windows codent en dur le chemin de My Documents sous la forme ProfilePath\My Documents. Ces programmes fonctionneraient sur des machines exécutant la version anglaise, mais sur les versions localisées de Windows, ce dossier porte normalement un nom différent. Par exemple, dans les versions italiennes, le dossier My Documents est nommé Documenti. My Documents peut également avoir été déplacé à l'aide de la redirection de dossiers dans la stratégie de groupe sous Windows 2000 ou version ultérieure. La bonne façon de l'obtenir est d'appeler la fonction SHGetKnownFolderPath (SHGetFolderPath sur les versions antérieures à Windows Vista).

Solution

Une référence indirecte, telle qu'une variable dans le programme appelée « FileName », pourrait être développée en accédant à une fenêtre de dialogue « parcourir pour trouver un fichier », et le code du programme n'aurait pas à être modifié si le fichier était déplacé.

Le codage en dur est particulièrement problématique lors de la préparation du logiciel en vue de sa traduction dans d'autres langues.

Dans de nombreux cas, une même valeur codée en dur, telle que la taille d'un tableau, peut apparaître plusieurs fois dans le code source d'un programme. Il s'agirait alors d'un nombre magique. Cela peut couramment provoquer un bogue si certaines occurrences de la valeur sont modifiées, mais pas toutes. Un tel bogue est difficile à trouver et peut rester longtemps dans le programme. Un problème similaire peut survenir si la même valeur codée en dur est utilisée pour plusieurs valeurs de paramètres, par exemple un tableau de 6 éléments et une longueur minimale de chaîne d'entrée de 6. Un programmeur peut modifier par erreur toutes les occurrences de la valeur (souvent à l'aide de la fonction de recherche-remplacement d'un éditeur) sans vérifier dans le code comment chaque occurrence est utilisée. On évite ces deux situations en définissant des constantes, qui associent des noms aux valeurs, et en utilisant les noms des constantes pour chaque occurrence dans le code.

Un cas important de codage en dur survient lorsque des chaînes de caractères sont placées directement dans le fichier, ce qui oblige les traducteurs à éditer le code source pour traduire un programme. (Il existe un outil appelé gettext qui permet de laisser les chaînes dans les fichiers, tout en laissant les traducteurs les traduire sans modifier le code source ; il « décode en dur » de fait les chaînes.)

Codage souple

Le codage souple est un terme de programmation informatique qui désigne l'obtention d'une valeur ou d'une fonction à partir d'une ressource externe, telle que les fichiers texte, les fichiers INI, les fichiers de configuration, les arguments de ligne de commande, les bases de données, les saisies utilisateur et les réponses de serveur HTTP. C'est l'opposé du codage en dur, qui désigne le fait de coder les valeurs et les fonctions dans le code source.

Bonne pratique de programmation

Éviter de coder en dur des valeurs fréquemment modifiées est une bonne pratique de programmation. Les utilisateurs du logiciel devraient pouvoir l'adapter à leurs besoins, dans la limite du raisonnable, sans avoir à éditer le code source du programme. De même, les programmeurs soigneux évitent les nombres magiques dans leur code afin d'en améliorer la lisibilité et de faciliter la maintenance. Ces pratiques ne sont généralement pas désignées par le terme codage souple.

Le terme est généralement employé lorsque le codage souple devient un anti-patron. Abstraire trop de valeurs et de fonctionnalités peut introduire davantage de complexité et de problèmes de maintenance que n'en occasionnerait la modification du code lorsque c'est nécessaire. Le codage souple, en ce sens, a fait l'objet d'un article sur The Daily WTF.

Problèmes potentiels

À l'extrême, les programmes à codage souple développent leurs propres langages de script, mal conçus et mal implémentés, ainsi que des fichiers de configuration qui requièrent des compétences de programmation avancées pour être édités. Cela peut conduire à produire des utilitaires destinés à faciliter la configuration du programme d'origine, et ces utilitaires finissent souvent par être eux-mêmes à codage souple.

La frontière entre une configurabilité appropriée et un codage souple problématique varie selon le style et la nature d'un programme. Les programmes à code source fermé doivent être très configurables, car l'utilisateur final n'a pas accès au code source pour y apporter des modifications. Les logiciels internes et les logiciels à diffusion limitée peuvent être moins configurables, car distribuer des copies modifiées est plus simple. Les applications web sur mesure gagnent souvent à n'avoir qu'une configurabilité limitée, car modifier les scripts n'est généralement pas plus difficile que de modifier un fichier de configuration.

Pour éviter le codage souple, évaluez l'intérêt, pour l'utilisateur final, de toute flexibilité supplémentaire que vous offrez, et comparez-le à l'accroissement de la complexité et aux coûts de maintenance continue qu'implique cette configurabilité ajoutée.

Obtenir de la flexibilité

Il existe plusieurs patrons de conception légitimes pour obtenir la flexibilité que le codage souple cherche à fournir. Une application nécessitant plus de flexibilité qu'il n'est approprié pour un fichier de configuration peut tirer parti de l'intégration d'un langage de script. Dans de nombreux cas, la conception appropriée est un langage dédié intégré à un langage de script établi. Une autre approche consiste à déplacer la majeure partie des fonctionnalités d'une application dans une bibliothèque, en fournissant une API pour écrire rapidement des applications connexes.

Exemple

Ce module intègre dans son code source l'adresse de la base de données, les identifiants et le taux de TVA. Exécuter la même version sur une base de recette, changer le mot de passe ou suivre une évolution fiscale impose de modifier et de redéployer le code — et le mot de passe se retrouve dans le gestionnaire de versions.

def connect():
    return Database(host="10.0.0.12", user="admin", password="s3cr3t!")


def price_with_vat(amount):
    return amount * 1.2

Les valeurs qui varient d'un environnement à l'autre ou dans le temps proviennent désormais de l'environnement ; le code ne garde que la logique (voir aussi Configuration codée en dur).

import os
from dataclasses import dataclass


@dataclass(frozen=True)
class Settings:
    db_host: str
    db_user: str
    db_password: str
    vat_rate: float

    @classmethod
    def from_env(cls) -> "Settings":
        return cls(
            db_host=os.environ["DB_HOST"],
            db_user=os.environ["DB_USER"],
            db_password=os.environ["DB_PASSWORD"],
            vat_rate=float(os.environ["VAT_RATE"]),
        )


def connect(settings: Settings):
    return Database(host=settings.db_host, user=settings.db_user, password=settings.db_password)


def price_with_vat(amount, settings: Settings):
    return amount * (1 + settings.vat_rate)

Adapté de l’article Wikipédia “Hard coding” (révision 1355219913), disponible sous licence CC BY-SA 4.0 ; le texte a été traduit et modifié, et des exemples ont été ajoutés.