Pourquoi avons-nous besoin de tant de classes en modèles de conception?

209

Je suis développeur junior parmi les seniors et j'ai beaucoup de mal à comprendre leurs pensées, leur raisonnement.

Je lis en DDD ( Domain-Driven Design ) et ne comprends pas pourquoi nous devons créer autant de classes. Si nous suivons cette méthode de conception de logiciel, nous aboutissons à 20-30 classes pouvant être remplacées par au plus deux fichiers et 3-4 fonctions. Oui, cela pourrait être compliqué, mais c'est beaucoup plus facile à gérer et à lire.

Chaque fois que je veux voir ce que fait quelque chose EntityTransformationServiceImpl, je dois suivre beaucoup de classes, interfaces, appels de fonction, constructeurs, leur création, etc.

Mathématiques simples:

  • 60 lignes de code factice contre 10 classes X 10 (disons que nous avons des logiques totalement différentes) = 600 lignes de code désordonné contre 100 classes + quelques autres pour les envelopper et les gérer; n'oubliez pas d'ajouter l'injection de dépendance.
  • Lecture de 600 lignes de code en désordre = un jour
  • 100 cours = une semaine, oublie toujours lequel fait quoi, quand

Tout le monde dit que c'est facile à maintenir, mais pour quoi? Chaque fois que vous ajoutez une nouvelle fonctionnalité, vous ajoutez cinq classes supplémentaires avec des fabriques, des entités, des services et des valeurs. J'ai l'impression que ce type de code se déplace beaucoup plus lentement que le code en désordre.

Supposons que si vous écrivez du code compliqué de 50 Ko en un mois, le processus DDD nécessite de nombreuses révisions et modifications (les tests ne me dérangent pas dans les deux cas). Un simple ajout peut prendre une semaine sinon plus.

En un an, vous écrivez beaucoup de code en désordre et pouvez même le réécrire plusieurs fois, mais avec le style DDD, vous n’avez toujours pas assez de fonctionnalités pour concurrencer le code en désordre.

S'il vous plaît, expliquez. Pourquoi avons-nous besoin de ce style DDD et de nombreux motifs?

UPD 1 : J'ai reçu tellement de bonnes réponses. Pouvez-vous ajouter un commentaire quelque part ou modifier votre réponse avec le lien pour la liste de lecture (vous ne savez pas par quoi commencer, DDD, Modèles de conception, UML, Code complet, Refactoring, Pragmatique,. .. tant de bons livres), bien sûr avec la séquence, de sorte que je puisse aussi commencer à comprendre et devenir senior comme certains d'entre vous.

utilisateur1318496
la source
81
Je pense qu'il y a une bonne question ici mais elle se cache derrière l'hyperbole et la frustration. @ user1318496, vous pourriez avoir intérêt à reformuler votre question un peu.
MetaFight
48
Au risque de marcher sur les pieds, parce que votre langage est nul. Ne prenez pas cela pour plus qu’il ne le fait: une langue insipide est souvent le bon choix technique pour diverses raisons, mais cela ne la rend pas non insipide. En ce qui concerne votre question, la correction est plus importante que la lisibilité. Autrement dit: la lisibilité est importante dans la mesure où elle permet de raisonner à propos de la correction. Alors, lequel est plus facile à tester, vos 100 classes ou votre classe de dieu monolithique? Je parie 100 classes simples.
Jared Smith
87
"Oui, cela pourrait être compliqué, mais c'est beaucoup plus facile à maintenir et à lire." Si c'est compliqué, comment peut-il être lisible et maintenable?
Polygnome
37
@ Polygnome: J'étais sur le point de taper exactement le même commentaire. Un autre commentaire de choix caractéristique des développeurs débutants est "Je sens que ce genre de code se déplace beaucoup plus lentement que le code en désordre". Ça ne sert à rien de courir aussi vite que possible si vous passez la moitié de votre temps à courir dans les murs! Lent est lisse, lisse est rapide.
Eric Lippert
40
Vous ne le faites pas, sauf si vous utilisez Java. Quand tout ce que vous avez est Java, tout ressemble à une classe.
Hobbs

Réponses:

336

C'est un problème d'optimisation

