Situation
Plus tôt dans la soirée, j'ai répondu à une question sur StackOverflow.
La question:
La modification d'un objet existant doit être effectuée dans la couche référentiel ou dans le service?
Par exemple, si j'ai un utilisateur qui a des dettes. Je veux changer sa dette. Dois-je le faire dans UserRepository ou dans le service par exemple BuyingService en récupérant un objet, en le modifiant et en le sauvegardant?
Ma réponse:
Vous devez laisser la responsabilité de la mutation d'un objet sur ce même objet et utiliser le référentiel pour récupérer cet objet.
Exemple de situation:
class User {
private int debt; // debt in cents
private string name;
// getters
public void makePayment(int cents){
debt -= cents;
}
}
class UserRepository {
public User GetUserByName(string name){
// Get appropriate user from database
}
}
Un commentaire que j'ai reçu:
La logique métier doit vraiment être dans un service. Pas dans un modèle.
Que dit Internet?
Cela m'a donc incité à chercher, car je n'ai jamais vraiment (consciemment) utilisé une couche de service. J'ai commencé à lire sur le modèle de couche de service et le modèle d'unité de travail, mais jusqu'à présent, je ne peux pas dire que je suis convaincu qu'une couche de service doit être utilisée.
Prenons par exemple cet article de Martin Fowler sur l'anti-pattern d'un modèle de domaine anémique:
Il existe des objets, dont beaucoup portent le nom des noms de l'espace de domaine, et ces objets sont liés aux relations riches et à la structure des vrais modèles de domaine. Le problème vient lorsque vous observez le comportement et vous vous rendez compte qu'il n'y a pratiquement aucun comportement sur ces objets, ce qui en fait un peu plus que des sacs d'accesseurs et de passeurs. En effet, ces modèles sont souvent accompagnés de règles de conception stipulant que vous ne devez mettre aucune logique de domaine dans les objets de domaine. Au lieu de cela, il existe un ensemble d'objets de service qui capturent toute la logique du domaine. Ces services vivent sur le modèle de domaine et utilisent le modèle de domaine pour les données.
(...) La logique qui devrait figurer dans un objet de domaine est la logique de domaine - validations, calculs, règles de gestion - comme vous voulez l'appeler.
Pour moi, cela semblait correspondre exactement à la situation: je préconisais la manipulation des données d'un objet en introduisant des méthodes à l'intérieur de cette classe. Cependant, je me rends compte que cela devrait être une donnée dans les deux sens, et cela a probablement plus à voir avec la façon dont ces méthodes sont appelées (en utilisant un référentiel).
J'ai également eu le sentiment que, dans cet article (voir ci-dessous), une couche de services est davantage considérée comme une façade qui délègue le travail au modèle sous-jacent, plutôt qu'une couche à forte intensité de travail.
Couche d'application [son nom pour la couche de service]: définit les tâches que le logiciel est censé effectuer et demande aux objets du domaine expressif de résoudre les problèmes. Les tâches dont cette couche est responsable ont une signification pour l'entreprise ou sont nécessaires pour une interaction avec les couches d'application d'autres systèmes. Cette couche est mince. Il ne contient pas de règles commerciales ni de connaissances, mais coordonne uniquement les tâches et délègue le travail aux collaborations d'objets de domaine dans la couche suivante. Son état ne reflète pas la situation de l'entreprise, mais il peut en être de même pour la progression d'une tâche pour l'utilisateur ou le programme.
Ce qui est renforcé ici :
Interfaces de service. Les services exposent une interface de service à laquelle tous les messages entrants sont envoyés. Vous pouvez considérer une interface de service comme une façade qui expose la logique métier implémentée dans l'application (généralement la logique de la couche de gestion) aux consommateurs potentiels.
Et ici :
La couche de service doit être dépourvue de toute logique applicative ou commerciale et se concentrer principalement sur quelques préoccupations. Il doit encapsuler les appels de la couche de gestion, traduire votre domaine dans un langage commun que vos clients peuvent comprendre et gérer le support de communication entre le serveur et le client demandeur.
C'est un contraste sérieux avec d' autres ressources qui parlent de la couche de service:
La couche service doit être composée de classes avec des méthodes qui sont des unités de travail avec des actions appartenant à la même transaction.
Ou la deuxième réponse à une question que j'ai déjà liée:
À un moment donné, votre application voudra une logique métier. En outre, vous pouvez valider l’entrée pour vous assurer qu’il n’ya rien de mal ou de non performant qui est demandé. Cette logique appartient à votre couche de service.
"Solution"?
En suivant les directives de cette réponse , j'ai proposé l'approche suivante qui utilise une couche de service:
class UserController : Controller {
private UserService _userService;
public UserController(UserService userService){
_userService = userService;
}
public ActionResult MakeHimPay(string username, int amount) {
_userService.MakeHimPay(username, amount);
return RedirectToAction("ShowUserOverview");
}
public ActionResult ShowUserOverview() {
return View();
}
}
class UserService {
private IUserRepository _userRepository;
public UserService(IUserRepository userRepository) {
_userRepository = userRepository;
}
public void MakeHimPay(username, amount) {
_userRepository.GetUserByName(username).makePayment(amount);
}
}
class UserRepository {
public User GetUserByName(string name){
// Get appropriate user from database
}
}
class User {
private int debt; // debt in cents
private string name;
// getters
public void makePayment(int cents){
debt -= cents;
}
}
Conclusion
Dans l'ensemble, peu de choses ont changé ici: le code du contrôleur a été transféré à la couche service (ce qui est une bonne chose, donc cette approche présente des avantages.) Cependant, cela ne semble pas avoir un rapport avec ma réponse initiale.
Je me rends compte que les modèles de conception sont des directives et non des règles immuables à appliquer autant que possible. Pourtant, je n'ai pas trouvé d'explication définitive sur la couche de service et sur la manière dont elle devrait être considérée.
Est-ce un moyen d'extraire simplement la logique du contrôleur et de la placer dans un service?
Est-il censé former un contrat entre le contrôleur et le domaine?
Devrait-il y avoir une couche entre le domaine et le service?
Et, dernier point mais non le moindre: suivre le commentaire original
La logique métier doit vraiment être dans un service. Pas dans un modèle.
Est-ce correct?
- Comment pourrais-je introduire ma logique métier dans un service au lieu du modèle?
la source
Réponses:
Afin de définir les responsabilités d' un service , vous devez d'abord définir ce qu'est un service .
Service n'est pas un terme logiciel canonique ou générique. En fait, le suffixe
Service
sur un nom de classe est un peu comme le tant décrié directeur : Il vous dit presque rien de ce que l'objet réellement fait .En réalité, ce qu'un service doit faire est hautement spécifique à l'architecture:
Dans une architecture en couches traditionnelle, service est littéralement synonyme de couche de logique métier . C'est la couche entre l'interface utilisateur et les données. Par conséquent, toutes les règles de gestion entrent dans les services. La couche de données ne doit comprendre que les opérations CRUD de base et la couche d'interface utilisateur doit uniquement traiter du mappage des DTO de présentation vers et depuis les objets métier.
Dans une architecture distribuée de style RPC (SOAP, UDDI, BPEL, etc.), le service est la version logique d'un noeud final physique . Il s'agit essentiellement d'un ensemble d'opérations que le responsable souhaite fournir en tant qu'API publique. Divers guides de bonnes pratiques expliquent qu’une opération de service doit en réalité être une opération au niveau de l’entreprise et non pas CRUD, et j’ai tendance à être d’accord.
Toutefois, étant donné que tout acheminer vers un service distant distant peut nuire gravement aux performances, il est généralement préférable de ne pas laisser ces services implémenter la logique métier eux-mêmes. au lieu de cela, ils doivent envelopper un ensemble "interne" d'objets métier. Un seul service peut impliquer un ou plusieurs objets métier.
Dans une architecture MVP / MVC / MVVM / MV *, les services n'existent pas du tout. Si tel est le cas, le terme est utilisé pour désigner tout objet générique pouvant être injecté dans un contrôleur ou un modèle de vue. La logique métier est dans votre modèle . Si vous souhaitez créer des "objets de service" pour orchestrer des opérations complexes, cela est considéré comme un détail d'implémentation. Malheureusement, beaucoup de gens implémentent MVC de cette manière, mais cela est considéré comme un anti-modèle ( modèle de domaine anémique ) car le modèle lui-même ne fait rien, il s'agit simplement d'un ensemble de propriétés pour l'interface utilisateur.
Certaines personnes pensent, à tort, que l’utilisation d’une méthode de contrôleur à 100 lignes et son intégration dans un service constituent en quelque sorte une meilleure architecture. Ce n'est vraiment pas; tout ce qu'il fait est d'ajouter une autre couche d'indirection, probablement inutile. En pratique , le contrôleur fait toujours le travail, il le fait simplement via un objet "helper" mal nommé. Je recommande vivement la présentation de Wicked Domain Models de Jimmy Bogard pour un exemple clair de la façon de transformer un modèle de domaine anémique en un modèle utile. Cela implique un examen minutieux des modèles que vous exposez et des opérations réellement valables dans un contexte commercial .
Par exemple, si votre base de données contient des commandes et que vous avez une colonne pour Montant total, votre application ne devrait probablement pas être autorisée à modifier ce champ en une valeur arbitraire, car (a) c'est l'historique et (b) c'est supposé être déterminé par ce qui est dans l'ordre, ainsi que peut - être d'autres données sensibles au temps / règles. Créer un service pour gérer les commandes ne résout pas nécessairement ce problème, car le code utilisateur peut toujours récupérer l'objet de commande réel et en modifier le montant. Au lieu de cela, la commande elle-même devrait être responsable de s'assurer qu'elle ne peut être modifiée que de manière sûre et cohérente.
Dans DDD, les services sont spécifiquement conçus pour la situation dans laquelle une opération n'appartient pas correctement à une racine d'agrégat . Vous devez faire attention ici, car souvent le besoin d'un service peut impliquer que vous n'utilisiez pas les racines correctes. Toutefois, à supposer que ce soit le cas, un service est utilisé pour coordonner des opérations sur plusieurs racines, ou parfois pour traiter des problèmes n’impliquant pas du tout le modèle de domaine (comme, par exemple, l’écriture d’informations dans une base de données BI / OLAP).
Un aspect notable du service DDD est qu’il est autorisé à utiliser des scripts de transaction . Lorsque vous travaillez sur des applications volumineuses, il est très probable que vous rencontriez des situations dans lesquelles il est beaucoup plus facile d'accomplir quelque chose avec une procédure T-SQL ou PL / SQL plutôt qu'avec le modèle de domaine. C'est OK, et cela appartient à un service.
C'est une rupture radicale avec la définition des services à architecture en couches. Une couche de service encapsule des objets de domaine; un service DDD encapsule tout ce qui ne se trouve pas dans les objets du domaine et n'a aucun sens.
Dans une architecture orientée services, un service est considéré comme l'autorité technique d'une capacité métier. Cela signifie qu'il est le propriétaire exclusif d'un certain sous-ensemble des données de l'entreprise et que rien d'autre n'est autorisé à toucher ces données - pas même à les lire .
Par nécessité, les services sont en réalité une proposition de bout en bout dans une SOA. Cela signifie qu'un service n'est pas tant un composant spécifique qu'une pile entière , et votre application entière (ou votre entreprise tout entière) est un ensemble de ces services fonctionnant côte à côte sans intersection, sauf au niveau des couches de messagerie et d'interface utilisateur. Chaque service a ses propres données, ses propres règles commerciales et sa propre interface utilisateur. Ils n'ont pas besoin d'orchestrer les uns avec les autres, car ils sont censés être alignés sur les affaires - et, à l'image de l'entreprise elle-même, chaque service a ses propres responsabilités et opère plus ou moins indépendamment des autres.
Ainsi, la définition de la SOA, chaque morceau de logique métier partout est contenu dans le service, mais là encore, est donc l'ensemble du système . Les services dans une SOA peuvent avoir des composants et des terminaux , mais il est assez dangereux d'appeler un morceau de code un service car il entre en conflit avec ce que le "S" original est censé signifier.
Comme la SOA est généralement très friande de la messagerie, les opérations que vous auriez peut-être empaquetées auparavant dans un service sont généralement encapsulées dans des gestionnaires , mais leur multiplicité est différente. Chaque gestionnaire gère un type de message, une opération. C'est une interprétation stricte du principe de responsabilité unique , mais elle permet une grande facilité d'entretien, car chaque opération possible appartient à sa propre classe. Vous n'avez donc pas vraiment besoin d' une logique métier centralisée, car les commandes représentent les opérations commerciales plutôt que les opérations techniques.
En fin de compte, quelle que soit l'architecture que vous choisissez, il y aura un composant ou une couche possédant la majeure partie de la logique métier. Après tout, si la logique métier est dispersée partout, il ne reste plus que du code spaghetti. Mais si vous appelez ce composant un service et comment il est conçu en termes de nombre ou de taille des opérations, cela dépend de vos objectifs architecturaux.
Il n'y a pas de bonne ou de mauvaise réponse, seulement ce qui s'applique à votre situation.
la source
En ce qui concerne votre titre , je ne pense pas que la question ait un sens. Le modèle MVC comprend des données et une logique métier. Dire que la logique devrait être dans le service et non dans le modèle, c'est comme dire: "Le passager devrait s'asseoir sur le siège, pas dans la voiture".
Là encore, le terme "Modèle" est un terme surchargé. Vous ne vouliez peut-être pas parler de modèle MVC, mais de modèle au sens de l'objet de transfert de données (DTO). AKA une entité. C’est ce dont parle Martin Fowler.
À mon avis, Martin Fowler parle de choses dans un monde idéal. Dans le monde réel de Hibernate et JPA (en Java), les DTO sont une abstraction super fuyante. J'aimerais mettre ma logique métier dans mon entité. Cela rendrait les choses plus propres. Le problème est que ces entités peuvent exister dans un état géré / mis en cache très difficile à comprendre et empêchant constamment vos efforts. Pour résumer mon opinion: Martin Fowler recommande la bonne façon, mais les ORM vous en empêchent.
Je pense que Bob Martin a une suggestion plus réaliste et il la donne dans cette vidéo qui n’est pas gratuite . Il parle de garder votre DTO libre de logique. Ils conservent simplement les données et les transfèrent vers une autre couche beaucoup plus orientée objet et n'utilisant pas directement les DTO. Cela évite l'abstraction qui fuit de vous mordre. La couche avec les DTO et les DTO eux-mêmes ne sont pas OO. Mais une fois que vous avez quitté cette couche, vous devenez aussi OO que le préconise Martin Fowler.
L'avantage de cette séparation est qu'elle supprime la couche de persistance. Vous pouvez passer de JPA à JDBC (ou inversement) et aucune logique métier ne doit être modifiée. Cela dépend des DTO, peu importe la façon dont ces DTO sont peuplés.
Pour modifier légèrement les sujets, vous devez tenir compte du fait que les bases de données SQL ne sont pas orientées objet. Mais les ORM ont généralement une entité - qui est un objet - par table. Donc, depuis le début, vous avez déjà perdu une bataille. D'après mon expérience, vous ne pouvez jamais représenter l'entité exactement de la manière que vous souhaitez orientée objet.
En ce qui concerne " un service", Bob Martin s'opposerait à ce qu'une classe soit nommée
FooBarService
. Ce n'est pas orienté objet. Que fait un service? Tout ce qui concerneFooBars
. Il peut aussi être étiquetéFooBarUtils
. Je pense qu'il préconiserait une couche de service (un meilleur nom serait la couche de logique applicative) mais chaque classe de cette couche aurait un nom significatif.la source
Je travaille sur le projet greenfield en ce moment et nous avons dû prendre quelques décisions architecturales pas plus tard qu'hier. Curieusement, j'ai dû revoir quelques chapitres de «Patterns of Enterprise Application Architecture».
Voici ce que nous avons trouvé:
Nous nous retrouvons avec ce qui suit:
Client -> Service -> Domaine -> Données
Nous pouvons remplacer la couche client, service ou data par une quantité de travail raisonnable. Si votre logique de domaine résidait dans le service et que vous aviez décidé de remplacer ou même de supprimer votre couche de service, vous auriez alors à déplacer toute la logique métier ailleurs. Une telle exigence est rare, mais cela pourrait arriver.
Cela dit, je pense que cela est assez proche de ce que Martin Fowler voulait dire par
Le diagramme ci-dessous illustre assez bien ceci:
http://martinfowler.com/eaaCatalog/serviceLayer.html
la source
C'est l'une de ces choses qui dépend vraiment du cas d'utilisation. L'intérêt général d'une couche de services est de consolider ensemble la logique métier. Cela signifie que plusieurs contrôleurs peuvent appeler le même UserService.MakeHimPay () sans se soucier de la façon dont le paiement est effectué. Ce qui se passe dans le service peut être aussi simple que de modifier une propriété d'objet ou de faire une logique complexe traitant d'autres services (par exemple, appeler des services tiers, appeler une logique de validation ou même simplement sauvegarder quelque chose dans la base de données. )
Cela ne signifie pas que vous devez retirer TOUTE la logique des objets du domaine. Parfois, il est plus logique de demander à une méthode sur l’objet domaine d’effectuer des calculs sur elle-même. Dans votre dernier exemple, le service est une couche redondante sur l'objet de référentiel / domaine. Il fournit un bon tampon contre les changements d’exigences, mais ce n’est vraiment pas nécessaire. Si vous pensez avoir besoin d'un service, essayez de faire en sorte que la simple logique "Modifiez la propriété X sur l'objet Y" au lieu de l'objet Domaine. La logique sur les classes de domaine a tendance à tomber dans le champ "calcule cette valeur à partir de champs" plutôt que d'exposer tous les champs via des getters / setters.
la source
Le moyen le plus simple d'illustrer pourquoi les programmeurs évitent de placer la logique de domaine dans les objets de domaine est qu'ils sont généralement confrontés à une situation de "où placer la logique de validation?" Prenez cet objet de domaine par exemple:
Nous avons donc une logique de validation de base dans le setter (ne peut pas être négatif). Le problème est que vous ne pouvez pas vraiment réutiliser cette logique. Quelque part, un écran, un ViewModel ou un contrôleur doit être validé avant de valider la modification de l'objet de domaine, car il doit informer l'utilisateur avant ou lorsqu'il clique sur le bouton Enregistrer qu'ils ne peuvent pas le faire. et pourquoi . Tester une exception lorsque vous appelez le poseur est un vilain piratage, car vous auriez dû faire toute la validation avant même d'avoir démarré la transaction.
C'est pourquoi les gens déplacent un type de service dans la logique de validation, tel que
MyEntityValidator
. Ensuite, l'entité et la logique d'appel peuvent à la fois obtenir une référence au service de validation et le réutiliser.Si vous ne le faites pas et que vous souhaitez toujours réutiliser la logique de validation, vous finissez par la placer dans les méthodes statiques de la classe d'entité:
Cela rendrait votre modèle de domaine moins "anémique" et conserverait la logique de validation à côté de la propriété, ce qui est génial, mais je ne pense pas que quiconque aime vraiment les méthodes statiques.
la source
Je pense que la réponse est claire si vous lisez l'article de Martin Fowler sur le modèle de domaine anémique .
Supprimer la logique métier, qui est le domaine, du modèle de domaine est en train de casser la conception orientée objet.
Passons en revue le concept de base orienté objet: un objet encapsule des données et des opérations. Par exemple, la fermeture d'un compte est une opération qu'un objet de compte doit effectuer sur lui-même. par conséquent, le fait qu'une couche de service effectue cette opération n'est pas une solution orientée objet. C'est une procédure et c'est ce à quoi Martin Fowler fait référence lorsqu'il parle d'un modèle de domaine anémique.
Si vous avez une couche de service qui ferme le compte plutôt que de laisser l'objet de compte se fermer elle-même, vous n'avez pas d'objet de compte réel. Votre compte "objet" est simplement une structure de données. Comme le suggère Martin Fowler, vous vous retrouvez avec un tas de sacs avec des accesseurs et des passeurs.
la source
Comment implémenteriez-vous votre logique métier dans la couche service? Lorsque vous effectuez un paiement à partir d'un utilisateur, vous créez un paiement, pas seulement en déduisant une valeur d'une propriété.
Votre méthode de paiement doit créer un enregistrement de paiement, augmenter la dette de cet utilisateur et conserver tout cela dans vos référentiels. Faire cela dans une méthode de service est incroyablement simple, et vous pouvez aussi encapsuler toute l'opération dans une transaction. Faire la même chose dans un modèle de domaine agrégé est beaucoup plus problématique.
la source
La version tl; dr:
Mes expériences et opinions indiquent que tout objet ayant une logique métier doit faire partie du modèle de domaine. Le modèle de données ne devrait probablement pas avoir de logique que ce soit. Les services devraient probablement relier les deux ensemble et traiter de problèmes transversaux (bases de données, journalisation, etc.). Cependant, la réponse acceptée est la plus pratique.
La version plus longue, à laquelle d’autres ont fait allusion, c’est qu’il existe une équivoque sur le mot "modèle". La publication bascule entre le modèle de données et le modèle de domaine comme si elles étaient identiques, ce qui est une erreur très courante. Il peut également y avoir une légère équivoque sur le mot "service".
En termes pratiques, vous ne devriez pas avoir de service qui modifie des objets de domaine. La raison en est que votre service aura probablement une méthode pour chaque propriété de votre objet afin de changer la valeur de cette propriété. C'est un problème car si vous avez une interface pour votre objet (ou même si ce n'est pas le cas), le service ne suit plus le principe Open-Closed; Au lieu de cela, chaque fois que vous ajoutez plus de données à votre modèle (indépendamment du domaine par rapport aux données), vous finissez par devoir ajouter plus de fonctions à votre service. Il existe certaines façons de contourner le problème, mais c’est la raison la plus courante pour laquelle les applications «entreprises» ont échoué, en particulier lorsque ces entreprises pensent que «entreprise» signifie «avoir une interface pour chaque objet du système». Pouvez-vous imaginer ajouter de nouvelles méthodes à une interface, puis à deux ou trois implémentations différentes (la première dans l'application, l'implémentation fictive et la première à déboguer, celle en mémoire?), juste pour une propriété unique sur votre modèle? Cela me semble une idée terrible.
Il y a un problème plus long dans lequel je n'entrerai pas dans les détails, mais l'essentiel est le suivant: la programmation orientée objet de type Hardcore indique que personne en dehors de l'objet concerné ne doit être en mesure de modifier la valeur d'une propriété dans l'objet, ni même " voir "la valeur de la propriété dans l'objet. Cela peut être atténué en rendant les données en lecture seule. Vous pouvez toujours rencontrer des problèmes, par exemple lorsque de nombreuses personnes utilisent les données même en lecture seule et que vous devez modifier le type de ces données. Il est possible que tous les consommateurs doivent changer pour s'adapter à cela. C'est pourquoi, lorsque vous faites en sorte que les API soient utilisées par tout le monde, il vous est conseillé de ne pas disposer de propriétés / données publiques ni même protégées; c'est la raison même pour laquelle la POO a été inventée, finalement.
Je pense que la majorité des réponses ici, mis à part celle qui est marquée comme acceptée, obscurcissent tout le problème. Celui qui est marqué comme accepté est bon, mais j’ai toujours ressenti le besoin de répondre et de convenir que le point 4 est la voie à suivre en général.
la source
La réponse est que cela dépend du cas d'utilisation. Mais dans la plupart des scénarios génériques, j’adhérerais à la logique d’entreprise reposant sur la couche service. L'exemple que vous avez fourni est très simple. Cependant, lorsque vous commencez à penser à des systèmes ou à des services découplés et que vous ajoutez en plus un comportement transactionnel, vous voulez vraiment que cela se produise dans la couche de service.
Les sources que vous avez citées pour la couche de service dépourvue de toute logique métier introduit une autre couche qui est la couche de gestion. Dans de nombreux scénarios, la couche service et la couche métier sont compressées en un. Cela dépend vraiment de la façon dont vous voulez concevoir votre système. Vous pouvez faire le travail en trois couches et continuer à décorer et à ajouter du bruit.
Ce que vous pouvez idéalement faire, ce sont des services de modèle qui englobent une logique métier pour travailler sur des modèles de domaine dans lesquels l’état persiste . Vous devriez essayer de découpler les services autant que possible.
la source
Dans MVC, le modèle est défini en tant que logique métier. Il est incorrect de prétendre que ce soit ailleurs, sauf s'il n'utilise pas MVC. Je considère les couches de service comme similaires à un système de module. Il vous permet de regrouper un ensemble de fonctionnalités connexes dans un package intéressant. Les internes de cette couche de service auront un modèle effectuant le même travail que le vôtre.
la source
Le concept de couche de service peut être visualisé du point de vue de DDD. Aaronaught l'a mentionné dans sa réponse, je viens juste de développer un peu.
Une approche courante consiste à avoir un contrôleur spécifique à un type de client. Disons que cela pourrait être un navigateur Web, une autre application, un test fonctionnel. Les formats de demande et de réponse peuvent varier. J'utilise donc le service d'application comme un outil pour utiliser une architecture hexagonale . J'y injecte des classes d'infrastructure spécifiques à une demande concrète. Par exemple, voici à quoi pourrait ressembler mon contrôleur répondant aux requêtes du navigateur Web:
Si j'écris un test fonctionnel, je souhaite utiliser un faux client de paiement et je n'aurais probablement pas besoin d'une réponse HTML. Donc, mon contrôleur pourrait ressembler à ça:
Le service d’application est donc un environnement que j’ai configuré pour exécuter la logique applicative. C'est là que les classes de modèle sont appelées - de manière agnostique d'implémentation d'infrastructure.
Alors, répondant à vos questions de cette perspective:
Non.
Eh bien, on peut appeler ça comme ça.
Nan.
Il existe une approche radicalement différente qui interdit totalement l'utilisation de tout type de service. Par exemple, David West, dans son livre Object Thinking, affirme que tout objet devrait disposer de toutes les ressources nécessaires pour faire son travail. Cette approche entraîne, par exemple, le rejet de tout ORM .
la source
Pour le compte rendu.
SRP:
Dans ce cas, vous pouvez effectuer les étapes suivantes:
Si la dette ne nécessite pas de calcul:
Cependant, si cela nécessite des calculs, alors:
ou aussi
Mais aussi, si le calcul est fait dans la couche de persistance, une telle procédure de stockage alors
Dans ce cas, nous voulons extraire l'utilisateur de la base de données et mettre à jour la dette, nous devons le faire en plusieurs étapes (en fait, deux) et il n'est pas nécessaire de l'envelopper / de l'encapsuler dans la fonction d'un service.
Et si cela nécessite de le stocker, nous pouvons ajouter une troisième étape
A propos de la solution proposée
a) Nous ne devrions pas avoir peur de laisser le développeur final en écrire quelques-uns au lieu de les encapsuler dans une fonction.
b) Et à propos d'Interface, certains développeurs adorent l'interface et ils vont bien, mais dans plusieurs cas, ils ne sont pas du tout nécessaires.
c) Le but d'un service est de créer un sans attributs, principalement parce que nous pouvons utiliser des fonctions partagées / statiques. Il est également facile d'effectuer des tests unitaires.
la source
"We shouldn't be afraid to left the end-developer to write a couple of instead of encapsulate it in a function.
"? Je ne peux que citer Lewis Black" Si ce n'était pour mon cheval, je n'aurais pas passé cette année à l'université ".