Efficacité
Les programmeurs expérimentés peuvent facilement distinguer une bonne architecture d'une mauvaise, mais si on leur demande de la décrire en quelques mots, il est peu probable qu'ils soient capables de le faire. Il n'y a pas de critère unique pour une bonne architecture et pas de définition unique.
Cependant, si vous y réfléchissez, vous pouvez écrire un certain nombre de critères qu'une bonne architecture doit satisfaire. Une bonne architecture est avant tout une architecture logique qui rend le processus de développement et de maintenance d'un programme plus simple et plus efficace.
Lorsqu'un programme a une bonne architecture, il est toujours assez facile de comprendre comment il fonctionne et où écrire du code. Un programme bien architecturé est plus facile à modifier, tester, déboguer et développer. Les gens intelligents ont formulé les critères suivants pour une bonne architecture :
- Efficacité;
- La flexibilité;
- Extensibilité ;
- Évolutivité ;
- testabilité ;
- Maintenabilité du code.
Efficacité du système. Le programme, bien sûr, doit résoudre les tâches assignées et bien remplir ses fonctions, et dans diverses conditions. Il semble que tout programme fasse ce qu'il doit faire (s'il est écrit), mais souvent ce n'est pas du tout le cas.
Vous rencontrerez constamment des programmes qui ne font pas ce qu'ils prétendent faire.
- Libre Office est un remplacement complet de Microsoft Office (pas vraiment) ;
- Le navigateur Edge prend en charge toutes les normes Web (pas vraiment) ;
- La banque se soucie de la sécurité des données personnelles de ses utilisateurs (en fait non).
Et nous n'avons pas encore abordé les performances, la fiabilité, les corrections de bogues en temps opportun ou la publication d'informations sur les vulnérabilités connues.
Il est clair que personne n'est parfait, mais le programme doit résoudre ses tâches principales. Donc, sans efficacité, nulle part.
La flexibilité
La seule chose plus importante que l'efficacité à mon avis est la flexibilité. Toute application doit changer au fil du temps, à mesure que les exigences changent, de nouvelles sont ajoutées. Plus il est rapide et pratique d'apporter des modifications à la fonctionnalité existante, moins cela cause de problèmes et d'erreurs, plus l'architecture du système est flexible .
Très souvent, les programmeurs/architectes novices pensent qu'ils ont besoin d'une architecture idéale pour les tâches courantes. Non. Vous avez besoin d'une architecture idéale pour les tâches qui vous seront annoncées dans un an. Vous, qui ne connaissez déjà pas les tâches futures, devriez savoir ce qu'elles seront.
Cela n'a aucun sens d'essayer de les prévoir, car il y aura toujours quelque chose d'inattendu. Mais vous devez tenir compte du fait que de telles tâches apparaîtront. Par conséquent, dans le processus de développement, essayez d'évaluer ce qui est obtenu en termes de la manière dont il devra être modifié.
Demandez-vous : « Que se passe-t-il si la décision architecturale actuelle s'avère erronée ? », « Quelle quantité de code sera modifiée ? ». La modification d'un fragment du système ne doit pas affecter ses autres fragments.
Dans la mesure du possible, les décisions architecturales ne doivent pas être figées et les conséquences des erreurs architecturales doivent être raisonnablement limitées. "Une bonne architecture permet de RETARDER les décisions clés" (Bob Martin) et minimise le "coût" des erreurs.
L'une de ces approches consiste à diviser l'application en microservices : il est facile de diviser la logique déjà existante en parties distinctes. Mais le plus gros problème est d'apporter des modifications futures à une douzaine de services à la fois pour implémenter une petite fonctionnalité.
Évolutivité
L'évolutivité est la capacité à réduire le temps de développement en ajoutant de nouvelles personnes au projet. L'architecture doit permettre de paralléliser le processus de développement afin que plusieurs personnes puissent travailler sur le programme en même temps.
Il semble que cette règle s'applique d'elle-même, mais en pratique, tout est exactement le contraire. Il existe même un livre très populaire, The Mythical Man-Month , qui explique pourquoi l'ajout de nouvelles personnes à un projet augmente le temps de développement.
Extensibilité
L'extensibilité est la capacité d'ajouter de nouvelles fonctionnalités et entités à un système sans violer sa structure de base. Au stade initial, il est logique de ne mettre que les fonctionnalités de base et les plus nécessaires dans le système.
C'est le soi-disant principe YAGNI - vous n'en aurez pas besoin , "vous n'en aurez pas besoin". Dans le même temps, l'architecture doit vous permettre d'augmenter facilement les fonctionnalités supplémentaires selon vos besoins. Et pour que l'introduction des changements les plus probables demande le moins d'efforts.
L'exigence que l'architecture du système soit flexible et extensible (c'est-à-dire qu'elle soit capable de changer et d'évoluer) est si importante qu'elle est même formulée comme un principe distinct - le « principe ouvert/fermé » . Le principe ouvert-fermé est le deuxième des cinq principes SOLID : les entités logicielles (classes, modules, fonctions) doivent être ouvertes pour l'extension, mais fermées pour la modification .
En d'autres termes : il devrait être possible de modifier et d'étendre le comportement du système sans réécrire les parties existantes du système .
Cela signifie que l'application doit être conçue de manière à ce que la modification de son comportement et l'ajout de nouvelles fonctionnalités soient réalisées en écrivant un nouveau code (extensions), sans avoir à modifier le code existant.
Dans ce cas, l'émergence de nouvelles exigences n'entraînera pas une modification de la logique existante, mais pourra être mise en œuvre principalement en l'élargissant. Ce principe est à la base de "l'architecture plug-in" (Plugin Architecture). Les techniques par lesquelles cela peut être réalisé seront discutées plus tard.
Vous vous souvenez des servlets et des filtres ? Pourquoi des filtres étaient-ils nécessaires, et même avec des interfaces séparées, si, en fait, la même logique pouvait être implémentée à l'aide de servlets ?
C'est l'invention du concept de filtres (servlets de service) qui a permis de déplacer diverses fonctions de service vers une couche distincte. Et à l'avenir, lors de la modification du comportement des filtres, il n'était plus nécessaire de modifier les servlets.
Avant l'invention des filtres, toute la logique de service responsable de la redirection des requêtes était située dans les servlets eux-mêmes. Et souvent, un petit changement de logique entraînerait la nécessité de parcourir toutes les servlets et d'apporter diverses modifications à toutes.
Testabilité
Si vous êtes un développeur Java Backend, vos applications serveur exposent souvent un ensemble de méthodes en tant qu'API REST. Et pour vérifier que toutes vos méthodes fonctionnent comme prévu, elles doivent être couvertes de tests.
En général, la couverture des tests API est un bon style. Cela vous permet de vous assurer que votre API fait vraiment ce pour quoi elle était censée faire. Et aussi, plus important encore, vous pouvez apporter des modifications à la logique du serveur et vérifier facilement que vous n'avez rien cassé accidentellement .
Dès que vous commencerez à écrire des tests, vous vous rendrez compte que la plupart du code ne peut pas du tout être testé : méthodes privées, couplage fort, classes et variables statiques.
"Pourquoi avons-nous besoin de tests si le code fonctionne ?", demandera le débutant.
"Pourquoi avons-nous besoin d'un code fonctionnel s'il ne peut pas être testé ?", demandera le professionnel.
Un code facile à tester contiendra moins de bogues et sera plus fiable. Mais les tests n'améliorent pas seulement la qualité du code. Presque tous les développeurs en viennent finalement à la conclusion que l'exigence d'une « bonne testabilité » est également une force directrice qui conduit automatiquement à une bonne conception.
Voici une citation du livre Architecture idéale : "Utilisez le principe de "testabilité" d'une classe comme un "test décisif" d'une bonne conception de classe. Même si vous n'écrivez pas une seule ligne de code de test, répondre à cette question en 90 % des cas aidera à comprendre comment tout va bien" ou "mauvais" avec sa conception."
Il existe toute une méthodologie pour développer des programmes basés sur des tests, qui s'appelle Test-Driven Development (TDD). C'est bien sûr l'autre extrême : écrire du code avant d'écrire du code.
Maintenabilité du code
En règle générale, beaucoup de gens travaillent sur le programme - certains partent, de nouveaux arrivent. La durée moyenne de travail d'un programmeur dans une société informatique est d'un an et demi. Donc, si vous êtes venu sur un projet qui a 5 ans, alors seulement 20 % de vos collègues y ont travaillé dès le début.
Maintenir et développer un programme que d'autres ont écrit est très difficile. Même si le programme est déjà écrit, il est souvent nécessaire de continuer à le maintenir : corriger les erreurs et apporter des corrections mineures. Et souvent cela doit être fait par des personnes qui n'ont pas participé à sa rédaction.
Par conséquent, une bonne architecture devrait permettre aux nouvelles personnes de comprendre le système relativement facilement et rapidement . Le projet doit être :
- Bien structuré.
- Ne pas contenir de doublons.
- Avoir un code bien formaté.
- Il est souhaitable d'inclure la documentation.
- Il est nécessaire d'appliquer des solutions standard et familières pour les programmeurs.
Vous pouvez facilement évaluer le projet sur lequel vous travaillez sur une échelle de 5 points . Comptez simplement deux points pour chacune de ces exigences . Et si vous en obtenez 5 ou plus, alors vous avez de la chance.
Les programmeurs ont même un principe de moindre surprise : plus le système est exotique, plus il est difficile à comprendre pour les autres. Habituellement, il est utilisé en relation avec l'interface utilisateur, mais il s'applique également à l'écriture de code.