Un bon ingénieur comprend qu'un problème d'optimisation n'a pas de sens sans cible. Vous ne pouvez pas simplement optimiser, vous devez optimiser pour quelque chose. Par exemple, vos options de compilateur incluent l'optimisation pour la vitesse et l'optimisation pour la taille du code; ce sont parfois des objectifs opposés.

J'aime dire à ma femme que mon bureau est optimisé pour les ajouts. C'est juste une pile et il est très facile d'ajouter des choses. Ma femme préfèrerait cela si j'optimisais la récupération, c'est-à-dire que j'organisais un peu mes fichiers pour que je puisse trouver des choses. Cela rend bien sûr plus difficile à ajouter.

Le logiciel est la même manière. Vous pouvez certainement optimiser la création de produits - générez une tonne de code monolithique le plus rapidement possible, sans vous soucier de son organisation. Comme vous l'avez déjà remarqué, cela peut être très, très rapide. L'alternative consiste à optimiser pour la maintenance - rendre la création d'une touche plus difficile, mais rendre les modifications plus faciles ou moins risquées. C'est le but du code structuré.

Je suggérerais qu'un logiciel réussi ne sera créé qu'une seule fois, mais modifié maintes et maintes fois. Des ingénieurs expérimentés ont constaté que des bases de code non structurées prenaient forme et se transformaient en produits de plus en plus grands et complexes, jusqu'à ce qu'il soit très difficile d'apporter des modifications, même minimes, sans générer d'énormes risques. Si le code était structuré, le risque peut être contenu. C'est pourquoi nous allons à tous ces problèmes.

La complexité vient des relations, pas des éléments

J'ai remarqué dans votre analyse que vous examiniez des quantités - quantité de code, nombre de classes, etc. Même si elles sont plutôt intéressantes, l'impact réel provient des relations entre les éléments, qui explosent de manière combinatoire. Par exemple, si vous avez 10 fonctions et aucune idée de ce qui dépend de chacune d'elles, vous avez 90 relations possibles (dépendances) dont vous devez vous soucier - chacune des dix fonctions peut dépendre de l'une des neuf autres fonctions, et 9 x 10 = 90. Vous n'avez peut-être aucune idée des fonctions qui modifient les variables ni le mode de transmission des données. Les codeurs doivent donc se soucier de beaucoup de choses pour résoudre un problème particulier. En revanche, si vous avez 30 classes mais qu'elles sont bien agencées, elles ne peuvent avoir que 29 relations, par exemple si elles sont superposées ou agencées en une pile.

Comment cela affecte-t-il le débit de votre équipe? Eh bien, il y a moins de dépendances, le problème est beaucoup plus facile à résoudre; les codeurs ne doivent pas jongler avec un zillion de choses dans leur tête à chaque changement. Donc, minimiser les dépendances peut considérablement booster votre capacité à raisonner sur un problème avec compétence. C’est pourquoi nous divisons les choses en classes ou en modules, en ajustant le plus possible les variables de périmètre et en utilisant les principes SOLID .

