¿Existen mejores prácticas para la organización de paquetes (Java)?

Hace poco, vi una pregunta aquí respondida sobre la organización detallada de los paquetes de Java. Por ejemplo, my.project.util, my.project.factory, my.project.service etc.

No puedo encontrarlo ahora, así que puedo hacer la pregunta.

¿Existen mejores prácticas con respecto a la organización de paquetes en Java y qué incluye?

¿Cómo organizas tus clases en tu proyecto Java?

Por ejemplo, un proyecto en el que estoy trabajando con algunas personas tiene un paquete llamado beans. Comenzó siendo un proyecto que contenía frijoles simples, pero que terminó (por mala experiencia y falta de tiempo) conteniendo todo (casi). Los he limpiado un poco, al poner algunas clases de fábrica en un paquete de fábrica (clases con métodos estáticos que crean frijoles) pero tenemos otras clases que hacen lógica de negocios y otras que hacen un procesamiento simple (no con lógica comercial) como recuperar un mensaje para un código de un archivo de propiedades.

Sus pensamientos y comentarios son apreciados.

La organización de paquetes o la estructuración de paquetes suele ser una acalorada discusión. A continuación hay algunas pautas simples para nombrar y estructurar paquetes:

  • Siga las convenciones de nomenclatura de paquetes de Java
  • Estructure sus paquetes de acuerdo con su rol funcional, así como su función comercial
    • Divide tus paquetes de acuerdo a su funcionalidad o módulos. eg com.company.product.modulea
    • Desglose adicional podría basarse en capas en su software. Pero no se exceda si tiene pocas clases en el paquete, entonces tiene sentido tener todo en el paquete. por ejemplo, com.company.product.module.web o com.company.product.module.util etc.
    • Evite exagerar con la estructuración, IMO evite el embalaje por separado para excepciones, fábricas, etc. a menos que haya una necesidad apremiante.
  • Si su proyecto es pequeño, manténgalo simple con pocos paquetes. ej. com.company.product.model y com.company.product.util , etc.
  • Eche un vistazo a algunos de los populares proyectos de código abierto que existen en los proyectos de Apache . Vea cómo utilizan la estructuración para proyectos de varios tamaños.
  • También considere construir y distribuir al nombrar (lo que le permite distribuir su API o SDK en un paquete diferente, consulte la apéndice del servlet)

Después de algunos experimentos y pruebas, debería poder diseñar una estructura con la que se sienta cómodo. No se obsesione con una convención, esté abierto a los cambios.

Organizo paquetes por características, no por patrones o roles de implementación. Creo que paquetes como:

  • frijoles
  • suerte
  • colecciones

estan equivocados. Yo prefiero, por ejemplo:

  • pedidos
  • almacenar
  • informes

entonces puedo ocultar los detalles de implementación a través de la visibilidad del paquete: la fábrica de pedidos debe estar en el paquete de pedidos para que los detalles sobre cómo crear un pedido estén ocultos.

Respuesta corta: un paquete por módulo / función, posiblemente con subpaquetes. Poner cosas estrechamente relacionadas en el mismo paquete. Evite las dependencias circulares entre paquetes.

Respuesta larga: estoy de acuerdo con la mayoría de este artículo

Prefiero la función antes que las capas, pero supongo que depende de tu proyecto. Considera tus fuerzas:

  • Dependencias Intente minimizar las dependencias del paquete, especialmente entre las funciones. Extraiga las API si es necesario.
  • Organización del equipo En algunas organizaciones, los equipos trabajan en funciones y en otras en capas. Esto influye en cómo se organiza el código, lo utiliza para formalizar las API o para fomentar la cooperación.
  • Despliegue y control de versiones. Al poner todo en un módulo, simplifica la implementación y el control de versiones, pero la corrección de errores es más difícil. Las divisiones permiten un mejor control, escalabilidad y disponibilidad.
  • Responde al cambio El código bien organizado es mucho más fácil de cambiar que una gran bola de barro.
  • Tamaño (personas y líneas de código). Cuanto más grande, más formalizado / estandarizado debe ser.
  • Importancia / calidad. Algunos códigos son más importantes que otros. Las API deberían ser más estables que la implementación. Por lo tanto, debe estar claramente separado.
  • Nivel de abstracción y punto de entrada. Debería ser posible que un extraño supiera de qué se trata el código y dónde comenzar a leer al mirar el árbol de paquetes.

Ejemplo:

 com/company/module + feature1/ - MainClass // The entry point for exploring + api/ // Public interface, used by other features + domain/ - AggregateRoot + api/ // Internal API, complements the public, used by web + impl/ + persistence/ + web/ // presentation layer + services/ // Rest or other remote API + support/ + feature2/ + support/ // Any support or utils used by more than on feaure + io + config + persistence + web 

Esto es solo un ejemplo. Es bastante formal. Por ejemplo, define 2 interfaces para feature1. Normalmente eso no es obligatorio, pero podría ser una buena idea si las personas lo usan de manera diferente. Puede dejar que la API interna amplíe al público.

