Pourquoi (pas) besoin de getters?

L'article précédent sur les setters / getters comme moyen de travailler avec une entité (en utilisant Symfony en PHP comme exemple) a fait l'objet d'une discussion animée. Dans cet article, je vais essayer d'exprimer séparément mes réflexions sur les getters: pourquoi et quand obtenir quelque chose, quelle responsabilité ils décident et quand il est approprié de les utiliser, quand ce n'est pas approprié. J'ai essayé de rassembler les pensées en un seul endroit et de les formaliser avec vous.

getHumanFactory (). getHuman (). getDoneWork (). getWorkTime ()


Des getters sont nécessaires pour obtenir un état de l'objet courant. Dans les langages POO, il s'agit de la valeur d'une variable de classe, généralement privée.

class Article {
     private String name

     public function getName(): String {
          return this.name
     }
}

La valeur de la variable de classe elle-même peut être obtenue comme vous le souhaitez. Nous demandons simplement à l'objet de nous donner ce qu'il est, le nom même de la méthode nous dit "donne": mais ne "fais" pas, "n'envoie" pas, ne "crée" pas, "ne compte pas". Dit donner - donner ce qui est. Cela fonctionne tout à fait normalement dans toutes sortes d'objets de données, dont la responsabilité consiste simplement à donner / transporter des informations.

Il ne peut pas y avoir de logique dans le getter, car la sémantique du mot est simple. "Maman, donne-moi une tarte " ne contient pas "Maman, achète de la farine, fais cuire une tarte et enfin donne-moi une tarte ." Peut-être que la phrase «donnez-moi un gâteau» peut en quelque sorte résumer toutes ces actions, mais ce n'est certainement pas «donner».

Vous serez surpris, mais j'ai rencontré cette façon de nommer toutes les méthodes plus d'une fois. La complexité du code augmente en même temps beaucoup, car dans les chaînes getter, il n'est pas toujours clair ce qui se passe exactement dans les couches d'application et quel type de connexions sont impliquées, en règle générale, tout n'est pas en ordre avec la conception et la connivence de ce type est une source d'erreurs.

getValue () throw WhyDoYouNeedIt? {}


Le but de l'objet de données est compréhensible - c'est le caporal du film de 1917, qui fuit quelque part pour transmettre un message sur la nécessité de battre en retraite.

Mais que faire des objets métier? Pourquoi l'entité «Document» donne-t-elle à quelqu'un une liste de ses champs?

S'il s'agit d'un objet métier, le document peut être enregistré, rejeté, vérifié (y compris dans ces champs), rempli ou confirmé.

S'il est nécessaire de "donner" le champ, ce document ne fait pas partie du processus métier. Pourquoi dois-je donner un champ à quelqu'un? Peut-être pour publication? Ou extraire, archiver ou envoyer une copie par courrier ou rapport? Il n'est pas tout à fait clair pourquoi et à qui - il existe une responsabilité distincte de «donner» comme celle d'un bon ancien objet de données, vous pouvez clairement voir l'utilisation sous la forme d'une source de lecture dans le contexte d'un autre processus métier qui n'est pas fondamental pour comprendre le document lui-même.

doEverythingEverywhere (world.getGod ())


Revenons aux entités commerciales. Si vous laissez des getters dans des entités, la tentation est grande d'utiliser ses getters exactement partout et comme vous le souhaitez. Nous sommes liés à l'état d'un certain objet et nous inversons absolument toute logique de la campagne. Il peut même sembler que nous n'avons pas rompu l'encapsulation. Mais qu'en est-il? Énoncer à un endroit, comportement à un autre - une violation d'encapsulation classique.

Par exemple, il existe une entité:

class Order
{
     private Status status
     private Boolean closed

     public function getStatus(): Status {
          return this.status
     }

     public function setClosed(Boolean closed): void {
           this.closed = closed
     }
}

Certes, avec une telle architecture, vous demanderez un statut dans une dizaine / centaine de places. Il peut s'agir de toutes sortes de services, contrôleurs, autres modules. Je n'ai vu qu'une seule fois lorsque des restrictions ont été créées artificiellement pour la distribution de ce code par un ensemble de règles pour les développeurs, pas par du code ... L'encapsulation a été fournie par des normes de codage, et non par la conception de code :).

Si vous aviez besoin de faire quelque chose comme ça quelque part:

if(order.getStatus() == input.getStatus()) {
      order.setClosed(true)
}

Il est fort probable que l'entité ne contienne pas de machine d'état. Cela signifie que les invariants de l'objet de l'intérieur ne sont en aucun cas contrôlés - il n'y a pas de vérification des données pour chaque opération de l'intérieur. En conséquence - une connectivité élevée, des tests fonctionnels complexes, car il ne suffit pas de vérifier la logique unitaire du code qui modifie l'état de l'entité, vous devez vérifier que l'état de l'entité externe au code est valide. Et en conséquence: complexité accrue, probabilité de bogues, code plus et tests complexes.

Bottom line: J'espère que mes collègues et vous utiliserez moins les getters comme n'importe quelle méthode qui fonctionne avec le résultat qui reviendra.

Et j'espère que plus de développeurs prêteront attention au concept CQRS, où les responsabilités de lecture et les opérations commerciales sont divisées.

Bon à tous!

All Articles