John Wu
la source
103
Je ferais toutefois remarquer qu'une surabondance de classes et d'indirection n’aide PAS à comprendre la maintenance ni la maintenance. Et aucun flux de contrôle alambiqué (alias Callback Hell).
Matthieu M.
9
@JohnWu cette explication est la meilleure et plus facile à comprendre une que j'ai jamais lu.
Adriano Repetti
13
Bien écrit, mais manque-t-il peut-être pourquoi «créé une fois mais modifié maintes et maintes fois» est important? (Si tout le code est dedans EntityTransformationServiceImpl, vous êtes obligé d'apprendre comment tout ça fonctionne avant de pouvoir le réparer - mais si, par exemple, quelque chose ne va pas avec le format et qu'une Formatterclasse le gère, il vous suffit de savoir comment cette pièce fonctionne . Plus Lire votre propre code après environ 3 mois revient à lire le code d'un étranger. Pas sûr à 100% à ce sujet.
R. Schmitz
17
Je choisirais la combinaison de 10 × 10 = 100: ces fonctions pourraient bien être récursives, et dans un code particulièrement médiocre, ce n'est pas forcément évident.
Kryan
32
"L'alternative consiste à optimiser pour la maintenance - rendre la création d'une touche plus difficile, mais rendre les modifications plus faciles ou moins risquées. C'est l'objectif du code structuré." Je suis en désaccord avec la notion implicite selon laquelle plus de classes = plus de facilité de maintenance. En particulier, la dispersion de la logique dans de nombreuses classes rend souvent difficile la recherche des concepts logiques globaux dans le code (surtout sans un souci très intentionnel de garantir la visibilité des concepts), ce qui dégrade énormément la maintenabilité.
jpmc26
67

Tout d’abord, la lisibilité et la maintenabilité sont souvent du ressort du spectateur.

Ce qui est lisible pour vous peut ne pas l'être pour votre voisin.

La maintenabilité se résume souvent à la découvrabilité (la facilité avec laquelle un comportement ou un concept est découvert dans la base de code) et la découvrabilité est une autre chose subjective.

DDD

DDD aide notamment les équipes de développeurs à suggérer un moyen spécifique (mais toujours subjectif) d’organiser vos concepts et comportements de code. Cette convention facilite la découverte et facilite donc la maintenance de l'application.

  • Les concepts de domaine sont codés sous forme d'entités et d'agrégats
  • Le comportement du domaine réside dans les entités ou les services de domaine
  • La cohérence est assurée par les racines globales
  • Les problèmes de persistance sont traités par les référentiels

Cette disposition n’est pas objectivement plus facile à maintenir. Il est toutefois beaucoup plus facile à maintenir lorsque tout le monde comprend qu’il fonctionne dans un contexte DDD.

Des classes

Les classes aident à la maintenabilité, à la lisibilité, à la découvrabilité, etc., car elles sont une convention bien connue .

Dans les paramètres orientés objet, les classes sont généralement utilisées pour regrouper les comportements étroitement liés et pour encapsuler l'état à contrôler soigneusement.

Je sais que cela semble très abstrait, mais vous pouvez y penser de la manière suivante:

Avec Classes, vous n'avez pas nécessairement besoin de savoir comment le code qu'il contient fonctionne. Vous avez juste besoin de savoir ce que la classe est responsable.

Les classes vous permettent de raisonner sur votre application en termes d' interactions entre des composants bien définis .

Cela réduit le fardeau cognitif lors du raisonnement sur le fonctionnement de votre application. Au lieu de devoir vous rappeler ce que 600 lignes de code accomplissent, vous pouvez réfléchir à la manière dont 30 composants interagissent.

Et, étant donné que ces 30 composants couvrent probablement 3 couches de votre application, il vous suffit probablement de raisonner environ 10 composants à la fois.

Cela semble assez gérable.

Sommaire

En gros, voici ce que vous voyez les développeurs seniors:

Ils décomposent l'application en facile à raisonner sur les classes.

Ils organisent ensuite ceux-ci dans facile à raisonner sur les couches.

Ils le font parce qu'ils savent que, à mesure que l'application grandit, il devient de plus en plus difficile de raisonner au sujet de l'ensemble. Le diviser en couches et en classes signifie qu’ils ne doivent jamais raisonner au sujet de l’application entière. Ils n'ont jamais besoin que de raisonner sur un petit sous-ensemble.

MetaFight
la source
5
En plus des classes plus petites sont plus faciles à remplacer / refactor.
Zalomon
12
Une ingénierie excessive ne donne pas un code plus facile à maintenir ou à comprendre, bien au contraire, malgré ce que vous affirmez. Qui a besoin d'un AddressServiceRepositoryProxyInjectorResolverquand vous pouvez résoudre le problème plus élégamment? Les modèles de conception pour les modèles de conception ne font que conduire à une complexité et à une verbosité inutiles.
vikingsteve
27
Oui, trop d'ingénierie, c'est mauvais. Tuer des chiots aussi. Personne ici ne préconise non plus. logicallyfallacious.com/tools/lp/Bo/LogicalFallacies/169/...
MetaFight
5
En outre, "l'élégance" dans le contexte de génie logiciel est souvent un mot Weasel. fr.wikipedia.org/wiki/Weasel_word
MetaFight
11
On pourrait en dire autant de toute approche d'organisation du code. Tout dépend de la volonté de l'équipe de maintenance de comprendre pourquoi le code est organisé tel quel. C'est tout l'intérêt d'utiliser des conventions bien établies et bien comprises.
MetaFight le
29

Expliquez-moi, pourquoi avons-nous besoin de ce style DDD, de nombreux motifs?

Tout d’abord, une remarque: la partie importante de DDD n’est pas les modèles , mais l’alignement des efforts de développement sur les activités. Greg Young a fait remarquer que les chapitres du livre bleu sont dans le mauvais ordre .

Mais pour répondre à votre question spécifique: il existe généralement beaucoup plus de classes que prévu, a) car un effort est fait pour distinguer le comportement du domaine de la plomberie et b) parce que des efforts supplémentaires sont déployés pour garantir dans le modèle de domaine sont exprimés explicitement.

