patron design-patterns nosql data-access-layer document-database

design patterns - patron - ¿Tiene sentido usar el patrón de repositorio con una base de datos de documentos?



laravel repository eloquent (5)

Actualmente estoy experimentando con MongoDB . Me estoy moviendo de una mentalidad de NHibernate / SQL , así que inicialmente implementé un patrón de repositorio para el acceso a datos.

Todo se veía bien hasta que empecé a usar documentos anidados. Ahora está empezando a parecer que hay un poco de desajuste. Sin embargo, me siento cómodo con los repositorios, y me gusta la abstracción, la separación de inquietudes y la comprobabilidad que proporcionan.

¿Las personas están utilizando con éxito el patrón de repositorio con bases de datos de documentos? Si no es así, ¿qué metodología de acceso a datos usas? ¿Qué pasa con la abstracción / SoC?


Eric Evens, en su libro Domain Driven Design, tiene una explicación muy compleja y muy buena del patrón del repositorio. Su definición es qué debe ser un repositorio y cómo debe usarse (en mi opinión personal). Puede encontrar una breve descripción aquí: Eric Evans en Repositorios

Básicamente, si mantiene sus repositorios como intermediarios entre el código del cliente y las fábricas, serán perfectos para lo que entiendo que necesita. Los repositorios deben ofrecer las interfaces de consulta / construcción / validación y hacer todo el personal de adquisición de datos (como la base de datos de conexión / consulta) y debe tener una o más fábricas (según sea necesario) que construirán los objetos y se los pasarán al cliente a través del repositorio.


Es una pregunta interesante. En mi uso de MongoDB, elegí no tener un repositorio. Esto fue primario porque la base de datos de documentos se usó como un almacén de lectura (por lo tanto, simplificando los datos que se almacenaron allí).

Supongo que debe restar importancia a lo que es un repositorio y qué ventajas obtiene de la capa adicional de abstracción. Un buen diseño tendrá el menor número de capas posibles .

Por lo tanto, un repositorio le proporciona cierta ignorancia de la persistencia y la capacidad de utilizar la unidad de trabajo en un contexto de datos común. También puede aumentar su capacidad para probar consultas contra los datos de forma aislada (debido a que generalmente se resumen como consultas o especificaciones).

Además, algunas bases de datos de documentos ya proporcionan un patrón de repositorio (RavenDB, etc.), por lo que no es necesario tener otra capa.

Por lo tanto, me parece que usar un repositorio no se trata tanto de si sus datos se almacenan como una tabla relacional o un documento, sino de lo que obtiene de la abstracción.


No sé si esto te ayudará, pero estuve escuchando un pod-cast un tiempo con Ayende Rahien hablando sobre RavenDB. Él estaba sugiriendo que un documento en realidad se asigna bastante bien a un agregado en la filosofía DDD. Si está utilizando documentos anidados para representar un agregado y se está ejecutando en problemas de diseño, ¿tal vez el anidamiento no sea la mejor opción?


Pensar en "¿Debo usar X o no" no es tan productivo como enfocarse en "¿Qué debo usar"?

¿Cuáles son las alternativas al patrón de repositorio, cuáles son las compensaciones y cómo se relacionan con su dominio e implementación?

Los repositorios son buenos para imponer un conjunto predefinido de patrones en un almacén de propósito general (como SQL). Para un almacén de documentos, mi impresión es que el esquema del documento determinará los patrones de acceso en mayor medida de lo que normalmente vería en un almacén basado en SQL. La implementación de un repositorio en este caso puede dar lugar a abstracciones muy permeables, donde los cambios en la estructura del documento subyacente tienen un impacto de 1: 1 en el código comercial relevante. En ese caso el repositorio aporta muy poco valor. Para mí, las tiendas de documentos se prestan naturalmente a los paradigmas de Unidad de Trabajo (UoW) donde la unidad de trabajo es un documento (o doc + subdocs anidados, o conjuntos de documentos).

Otra fortaleza del patrón de repositorio es, como mencionó, la abstracción sobre el mecanismo de almacenamiento. La compensación generalmente es la pérdida de acceso a las características específicas de implementación de bajo nivel de Mongo. ¿Es un intercambio que vale la pena para ti? NHibernate está muy unido a SQL, y por lo tanto tiene abstracciones ricamente funcionales sobre todas las características importantes de un RDBMS. No tengo conocimiento de ningún marco similar para Mongo, por lo que realmente estaría elevando el nivel de abstracción un poco.

¿Necesita soportar múltiples almacenes de datos concurrentes? Por ejemplo, ¿escribirá algunos tipos de datos en SQL y otros en Mongo, a través de la misma abstracción de la capa de datos? Si es así, entonces un repositorio es una buena opción.

Si puede proporcionar más detalles de su dominio e implementación, podemos profundizar en las compensaciones específicas que puede considerar


Uso MongoDB en el código de producción con el patrón de repositorio durante más de 2 años y puedo decir que realmente me ayudó con el tiempo. Las abstracciones sirven bien para pruebas (en memoria) y producción (MongoDB).

Uso Java y el código se parece a esto (aproximadamente):

public interface MyStorage { boolean add(MyDoc doc); boolean update(MyDoc doc); boolean remove(String docId); boolean commit(); MyDoc get(String docId); MyStorageQuery newQuery(); List<MyDoc> query(MyStorageQuery q); }

Tengo una fábrica para cada implementación de almacenamiento que crea nuevas instancias del objeto MyDoc. Intercambio la implementación entre MongoDb y mi propio simulacro hecho a mano para las pruebas.

La implementación de MongoDB utiliza una clase MyDoc que extiende el objeto BasicDBO de esta forma:

public interface MyDoc { Data getData(); // let''s assume this is a nested doc void setData(Data d); String getId(); long getTimestamp(); void setTimestamp(long time); } MongoDbMyDoc extends BasicDBObject implements MyDoc { MongoDbObject() { } void setId(String id) { this.put("_id", id); } String getId() { return super.get("_id"); } void setData(Data d) { dataObj = new BasicDBObject(); dataObj.put("someField",d.someField); dataObj.put("someField2", d.someField2); super.put("data",dataObj); } ... }

Luego, en la implementación de almacenamiento real, uso el cliente Java de MongoDB para devolver instancias de mi implementación desde la base de datos. Aquí está el constructor para mi implementación de almacenamiento MongoDB:

public MongoDbMyStorage(DB db, String collection) { //DB in a mongodb object (from the client library) which was instantiated elsewhere dbCollection = db.getCollection(collection); dbCollection.setObjectClass(MongoDbMyDoc.class); this.factory = new MongoDbMyDocFactory(); }

Aquí hay 2 interfaces más: MyStorageQuery que también se implementa como un objeto BasicDBO para la implementación de MongoDB y se genera utilizando el newQuery() de la interfaz de almacenamiento. Y MyDocFactory que no se presenta aquí, pero es básicamente una fábrica de documentos que sabe cuál es la implementación de almacenamiento y genera las instancias de MyDoc consecuencia.

Advertencias:
Una cosa donde la abstracción no tiene mucho sentido es en la definición de los índices utilizados por el almacenamiento de MongoDB. Puse todas mis ensureIndex(...) en el constructor, no muy genéricas, pero la definición de índices por colección es una optimización específica de MongoDB para que pueda vivir con él.
Otra es que el compromiso se implementa utilizando el getLastError() que, según mi experiencia, no funcionó tan bien. No es un problema para mí, ya que casi nunca cometo un cambio explícitamente.