J'aime SOLID, et je fais de mon mieux pour l'utiliser et l'appliquer lorsque je développe. Mais je ne peux pas m'empêcher de penser que l'approche SOLID transforme votre code en code 'framework' - c'est-à-dire du code que vous concevriez si vous créiez un framework ou une bibliothèque pour que d'autres développeurs l'utilisent.
J'ai généralement pratiqué 2 modes de programmation - créant plus ou moins exactement ce qui est demandé via les exigences et KISS (programmation typique), ou créant une logique, des services, etc. très génériques et réutilisables qui fournissent le flexibilité dont d'autres développeurs peuvent avoir besoin (programmation du framework).
Si l'utilisateur veut vraiment qu'une application fasse des choses x et y, est-il logique de suivre SOLID et d'ajouter tout un tas de points d'entrée d'abstraction, quand vous ne savez même pas si c'est même un problème valable pour commencer? Si vous ajoutez ces points d'entrée d'abstraction, remplissez-vous vraiment les exigences des utilisateurs ou créez-vous un cadre au-dessus de votre cadre existant et de votre pile technologique pour faciliter les ajouts futurs? Dans quel cas servez-vous les intérêts du client ou du développeur?
C'est quelque chose qui semble courant dans le monde Java Enterprise, où vous avez l'impression de concevoir votre propre framework au-dessus de J2EE ou Spring afin que ce soit une meilleure UX pour le développeur, à la place de se concentrer sur UX pour l'utilisateur?
Votre observation est correcte, les principes SOLID sont à mon humble avis avec des bibliothèques réutilisables ou du code cadre. Lorsque vous les suivez tous aveuglément, sans demander si cela a du sens ou non, vous risquez pour généraliser et investir beaucoup plus d'efforts dans votre système que nécessaire.
Il s'agit d'un compromis, et il a besoin d'une certaine expérience pour prendre les bonnes décisions quant au moment de généraliser et quand non. Une approche possible consiste à s'en tenir au principe YAGNI - ne faites pas votre code SOLID "juste au cas où" - ou, pour utiliser vos mots: ne faites pas
fournir la flexibilité aux autres développeurs peut besoin
au lieu de cela, offrez la flexibilité aux autres développeurs en fait ont besoin dès qu'ils en ont besoin, mais pas plus tôt.
Donc, chaque fois que vous avez une fonction ou une classe dans votre code, vous ne savez pas si elle pourrait être réutilisée, ne la placez pas dans votre framework pour le moment. Attendez d'avoir un cas réel pour la réutilisation et refactor à "Assez solide pour ce cas". N'implémentez pas plus de configurabilité (en suivant l'OCP) ou de points d'entrée d'abstraction (en utilisant le DIP) dans une classe telle que vous en avez vraiment besoin pour le cas réel de réutilisation. Ajoutez la flexibilité suivante lorsque la prochaine exigence de réutilisation est réellement là.
Bien sûr, cette façon de travailler nécessitera toujours une certaine refactorisation sur la base de code de travail existante. C'est pourquoi les tests automatiques sont importants ici. Donc, rendre votre code SOLID suffisant dès le départ pour qu'il soit testable à l'unité n'est pas une perte de temps, et cela ne contredit pas YAGNI. Les tests automatiques sont un cas valable pour " réutilisation de code ", car le code en jeu est utilisé à partir du code de production ainsi que des tests. Mais gardez à l'esprit, ajoutez simplement la flexibilité dont vous avez réellement besoin pour faire fonctionner les tests, ni plus ni moins.
Il s'agit en fait d'une vieille sagesse. Il y a longtemps avant que le terme SOLID ne devienne populaire, quelqu'un me l'a dit avant d'essayer d'écrire re code utilisable, nous devrions écrire tilisable code. Et je pense toujours que c'est une bonne recommandation.
D'après mon expérience, lors de l'écriture d'une application, vous avez trois choix:
Dans le premier cas, il est courant de se retrouver avec un code étroitement couplé qui manque de tests unitaires. Bien sûr, c'est rapide à écrire, mais c'est difficile à tester. Et c'est une vraie douleur royale de changer plus tard lorsque les exigences changent.
Dans le deuxième cas, une énorme quantité de temps est consacrée à essayer d'anticiper les besoins futurs. Et trop souvent, ces besoins futurs prévus ne se matérialisent jamais. Cela semble être le scénario que vous décrivez. C'est un gaspillage d'efforts la plupart du temps et se traduit par un code inutilement complexe qui est toujours difficile à modifier lorsqu'une exigence qui n'était pas prévue pour apparaît.
Le dernier cas est celui à viser selon moi. Utilisez TDD ou des techniques similaires pour tester le code au fur et à mesure et vous vous retrouverez avec du code faiblement couplé, facile à modifier tout en étant rapide à écrire. Et le fait est que, ce faisant, vous suivez naturellement bon nombre des principes SOLID: petites classes et fonctions; interfaces et dépendances injectées. Et Mme Liskov est généralement satisfaite aussi comme des classes simples avec des classes simples ses responsabilités ne respectent que rarement son principe de substitution.
Le seul aspect de SOLID qui ne s'applique pas vraiment ici est le principe ouvert/fermé. Pour les bibliothèques et les frameworks, c'est important. Pour une application autonome, pas tellement. Vraiment c'est un cas d'écriture de code qui suit " GLISSÉ ": facile à écrire (et à lire), facile à tester et facile à entretenir.
La perspective que vous avez peut être faussée par votre expérience personnelle. Il s'agit d'une pente glissante de faits qui sont individuellement corrects, mais l'inférence qui en résulte ne l'est pas, même si elle semble correcte à première vue.
Cela signifie que lorsque vous interagissez avec des frameworks et des bibliothèques plus petites, le code de bonne pratique avec lequel vous interagirez se retrouvera le plus souvent dans les frameworks plus grands.
Cette erreur est très courante, par exemple chaque médecin par lequel j'ai été traité était arrogant. Par conséquent, je conclus que tous les médecins sont arrogants. Ces erreurs souffrent toujours de faire une couverture inférence basée sur des expériences personnelles.
Dans votre cas, il est possible que vous ayez principalement expérimenté les bonnes pratiques dans des cadres plus grands et non dans des bibliothèques plus petites. Votre observation personnelle n'est pas fausse, mais c'est une preuve anecdotique et non universellement applicable.
2 modes de programmation - créant plus ou moins exactement ce qui est demandé via les exigences et KISS (programmation typique), ou créant une logique, des services, etc. très génériques et réutilisables qui offrent la flexibilité dont d'autres développeurs peuvent avoir besoin (programmation-cadre)
Vous confirmez quelque peu cela ici. Pensez à ce qu'est un cadre. Ce n'est pas une application. C'est un "modèle" généralisé que d'autres peuvent utiliser pour créer toutes sortes d'applications. Logiquement, cela signifie qu'un framework est construit dans une logique beaucoup plus abstraite afin d'être utilisable par tous.
Les constructeurs de frameworks sont incapables de prendre des raccourcis, car ils ne savent même pas quelles sont les exigences des applications suivantes. La construction d'un cadre les incite intrinsèquement à rendre leur code utilisable pour les autres.
Cependant, les créateurs d'applications ont la possibilité de faire des compromis sur l'efficacité logique car ils se concentrent sur la livraison d'un produit. Leur objectif principal n'est pas le fonctionnement du code mais plutôt l'expérience de l'utilisateur.
Pour un framework, l'utilisateur final est un autre développeur, qui interagira avec votre code. La qualité de votre code est importante pour votre utilisateur final.
Pour une application, l'utilisateur final est un non-développeur, qui n'interagira pas avec votre code. La qualité de votre code n'a pas d'importance pour eux.
C'est exactement la raison pour laquelle les architectes d'une équipe de développement agissent souvent en tant que responsables de l'application des bonnes pratiques. Ils sont à une étape de la livraison du produit, ce qui signifie qu'ils ont tendance à regarder le code objectivement, plutôt que de se concentrer sur la livraison de l'application elle-même.
Si vous ajoutez ces points d'entrée d'abstraction, remplissez-vous vraiment les exigences des utilisateurs ou créez-vous un cadre au-dessus de votre cadre existant et de votre pile technologique pour faciliter les ajouts futurs? Dans quel cas êtes-vous au service des intérêts du client ou du développeur?
C'est un point intéressant, et c'est (selon mon expérience) la principale raison pour laquelle les gens essaient toujours de justifier d'éviter les bonnes pratiques.
Pour résumer les points ci-dessous: Ignorer les bonnes pratiques ne peut être justifié que si vos exigences (telles que connues actuellement) sont immuables, et il n'y aura jamais aucun changement/ajout à la base de code. Alerte spoiler: c'est rarement le cas.
Par exemple, lorsque j'écris une application console de 5 minutes pour traiter un fichier particulier, je n'utilise pas de bonnes pratiques. Parce que je ne vais utiliser l'application qu'aujourd'hui et qu'elle n'a pas besoin d'être mise à jour à l'avenir (il serait plus facile d'écrire une application différente si j'en ai besoin à nouveau).
Supposons que vous puissiez créer une application de manière médiocre en 4 semaines et que vous pouvez la créer correctement en 6 semaines. À première vue, la construction de mauvaise qualité semble meilleure. Le client obtient sa candidature plus rapidement et l'entreprise doit consacrer moins de temps aux salaires des développeurs. Gagner/gagner, non?
Cependant, c'est une décision prise sans réfléchir à l'avance. En raison de la qualité de la base de code, apporter une modification majeure à celle construite de manière médiocre prendra 2 semaines, tandis que les mêmes modifications apportées à celle correctement construite prend 1 semaine. Plusieurs de ces changements pourraient survenir à l'avenir.
En outre, il y a une tendance à ce que de manière inattendue nécessite plus de travail que vous ne le pensiez initialement dans des bases de code construites de manière médiocre, ce qui pousse probablement votre temps de développement à trois semaines au lieu de deux.
Et puis il y a aussi la tendance à perdre du temps à chercher des insectes. C'est souvent le cas dans les projets où la journalisation a été ignorée en raison de contraintes de temps ou de la pure réticence à la mettre en œuvre parce que vous travaillez distraitement en supposant que le produit final fonctionnera comme prévu.
Il n'a même pas besoin d'être une mise à jour majeure. Chez mon employeur actuel, j'ai vu plusieurs projets qui ont été construits rapidement et sales, et quand le moindre bug/changement a dû être fait en raison d'une mauvaise communication dans les exigences, qui a conduit à une réaction en chaîne de la nécessité de refactoriser module après module . Certains de ces projets ont fini par s'effondrer (et laisser derrière eux un gâchis incontrôlable) avant même de publier leur première version.
Les décisions de raccourci (programmation rapide et sale) ne sont bénéfiques que si vous pouvez garantir de manière concluante que les exigences sont exactement correctes et n'auront jamais besoin de changer. D'après mon expérience, je n'ai jamais rencontré un projet où cela est vrai.
Investir le temps supplémentaire dans les bonnes pratiques, c'est investir dans l'avenir. Les futurs bugs et modifications seront tellement plus faciles lorsque la base de code existante sera construite sur les bonnes pratiques. Il paiera déjà des dividendes après seulement deux ou trois changements.
Comment SOLID transforme-t-il du code simple en code framework? Je suis pas un stan pour SOLID par tous les moyens mais ce n'est vraiment pas évident ce que vous voulez dire ici.
J'avoue que je ne pense pas en termes SOLID moi-même, parce que je suis passé par les écoles de programmation Gang of Four et Josh Bloch , pas l'école Bob Martin. Mais je pense vraiment que si vous pensez "SOLID" = "ajouter plus de couches à la pile technologique", vous vous trompez.
P.S. Ne vendez pas les avantages d'une "meilleure expérience utilisateur pour le développeur". Le code passe la majeure partie de sa vie en maintenance. n développeur est vous .