En clair, si vous avez deux concepts différents dans le domaine, ils doivent alors être distincts dans le modèle, même s’ils partagent la même chose dans la représentation en mémoire .

En fait, vous construisez un langage spécifique à un domaine qui décrit votre modèle dans le langage de l'entreprise, de sorte qu'un expert du domaine puisse le consulter et détecter les erreurs.

De plus, vous voyez un peu plus d'attention accordée à la séparation des préoccupations; et l'idée d'isoler les consommateurs d'une certaine capacité des détails de la mise en œuvre. Voir DL Parnas . Les limites claires vous permettent de modifier ou d'étendre la mise en œuvre sans que les effets ne se répercutent sur l'ensemble de votre solution.

La motivation ici: pour une application qui fait partie de la compétence principale d’une entreprise (c’est-à-dire un endroit où elle tire un avantage concurrentiel), vous voudrez pouvoir remplacer facilement et à moindre coût un comportement de domaine par une meilleure variation. En effet, vous avez des parties du programme que vous souhaitez évoluer rapidement (comment l’état évolue avec le temps), et d’autres que vous souhaitez modifier lentement (comment l’état est stocké); les couches supplémentaires d'abstraction aident à éviter les couplages par inadvertance de l'un à l'autre.

Pour être juste: une partie est aussi une lésion cérébrale liée à un objet. Les modèles décrits à l'origine par Evans sont basés sur des projets Java auxquels il a participé il y a plus de 15 ans. Dans ce style, l'état et le comportement sont étroitement liés, ce qui entraîne des complications que vous pourriez préférer éviter. voir Perception and Action de Stuart Halloway ou Inlining Code de John Carmack.

Peu importe la langue dans laquelle vous travaillez, la programmation dans un style fonctionnel offre des avantages. Vous devriez le faire chaque fois que cela vous convient et réfléchir sérieusement à la décision lorsque ce n'est pas pratique. Carmack, 2012

VoiceOfUnreason
la source
2
J'allais ajouter ma propre réponse jusqu'à ce que je lise ceci. Je voudrais souligner le premier paragraphe, que l'objectif est de modéliser les concepts métier dans les logiciels pour les aligner sur les exigences de l'entreprise. Pour être juste, l'analyste qui dirige le projet doit également indiquer le temps qu'il lui faut pour livrer le produit, et la qualité ou l'exhaustivité du code / des tests doit être ajustée en conséquence.
Sentinel
1
John Carmack est un excellent exemple de l’OMI, car il est bien connu pour écrire un code à la fois propre et facile à comprendre, tout en étant performant. Ceci est particulièrement visible lorsque vous suivez son code avec les technologies avancées - avec de meilleurs processeurs et de la mémoire, vous pouvez voir beaucoup de choses poussées de "cela doit être vraiment laconique" à "cela doit être vraiment clair / isolé / ... ". L'un des programmeurs les plus pragmatiques que je connaisse :)
Luaan
Je pense que c'est la meilleure réponse ici. Bien que je ne sois en aucun cas vendu sur DDD, cette réponse explique certainement du moins ce qu’elle est vraiment et une motivation réelle, plutôt que de faire appel à des platitudes communes qui ne veulent rien dire.
jpmc26
29

Les autres réponses comportent de nombreux points positifs, mais je pense qu’elles manquent ou ne soulignent pas une erreur conceptuelle importante que vous faites:

Vous comparez les efforts pour comprendre le programme complet.

Ce n'est pas une tâche réaliste avec la plupart des programmes. Même des programmes simples contiennent tellement de code qu'il est tout simplement impossible de tout gérer dans la tête à un moment donné. Votre seule chance est de trouver la partie d'un programme qui est pertinente pour la tâche à accomplir (corriger un bogue, implémenter une nouvelle fonctionnalité) et de travailler avec cela.

