En mi opinión, no es así en absoluto. Y es una violación de DRY.
La idea es que el objeto de entidad / dominio en el medio está modelado para representar el dominio lo mejor y lo más conveniente posible. Está en el centro de todo y todo puede depender de él, ya que el dominio en sí no cambia la mayor parte del tiempo.
Si su base de datos en el exterior puede almacenar esos objetos directamente, entonces asignarlos a otro formato en aras de separar capas no solo no tiene sentido, sino que crea duplicados del modelo y esa no es la intención.
Para empezar, la arquitectura limpia se realizó con un entorno / escenario típico diferente en mente. Aplicaciones de servidor empresarial con capas externas gigantes que necesitan sus propios tipos de objetos especiales. Por ejemplo, bases de datos que producen SQLRow
objetos y necesitan SQLTransactions
a cambio de actualizar elementos. Si usara los del centro, violaría la dirección de dependencia porque su núcleo dependería de la base de datos.
Con ORM livianos que cargan y almacenan objetos de entidad, ese no es el caso. Ellos hacen el mapeo entre su SQLRow
dominio interno y el suyo. Incluso si necesita poner una @Entitiy
anotación del ORM en su objeto de dominio, diría que esto no establece una "mención" de la capa externa. Debido a que las anotaciones son solo metadatos, ningún código que no las busque específicamente las verá. Y lo más importante, nada necesita cambiar si los elimina o los reemplaza con una anotación de base de datos diferente.
Por el contrario, si cambias tu dominio e hiciste todos esos mapeadores, tienes que cambiar mucho.
Enmienda: Arriba está un poco simplificado e incluso podría estar equivocado. Porque hay una parte en la arquitectura limpia que quiere que crees una representación por capa. Pero eso tiene que verse en el contexto de la aplicación.
A saber, lo siguiente aquí https://blog.8thlight.com/uncle-bob/2012/08/13/the-clean-architecture.html
Lo importante es que las estructuras de datos simples y aisladas se pasan a través de los límites. No queremos engañar y pasar entidades o filas de bases de datos. No queremos que las estructuras de datos tengan ningún tipo de dependencia que viole la Regla de dependencia.
Pasar entidades desde el centro hacia las capas externas no viola la regla de dependencia, pero se mencionan. Pero esto tiene una razón en el contexto de la aplicación prevista. Pasar entidades alrededor movería la lógica de la aplicación hacia el exterior. Las capas externas necesitarían saber cómo interpretar los objetos internos, efectivamente tendrían que hacer lo que se supone que deben hacer las capas internas como la capa de "caso de uso".
Además de eso, también desacopla las capas para que los cambios en el núcleo no requieran necesariamente cambios en las capas externas (vea el comentario de SteveCallender). En ese contexto, es fácil ver cómo los objetos deben representar específicamente el propósito para el que se usan. Además, las capas deben comunicarse entre sí en términos de objetos que están hechos específicamente para el propósito de esta comunicación. Esto puede incluso significar que hay 3 representaciones, 1 en cada capa, 1 para el transporte entre capas.
Y hay https://blog.8thlight.com/uncle-bob/2011/11/22/Clean-Architecture.html que aborda arriba:
Otras personas se han preocupado de que el resultado neto de mi consejo sería una gran cantidad de código duplicado y muchas copias de memoria de una estructura de datos a otra a través de las capas del sistema. Ciertamente tampoco quiero esto; y nada de lo que he sugerido conduciría inevitablemente a la repetición de estructuras de datos y a una excesiva copia de campo.
Esa OMI implica que la copia simple de objetos 1: 1 es un olor en la arquitectura porque en realidad no estás usando las capas y / o abstracciones adecuadas.
Más tarde explica cómo imagina todas las "copias"
Separa la interfaz de usuario de las reglas de negocio al pasar estructuras de datos simples entre los dos. No deja que sus controladores sepan nada sobre las reglas comerciales. En cambio, los controladores desempaquetan el objeto HttpRequest en una estructura de datos simple y luego pasan esa estructura de datos a un objeto interactivo que implementa el caso de uso invocando objetos de negocios. El interactor luego reúne los datos de respuesta en otra estructura de datos vainilla y los devuelve a la IU. Las vistas no conocen los objetos comerciales. Simplemente miran esa estructura de datos y presentan la respuesta.
En esta aplicación, hay una gran diferencia entre las representaciones. Los datos que fluyen no son solo las entidades. Y esto garantiza y exige diferentes clases.
Sin embargo, se aplica a una aplicación simple de Android como un visor de fotos donde la Photo
entidad tiene aproximadamente 0 reglas de negocio y el "caso de uso" que trata con ellas es casi inexistente y en realidad está más preocupado por el almacenamiento en caché y la descarga (ese proceso debería ser IMO representado más explícitamente), el punto de hacer representaciones separadas de una foto comienza a desaparecer. Incluso tengo la sensación de que la foto en sí misma es el objeto de transferencia de datos mientras falta la verdadera capa de núcleo de lógica de negocios.
Existe una diferencia entre "separar la interfaz de usuario de las reglas de negocio al pasar estructuras de datos simples entre los dos" y "cuando desee mostrar una foto, renómbrela 3 veces en el camino" .
Además de eso, el punto en el que veo que esas aplicaciones de demostración no representan la arquitectura limpia es que agregan un gran énfasis en la separación de capas en aras de la separación de capas, pero ocultan efectivamente lo que hace la aplicación. Eso contrasta con lo que se dice en https://blog.8thlight.com/uncle-bob/2011/09/30/Screaming-Architecture.html , es decir, que
la arquitectura de una aplicación de software grita sobre los casos de uso de la aplicación
No veo ese énfasis en separar capas en la arquitectura limpia. Se trata de la dirección de dependencia y de centrarse en representar el núcleo de la aplicación (entidades y casos de uso) en Java de forma ideal sin dependencias hacia el exterior. No se trata tanto de dependencias hacia ese núcleo.
Entonces, si su aplicación realmente tiene un núcleo que representa las reglas de negocios y los casos de uso, y / o diferentes personas trabajan en diferentes capas, sepárelas de la manera prevista. Si, por el contrario, solo escribe una aplicación simple, no se exceda. 2 capas con límites fluidos pueden ser más que suficientes. Y las capas se pueden agregar más adelante también.
BankAccount
pero con reglas específicas de la aplicación, qué puede hacer con esa cuenta.@SerializedName
anotaciones de Gson en un modelo de dominio? ¿O crearía un nuevo objeto responsable de asignar la respuesta web al modelo de dominio?En realidad lo entendiste bien. Y no hay violación de DRY porque acepta SRP.
Por ejemplo: tiene un método empresarial createX (nombre de cadena), entonces puede tener un método createX (nombre de cadena) en la capa DAO, llamado dentro del método empresarial. Pueden tener la misma firma y tal vez solo haya una delegación, pero tienen diferentes propósitos. También puede tener un createX (nombre de cadena) en UseCase. Incluso entonces no es redundante. Lo que quiero decir con esto es: las mismas firmas no significan la misma semántica. Elija otros nombres para que tenga clara la semántica. Nombrarse a sí mismo esto no afecta a SRP en absoluto.
UseCase es responsable de la lógica específica de la aplicación, el objeto comercial es responsable de la lógica independiente de la aplicación y el DAO es responsable del almacenamiento.
Debido a la semántica diferente, todas las capas pueden tener su propio modelo de representación y comunicación. A menudo ve "entidades" como "objetos comerciales" y, a menudo, no ve la necesidad de separarlos. Pero en los proyectos "enormes" se debe hacer un esfuerzo para separar adecuadamente las capas. Cuanto mayor sea el proyecto, aumenta la posibilidad de que necesite las diferentes semánticas representadas en diferentes capas y clases.
Puedes pensar en diferentes aspectos de la misma semántica. Un objeto de usuario debe mostrarse en la pantalla, tiene algunas reglas de coherencia interna y debe almacenarse en algún lugar. Cada aspecto debe estar representado en una clase diferente (SRP). Crear los mapeadores puede ser una molestia, por lo que en la mayoría de los proyectos que trabajé en estos aspectos se fusionan en una sola clase. Esto es claramente una violación de SRP pero a nadie realmente le importa.
Llamo a la aplicación de arquitectura limpia y SÓLIDA "no socialmente aceptable". Trabajaría con eso si me lo permiten. Actualmente no tengo permitido hacerlo. Espero el momento en que tenemos que pensar en tomar SOLID en serio.
fuente
No, no necesita crear clases de modelo en cada capa.
Entidad (
DATA_LAYER
): es una representación total o parcial del objeto Base de datos.DATA_LAYER
Mapper (
DOMAIN_LAYER
): en realidad es una clase que convierte Entity en ModelClass, que se utilizará enDOMAIN_LAYER
Echa un vistazo: https://github.com/lifedemons/photoviewer
fuente