web-dev-qa-db-fra.com

SOLID vs. Éviter l'abstraction prématurée

Je comprends ce qui SOLIDE est censé accomplir et l'utiliser régulièrement dans des situations où la modularité est importante et que ses objectifs sont clairement utiles. Cependant, deux choses m'empêchent de l'appliquer systématiquement sur mon codebase:

  • Je veux éviter l'abstraction prématurée. Dans mon expérience, dessinez des lignes d'abstraction sans cas d'utilisation concrète (le genre existant maintenant ou dans le prévisible futur) conduit à eux étant dessinés dans les mauvais endroits. Lorsque j'essaie de modifier ce code, les lignes d'abstraction gênent plutôt que d'aider. Par conséquent, j'ai tendance à vous tromper du côté de ne pas dessiner de lignes d'abstraction tant que je n'ai aucune idée d'où ils seraient utiles.

  • J'ai du mal à justifier une modularité croissante pour son propre saké si elle rend mon code plus verbose, plus difficile à comprendre, etc. et n'élimine aucune duplication. Je trouve que le code d'objet procédural ou dieu simple, étroitement couplé est parfois plus facile à comprendre que le code de raviolis très bien factorisé, car le flux est simple et linéaire. C'est aussi beaucoup plus facile à écrire.

D'autre part, cet état d'esprit conduit souvent à des objets de Dieu. Je refactorisez généralement ces points de conservation, ajoutant des lignes d'abstraction claires uniquement lorsque je vois des motifs clairs émergents. Quoi, si quelque chose, ce qui ne va pas avec des objets de Dieu et un code étroitement couplé si vous n'avez pas besoin de plus de modularité, ne disposez pas d'une duplication importante et que le code est lisible?

EDIT: En ce qui concerne les principes individuels SOLID _, je voulais souligner que la substitution de Liskov est imho une formalisation du bon sens et doit être appliquée partout, car les abstractions n'ont aucun sens si ce n'est pas le cas. De plus, chaque classe devrait avoir une responsabilité unique à un niveau d'abstraction, bien qu'il puisse être un niveau très élevé avec les détails de la mise en œuvre tous entassés dans une vaste classe de 2 000 lignes. Fondamentalement, vos abstractions auraient un sens où vous choisissez de résumé. Les principes que je posets dans les cas où la modularité n'est pas clairement utile, la ségrégation d'interface et l'inversion d'interface et en particulier l'inversion de dépendance, car elles sont sur la modularité, non seulement que les abstractions ont du sens.

27
dsimcha

Les principes suivants sont des principes simples que vous pouvez appliquer pour vous aider à comprendre comment équilibrer votre conception système:

  • Principe de responsabilité unique: le S en solide. Vous pouvez avoir un objet très important en termes de nombre de méthodes ou de la quantité de données et de respecter ce principe. Prenez par exemple le Ruby = objet de chaîne. Cet objet a plus de méthodes que vous pouvez secouer un bâton, mais il n'a toujours qu'une seule responsabilité: contenir une chaîne de texte pour l'application. Dès que possible Votre objet commence à prendre une nouvelle responsabilité, commencez à réfléchir fort à ce sujet. Le problème de maintenance vous demande ", où puis-je vous attendre à trouver ce code si j'avais des problèmes avec cela plus tard?"
  • Compte de simplicité: Albert Einstein a déclaré: "Faites tout aussi simple que possible que possible, mais pas plus simple." Avez-vous vraiment besoin de cette nouvelle méthode? Pouvez-vous accomplir ce dont vous avez besoin avec la fonctionnalité existante? Si vous pensez vraiment qu'il faut y avoir une nouvelle méthode, pouvez-vous modifier une méthode existante pour satisfaire tout ce dont vous avez besoin? Dans le refacteur d'essence lorsque vous construisez de nouvelles choses.

En substance, vous essayez de faire ce que vous pouvez ne pas vous tirer dessus au pied quand il vient le temps de maintenir le logiciel. Si vos gros objets sont des abstractions raisonnables, il y a peu de raisons de les diviser juste parce que quelqu'un est venu avec une métrique indiquant qu'une classe ne devrait pas être plus que des lignes/méthodes/propriétés/etc. Si quelque chose, ce sont lignes directrices et pas de règles difficiles et rapides.

8
Berin Loritsch

Je pense que pour la plupart, vous avez répondu à votre propre question. SOLID est défini de lignes directrices sur la manière de refactuer votre code, lorsque les concepts doivent augmenter les niveaux d'abstraction.

Comme toutes les autres disciplines créatives, il n'y a pas d'absolus - juste des compromis. Plus vous le faites, il devient "plus facile" de décider quand il suffit de votre domaine ou des exigences actuelles.

Ayant dit que - Résumé est le cœur du développement de logiciels - donc s'il n'y a pas de bonne raison de ne pas le faire, la pratique vous fera mieux de vous améliorer, et vous obtiendrez une sensation d'intestinaire pour les compromis. Alors la favorise si cela ne devient préjudiciable.