Si votre programme est constitué d'énormes fonctions / méthodes / classes, c'est presque impossible. Vous devrez comprendre des centaines de lignes de code pour décider si cette partie de code est pertinente pour votre problème. Avec les estimations que vous avez données, il devient facile de passer une semaine à trouver le code sur lequel vous devez travailler.

Comparez cela à une base de code avec de petites fonctions / méthodes / classes nommées et organisées en packages / espaces de noms qui indique clairement où trouver / placer un élément de logique donné. Lorsque cela est fait correctement, dans de nombreux cas, vous pouvez aller directement au bon endroit pour résoudre votre problème, ou au moins à un endroit d'où allumer votre débogueur vous amènera au bon endroit quelques fois.

J'ai travaillé dans les deux types de systèmes. La différence peut facilement représenter deux ordres de grandeur de performance pour des tâches et une taille de système comparables.

L'effet que cela a sur d'autres activités:

  • le test devient beaucoup plus facile avec des unités plus petites
  • moins de conflits de fusion car les chances pour deux développeurs de travailler sur le même morceau de code sont plus petites.
  • moins de duplication car il est plus facile de réutiliser des morceaux (et de trouver les morceaux en premier lieu).
Jens Schauder
la source
19

Parce que tester du code est plus difficile que d'écrire du code

Beaucoup de réponses ont donné un bon raisonnement du point de vue du développeur - que la maintenance peut être réduite, au prix de rendre le code plus pénible à écrire.

Cependant, il y a un autre aspect à prendre en compte: les tests ne peuvent être définis que comme votre code d'origine.

Si vous écrivez tout dans un monolithe, le seul test efficace que vous puissiez écrire est "Compte tenu de ces entrées, la sortie est-elle correcte?". Cela signifie que tous les bugs trouvés sont "quelque part dans cette pile de code géante".

Bien sûr, vous pouvez ensuite demander à un développeur de s’asseoir avec un débogueur pour rechercher l’origine exacte du problème et travailler sur un correctif. Cela prend beaucoup de ressources et représente une mauvaise utilisation du temps du développeur. Imaginez que ce bogue mineur ait pour conséquence qu'un développeur ait à déboguer à nouveau le programme complet.

La solution: de nombreux petits tests identifiant chacun un échec potentiel.

Ces petits tests (par exemple, les tests unitaires) ont l’avantage de vérifier une zone spécifique de la base de code et de rechercher les erreurs dans une portée limitée. Cela accélère non seulement le débogage en cas d'échec d'un test, mais signifie également que si tous vos petits tests échouent, vous pouvez trouver plus facilement l'échec dans vos tests plus volumineux (c'est-à-dire que si ce n'est pas dans une fonction testée spécifique, ce doit être dans l'interaction entre eux).

Comme cela devrait être clair, faire des tests plus petits signifie que votre base de code doit être scindée en morceaux plus petits testables. La façon de le faire, sur une base de code commerciale importante, donne souvent un code qui ressemble à celui avec lequel vous travaillez.

Juste comme note de côté: Cela ne veut pas dire que les gens ne prendront pas les choses "trop ​​loin". Mais il existe une raison légitime de séparer les bases de code en parties plus petites / moins connectées - si cela est fait judicieusement.

Bilkokuya
la source
5
Bien que votre réponse ne concerne que les tests et la testabilité, il s’agit du problème le plus important que certaines des autres réponses ont complètement ignoré, de sorte que +1.
Skomisa
17

Expliquez-moi, pourquoi avons-nous besoin de ce style DDD, de nombreux motifs?

Beaucoup (la plupart ...) d'entre nous n'en ont vraiment pas besoin . Des théoriciens et des programmeurs très expérimentés et chevronnés écrivent des livres sur les théories et les méthodologies résultant de nombreuses recherches et de leur profonde expérience - cela ne signifie pas que tout ce qu'ils écrivent est applicable à tous les programmeurs dans leur pratique quotidienne.

