Situación
A principios de esta tarde, respondí a una pregunta sobre StackOverflow.
La pregunta:
¿La edición de un objeto existente debe hacerse en la capa de repositorio o en servicio?
Por ejemplo, si tengo un usuario que tiene deudas. Quiero cambiar su deuda. ¿Debo hacerlo en UserRepository o en el servicio, por ejemplo, BuyService obteniendo un objeto, editándolo y guardándolo?
Mi respuesta:
Debe dejar la responsabilidad de mutar un objeto a ese mismo objeto y usar el repositorio para recuperar este objeto.
Situación de ejemplo:
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 comentario que recibí:
La lógica empresarial realmente debería estar en un servicio. No en un modelo.
¿Qué dice internet?
Entonces, esto me llevó a buscar ya que nunca he usado (conscientemente) una capa de servicio. Comencé a leer sobre el patrón de la capa de servicio y el patrón de la unidad de trabajo, pero hasta ahora no puedo decir que esté convencido de que se debe usar una capa de servicio.
Tomemos, por ejemplo, este artículo de Martin Fowler sobre el antipatrón de un modelo de dominio anémico:
Hay objetos, muchos con nombres de nombres en el espacio de dominio, y estos objetos están conectados con las relaciones y la estructura rica que tienen los verdaderos modelos de dominio. El truco se produce cuando observas el comportamiento y te das cuenta de que casi no hay comportamiento en estos objetos, lo que los convierte en poco más que bolsas de captadores y colocadores. De hecho, a menudo estos modelos vienen con reglas de diseño que dicen que no debe poner ninguna lógica de dominio en los objetos de dominio. En cambio, hay un conjunto de objetos de servicio que capturan toda la lógica del dominio. Estos servicios viven sobre el modelo de dominio y usan el modelo de dominio para datos.
(...) La lógica que debería estar en un objeto de dominio es la lógica de dominio: validaciones, cálculos, reglas de negocio, como quiera llamarlo.
Para mí, esto parecía exactamente de qué se trataba la situación: abogaba por la manipulación de los datos de un objeto mediante la introducción de métodos dentro de esa clase que hacen exactamente eso. Sin embargo, me doy cuenta de que esto debería ser de cualquier manera, y probablemente tenga más que ver con cómo se invocan estos métodos (usando un repositorio).
También tuve la sensación de que en ese artículo (ver más abajo), una capa de servicio se considera más como una fachada que delega el trabajo al modelo subyacente, que una capa de trabajo intensivo real.
Capa de aplicación [su nombre para Capa de servicio]: define los trabajos que se supone que debe hacer el software y dirige los objetos de dominio expresivo para resolver problemas. Las tareas de las que es responsable esta capa son significativas para el negocio o necesarias para la interacción con las capas de aplicación de otros sistemas. Esta capa se mantiene delgada. No contiene reglas de negocio o conocimiento, sino que solo coordina tareas y delega el trabajo a colaboraciones de objetos de dominio en la siguiente capa hacia abajo. No tiene un estado que refleje la situación comercial, pero puede tener un estado que refleje el progreso de una tarea para el usuario o el programa.
Lo que se refuerza aquí :
Interfaces de servicio. Los servicios exponen una interfaz de servicio a la que se envían todos los mensajes entrantes. Puede pensar en una interfaz de servicio como una fachada que expone la lógica empresarial implementada en la aplicación (normalmente, la lógica en la capa empresarial) a los consumidores potenciales.
Y aqui :
La capa de servicio debe estar desprovista de cualquier aplicación o lógica empresarial y debe centrarse principalmente en algunas preocupaciones. Debe envolver las llamadas de Business Layer, traducir su Dominio a un lenguaje común que sus clientes puedan entender y manejar el medio de comunicación entre el servidor y el cliente solicitante.
Este es un serio contraste con otros recursos que hablan sobre la capa de servicio:
La capa de servicio debe consistir en clases con métodos que sean unidades de trabajo con acciones que pertenezcan a la misma transacción.
O la segunda respuesta a una pregunta que ya he vinculado:
En algún momento, su aplicación querrá cierta lógica empresarial. Además, es posible que desee validar la entrada para asegurarse de que no se solicite algo malo o que no funcione. Esta lógica pertenece a su capa de servicio.
"Solución"?
Siguiendo las pautas de esta respuesta , se me ocurrió el siguiente enfoque que utiliza una capa de servicio:
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;
}
}
Conclusión
En conjunto, no ha cambiado mucho aquí: el código del controlador se ha movido a la capa de servicio (lo cual es algo bueno, por lo que este enfoque tiene una ventaja). Sin embargo, esto no parece tener nada que ver con mi respuesta original.
Me doy cuenta de que los patrones de diseño son pautas, no reglas establecidas para ser implementadas siempre que sea posible. Sin embargo, no he encontrado una explicación definitiva de la capa de servicio y cómo debería considerarse.
¿Es un medio para simplemente extraer la lógica del controlador y ponerla dentro de un servicio?
¿Se supone que forma un contrato entre el controlador y el dominio?
¿Debería haber una capa entre el dominio y la capa de servicio?
Y, por último pero no menos importante: siguiendo el comentario original
La lógica empresarial realmente debería estar en un servicio. No en un modelo.
¿Es esto correcto?
- ¿Cómo introduciría mi lógica comercial en un servicio en lugar del modelo?
fuente
Respuestas:
Para definir cuáles son las responsabilidades de un servicio , primero debe definir qué es un servicio .
El servicio no es un término de software canónico o genérico. De hecho, el sufijo
Service
en el nombre de una clase se parece mucho al muy difamado Administrador : no le dice casi nada sobre lo que el objeto realmente hace .En realidad, lo que debe hacer un servicio es altamente específico de la arquitectura:
En una arquitectura tradicional en capas, el servicio es literalmente sinónimo de capa de lógica empresarial . Es la capa entre la interfaz de usuario y los datos. Por lo tanto, todas las reglas comerciales entran en los servicios. La capa de datos solo debe comprender las operaciones CRUD básicas, y la capa de interfaz de usuario solo debe ocuparse de la asignación de DTO de presentación hacia y desde los objetos comerciales.
En una arquitectura distribuida de estilo RPC (SOAP, UDDI, BPEL, etc.), el servicio es la versión lógica de un punto final físico . Es esencialmente una colección de operaciones que el responsable de mantenimiento desea proporcionar como una API pública. Varias guías de mejores prácticas explican que una operación de servicio debería ser de hecho una operación de nivel empresarial y no CRUD, y tiendo a estar de acuerdo.
Sin embargo, debido a que enrutar todo a través de un servicio remoto real puede perjudicar seriamente el rendimiento, normalmente es mejor no hacer que estos servicios implementen la lógica de negocios; en su lugar, deberían envolver un conjunto "interno" de objetos comerciales. Un solo servicio puede involucrar uno o varios objetos comerciales.
En una arquitectura MVP / MVC / MVVM / MV *, los servicios no existen en absoluto. O si lo hacen, el término se usa para referirse a cualquier objeto genérico que se pueda inyectar en un controlador o modelo de vista. La lógica de negocios está en su modelo . Si desea crear "objetos de servicio" para organizar operaciones complicadas, eso se ve como un detalle de implementación. Lamentablemente, muchas personas implementan MVC de esta manera, pero se considera un antipatrón (modelo de dominio anémico ) porque el modelo en sí no hace nada, es solo un conjunto de propiedades para la interfaz de usuario.
Algunas personas piensan erróneamente que tomar un método de controlador de 100 líneas y ponerlo todo en un servicio de alguna manera mejora la arquitectura. Realmente no lo hace; todo lo que hace es agregar otra capa de indirección, probablemente innecesaria. Hablando en términos prácticos , el controlador todavía está haciendo el trabajo, solo lo está haciendo a través de un objeto "ayudante" mal llamado. Recomiendo encarecidamente la presentación de los Modelos de Dominio Malvado de Jimmy Bogard para un ejemplo claro de cómo convertir un modelo de dominio anémico en uno útil. Implica un examen cuidadoso de los modelos que está exponiendo y qué operaciones son realmente válidas en un contexto comercial .
Por ejemplo, si su base de datos contiene Órdenes, y tiene una columna para Cantidad total, su aplicación probablemente no debería poder cambiar ese campo a un valor arbitrario, porque (a) es historial y (b) se supone que es determinado por lo que está en el orden, así como quizás por otros datos / reglas sensibles al tiempo. Crear un servicio para administrar pedidos no necesariamente resuelve este problema, porque el código de usuario aún puede tomar el objeto de pedido real y cambiar la cantidad en él. En cambio, el pedido en sí debería ser responsable de garantizar que solo pueda modificarse de manera segura y coherente.
En DDD, los servicios están destinados específicamente a la situación en la que tiene una operación que no pertenece adecuadamente a ninguna raíz agregada . Debe tener cuidado aquí, porque a menudo la necesidad de un servicio puede implicar que no utilizó las raíces correctas. Pero suponiendo que lo haya hecho, un servicio se usa para coordinar operaciones a través de múltiples raíces, o en ocasiones para manejar inquietudes que no involucran el modelo de dominio (como, tal vez, escribir información en una base de datos de BI / OLAP).
Un aspecto notable del servicio DDD es que está permitido usar scripts de transacción . Cuando trabaje en aplicaciones grandes, es muy probable que eventualmente se encuentre con instancias en las que es mucho más fácil lograr algo con un procedimiento T-SQL o PL / SQL que preocuparse con el modelo de dominio. Esto está bien y pertenece a un servicio.
Esta es una desviación radical de la definición de servicios de arquitectura en capas. Una capa de servicio encapsula objetos de dominio; un servicio DDD encapsula lo que no está en los objetos de dominio y no tiene sentido serlo.
En una arquitectura orientada a servicios , un servicio se considera la autoridad técnica para una capacidad comercial. Eso significa que es el propietario exclusivo de un determinado subconjunto de datos comerciales y que nada más puede tocar esos datos, ni siquiera para leerlos .
Por necesidad, los servicios son en realidad una propuesta de extremo a extremo en una SOA. Es decir, un servicio no es tanto un componente específico como una pila completa , y toda su aplicación (o toda su empresa) es un conjunto de estos servicios que se ejecutan uno al lado del otro sin intersección, excepto en las capas de mensajería y UI. Cada servicio tiene sus propios datos, sus propias reglas comerciales y su propia interfaz de usuario. No necesitan orquestar entre sí porque se supone que están alineados con el negocio, y, al igual que el negocio en sí, cada servicio tiene sus propias responsabilidades y opera de manera más o menos independiente de los demás.
Entonces, según la definición de SOA, cada pieza de lógica de negocios en cualquier lugar está contenida dentro del servicio, pero, de nuevo, también lo está todo el sistema . Los servicios en una SOA pueden tener componentes y pueden tener puntos finales , pero es bastante peligroso llamar a cualquier pieza de código un servicio porque entra en conflicto con lo que se supone que significa la "S" original.
Dado que SOA generalmente está muy interesado en la mensajería, las operaciones que podría haber empaquetado en un servicio anteriormente generalmente están encapsuladas en controladores , pero la multiplicidad es diferente. Cada controlador maneja un tipo de mensaje, una operación. Es una interpretación estricta del Principio de Responsabilidad Única , pero ofrece una gran capacidad de mantenimiento porque cada operación posible está en su propia clase. Por lo tanto, realmente no necesita una lógica comercial centralizada, porque los comandos representan operaciones comerciales en lugar de técnicas.
Finalmente, en cualquier arquitectura que elija, habrá algún componente o capa que tenga la mayor parte de la lógica de negocios. Después de todo, si la lógica de negocios está dispersa por todo el lugar, entonces solo tienes un código de espagueti. Pero si llama a ese componente un servicio o no , y cómo está diseñado en términos de cosas como el número o el tamaño de las operaciones, depende de sus objetivos arquitectónicos.
No hay una respuesta correcta o incorrecta, solo lo que se aplica a su situación.
fuente
En cuanto a su título , no creo que la pregunta tenga sentido. El modelo MVC consta de datos y lógica empresarial. Decir que la lógica debe estar en el Servicio y no en el Modelo es como decir: "El pasajero debe sentarse en el asiento, no en el automóvil".
Por otra parte, el término "Modelo" es un término sobrecargado. Quizás no se refería al modelo MVC pero se refería al modelo en el sentido del objeto de transferencia de datos (DTO). También conocido como una entidad. De esto está hablando Martin Fowler.
A mi modo de ver, Martin Fowler está hablando de cosas en un mundo ideal. En el mundo real de Hibernate y JPA (en tierra Java), los DTO son una abstracción súper permeable. Me encantaría poner mi lógica de negocios en mi entidad. Haría las cosas mucho más limpias. El problema es que estas entidades pueden existir en un estado administrado / en caché que es muy difícil de entender y constantemente evita sus esfuerzos. Para resumir mi opinión: Martin Fowler recomienda la forma correcta, pero los ORM impiden que lo haga.
Creo que Bob Martin tiene una sugerencia más realista y la da en este video que no es gratis . Él habla sobre mantener sus DTO libres de lógica. Simplemente almacenan los datos y los transfieren a otra capa que está mucho más orientada a objetos y no usa los DTO directamente. Esto evita que la abstracción permeable te muerda. La capa con los DTO y los DTO en sí mismos no son OO. Pero una vez que salgas de esa capa, serás tan OO como Martin Fowler defiende.
El beneficio de esta separación es que abstrae la capa de persistencia. Podría cambiar de JPA a JDBC (o viceversa) y ninguna de las lógicas comerciales tendría que cambiar. Solo depende de los DTO, no le importa cómo se llenen esos DTO.
Para cambiar ligeramente los temas, debe tener en cuenta el hecho de que las bases de datos SQL no están orientadas a objetos. Pero los ORM generalmente tienen una entidad, que es un objeto, por tabla. Así que desde el principio ya has perdido una batalla. En mi experiencia, nunca puedes representar a la Entidad de la manera exacta que deseas de una manera orientada a objetos.
En cuanto a " un servicio", Bob Martin estaría en contra de tener una clase llamada
FooBarService
. Eso no está orientado a objetos. ¿Qué hace un servicio? Cualquier cosa relacionada conFooBars
. También puede ser etiquetadoFooBarUtils
. Creo que abogaría por una capa de servicio (un mejor nombre sería la capa de lógica de negocios) pero cada clase en esa capa tendría un nombre significativo.fuente
Estoy trabajando en el proyecto greenfield en este momento y ayer tuvimos que tomar algunas decisiones arquitectónicas. Curiosamente tuve que volver a visitar algunos capítulos de 'Patrones de arquitectura de aplicaciones empresariales'.
Esto es lo que se nos ocurrió:
Terminamos con lo siguiente:
Cliente -> Servicio -> Dominio -> Datos
Podemos reemplazar la capa de cliente, servicio o datos con una cantidad razonable de trabajo. Si su lógica de dominio vivía en el servicio y ha decidido que desea reemplazar o incluso eliminar su capa de servicio, entonces tendría que mover toda la lógica comercial a otro lugar. Tal requisito es raro, pero podría suceder.
Habiendo dicho todo esto, creo que esto está bastante cerca de lo que Martin Fowler quiso decir con
El diagrama a continuación ilustra esto bastante bien:
http://martinfowler.com/eaaCatalog/serviceLayer.html
fuente
Esta es una de esas cosas que realmente depende del caso de uso. El objetivo general de una capa de servicio es consolidar la lógica de negocios juntos. Esto significa que varios controladores pueden llamar al mismo UserService.MakeHimPay () sin preocuparse realmente de cómo se realiza el pago. Lo que sucede en el servicio puede ser tan simple como modificar una propiedad de objeto o puede estar haciendo una lógica compleja que trata con otros servicios (es decir, llamar a servicios de terceros, llamar a la lógica de validación o incluso simplemente guardar algo en la base de datos). )
Esto no significa que tenga que quitar TODA la lógica de los objetos de dominio. A veces tiene más sentido tener un método en el objeto de dominio que haga algunos cálculos sobre sí mismo. En su ejemplo final, el servicio es una capa redundante sobre el repositorio / objeto de dominio. Proporciona un buen búfer contra los cambios de requisitos, pero realmente no es necesario. Si cree que necesita un servicio, intente que haga la lógica simple "modificar propiedad X en objeto Y" en lugar del objeto de dominio. La lógica en las clases de dominio tiende a caer en el "cálculo de este valor de los campos" en lugar de exponer todos los campos a través de captadores / establecedores.
fuente
La forma más fácil de ilustrar por qué los programadores evitan poner la lógica de dominio en los objetos de dominio es que generalmente se enfrentan a una situación de "¿dónde pongo la lógica de validación?" Tome este objeto de dominio por ejemplo:
Entonces tenemos algo de lógica de validación básica en el setter (no puede ser negativo). El problema es que realmente no puedes reutilizar esta lógica. En algún lugar hay una pantalla o un ViewModel o un Controlador que necesita validación antes de que realmente confirme el cambio al objeto de dominio, porque necesita informar al usuario antes o cuando hace clic en el botón Guardar que no puede hacer eso, y por qué . Probar una excepción cuando llamas al setter es un truco feo porque realmente deberías haber hecho toda la validación antes de comenzar la transacción.
Es por eso que la gente mueve la lógica de validación a algún tipo de servicio, como
MyEntityValidator
. Entonces, la entidad y la lógica de llamada pueden obtener una referencia al servicio de validación y reutilizarlo.Si no hace eso y todavía desea reutilizar la lógica de validación, termina poniéndola en métodos estáticos de la clase de entidad:
Esto hará que su modelo de dominio sea menos "anémico" y mantenga la lógica de validación al lado de la propiedad, lo cual es genial, pero no creo que a nadie le gusten los métodos estáticos.
fuente
Creo que la respuesta es clara si lees el artículo del Modelo de dominio anémico de Martin Fowler .
Eliminar la lógica de negocios, que es el dominio, del modelo de dominio es esencialmente romper el diseño orientado a objetos.
Repasemos el concepto orientado a objetos más básico: un objeto encapsula datos y operaciones. Por ejemplo, cerrar una cuenta es una operación que un objeto de cuenta debe realizar en sí mismo; por lo tanto, tener una capa de servicio que realice esa operación no es una solución orientada a objetos. Es de procedimiento, y es a lo que se refiere Martin Fowler cuando habla de un modelo de dominio anémico.
Si tiene una capa de servicio que cierra la cuenta, en lugar de que el objeto de la cuenta se cierre, no tiene un objeto de cuenta real. El "objeto" de su cuenta es simplemente una estructura de datos. Con lo que termina, como sugiere Martin Fowler, es un montón de bolsas con captadores y colocadores.
fuente
¿Cómo implementaría su lógica de negocios en la capa de servicio? Cuando realiza un pago de un usuario, está creando un pago, no solo deduciendo un valor de una propiedad.
Su método de pago debe crear un registro de pago, aumentar la deuda de ese usuario y mantener todo esto en sus repositorios. Hacer esto en un método de servicio es increíblemente sencillo, y también puede envolver toda la operación en una transacción. Hacer lo mismo en un modelo de dominio agregado es mucho más problemático.
fuente
La versión tl; dr:
Mis experiencias y opiniones dicen que cualquier objeto que tenga lógica de negocios debería ser parte del modelo de dominio. El modelo de datos probablemente no debería tener ninguna lógica en absoluto. Es probable que los servicios los unan y aborden las preocupaciones transversales (bases de datos, registro, etc.). Sin embargo, la respuesta aceptada es la más práctica.
La versión más larga, a la que otros han aludido, es que existe un error en la palabra "modelo". La publicación cambia entre el modelo de datos y el modelo de dominio como si fueran iguales, lo cual es un error muy común. También puede haber una ligera equivocación en la palabra "servicio".
En términos prácticos, no debe tener un servicio que realice cambios en ningún objeto de dominio; La razón de esto es que su servicio probablemente tendrá algún método para cada propiedad en su objeto a fin de cambiar el valor de esa propiedad. Esto es un problema porque entonces, si tiene una interfaz para su objeto (o incluso si no), el servicio ya no sigue el Principio Abierto-Cerrado; en cambio, cada vez que agrega más datos a su modelo (independientemente del dominio frente a los datos), termina teniendo que agregar más funciones a su servicio. Hay ciertas formas de evitarlo, pero esta es la razón más común por la que he visto fallar las aplicaciones "empresariales", especialmente cuando esas organizaciones piensan que "empresa" significa "tener una interfaz para cada objeto en el sistema". ¿Te imaginas agregar nuevos métodos a una interfaz, luego a dos o tres implementaciones diferentes (¿la en la aplicación, la implementación simulada y la de depuración, la en memoria?), ¿solo para una sola propiedad en su modelo? Suena como una idea terrible para mí.
Aquí hay un problema más largo que no voy a abordar, pero la esencia es esta: la programación orientada a objetos hardcore dice que nadie fuera del objeto relevante debería poder cambiar el valor de una propiedad dentro del objeto, ni siquiera " ver "el valor de la propiedad dentro del objeto. Esto se puede aliviar haciendo que los datos sean de solo lectura. Todavía puede encontrarse con problemas como cuando mucha gente hace uso de los datos incluso como de solo lectura y tiene que cambiar el tipo de datos. Es posible que todos los consumidores tengan que cambiar para adaptarse a eso. Es por eso que, cuando haces que las API sean consumidas por todos y cada uno, se recomienda no tener propiedades / datos públicos o incluso protegidos; Es la razón por la que se inventó la POO, en última instancia.
Creo que la mayoría de las respuestas aquí, aparte de la marcada como aceptada, están nublando el problema. El marcado como aceptado es bueno, pero aún siento la necesidad de responder y acepto que la viñeta 4 es el camino a seguir, en general.
fuente
La respuesta es que depende del caso de uso. Pero en la mayoría de los escenarios genéricos, me adheriría a la lógica de negocios que se encuentra en la capa de servicio. El ejemplo que ha proporcionado es realmente simple. Sin embargo, una vez que comience a pensar en sistemas o servicios desacoplados y agregue un comportamiento transaccional, realmente querrá que suceda como parte de la capa de servicio.
Las fuentes que ha citado para que la capa de servicio carezca de lógica empresarial introduce otra capa que es la capa de negocios. En muchos escenarios, la capa de servicio y la capa empresarial se comprimen en una sola. Realmente depende de cómo desee diseñar su sistema. Puede hacer el trabajo en tres capas y seguir decorando y agregando ruido.
Lo que idealmente puede hacer es modelar servicios que abarquen la lógica de negocios para trabajar en modelos de dominio para mantener el estado . Debe intentar desacoplar los servicios tanto como sea posible.
fuente
En MVC, el modelo se define como la lógica de negocios. Afirmar que debería estar en otro lugar es incorrecto a menos que no esté usando MVC. Veo las capas de servicio como similares a un sistema de módulos. Le permite agrupar un conjunto de funcionalidades relacionadas en un paquete agradable. Las partes internas de esa capa de servicio tendrían un modelo haciendo el mismo trabajo que el suyo.
fuente
El concepto de capa de servicio se puede ver desde la perspectiva DDD. Aaronaught lo mencionó en su respuesta, solo lo explico un poco.
Enfoque común es tener un controlador que sea específico para un tipo de cliente. Digamos, podría ser un navegador web, podría ser alguna otra aplicación, podría ser una prueba funcional. Los formatos de solicitud y respuesta pueden variar. Así que uso el servicio de aplicaciones como herramienta para utilizar una arquitectura hexagonal . Inyecto allí clases de infraestructura específicas para una solicitud concreta. Por ejemplo, así podría verse mi controlador que atiende solicitudes de navegador web:
Si estoy escribiendo una prueba funcional, quiero usar un cliente de pago falso y probablemente no necesite una respuesta html. Entonces mi controlador podría verse así:
Por lo tanto, el servicio de aplicaciones es un entorno que configuré para ejecutar lógica de negocios. Es donde se llaman las clases modelo, agnósticamente de una implementación de infraestructura.
Entonces, respondiendo a sus preguntas desde esta perspectiva:
No.
Bueno, uno puede llamarlo así.
No.
Sin embargo, existe un enfoque radicalmente diferente que niega totalmente el uso de cualquier tipo de servicio. Por ejemplo, David West en su libro Object Thinking afirma que cualquier objeto debe tener todos los recursos necesarios para hacer su trabajo. Este enfoque da como resultado, por ejemplo, el descarte de cualquier ORM .
fuente
Para el registro.
SRP:
En este caso, está bien seguir los siguientes pasos:
Si la deuda no requiere algún cálculo:
Sin embargo, si requiere algún cálculo, entonces:
o tambien
Pero también, si el cálculo se realiza en la capa de persistencia, tal procedimiento de almacenamiento entonces
En este caso, si queremos recuperar al usuario de la base de datos y actualizar la deuda, debemos hacerlo en varios pasos (de hecho, dos) y no es necesario envolverlo / encapsularlo en la función de un servicio.
Y si requiere almacenarlo, entonces podemos agregar un tercer paso
Sobre la solución propuesta
a) No debemos tener miedo de dejar que el desarrollador final escriba un par de en lugar de encapsularlo en una función.
b) Y sobre la interfaz, a algunos desarrolladores les encanta la interfaz y están bien, pero en varios casos, no son necesarios en absoluto.
c) El objetivo de un servicio es crear uno sin atributos, principalmente porque podemos usar funciones compartidas / estáticas. También es fácil realizar pruebas unitarias.
fuente
"We shouldn't be afraid to left the end-developer to write a couple of instead of encapsulate it in a function.
si no fuera por mi caballo no habría pasado ese año en la universidad ' "Sólo puedo citar Lewis Negro?'.