Les dangers de l’over-architecture

L’objectif de cet article est de vous présenter les pistes pour identifier l’over-architecture et ses conséquences :

  • Un rapide rappel de ce qu’est l’architecture.
  • Les causes et les conséquences de l’over-architecture
  • Un exemple concret chez TheCodingMachine

Qu’est ce que l’architecture chez TheCodingMachine ?

◇ L’architecture va de pair avec l’analyse fonctionnelle (spécification fonctionnelle).
L’architecture répond au “comment”, quand la spécification fonctionnelle répond à “quoi faire”.

◇ Il y a de nombreuses façons de coder, l’architecture permet de donner une cohérence au système afin de faciliter la diffusion de la connaissance de l’application.

◇ L’architecture c’est aussi le maintien et l’évolutivité de l’application, c’est-à-dire la scalabilité du code (ne pas tout écrire dans le controller)

L’architecture transmet donc une intention, elle résulte généralement par la combinaison de best practices et de plusieurs “patron de conception”.
Bref, le besoin et les développeurs sont les centres d’intérêts de l’architecture. La “bonne” architecture étant un concept subjectif, il est important de choisir des critères de réussite. Généralement, on priorise ces critères de réussite. Quelques critères de réussite communs:
Maintenabilité, scalabilité, rapidité d’écriture du code, performance globale de l’application.

Pourquoi parlons nous donc d’over architecting ? Pouvons-nous rendre le code “trop” scalable ? Trop maintenable ? Trop proche du besoin ?
En réalité, on parle plutôt d’une architecture qui ne correspond pas au contexte de l’application.

Définissons ensemble le contexte d’un projet chez TheCodingMachine:

À TheCodingMachine, on développe généralement des applications pour des projets métiers. On ne code pas des briques à vocation technique, comme un framework ou un paquet open source. Les applications que l’on développe sont orientées business, et ne sont pas utilisées dans d’autres contextes métiers (c’est-à-dire sur d’autres projets). Nous codons aussi des applications qui sont souvent maintenues par d’autres développeurs, internes ou externes à TheCodingMachine. Il est donc important que l’organisation du code soit claire, concise et classique, afin que le développeur suivant puisse savoir où et comment chercher le bout de code en question. Il nous faut donc aussi respecter les intentions initiales, afin que le code soit cohérent. Cela ne signifie pas qu’il faut maintenir la dette technique. Si les intentions initiales ne correspondent plus au besoin, il ne faut pas hésiter à introduire de nouveaux concepts ou de modifier les concepts existant via du refactoring.

Dans notre contexte , l’over-architecture c’est donc écrire du code réutilisable qui n’est jamais réutilisé. On introduit des concepts techniques très abstraits qui ne correspondent plus au besoin. L’utilisation de ce code abstrait est plus complexe et donc, plus susceptible de bugger. Pire encore, la courbe d’apprentissage pour l’onboarding d’un développeur ou pour la transmission de connaissances est immense. On est tous tombé sur un projet où “Je comprends rien à ce projet”, “Je ne sais pas par où commencer pour chercher
D’expérience, il y a au moins trois raisons pour lesquelles un développeur veux écrire du code réutilisable:

◉ La première, le développeur (ou l’architecte) prévoit une abstraction pour une fonctionnalité potentielle, “au cas où”. Déjà qu’il est rare que le besoin final soit le même que celui initialement prévu (c’est pour ça qu’on essaie d’être “agile”), il est encore plus rare qu’un besoin potentiel se concrétise. Cette préparation au besoin future a un coût, alors qu’elle ne bénéficie pas au projet. Dans un forfait, ce coût n’est pas forcément amortit. De plus, même si ce besoin se concrétise, les techniques, outils, ont évolué entre temps. Cela ne signifie pas qu’il ne faut pas prendre du recul sur votre code, au contraire, je vous conseille de rester “agile”, c’est-à-dire d’itérer sur votre code au fil du besoin. Répondez à la feature spécifiée, prenez du recul lorsque la “feature potentielle” se concrétise et faites du refactoring à ce moment. Il est donc important de comprendre le métier pour proposer l’équilibre entre complexité et réutilisabilité. Nous ne pouvons pas prédire le futur, alors pourquoi écrire du code qui gère tous les scénarios. Par contre, il est possible d’analyser le passé et d’architecturer un code qui correspond aux fonctionnalités spécifiées et aux fonctionnalités existantes. N’essayez pas de caler votre architecture sur celle d’Amazon, de Google, de Netflix. Leurs besoins sont spécifiques et ils ont besoin de couvrir bien plus de scénarios que nos projets classiques. (bien que tout aussi passionnant).