En tant que développeur débutant, il est bon de lire des livres tels que celui que vous avez mentionné pour élargir vos perspectives et vous faire prendre conscience de certains problèmes. Cela vous évitera également d’être embarrassé et décontenancé lorsque vos collègues seniors utilisent une terminologie avec laquelle vous n'êtes pas familier. Si vous trouvez quelque chose de très difficile et qui semble ne pas avoir de sens ou qui semble utile, ne vous tuez pas, mais limitez-vous à l'idée qu'il existe un tel concept ou une telle approche.

Dans votre développement quotidien, à moins que vous ne soyez un universitaire, votre travail consiste à trouver des solutions viables et maintenables. Si les idées que vous trouvez dans un livre ne vous aident pas à atteindre cet objectif, ne vous inquiétez pas pour le moment, aussi longtemps que votre travail est jugé satisfaisant.

Il se peut que vous découvriez à un moment donné que vous pouvez utiliser une partie de ce que vous avez lu mais que vous n'avez pas tout à fait "compris" au début, ou peut-être pas.

Vecteur
la source
12
Bien qu’à un niveau pur, c’est correct, cela ressemble à DDD et les autres modèles ne sont que théorie. Ils ne sont pas. Ce sont des outils importants pour obtenir un code lisible et maintenable.
Jens Schauder
9
@PeteKirkham le dilemme des OP est l' abus de modèles de conception. Avez-vous vraiment besoin d'un AccountServiceFacadeInjectResolver(exemple réel que je viens de trouver dans un système au travail) - la réponse est très probablement non.
vikingsteve
4
@vikingsteve OP n'est pas un gourou de la programmation qui commente la surutilisation générale des modèles de conception. OP est un apprenti et pense qu'ils sont trop utilisés dans son magasin . Je sais que débutant aurait pensé de la même façon au code que je rédige aujourd'hui, mais débutant, de nombreux projets personnels ont échoué parce qu'ils étaient trop compliqués.
R. Schmitz
3
@ R.Schmitz Cela dit, les débutants avaient de nombreux projets personnels qui échouaient parce qu'ils essayaient trop de rendre les choses bien conçues, organisées, structurées, POO ... Ce sont tous des outils. Ils doivent être compris et utilisés correctement, et vous pouvez difficilement blâmer le marteau pour sa piètre qualité de vissage. Étonnamment, cela semble prendre beaucoup de perspicacité et d’expérience pour comprendre cette chose simple :)
Luaan
3
@Luaan Si vous vous souciez déjà de bien structuré, organisé, structuré, POO, je n'appellerais guère ce débutant, mais oui, en abuser, c'est mauvais. Cependant, la question est davantage de savoir comment OP ne comprend pas vraiment quels problèmes ces problèmes résolvent. Si vous ne connaissez pas la raison, il semble qu'il n'y en ait aucune - mais en réalité, vous ne le savez pas encore.
R. Schmitz
8

Comme votre question couvre beaucoup de terrain, avec beaucoup d’hypothèses, je vais préciser le sujet de votre question:

Pourquoi avons-nous besoin de tant de classes dans les patrons de conception

Nous ne faisons pas. Aucune règle généralement acceptée ne dit qu'il doit y avoir plusieurs classes dans les modèles de conception.

Il existe deux guides clés pour décider où placer le code et comment découper vos tâches en différentes unités de code:

  • Cohésion: toute unité de code (que ce soit un package, un fichier, une classe ou une méthode) doit appartenir ensemble . C'est-à-dire que toute méthode spécifique devrait avoir une tâche et bien la faire. Toute classe devrait être responsable d’ un sujet plus vaste (quel qu’il soit). Nous voulons une grande cohésion.
  • Couplage: deux unités de code quelconques doivent dépendre le moins possible l'une de l'autre - il ne doit en aucun cas exister de dépendances circulaires. Nous voulons un couplage faible.

