Carpeta por tipo o Carpeta por función

59

Hago uso de una guía de estilo AngularJS. Dentro de esta guía hay un estilo llamado folder-by-feature, en lugar de folder-by-type, y tengo curiosidad por saber cuál es el mejor enfoque (en este ejemplo para Java)

Digamos que tengo una aplicación donde puedo recuperar Users & Pets, usando servicios, controladores, repositorios y, por supuesto, objetos de dominio.

Tomando los estilos de carpeta por ... tenemos dos opciones para nuestra estructura de empaque:

1. Carpeta por tipo

com.example
├── domain
│    ├── User.java
│    └── Pet.java
├── controllers
│    ├── UserController.java
│    └── PetController.java
├── repositories
│    ├── UserRepository.java
│    └── PetRepository.java
├── services
│    ├── UserService.java
│    └── PetService.java
│   // and everything else in the project
└── MyApplication.java

2. Carpeta por función

com.example
├── pet
│    ├── Pet.java
│    ├── PetController.java
│    ├── PetRepository.java
│    └── PetService.java
├── user
│    ├── User.java
│    ├── UserController.java
│    ├── UserRepository.java
│    └── UserService.java
│   // and everything else in the project
└── MyApplication.java

¿Cuál sería un buen enfoque y cuáles son los argumentos para hacerlo?

Jelle
fuente
1
No sé @Laiv. ¿El lenguaje / marco realmente afecta la respuesta? En cualquier caso, la otra pregunta es ciertamente relevante.
RubberDuck
1
Entonces tengo que editar mi respuesta. Y sí, es un posible duplicado
Laiv
2
Nunca entendí el beneficio de la carpeta por tipo. Si estoy trabajando en un boleto relacionado con la función Mascota, probablemente me beneficiaría de la localidad del Petcontrolador, el repositorio y el servicio. ¿En qué situación necesitaría alguna vez todos los controladores, pero no las vistas, repositorios o servicios?
Alexander
2
Nadie parece haber mencionado que los paquetes en Java no son solo carpetas; También afectan el acceso a las clases contenidas. Por esta razón, paquete / capa / tipo puede proporcionar algún valor semántico en Java.
Angus Goldsmith

Respuestas:

69

La carpeta por tipo solo funciona en proyectos a pequeña escala. La carpeta por función es superior en la mayoría de los casos.

Carpeta por tipo está bien cuando solo tiene una pequeña cantidad de archivos (menos de 10 por tipo, digamos). Tan pronto como obtenga múltiples componentes en su proyecto, todos con múltiples archivos del mismo tipo, se hace muy difícil encontrar el archivo real que está buscando.

Por lo tanto, la carpeta por característica es mejor debido a su escalabilidad. Sin embargo, si su carpeta por característica termina perdiendo información sobre el tipo de componente que representa un archivo (porque ya no está en una controllercarpeta, digamos), entonces esto también se vuelve confuso. Hay 2 soluciones simples para esto.

Primero, puede cumplir con las convenciones de nomenclatura comunes que implican tipografía en el nombre del archivo. Por ejemplo, la popular guía de estilo AngularJS de John Papa tiene lo siguiente:

Pautas de nomenclatura

  • Use nombres consistentes para todos los componentes siguiendo un patrón que describa la característica del componente y luego (opcionalmente) su tipo. Mi
    patrón recomendado es feature.type.js. Hay 2 nombres para la mayoría de los
    activos:

    • el nombre del archivo (avengers.controller.js)
    • el nombre del componente registrado con Angular (AvengersController)

En segundo lugar, puede combinar estilos de carpeta por tipo y carpeta por característica en carpeta por característica:

com.example
├── pet
|   ├── Controllers
│   |   ├── PetController1.java
|   |   └── PetController2.java
|   └── Services
│       ├── PetService1.java
│       └── PetService2.java
├── user
|   ├── Controllers
│   |   ├── UserController1.java
│   |   └── UserController2.java
|   └── Services
│       ├── UserService1.java
│       └── UserService2.java
Reinstalar a Mónica
fuente
1
La guía de estilo de johnpapa era exactamente la que estaba falsificando :-)
Jelle
1
Algunas veces (más de lo que pensamos) agregamos demasiada complejidad a las cosas que se suponía que eran fáciles. Nombrar y empaquetar son algunas de estas cosas. El mejor consejo es que sea simple. Mezclar ambos tiene las ventajas y las desventajas de ambos enfoques.
Laiv
1
@Laiv En el ejemplo que di, estoy de acuerdo con su exageración, pero en la mayoría de mis casos de negocios reales donde cada carpeta de tipos puede tener fácilmente 10-20 archivos, creo que es muy útil porque la carpeta de características general tendría del orden de 50 archivos de lo contrario.
Vuelva a instalar Mónica
66
fakking, gracias iPhone auto-corregir! Quise decir 'hablando'.
Jelle
2
@Chaotic Este ejemplo es demasiado trivial para comenzar a hablar de detalles, pero en los casos en que tiene piezas que se utilizan en varios componentes, entonces probablemente debería ser un componente propio del que dependen otros componentes.
Vuelva a instalar Mónica
26

Esto realmente no tiene nada que ver con la tecnología en cuestión, a menos que use un marco que lo obligue a crear carpetas por tipo como parte de un enfoque de convención sobre configuración.

Personalmente, creo firmemente que la carpeta por característica es muy superior y debe usarse en todas partes tanto como sea posible. Agrupa las clases que realmente funcionan juntas, mientras que la carpeta por tipo simplemente duplica algo que generalmente ya está presente en el nombre de la clase.

Michael Borgwardt
fuente
10
Agregaría que en la carpeta por función hace que sea más fácil jugar con los ámbitos de clases y métodos (protegido, paquete, ...).
Laiv
Para proyectos más pequeños, es posible que solo tenga una característica. Es mucho más fácil organizar por tipo en ese escenario.
aaaaaa
A modo de ejemplo, Griales hace la fuerza carpeta por tipo para sus dominios, controladores, servicios, etc.
tylerwal
17

Trabajar con paquetes por características destaca por su alta modularidad y cohesión . Nos permite jugar con el alcance de los componentes. Por ejemplo, podemos usar los modificadores de acceso para aplicar LoD y la inversión de dependencia para integraciones o extensiones.

Otras razones son:

  • Navegación de código más fácil
  • Un mayor nivel de abstracción.
  • Minimizar ámbitos (contextos delimitadores)
  • Modularización vertical

Carpeta por capa pone demasiado énfasis en los detalles de implementación , (como mencionó @David) lo que no dice demasiado sobre la aplicación en la que estamos trabajando. A diferencia de paquete por característica , paquete por capa fomenta la modularización horizontal. Este tipo de modularización hace que trabajar con componentes transversales sea difícil y tedioso.

Finalmente, hay una tercera opción. " Paquete por componente " que, en palabras del tío Bob, parece estar mejor alineado con los principios de su paquete . Si la opinión del tío Bob es importante o no, te dejo decidir. Me parece interesante ya que esta convención está alineada con su Arquitectura limpia, que me gusta.

Laiv
fuente