5
Stephen Bailey
I want to avoid premature abstraction.In my experience drawing abstraction lines without concrete use cases... 

Ceci est partiellement juste et partiellement faux.

faux
[.____] Ce n'est pas une raison pour empêcher l'une d'appliquer des principes OO/solides. Cela n'empêche que les appliquer trop tôt.

Lequel est...

Droite
[.____] Ne refactez pas le code avant de se refaire refâchable; quand ce sont les exigences complètes. Ou, lorsque les "cas d'utilisation" sont tous là comme vous le dites.

I find simple, tightly coupled procedural or God object code is sometimes easier to understand than very well-factored...

Lorsque vous travaillez seul ou dans un silo
[.____] Le problème de ne pas faire OO n'est pas immédiatement évident. Après avoir écrit la première version d'un programme:

Code is fresh in your head
Code is familiar
Code is easy to mentally compartmentalize
You wrote it

3/4 de ces bonnes choses meurent rapidement sur une courte période.

Enfin, vous reconnaissez que vous avez des objets de Dieu (objets avec de nombreuses fonctions), vous reconnaissez donc des fonctions individuelles. Encapsuler. Mettez-les dans des dossiers. Utilisez des interfaces de temps en temps. Faites-vous une faveur pour la maintenance à long terme. Surtout que des méthodes non refoulées ont tendance à gonfler infiniment et devenir des méthodes de Dieu.

Dans une équipe
[.____] Les problèmes de ne pas faire OO sont immédiatement perceptibles. Le code OO est au moins un peu auto-documentant et lisible. Surtout quand combiné avec un bon code vert. En outre, le manque de structure rend difficile de séparer les tâches et l'intégration beaucoup plus complexes.

5
P.Brian.Mackey

J'ai tendance à aborder cela plus de ceux que vous n'aurez pas besoin de point de vue. Cet article se concentrera sur un élément en particulier: héritage.

Dans mon design initial, je crée une hiérarchie de choses que je sais qu'il y aura deux ou plus. Il y a de fortes chances qu'ils auront besoin d'une grande partie du même code. Il vaut donc la peine de la concevoir dès le début. Après que le code initial est en place, et je dois ajouter plus de fonctionnalités/fonctionnalités, je regarde ce que j'ai et pense, "Est-ce que quelque chose que j'ai déjà implémenté la même fonction ou la même fonction similiaire?" Si tel est le cas, c'est probablement une nouvelle abstraction mendiant d'être libérée.

Un bon exemple de ceci est un cadre MVC. À partir de zéro, vous créez une grande page avec un code derrière. Mais alors vous voulez ajouter une autre page. Cependant, le code d'un seul code implémente déjà beaucoup de la logique la nouvelle page nécessite. Donc, vous résumez une Controller class/interface qui implémentera la logique spécifique à cette page laissant les choses communes dans le "dieu" original - derrière.

2
Michael K

Si vous savez comme un développeur quand ne pas appliquer les principes en raison de l'avenir du code, alors bon pour vous.

J'espère SOLID reste à l'arrière de votre esprit pour savoir quand les choses doivent être abstraites pour éviter la complexité et améliorer la qualité du code s'il commence à se dégrader dans les valeurs que vous avez indiquées.

Plus important encore, considérez que la majorité des développeurs font le travail de jour et ne se soucient pas autant que vous. Si vous définissez initialement des méthodes de course à longues longues, quels sont les autres développeurs qui entrent dans le code vont penser quand ils viennent le maintenir ou l'étendre? ... Oui, vous devinez, de plus grandes fonctions, de cours de course plus longs, etc. Dieu est des objets, et ils n'ont pas les principes à l'esprit pour pouvoir attraper le code en croissance et l'encapsuler correctement. Vous êtes "lisible" le code devient maintenant un désordre de pourriture.

Donc, vous pouvez faire valoir qu'un mauvais développeur va faire cela, mais au moins vous avez un meilleur avantage si les choses sont restées simples et bien organisées depuis le début.

Je ne pense pas particulièrement à une "carte de registre" mondiale ou un "objet de Dieu" si elles sont simples. Cela dépend vraiment de la conception du système, parfois, vous pouvez vous en tirer et rester simple, parfois vous ne pouvez pas.

N'oublions pas non plus que de grandes fonctions et des objets de Dieu peuvent s'avérer extrêmement difficiles à tester. Si vous souhaitez rester agile et que vous vous sentez "sûr" lors de la récupération et de la modification du code, vous avez besoin de tests. Les tests sont difficiles à écrire lorsque des fonctions ou des objets font de nombreuses choses.

1
Martin Blore

Le problème avec un objet de Dieu est que vous pouvez généralement le briser de manière rentable. Par définition, cela fait plus d'une chose. Tout le but de la rompre dans des classes plus petites est de pouvoir avoir une classe qui fait une chose bien (et vous ne devriez pas étirer la définition de "une chose" non plus). Cela signifie que, pour une classe donnée, une fois que vous connaissez la seule chose qu'elle est censée faire, vous devriez être capable de le lire assez facilement et de dire si cela fait ou non une chose correctement.