Pourquoi ces deux devraient-ils être importants?

  • Cohésion: une méthode qui fait beaucoup de choses (par exemple, un script CGI à l'ancienne qui fait une interface graphique, une logique, un accès à une base de données, etc. dans un long gâchis de code) devient difficile à manier. Au moment de la rédaction de cet article, il est tentant de simplement mettre votre esprit au cœur d'une longue méthode. Cela fonctionne, il est facile de présenter et tel, et vous pouvez être fait avec elle. Le problème se pose plus tard: après quelques mois, vous pouvez oublier ce que vous avez fait. Une ligne de code en haut peut être située à quelques écrans d'une ligne en bas; il est facile d'oublier tous les détails. Tout changement n'importe où dans la méthode peut casser toute quantité de comportements de la chose complexe. Il sera très difficile de refactoriser ou de réutiliser certaines parties de la méthode. Etc.
  • Couplage: chaque fois que vous modifiez une unité de code, vous détruisez potentiellement toutes les autres unités qui en dépendent. Dans les langages stricts tels que Java, vous pouvez obtenir des indications lors de la compilation (par exemple, sur les paramètres, les exceptions déclarées, etc.). Mais de nombreux changements ne déclenchent pas de tels changements (c.-à-d. Des changements de comportement), et d'autres langages, plus dynamiques, ne disposent pas de telles possibilités. Plus le couplage est élevé, plus il devient difficile de changer quoi que ce soit, et vous risquez de vous arrêter, où une réécriture complète est nécessaire pour atteindre un objectif.

Ces deux aspects constituent la base des "pilotes" permettant de choisir "où placer quoi" dans n'importe quel langage de programmation et n'importe quel paradigme (pas seulement OO). Tout le monde n'en est pas explicitement conscient, et il faut du temps, souvent des années, pour se faire une idée automatique et profondément enracinée de la manière dont ces logiciels influencent.

De toute évidence, ces deux concepts ne vous disent rien sur ce qu'il faut réellement faire . Certaines personnes penchent pour trop, d’autres pour trop peu. Certaines langues (en Java, par exemple) ont tendance à favoriser beaucoup de classes en raison de la nature extrêmement statique et pédante de la langue elle-même (ce n'est pas une déclaration de valeur, mais c'est ce qu'elle est). Cela devient particulièrement visible lorsque vous le comparez à des langages dynamiques et plus expressifs, tels que Ruby.

Un autre aspect est que certaines personnes souscrivent à l’approche agile consistant à n’écrire que le code nécessaire à l’ heure actuelle , et à la refactoriser fortement ultérieurement, le cas échéant. Dans ce style de développement, vous ne créeriez pas d' interfaceoutil lorsque vous ne disposez que d'une seule classe d'implémentation. Vous voudriez simplement implémenter la classe concrète. Si, plus tard, vous avez besoin d'un deuxième cours, vous feriez une refactorisation.

Certaines personnes ne travaillent tout simplement pas de cette façon. Ils créent des interfaces (ou, plus généralement, des classes de base abstraites) pour tout ce qui pourrait être utilisé plus généralement; cela conduit à une explosion de classe rapidement.

Encore une fois, il y a des arguments pour et contre, et peu importe ce que je préfère ou que vous préférez. En tant que développeur de logiciels, vous rencontrerez tous les extrêmes, des méthodes de spaghetti longues aux conceptions de classes éclairées et suffisamment grandes pour atteindre des schémas de classes incroyablement éclatés et beaucoup trop conçus. Au fur et à mesure que vous gagnerez en expérience, vous évoluerez davantage dans des rôles "architecturaux" et pourrez commencer à influencer cela dans la direction que vous souhaitez. Vous découvrirez un juste milieu pour vous-même et vous constaterez toujours que de nombreuses personnes ne seront pas d’accord avec vous, quoi que vous fassiez.

Par conséquent, garder l’esprit ouvert est la partie la plus importante, et c’est ce que j’aimerais vous conseiller, étant donné que vous semblez beaucoup souffrir du problème, à en juger par le reste de votre question ...

AnoE
la source
7

Les codeurs expérimentés ont appris:

  • Parce que ces petits programmes et groupes commencent à se développer, en particulier ceux qui ont réussi. Ces modèles simples qui ont fonctionné à un niveau simple ne sont pas à l’échelle.
  • Parce qu'il peut sembler fastidieux de devoir ajouter / modifier plusieurs artefacts à chaque ajout / modification, mais vous savez quoi ajouter et il est facile de le faire. 3 minutes de frappe bat 3 heures de codage intelligent.
  • Beaucoup de petites classes ne sont pas "désordonnées" simplement parce que vous ne comprenez pas pourquoi les frais généraux sont en fait une bonne idée
  • Sans la connaissance du domaine ajoutée, le code "évident pour moi" est souvent mystérieux pour mes coéquipiers ... plus le futur pour moi.
  • Les connaissances tribales peuvent rendre les projets extrêmement difficiles à ajouter aux membres de l'équipe, ce qui les rend facilement et difficilement productifs rapidement.
  • Nommer est l’un des deux problèmes les plus difficiles en informatique et reste vrai. De nombreuses classes et méthodes constituent souvent un exercice intense de dénomination que beaucoup trouvent très bénéfique.
