Identificador vs objeto de dominio como parámetro de método

10

¿Hay algún argumento objetivo a favor o en contra del uso de objetos vs ID único como parámetros de método / función? (y miembros de otros objetos?). Especialmente en el contexto de lenguajes estáticamente escritos (C # / Java / Scala)

Ventajas del objeto mismo:

  • Más llamadas de typesafe. Con las ID existe el riesgo de un ordenamiento incorrecto de los argumentos. Sin embargo, esto puede mitigarse manteniendo una clase 'mini' para cada clase que solo almacene el ID de esa clase.
  • Obtenga una vez de la persistencia, no es necesario volver
  • Con ID, si el tipo de identificación cambia, diga int -> long, entonces requeriría un cambio en todos los ámbitos con posibilidad de errores. (Courtsey: https://softwareengineering.stackexchange.com/a/284734/145808 )

Ventajas de usar ID:

  • La mayoría de las veces no es necesario el objeto real, solo uniqueid lo haría, por lo que tener ID ahorra tiempo de obtenerlo de la persistencia.

Una combinación de estas técnicas, hasta donde puedo ver, solo tendría contras de ambos y pros de ninguno.

Dado que este es un problema definido de manera concreta, espero que haya respuestas objetivas y no tipos "Creo" o "Me gusta" ... :-).

EDITAR: Contexto sobre la sugerencia de un comentarista. La única restricción es un lenguaje estáticamente tipado. La aplicación es de uso general, aunque también está contenta de obtener respuestas basadas en escenarios de uso específicos.

EDITAR: algo más de contexto. Digamos que tengo un sistema de gestión de libros. Mi modelo es:

Book: { id: Int, isbn: String, donatedBy: Member, borrowedBy: Member }
Member: {id: Int, name: String}

Table- wishlist: { isbn: String, memberId: Int}
Table- borrows:  { id: Int, memberId: Int}  

Method: 
isInWishList( book: Book, member: Member ) vs isInWishList( bookId: Int,  memberId: Int)

handleBorrowRequest( memberId: Int, book: Book ){ 
   //the login system doesn't actually get the entire member structure, only the member id. I don't need the full member yet. can run a query to verify that the memberId has less than max allowed books for borrowing. 
}

¿Por qué querría mantener solo la identificación y no el miembro completo? Digamos que cuando recibo información sobre el libro, rara vez necesito saber quién lo ha donado o prestado. Obtener su información completa para llenar los campos donado por y prestado por es una exageración.

Por supuesto, estos son solo mis puntos. Estoy seguro de que me faltan cosas, así que quería saber cuáles son los puntos a favor / en contra.

0fnt
fuente
¿Podrías editar tu pregunta con un poco más de contexto? No está claro cuál es el escenario. Voy a adivinar que estás hablando de objetos gestionados por un sistema ORM (como Hibernate) y que por "mini-clase" te refieres a un objeto proxy de carga lenta.
Darien
2
Posiblemente relacionado? programmers.stackexchange.com/questions/284634/…
hjk
Agregar como comentario aquí (hasta que pueda obtener suficiente contexto para expandirme a una respuesta con todas las funciones): a menos que esté codificando valores de identificación en su código (un gran no-no), aún tendrá que cargar sus valores de identificación de algún lado ¿verdad? "La mayor parte del tiempo" también es bastante vago en mi humilde opinión ...
hjk
@hjk Agregó un poco más de contexto, gracias. Tienes un punto, todavía tienes que cargar los valores de ID desde algún lugar. Sin embargo, no se trata de no 'tocar' la base de datos, sino de minimizar el uso y el ancho de banda de la base de datos. Puedo obtener identificadores de todos aquellos que quieren pedir prestado un libro, pero en realidad no sería necesario obtener todos sus detalles.
2015
Parece que dependería de varias cosas: (1) si los casos de uso requieren los atributos reales (columnas) o solo la ID, que depende de esos casos de uso; (2) si usa algunas técnicas de almacenamiento en caché o de mejora del rendimiento que harían que la consulta de ID a atributos sea fácil, y si sus casos de uso serían lo suficientemente pesados ​​como para romper tales esquemas de almacenamiento en caché.
rwong

Respuestas:

8

Dependiendo de su entorno y contexto del problema, la necesidad de ir a la base de datos puede mitigarse y, como resultado (IMO), se pierde el argumento para usar solo las identificaciones.

Por ejemplo, Doctrine2 ORM de PHP tiene EntityManager::getReferenceque produce un proxy con carga lenta para una entidad que usa la identificación proporcionada; No sé cuántos otros ORM hacen eso, pero coincide aproximadamente con la noción de una "mini-clase" que mencionas. Para la mayoría de los propósitos, esta es una entidad totalmente hidratada, por lo que puede pasarla y usarla como cualquier otra.

El único caso en el que no lo es es cuando se le da una identificación no válida, y en ese caso, de todos modos, querrá ir a la base de datos para validar; Además, para reducir el costo de obtener entidades, la mayoría de los ORM tienen funcionalidades de almacenamiento en caché (primer y segundo nivel) disponibles de alguna forma.

Una vez que reducimos la necesidad y el costo de ir a la base de datos, nos quedamos en gran medida con los profesionales de usar la entidad como parámetro:

  1. Escriba seguridad.
  2. Menos conocimiento requerido por la persona que llama. Un desarrollador 6 meses después no puede pasar por error la identificación de la entidad incorrecta.
  3. Costo de refactorización reducido. Si un método cambiara para requerir 2 piezas de información de la entidad, no hay ningún costo en cambiar la persona que llama para proporcionarla, suponiendo que la persona que llama tiene la entidad completamente hidratada para empezar.
  4. Se requiere menos validación por método. Muchos métodos pueden suponer que la entidad que se les da existe en la base de datos (porque proviene del ORM), por lo que ya no tienen que validar la identificación.
  5. (Potencialmente) menos llamadas a la base de datos. Si está pasando identificaciones a 3 métodos, y cada uno tiene que validarlo o buscar más datos en la entidad, eso es 3 veces más llamadas a la base de datos que 1 método que busca la entidad y 2 que operan en ella.

Por supuesto, hay casos en los que uno podría querer pasar solo una identificación: por ejemplo, al cruzar un límite de contexto acotado (en el diseño dirigido por el dominio, por ejemplo). Si consideramos dos contextos delimitados con diferentes nociones de lo que constituye una cuenta (por ejemplo, las relaciones entre finanzas y clientes), entonces no podemos pasar la cuenta del contexto A al contexto B. En cambio, una identificación de la cuenta (en el idioma del dominio) puede ser cruzado

Andy Hunt
fuente
El almacenamiento en caché no se escalaría bien con múltiples instancias de ejecución de aplicaciones. Tengo mi propio almacenamiento en caché. Sin embargo, los puntos son excelentes.
0fnt
Supongo que un punto más en contra de las ID es que usar ID implica llamar a la persistencia además de la validación, para obtener el objeto también.
2015
3

Para este tipo de preguntas, delego a la solución que mejor comunique mi intención como programador y facilite el trabajo de "Future Greg".

Usar el objeto como argumentos hace que sea más fácil obtener la llamada al método dentro de 6 meses y he olvidado los detalles valientes de esta aplicación. Para construir sobre su "es este libro en el ejemplo de la lista de deseos de esta persona", digamos que el isInWishListmétodo realmente solo necesita comparar los ID enteros de libros y miembros. En realidad, este método solo necesita dos datos para hacer su trabajo. Ahora, demos un paso atrás de este método y veamos todo el sistema de software. Dudo que solo requiera una identificación de libro y una identificación de miembro para poder funcionar. De todos modos, extraerá el libro completo y el miembro de la base de datos antes de llamar, isInWishListya que es probable que deba hacer algo más que simplemente llamar a este método. Quizás lo hagas, pero la mayoría de las veces tendrás que hacer más.

Dado eso, no incurrirá de manera realista en una penalización de rendimiento al buscar y asignar ambos objetos en su totalidad desde la base de datos. Teóricamente necesitará menos llamadas a la base de datos, pero en la práctica encontrará que esto simplemente no es cierto. Si pasa esos Ids como parámetros en la cadena de consulta al servidor, entonces sí, solo tendrá que buscar la lista de deseos de la base de datos. Pero esta es una vista muy estrecha de toda su aplicación. Habrá escenarios cuando realice otras operaciones además de verificar una lista de deseos, por ejemplo, agregar un libro a una lista de deseos. No desea agregar elementos duplicados.

Busca la solución que sea más fácil de entender para un nuevo programador, o tu Yo Futuro, que es pasar los objetos Booky Member. Solo después de encontrar un problema de rendimiento real deberías preocuparte por pasar los Ids.

O bien, podríamos recordar que los lenguajes de tipo estático como Java ofrecen una sobrecarga de métodos, por lo que puede tener su pastel y comerlo también:

public boolean isInWishList(int bookId, int memberId) {
    // ...
}

public boolean isInWishList(Book book, Member member) {
    return isInWishList(book.getId(), member.getId());
}

La verdadera respuesta a esta pregunta es escribir ambos métodos, llamar a la versión de solo entero de la versión fuertemente tipada, y Bob es tu tío.

Greg Burghardt
fuente