No me gustan los nombres ‘impl’ o ‘support’, pero ayudan a separar las cosas menos importantes de las importantes (dominio y api). Cuando se trata de nombrar, me gusta ser lo más concreto posible. Si tiene un paquete llamado ‘utils’ con 20 clases, mueva StringUtils para admitir / cadena, HttpUtil para admitir / http y así sucesivamente.

¿Existen mejores prácticas con respecto a la organización de paquetes en Java y qué incluye?

No, realmente no. Hay muchas ideas y muchas opiniones, pero la “mejor práctica” es usar tu sentido común.

Sin embargo, hay un principal que probablemente tiene una amplia aceptación. La estructura de su paquete debe reflejar la estructura del módulo (informal) de su aplicación, y debe tratar de minimizar (o idealmente evitar por completo) las dependencias cíclicas entre los módulos.

(Las dependencias cíclicas entre clases en un paquete / módulo están bien, pero los ciclos entre paquetes tienden a dificultar la comprensión de la architecture de su aplicación y pueden ser una barrera para la reutilización del código. En particular, si usa Maven, encontrará que el ciclo es cíclico Las dependencias entre paquetes / entre módulos significan que todo el lío interconectado tiene que ser un artefacto de Maven).

También debería agregar que hay una mejor práctica ampliamente aceptada para los nombres de paquetes. Y es que los nombres de sus paquetes deberían comenzar con el nombre de dominio de su organización en orden inverso. Si sigues esta regla, reduces la probabilidad de que los problemas causados ​​por tus nombres de clase (completos) choquen con los de otras personas.

He visto a algunas personas promocionar ‘paquete por elemento’ sobre ‘paquete por capa’, pero he utilizado bastantes enfoques durante muchos años y he encontrado ‘paquete por capa’ mucho mejor que ‘paquete por elemento’.

Además de eso, he encontrado que una estrategia híbrida: ‘paquete por módulo, capa y función’ funciona extremadamente bien en la práctica, ya que tiene muchas ventajas de ‘paquete por función’:

  • Promueve la creación de marcos reutilizables (bibliotecas con aspectos tanto de modelo como de UI)
  • Permite implementaciones de capa plug and play: prácticamente imposible con ‘paquete por función’ porque coloca las implementaciones de capa en el mismo paquete / directorio como código de modelo.
  • Mucho mas…

Aquí explico en profundidad: estructura y organización del nombre del paquete Java, pero mi estructura de paquete estándar es:

revdomain.moduleType.moduleName.layer. [layerImpl] .feature.subfeatureN.subfeatureN + 1 …

Dónde:

revdomain Dominio inverso ej. com.mycompany

moduleType [app * | framework | util]

moduleName eg myAppName si el tipo de módulo es una aplicación o ‘finance’ si es un marco de contabilidad

capa [modelo | ui | persistencia | seguridad, etc.,]

layerImpl ej., wicket, jsp, jpa, jdo, hibernate (Nota: no se usa si la capa es modelo)

característica por ej., finanzas

subfeatureN eg., contabilidad

subfeatureN + 1 por ejemplo, depreciación

* A veces, la ‘aplicación’ se omite si moduleType es una aplicación, pero ponerla allí hace que la estructura del paquete sea coherente en todos los tipos de módulos.

No conozco las prácticas estándar para la organización de paquetes. Generalmente creo paquetes que cubren un espectro razonablemente amplio, pero puedo diferenciarlos dentro de un proyecto. Por ejemplo, un proyecto personal en el que estoy trabajando actualmente tiene un paquete dedicado a mis controles personalizados de interfaz de usuario (lleno de clases que subclasan clases de swing). Tengo un paquete dedicado a mis cosas de gestión de bases de datos, tengo un paquete para un conjunto de oyentes / eventos que he creado, y así sucesivamente.

Por otro lado, un compañero de trabajo ha creado un nuevo paquete para casi todo lo que hizo. Cada MVC diferente que quería tenía su propio paquete, y parecía que un conjunto de MVC era la única agrupación de clases permitidas en el mismo paquete. Recuerdo que en cierto momento él tenía 5 paquetes diferentes que tenían una sola clase en cada uno de ellos. Creo que su método es un poco extremo (y el equipo lo obligó a reducir su conteo de paquetes cuando simplemente no podía manejarlo), pero para una aplicación no trivial, lo pondría todo en el mismo paquete. Es un punto de equilibrio que tú y tus compañeros de equipo deben encontrar por sí mismos.

Una cosa que puede hacer es tratar de dar un paso atrás y pensar: si fue un nuevo miembro introducido en el proyecto, o su proyecto se lanzó como código abierto o una API, ¿qué tan fácil / difícil sería encontrar lo que desea? Porque para mí, eso es lo que realmente quiero de paquetes: organización. De forma similar a como guardo los archivos en la carpeta de mi computadora, espero poder encontrarlos de nuevo sin tener que buscar todo el disco. Espero poder encontrar la clase que quiero sin tener que buscar en la lista de todas las clases del paquete.

Normalmente organizo por capas, porque escribo muchas aplicaciones web. Así que tendré persistencia, servicio, modelo, vista, utilidad, etc.