Frankenstein en programmation est un code assemblé à partir de parties incompatibles de différentes technologies, styles et architectures. Selon l'étude ThoughtWorks Technology Radar (2024), 28% des grands projets présentent des signes du syndrome de Frankenstein — un éclectisme architectural résultant de l'absence d'une vision technique unifiée. Par analogie avec le roman de Mary Shelley, ce code fonctionne, mais sa maintenance devient un cauchemar.
Points clés
Frankenstein (code Frankenstein, patron Frankenstein) est un anti-patron où un système logiciel est assemblé à partir de parties non conçues pour fonctionner ensemble. Comme le monstre de Frankenstein, ce code peut fonctionner, mais il est laid, imprévisible et dangereux au moindre changement.
Le terme vient de la littérature : dans le roman de Mary Shelley « Frankenstein ou le Prométhée moderne » (1818), un scientifique a créé un être vivant à partir de fragments de corps de différents morts. En programmation, l'analogie est exacte — les développeurs prennent des morceaux de différents frameworks, bibliothèques, langages et les collent « à vif », obtenant un résultat fonctionnel mais monstrueux.
La différence entre Frankenstein et le code spaghetti réside dans l'échelle et la nature. Le code spaghetti est une structure emmêlée au sein d'une seule pile technologique. Frankenstein est un éclectisme au niveau de l'architecture : différentes technologies, paradigmes incompatibles, approches conflictuelles au sein du même système.
L'architecture microservices permet d'utiliser différentes technologies pour différents services, mais à condition de limites claires et de protocoles d'interaction standardisés. Frankenstein est un mélange chaotique sans limites : REST et GraphQL dans le même contrôleur, deux ORM dans le même module, SQL et NoSQL pour la même entité.
L'absence d'un leader technique ou d'un architecte est la cause profonde. Quand il n'y a personne responsable de l'intégrité architecturale, chaque développeur choisit des outils « pour soi ». L'un aime Spring, l'autre Guice, un troisième utilise un DI personnalisé. Le résultat — un mélange architectural.
La fusion de projets est la deuxième cause courante. Deux équipes ont développé leurs modules indépendamment, en utilisant des piles différentes. Lorsque les modules doivent être combinés en une seule application, ils sont simplement « collés » avec des adaptateurs et des couches intermédiaires. Le résultat est Frankenstein.
Les acquisitions d'entreprises sont le troisième scénario. La société A a acheté la société B et veut intégrer son produit au sien. Au lieu de réécrire — collage via des API, bases de données partagées et rustines. Après un an, le système devient un monstre que personne ne comprend.
| Cause | Description | Résultat typique |
|---|---|---|
| Pas d'architecte | Chaque développeur choisit sa propre pile | 3 clients HTTP différents dans un module |
| Fusion de projets | Deux produits collés en un | Deux ORM, deux façons de journaliser |
| M&A | Acquisition d'une entreprise avec son produit | Hybride de différentes architectures et styles |
| Expérimentations | Introduction de nouvelles technologies sans stratégie | Fonctionnalités Java 8 + Java 21 dans un fichier |
| Décisions politiques | Technologie imposée d'en haut sans contexte | Framework d'entreprise pour un script simple |
Les développeurs expérimentés qui veulent essayer de nouvelles technologies en production deviennent souvent la source de Frankenstein. Au lieu de limiter les expériences à un module isolé, ils introduisent du code expérimental dans des parties critiques du système.
Un exemple classique est l'utilisation de plusieurs ORM dans une seule application. Certains modules utilisent Hibernate, certains MyBatis, et certains des requêtes JDBC directes. Les transactions deviennent ingérables, le cache incohérent, et un nouveau développeur ne sait pas quelle approche utiliser pour une nouvelle fonctionnalité.
Un deuxième exemple est le mélange de styles architecturaux. Dans un contrôleur REST API, vous trouvez des appels de service SOAP, des requêtes SQL directes, un accès au système de fichiers et une génération HTML. Une telle application est impossible à tester, étendre ou documenter.
Un troisième exemple est une pile technologique où Python est utilisé pour le backend, Node.js pour un microservice, C# pour un client de bureau et Java pour une application Android, tandis que toute la logique métier est dispersée entre eux sans séparation claire des responsabilités.
// Frankenstein — styles et technologies mélangés
// callbacks, Promises et async/await combinés
// callbacks
db.query("SELECT * FROM users", function(err, rows) {
if (err) handleError(err);
// Promise dans un callback
fetch("/api/data").then(function(data) {
// async/await dans then
(async () => {
const result = await processData(data);
sendResponse(result);
})();
});
});
// code propre — style async/await unifié
async function getUserData(userId) {
const user = await db.query("SELECT * FROM users WHERE id = ?", [userId]);
const data = await fetch("/api/data/" + userId);
return await processData(user, data);
}
Une seule base de données est utilisée simultanément comme SQL relationnelle (avec normalisation) et comme NoSQL orientée documents (avec colonnes JSON). Certaines requêtes passent par ORM, certaines par des procédures stockées, certaines par SQL direct depuis le code. Le schéma de la BD n'est pas documenté, les migrations entrent en conflit.
La complexité d'intégration est la première conséquence. Un nouveau développeur doit connaître 5 langues, 3 frameworks, 2 styles architecturaux pour comprendre comment le système fonctionne. L'intégration s'étend de semaines à mois. Selon LinkedIn (2023), les projets avec éclectisme technologique perdent les nouveaux employés 2 fois plus souvent.
L'imprévisibilité du comportement est la deuxième conséquence. Une modification dans le microservice Python peut casser de manière inattendue le module Java car ils partagent une base de données sans contrats clairs. Déboguer de tels problèmes nécessite une connaissance simultanée de toutes les technologies de la pile.
La sécurité est la troisième conséquence. Chaque technologie de la pile nécessite sa propre configuration de sécurité, ses propres correctifs, sa propre surveillance. Maintenir la sécurité à un niveau acceptable pour 5-6 technologies hétérogènes est pratiquement impossible. L'une d'elles sera inévitablement vulnérable.
SonarQube peut mesurer la dette technique, mais ne peut pas mesurer la « dette architecturale » — l'incompatibilité des composants. Cette dette se manifeste non pas dans les avertissements du linter, mais dans l'impossibilité d'ajouter une nouvelle fonctionnalité sans modifier trois modules différents écrits dans des technologies différentes.
La première et principale étape est de nommer un architecte ou un tech lead responsable de l'intégrité de la pile technologique. Cette personne a un droit de veto sur l'introduction de nouvelles technologies sans revue architecturale. Pas de démocratie, mais une décision individuelle responsable sur les technologies clés.
La deuxième étape est d'implémenter le processus Architecture Decision Record (ADR). Toute décision architecturale significative (choix de BD, framework, protocole) est documentée sous forme d'un texte court : contexte, alternatives considérées, décision prise, conséquences. Les ADR sont stockés dans le dépôt et disponibles pour toute l'équipe.
La troisième étape est d'établir le principe « une tâche — un outil ». Pour les requêtes HTTP — un client. Pour ORM — une bibliothèque. Pour la journalisation — un framework. Les exceptions ne sont autorisées que via ADR avec justification. Si le projet a déjà Axios — n'ajoutez pas fetch, s'il a SLF4J — n'écrivez pas via System.out.
Les expérimentations sont autorisées, mais dans un environnement isolé. Allouez un module ou un service qui peut être réécrit avec une nouvelle technologie sans affecter le reste du système. Si l'expérience réussit — standardisez-la via ADR. Sinon — supprimez-la sans conséquences.
Inventaire — la première étape. Créez une carte complète de la pile technologique : quels frameworks, bibliothèques, langages, protocoles sont utilisés, dans quels modules et pour quelles tâches. Vous verrez l'ampleur du problème : duplication d'outils, technologies conflictuelles, dépendances inutilisées.
Standardisation — la deuxième étape. Choisissez un outil pour chaque tâche. Par exemple : seulement Hibernate pour ORM, seulement SLF4J + Logback pour la journalisation, seulement REST pour API. Documentez la norme dans ADR. Commencez le remplacement par les modules où l'éclectisme cause le plus de problèmes.
Stratégie Parallel Run — la troisième étape. Les outils ancien et nouveau fonctionnent en parallèle jusqu'à ce que le nouveau prouve sa fiabilité. Par exemple, l'ancien client HTTP et le nouveau fonctionnent simultanément, mais le nouveau ne traite qu'une partie des requêtes. Après une période de stabilisation, l'ancien est supprimé.
// Frankenstein — trois approches HTTP dans un projet
// Module A : OkHttp
OkHttpClient client = new OkHttpClient().newCall(request);
// Module B : RestTemplate (Spring)
restTemplate.getForObject(url, String.class);
// Module C : java.net.HttpURLConnection
HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
// approche unifiée : RestTemplate pour synchrone, WebClient pour réactif
@Autowired
private RestTemplate restTemplate;
public String callApi(String url) {
return restTemplate.getForObject(url, String.class);
}
Un leader technique est l'outil principal pour lutter contre Frankenstein. Pas un manager, pas un architecte dans une tour d'ivoire, mais un développeur praticien qui écrit du code, révise les PR et prend des décisions architecturales. Sans une telle personne, le projet glisse inévitablement dans l'éclectisme technologique.
RFC (Request for Comments) est un processus emprunté aux communautés open source. Avant d'introduire une technologie significative, l'auteur écrit un RFC : problème, solution proposée, alternatives, plan d'implémentation. L'équipe discute, vote, accepte ou rejette. RFC crée de la transparence et empêche les décisions architecturales « silencieuses ».
Le Radar Technologique (ThoughtWorks Technology Radar) est un outil de catégorisation : Adopt, Trial, Assess, Hold. L'équipe révise régulièrement le radar et met à jour les statuts. Cela aide à distinguer le « tendance » du « utile » et à éviter l'introduction de technologies non éprouvées dans du code critique.
La qualité la plus importante de l'architecture est la cohérence. Même un outil pas très bon utilisé dans tout le projet est meilleur que le meilleur outil utilisé seulement dans un module. La cohérence réduit la charge cognitive, simplifie l'intégration et rend le code prévisible.
Questions fréquentes
Polyglot persistence est l'utilisation consciente de différentes bases de données pour différentes tâches (PostgreSQL pour les transactions, Redis pour le cache, Elasticsearch pour la recherche). Frankenstein est un mélange chaotique sans stratégie. La différence réside dans la présence d'une décision architecturale : polyglot est un plan, Frankenstein est son absence.
Oui, et c'est un problème fréquent. Lorsque chaque microservice utilise son propre langage, sa propre BD, son propre protocole et sa propre approche de déploiement sans standards centralisés — vous obtenez un Frankenstein distribué. Pour les microservices, les standards communs sont importants : protocole unifié (REST/gRPC), format de log commun, observabilité centralisée.
N'interdisez pas — guidez. Suggérez à l'auteur d'écrire un RFC : décrivez pourquoi la solution existante ne convient pas, quelles alternatives ont été considérées, comment la migration sera effectuée. Souvent, dans le processus d'écriture d'un RFC, le développeur lui-même réalise que la nouvelle technologie n'est pas nécessaire. Si le RFC est convaincant — implémentez-le, mais avec un plan et des limites.
D'abord inventaire, puis standardisation. N'essayez pas de tout réécrire à la fois. Sélectionnez une couche (par exemple, les clients HTTP ou la journalisation), choisissez un outil unique, écrivez un ADR et migrez progressivement. Le motif Strangler Fig — remplacez les anciens composants par de nouveaux un par un sans arrêter l'application.
Moins il y en a, mieux c'est. Idéalement — un langage, un framework, une BD, une méthode de journalisation. Réalistiquement — 2-3 langages (avec séparation claire), 1-2 BD, 1-2 frameworks. Chaque technologie supplémentaire augmente la charge cognitive de l'équipe et le coût de maintenance.
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