orm - programacion - Arquitectura para un objeto de negocios/capa de acceso a la base de datos
base de datos por capas (7)
¿Podría sugerir otra alternativa, posiblemente con un mejor desacoplamiento: los objetos de negocio usan objetos de datos y los objetos de datos implementan objetos de almacenamiento? Esto debería mantener las reglas comerciales en los objetos comerciales pero sin depender del formato o fuente de almacenamiento, al tiempo que permite que los objetos de datos admitan las manipulaciones necesarias, incluido el cambio dinámico de los objetos de almacenamiento (por ejemplo, para la manipulación en línea / fuera de línea)
esto cae en la segunda categoría anterior (los objetos comerciales encapsulan objetos de almacenamiento de datos), pero separa la semántica de los datos de los mecanismos de almacenamiento de forma más clara
Por diversas razones, estamos escribiendo una nueva biblioteca de objetos comerciales / almacenamiento de datos. Uno de los requisitos de esta capa es separar la lógica de las reglas comerciales y la capa de almacenamiento de datos real.
Es posible tener múltiples capas de almacenamiento de datos que implementen acceso al mismo objeto, por ejemplo, una fuente principal de almacenamiento de datos de "base de datos" que implementa la mayoría de los objetos, y otra fuente "ldap" que implementa un objeto Usuario. En este escenario, el usuario puede venir de una fuente LDAP, tal vez con una funcionalidad ligeramente diferente (por ejemplo, no es posible guardar / actualizar el objeto Usuario), pero de lo contrario la aplicación lo utiliza de la misma manera. Otro tipo de almacenamiento de datos podría ser un servicio web o una base de datos externa.
Hay dos formas principales en que estamos considerando implementar esto, y yo y un compañero de trabajo discrepan en un nivel fundamental que es correcto. Me gustaría un consejo sobre cuál es el mejor para usar. Trataré de mantener mis descripciones de cada una lo más neutral posible, ya que estoy buscando algunos puntos de vista objetivos aquí.
Los objetos comerciales son clases base y los objetos de almacenamiento de datos heredan objetos comerciales. El código del cliente se ocupa de los objetos de almacenamiento de datos.
En este caso, las reglas comerciales comunes son heredadas por cada objeto de almacenamiento de datos, y son los objetos de almacenamiento de datos los que utiliza directamente el código del cliente.
Esto tiene la consecuencia de que el código del cliente determina qué método de almacenamiento de datos usar para un objeto dado, porque tiene que declarar explícitamente una instancia para ese tipo de objeto. El código del cliente necesita conocer explícitamente la información de conexión para cada tipo de almacenamiento de datos que está utilizando.
Si una capa de almacenamiento de datos implementa una funcionalidad diferente para un objeto dado, el código del cliente lo conoce explícitamente en el momento de la compilación porque el objeto se ve diferente. Si se cambia el método de almacenamiento de datos, el código del cliente debe actualizarse.
Los objetos comerciales encapsulan objetos de almacenamiento de datos.
En este caso, los objetos comerciales son utilizados directamente por la aplicación del cliente. La aplicación cliente pasa a lo largo de la información de conexión base a la capa empresarial. La decisión sobre qué método de almacenamiento de datos utiliza un determinado objeto se realiza mediante código de objeto comercial. La información de conexión sería un fragmento de datos tomados de un archivo de configuración (la aplicación cliente no sabe / se preocupa por detalles), que puede ser una cadena de conexión única para una base de datos, o varias cadenas de conexión para varios tipos de almacenamiento de datos. Los tipos de conexión de almacenamiento de datos adicionales también podrían leerse desde otro lugar; por ejemplo, una tabla de configuración en una base de datos que especifique las URL para varios servicios web.
El beneficio aquí es que si se agrega un nuevo método de almacenamiento de datos a un objeto existente, se puede establecer una configuración en tiempo de ejecución para determinar qué método usar y es completamente transparente para las aplicaciones del cliente. Las aplicaciones cliente no necesitan ser modificadas si cambia el método de almacenamiento de datos para un objeto determinado.
Los objetos comerciales son clases base, los objetos de origen de datos heredan de los objetos comerciales. El código de cliente trata principalmente con clases base.
Esto es similar al primer método, pero el código del cliente declara las variables de los tipos básicos de objetos comerciales, y los métodos estáticos Load () / Create () / etc en los objetos comerciales devuelven los objetos apropiados de fuente de datos.
La arquitectura de esta solución es similar al primer método, pero la principal diferencia es la decisión sobre qué objeto de almacenamiento de datos usar para un objeto comercial dado, lo hace la capa empresarial, no el código del cliente.
Sé que ya existen bibliotecas ORM que proporcionan algunas de estas funcionalidades, pero descontácelas por ahora (existe la posibilidad de que se implemente una capa de almacenamiento de datos con una de estas bibliotecas ORM). También tenga en cuenta que deliberadamente no le estoy diciendo qué idioma se usa aquí, aparte de que está fuertemente tipado.
Estoy buscando algunos consejos generales aquí sobre qué método es mejor usar (o no dude en sugerir algo más) y por qué.
Bueno, aquí estoy, el compañero de trabajo que Greg mencionó.
Greg describió las alternativas que hemos estado considerando con gran precisión. Solo quiero agregar algunas consideraciones adicionales a la descripción de la situación.
El código de cliente puede ignorar el almacenamiento de datos donde se almacenan los objetos comerciales, pero es posible en el caso de que solo haya un almacenamiento de datos o múltiples tipos de datos para el mismo tipo de objeto comercial (usuarios almacenados en la base de datos local y en LDAP externo) pero el cliente no crea estos objetos comerciales. En términos de análisis del sistema, significa que no debería haber casos de uso en los que la existencia de dos datastores de objetos del mismo tipo pueda afectar el flujo de casos de uso.
Tan pronto como surja la necesidad de distinguir objetos creados en diferentes almacenamientos de datos, el componente del cliente debe conocer la multiplicidad de almacenamientos de datos en su universo, y será inevitablemente responsable de la decisión de qué almacenamiento de datos usar en el momento de la creación del objeto. (y, creo, cargar objetos desde un almacenamiento de datos). La capa empresarial puede pretender que está tomando estas decisiones, pero el algoritmo de toma de decisiones se basará en el tipo y el contenido de la información proveniente del componente Cliente, haciendo que el cliente sea efectivamente responsable de la decisión.
Esta responsabilidad se puede implementar de muchas maneras: puede ser un objeto de conexión de tipo específico para cada almacenamiento de datos; se pueden segregar métodos para llamar y crear nuevas instancias de BO, etc.
Saludos,
Miguel
Echa un vistazo a CSLA.net por Rocky Lhotka.
Los clientes nunca deben tratar con objetos de almacenamiento directamente. Pueden tratar directamente con DTO, pero el cliente no debe llamar directamente a ningún objeto que tenga una lógica de almacenamiento que no esté incluida en su objeto comercial.
También puede tener una fachada para evitar que su cliente llame al negocio directamente. También crea puntos de entrada comunes para su negocio.
Como se dijo, su negocio no debe exponerse a nada más que a su DTO y Facade.
Sí. Su cliente puede tratar con DTOs. Es la forma ideal de pasar datos a través de su aplicación.
Generalmente prefiero que el "objeto comercial encapsule el objeto / almacenamiento de datos" sea el mejor. Sin embargo, en el corto plazo, puede encontrar una gran redundancia con sus objetos de datos y sus objetos de negocios que pueden parecerle que no valen la pena. Esto es especialmente cierto si opta por un ORM como base de su capa de acceso a datos (DAL). Pero, en el largo plazo es donde el verdadero beneficio es: ciclo de vida de la aplicación. Como se ilustra, no es raro que los "datos" provengan de uno o más subsistemas de almacenamiento (no se limitan a RDBMS), especialmente con el advenimiento de la computación en la nube, y como comúnmente ocurre en los sistemas distribuidos. Por ejemplo, puede tener algunos datos que provienen de un servicio Restful, otro fragmento u objeto de un RDBMS, otro de un archivo XML, LDAP, etc. Con esta comprensión, esto implica la importancia de una muy buena encapsulación del acceso a los datos del negocio. Tenga cuidado con las dependencias que expone (DI) a través de sus ctorres y propiedades, también.
Dicho esto, un enfoque con el que he estado jugando es poner la "carne" de la arquitectura en un controlador comercial. Al pensar en el acceso a datos contemporáneo más como un recurso que en el pensamiento tradicional, el controlador acepta en un URI u otra forma de metadatos que se puede utilizar para saber qué recursos de datos debe administrar para los objetos comerciales. Entonces, los objetos comerciales NO encapsulan el acceso a los datos; más bien el controlador sí. Esto mantiene los objetos de su negocio livianos y específicos y le permite a su controlador brindar optimización, capacidad de compilación, ambiente de transacción, etc. Tenga en cuenta que su controlador entonces "alojará" sus colecciones de objetos comerciales, al igual que la pieza del controlador de muchos ORMs.
Además, también considere la administración de reglas comerciales. Si bizquea con fuerza en su UML (o el modelo en su cabeza como lo hago yo: D), notará que su modelo de reglas de negocios es en realidad otro modelo, a veces incluso persistente (si está usando un motor de reglas de negocios, por ejemplo) . Consideraría permitir que el controlador de negocio también controle realmente su subsistema de reglas, y permitir que su objeto comercial haga referencia a las reglas a través del controlador. La razón es porque, inevitablemente, las implementaciones de reglas a menudo necesitan realizar búsquedas y comprobaciones cruzadas para determinar la validez. A menudo, puede requerir búsquedas de objetos comerciales hidratados, así como búsquedas en bases de datos de fondo. Considere detectar entidades duplicadas, por ejemplo, donde solo el "nuevo" está hidratado. Dejando que las reglas sean administradas por el controlador de su empresa, puede hacer la mayoría de lo que necesite sin sacrificar esa bonita abstracción limpia en su "modelo de dominio".
En pseudo-código:
using(MyConcreteBusinessContext ctx = new MyConcreteBusinessContext("datares://model1?DataSource=myserver;Catalog=mydatabase;Trusted_Connection=True ruleres://someruleresource?type=StaticRules&handler=My.Org.Business.Model.RuleManager")) {
User user = ctx.GetUserById("SZE543");
user.IsLogonActive = false;
ctx.Save();
}
//a business object
class User : BusinessBase {
public User(BusinessContext ctx) : base(ctx) {}
public bool Validate() {
IValidator v = ctx.GetValidator(this);
return v.Validate();
}
}
// a validator
class UserValidator : BaseValidator, IValidator {
User userInstance;
public UserValidator(User user) {
userInstance = user;
}
public bool Validate() {
// actual validation code here
return true;
}
}
CLSA ha existido por mucho tiempo. Sin embargo, me gusta el enfoque que se discute en el libro de Eric Evans http://dddcommunity.org/