◉ Deuxième raison, le développeur ou l’architecte essaye d’être state-of-art, de montrer son savoir-faire. Il fait donc un découpage du code très imposant, de manière à respecter certains principes d’architecture parfaite (comme les principes SOLID). Il pose des bases techniques très réutilisables dans l’application. Pour faire simple : il écrit un framework dédié au projet. Plus le code est réutilisable/extensible, plus il est long à écrire et plus il est sujet aux bugs, donc plus la maintenance est coûteuse. Trop de découpage signifie aussi plus de friction entre les composants de l’application, c’est-à-dire plus de bug lors de leur assemblage. Modifier et comprendre un code réutilisé (et donc configurable) de manière transverse dans l’application est très difficile lorsqu’on ne l’a pas mise en place. Une bonne manière d’appréhender ce raisonnement est le principe KISS (Keep It Simple, Stupid) et relaxez-vous, personne ne vous juge (même votre reviewer de PR). C’est de la responsabilité du framework (et des paquets utilisés) d’être flexible. Si vous tenez à écrire un code flexible, créer votre propre paquet open source ou proposez ces features aux développeurs du framework en question (en bonus, avec une petite PR sur ce framework).

◉ Et pour finir, c’est toujours plus fun d’écrire du code configurable, réutilisable et extensible par les autres développeurs. Cette envie, je l’ai tous les jours. Dans ce cas, intéressez-vous à l’open source, aidez à la maintenance des projets. En plus d’apprendre, votre code sera vraiment utilisé par des centaines voire milliers de développeurs.

J’aimerais finir par ajouter que la complexité n’est pas un problème, tant que cette complexité est nécessaire au projet.

Récemment, j’ai réouvert un de mes anciens projets qui, avec du recul, est victime d’over-architecture. L’objectif du projet était d’exporter certaines entités de la base de données vers une archive contenant un ensemble de fichiers json. Cette application est développée avec un framework MVC. Pour cet article, vous pourrez observer trois approches différentes:

Avec une approche “Quick And Dirty”:

Ici, tout est codé directement dans la Commande ou dans le Controller. Cette approche a l’avantage d’être facile à coder et à comprendre, par contre, il y a énormément de duplication de code entre la commande et le controller. De plus, plus il y a de type d’entités à mapper, plus le code au sein du controller (et de la commande) grossit. Avec un petit peu de refactoring, nous arrivons facilement à:

Ici, le code est scalable pour le besoin (l’ajout de nouvelle entité à exporter ne fait pas grossir le use case) et le code d’export est réutilisable dans d’autres contextes. Le code est donc mutualisé entre le controller et la commande d’export. Cette architecture est suffisante pour le besoin et assez rapide à développer. Cette architecture représente donc, à mon sens, celle qui doit être réalisée. Celle qui a été développé pour le projet est une architecture proche des principes SOLID, poussée à l’extrême:

Ici le code est abstrait, réutilisable dans d’autres projets, extensible pour des nouveaux besoins. Par contre, la mise en place de l’architecture est coûteuse, difficile à maintenir et difficile à comprendre. Pire encore, le code n’a jamais été étendu, et aucune nouvelle fonctionnalité liée à ce développement a été développée. Bref, le temps de mise en place par rapport au cas précédent a été perdu. N’oublions pas, les bonnes pratiques n’ont pas d’impact si aucun développeur n’utilise ou étend votre code.

Pour conclure cet article:
◇ Personne ne prête attention à votre code si personne n’utilise votre code
◇ Des architectures pour votre projet, pas pour le projet qu’il pourrait devenir
◇ Refactorez au fil du besoin
◇ Soyez agile, itérez sur le code, sprint par sprint
◇ Restez simple, “keep it simple”


par Benoît Ngo

Articles similaires TAG