Pienso que al cabo de los años, todos tendemos un poco a usar lo mismo. Afortunádamente usamos todos lo mismo..para bien, si es que puede haber un "bien". Leyendo las respuestas de los demás, veo que son muy parecidas. Aunque acabemos llamando a cada capa de forma distinta, igualmente su propósito acaba siendo el mismo.
Por mi parte, he visto un poco de todo en cuanto a organización de paquetes, pero creo que lo que más fácil me ha resultado siempre a la hora de organizar el código y poder explorarlo inicialmente, o poder pensar de forma intuitiva dónde es más probable que encuentre algo, es cuando se organiza por capas (y dentro de las capas por funcionalidad) en vez de al revés. En esencia es lo mismo, pero los programadores creo que tendemos a pensar más en la implementación y en la parte técnica que en la parte funcional o del dominio. Es más fácil que nos acuda a la mente antes que para salvar los datos de consumos del usuario tengamos que acudir a la capa de servicios ,que a su vez llamara a la capa de persistencia, que a su vez llamará al ORM (o no) de turno, antes que pensar que los datos de consumo del usuario están en el subproyecto de gestión de usuarios, apartado consumos, subapartado...
Otra forma que he leído de organizar el código es cuando tienes un modelo "rico", donde los propios objetos del dominio contienen los métodos necesarios para operar sobre ellos, creando una interfaz más fluida e intuitiva. He tenido la oportunidad de debatir sobre el tema, y creo que a largo plazo, aunque la idea del modelo enriquecido tiene su valor desde un punto de vista de orientación a objetos, y de ayudar a explorar el aspecto funcional de la aplicación que estamos manteniendo, creo que ayuda mucho más a que la aplicación pueda escalar y también a no tener que invertir demasiado esfuerzo en entender el sistema por parte del programador, el usar una arquitectura n-tier, que es la que se usa en casi todos los lados. Este modelo a mitad entre estructurado y orientado a objetos que usamos en el desarrollo java empresarial creo que es capaz de escalar mucho mejor (por el hecho de no mantener estado que persistir entre distintos nodos de un cluster). Al fin y al cabo, la pureza de la orientación a objetos es un poco irrelevante, no es ese el objetivo de nuestro trabajo.
Normalmente, cuando entamo un proyecto personal, pienso en distribuirlo multiplataforma. Por ejemplo, versión desktop (javaFX, QT, etc), versión android y versión web. Para ello, necesito siempre que el modelo sea totalmente agnóstico de la persistencia, y los servicios también necesito que sean independientes de su implementación, para poder tener cierta libertad entre cada plataforma, pero siempre manteniendo el mismo modelo funcional. Prefiero configurar con un xml que usar anotaciones por esa razón.
- Modelo, que incluye tanto las entidades lógicas como las interfaces de los servicios que operan sobre ellas. No me gustan los objetos DTO como objeto de intercambio entre controlador y servicio, encuentro que ensucian y complican la comprensión de la aplicación porque al principio es fácil confundir el DTO con el modelo, te abstrae de cómo está implementado por detrás (el modelo suele parecerse más a las tablas que le dan soporte a los datos, mientras que los DTO pueden ser una amalgama de atributos de muchas entidades distintas).
- Capa de servicios agnóstica de cómo es usada. Empaquetada como librería jar para ser usada en otros proyectos. Implementa las interfaces de los componentes de servicio del modelo.
- Una interfaz que permita a los clientes acceder a los servicios. Normalmente REST, si puedo elegir. Desplegada en algún servidor tipo OpenShift.
- Por cada cliente, una capa cliente, que incluye tanto el controlador como la vista de ese cliente.
Por supuesto, dentro de cada capa sí que divido funcionalmente los paquetes.