Michael Durrant
la source
5
Mais les frais généraux sont-ils nécessaires? Dans de nombreux cas que je vois, les modèles de conception sont surutilisés. La surcomplexité a pour conséquence une difficulté accrue de compréhension, de maintenance, de test et de débogage du code. Lorsque vous avez 12 classes et 4 modules maven autour d'une classe de service simple (un exemple que je viens de voir), cela devient rapidement moins gérable que vous ne le pensez.
vikingsteve
4
@vikingsteve Vous continuez à faire référence à un seul exemple d'implémentation imparfaite dans l'espoir de prouver que le code structuré, en général, est une mauvaise idée. Cela ne suit tout simplement pas.
MetaFight le
2
@MetaFight OP ne parle pas de code de structure. Il parle de ce qu'il voit comme trop d'abstractions. Je soutiens que si vous avez trop d'abstractions, vous obtenez rapidement du code très très non structuré et de nombreux morceaux presque identiques, tout simplement parce que les gens ne peuvent pas gérer le nombre de problèmes auxquels ils doivent faire face.
Clairière le
4
@Clearer Je suis presque sûr que tout le monde ici convient que la mauvaise application hypothétique du code structuré est une mauvaise chose. L'OP dit qu'ils sont junior. C'est pourquoi les gens supposent qu'il / elle ne connaît pas les avantages du code structuré et les réitère.
MetaFight le
2

Les réponses jusqu'à présent, toutes bonnes, ayant commencé avec la supposition raisonnable que le demandeur manque quelque chose, ce que le demandeur reconnaît également. Il est également possible que le demandeur ait fondamentalement raison et il est utile de discuter de la manière dont cette situation peut se produire.

L’expérience et la pratique sont puissantes et, si les aînés acquièrent leur expérience dans des projets vastes et complexes où la seule façon de garder le contrôle de la situation consiste à multiplier les expériences EntityTransformationServiceImpl, alors ils deviennent rapides et à l'aise avec les modèles de conception et respectueux du DDD. Ils seraient beaucoup moins efficaces en utilisant une approche légère, même pour les petits programmes. Comme l'intrus, vous devez vous adapter et ce sera une excellente expérience d'apprentissage.

Même si vous vous adaptez, vous devriez prendre cela comme une leçon sur l'équilibre entre apprendre une seule approche en profondeur, au point de le faire fonctionner n'importe où, au lieu de rester polyvalent et de savoir quels outils sont disponibles sans être nécessairement un expert avec aucun d'entre eux. Les deux avantages et les deux sont nécessaires dans le monde.

Josh Rumbut
la source
-4

Faire plus de classe et de fonction selon l'utilisation sera une excellente approche pour résoudre les problèmes d'une manière spécifique qui aidera à l'avenir à résoudre les problèmes.

Plusieurs classes aident à identifier comme travail de base et n'importe quelle classe peut être appelée à tout moment.

Cependant, si vous avez beaucoup de classes et de fonctions, elles sont faciles à appeler et à gérer. Cela s'appelle un code propre.

Sanjeev Chauhan
la source
9
Désolé, mais que dites-vous?
Déduplicateur
@DuDuplicator Prenons un exemple en Java si nous concevons nous utilisons des threads et des classes jframes pour leur héritage. D'une seule classe, nous ne pouvons pas utiliser certaines œuvres de Java pour la conception. Nous devons donc créer plus de classes.
Sanjeev Chauhan
2
Cette réponse doit présenter la ou les idées qu'il est censé présenter dans un anglais plus clair. Il semble que l’idée principale de la réponse soit que les classes plus petites, chacune avec une fonctionnalité bien définie, sont une bonne idée, mais la grammaire terrible rend la compréhension presque impossible. De plus, cette affirmation pourrait ne pas suffire.
Talonx