Je pense qu'il y a est une telle chose que d'avoir trop de modularité et une trop grande flexibilité, mais c'est plus un problème de surintensité et de surintensité, où vous comptez des exigences que vous n'avez pas. t même connaître le client veut. Beaucoup d'idées de conception sont orientées autour de pouvoir contrôler facilement les modifications de la manière dont le code est exécuté, mais si personne n'attend que le changement, il est inutile d'inclure la flexibilité.

1
jprete

J'utilise une ligne directrice plus simple: si vous pouvez écrire des tests d'unité pour cela et n'avez aucune duplication de code, c'est assez abstrait. De plus, vous êtes dans une bonne position pour refactoriser plus tard.

Au-delà de cela, vous devriez garder SOLID à l'esprit, mais plus à titre de directive qu'une règle.

1
Jeffrey Faust

Quoi, si quelque chose, ce qui ne va pas avec des objets de Dieu et un code étroitement couplé si vous n'avez pas besoin de plus de modularité, ne disposez pas d'une duplication importante et que le code est lisible?

Si l'application est suffisamment petite, tout est maintenu. Dans des applications plus importantes, Dieu Objets deviennent rapidement un problème. La mise en œuvre éventuellement d'une nouvelle fonctionnalité nécessite de modifier 17 objets de Dieu. Les gens ne font pas très bien les procédures en 17 étapes. Les objets de Dieu sont constamment modifiés par plusieurs développeurs et ces changements doivent être fusionnés à plusieurs reprises. Vous ne voulez pas y aller.

0
kevin cline

Je partage vos préoccupations concernant l'abstraction excessive et inappropriée, mais je ne suis pas nécessairement aussi préoccupé par l'abstraction prématurée.

Cela sonne probablement comme une contradiction, mais il est peu probable que l'utilisation d'une abstraction soit susceptible de causer un problème aussi longtemps que vous ne l'aboutissez pas trop tôt - c'est-à-dire tant que vous êtes prêt et capable de refracteur si nécessaire.

Ce que cela implique est un certain degré de prototypage, d'expérimentation et de retour en arrière dans le code.

Cela dit, il n'y a pas de règle déterministe simple à suivre qui résoudra tous les problèmes. L'expérience compte beaucoup, mais vous devez acquérir cette expérience en faisant des erreurs. Et il y a toujours plus d'erreurs pour que les erreurs précédentes ne vous auront pas préparées.

Malgré tout, traitez les principes du manuel comme point de départ, puis apprenez les lots de programmation et voyant comment ces principes fonctionnent. S'il était possible de donner des lignes directrices meilleures, plus précises et fiables que des choses telles que Solid, une personne aurait probablement déjà fait, et même s'ils l'avaient eu, ces principes améliorés seraient toujours imparfaits et que les gens poseraient les limites de ces .

Bon travail également - si quelqu'un pouvait fournir un algorithme clair et déterministe pour la conception et le codage des programmes, il n'y aurait qu'un dernier programme pour l'homme à écrire - le programme qui écrirait automatiquement tous les programmes futurs sans intervention humaine.

0
Steve314

Dessiner les lignes d'abstraction appropriées est quelque chose que l'on tire de l'expérience. Vous ferez des erreurs dans le faire, c'est indéniable.

Solid est une forme concentrée de cette expérience qui vous est remise par des personnes qui ont gagné cette expérience de manière difficile. Vous avez à peu près cloué quand vous dites que vous vous éviteriez de créer une abstraction avant de voir le besoin de cela. Eh bien, l'expérience =SOLID Fournit que vous vous aiderez à résoudre des problèmes vous n'avez jamais existé. Mais faites-moi confiance à moi ... il y a très réel.

Solid est à propos de la modularité, la modularité concerne la maintenabilité et la maintenabilité consiste à vous permettre de conserver un horaire de travail humain une fois que le logiciel atteindra la production et le client commencent à remarquer des bugs que vous n'avez pas.

Le principal avantage de la modularité est la qualification. Plus votre système est modulaire, plus facile à tester et plus vite, vous pouvez créer des fondations solides pour que les aspects plus difficiles de votre problème. Donc, votre problème peut ne pas exiger cette modularité, mais simplement le fait que cela vous permettra de créer un meilleur code de test plus rapidement est une évidence pour s'efforcer de la modularité.

Être agile consiste à tenter de frapper l'équilibre délicat entre l'expédition rapide et de fournir une bonne qualité. Agile ne signifie pas que nous devrions couper le coin, en fait, les projets agiles les plus réussis que j'ai participé sont ceux qui ont porté une attention particulière à de telles directives.

0
Newtopian

Un point important qui semble avoir été négligé est que SOLID est pratiqué avec TDD. TDD a tendance à mettre en évidence ce qui est "approprié" dans votre contexte particulier et aide à atténuer beaucoup d'équivoque qui apparaît être dans le conseil.

0
delitescere