Ordner nach Typ oder Ordner nach Funktion

59

Ich benutze einen AngularJS-Styleguide. In diesem Handbuch gibt es einen Stil namens folder-by-featurestatt folder-by-typeund ich bin gespannt, was der beste Ansatz ist (in diesem Beispiel für Java).

Angenommen, ich habe eine Anwendung, mit der ich Benutzer und Haustiere mithilfe von Diensten, Controllern, Repositorys und natürlich Domänenobjekten abrufen kann.

Unter Berücksichtigung der Ordner-nach -...-Stile haben wir zwei Optionen für unsere Verpackungsstruktur:

1. Ordner nach Typ

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. Ordner nach Funktion

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

Was wäre ein guter Ansatz und welche Argumente sprechen dafür?

Jelle
quelle
1
Ich kenne @Laiv nicht. Beeinflusst die Sprache / das Framework die Antwort wirklich? Unabhängig davon ist die andere Frage sicherlich relevant.
RubberDuck
1
Dann muss ich meine Antwort bearbeiten. Und ja, es ist ein mögliches Duplikat
Laiv
2
Ich habe den Vorteil von Ordner-nach-Typ nie verstanden. Wenn ich an einem Ticket für die Pet-Funktion arbeite, würde ich wahrscheinlich von der Lokalität Pet, dem Controller, dem Repository und dem Service profitieren . In welcher Situation würde ich jemals alle Controller benötigen, außer den Views, Repos oder Services?
Alexander
2
Niemand scheint erwähnt zu haben, dass Pakete in Java nicht nur Ordner sind. Sie wirken sich auch auf den Zugriff für die enthaltenen Klassen aus. Aus diesem Grund kann package-by-layer / type in Java tatsächlich einen semantischen Wert liefern.
Angus Goldsmith

Antworten:

69

Folder-by-Type funktioniert nur bei kleinen Projekten. Folder-by-Feature ist in den meisten Fällen überlegen.

Folder-by-Type ist in Ordnung, wenn Sie nur eine kleine Anzahl von Dateien haben (unter 10 pro Typ sagen wir mal). Sobald Sie mehrere Komponenten in Ihrem Projekt haben, alle mit mehreren Dateien desselben Typs, wird es sehr schwierig, die tatsächliche Datei zu finden, nach der Sie suchen.

Ordnerweise ist daher aufgrund der Skalierbarkeit besser. Wenn Sie jedoch nach Funktion ordnen, verlieren Sie Informationen über den Typ der Komponente, die eine Datei darstellt (weil sie sich beispielsweise nicht mehr in einem controllerOrdner befindet), was ebenfalls verwirrend wird. Hierfür gibt es 2 einfache Lösungen.

Erstens können Sie allgemeine Namenskonventionen einhalten, die die Schreibweise des Dateinamens implizieren. Zum Beispiel hat der beliebte AngularJS-Styleguide von John Papa Folgendes:

Namensrichtlinien

  • Verwenden Sie für alle Komponenten konsistente Namen nach einem Muster, das die Funktion der Komponente und (optional) deren Typ beschreibt. Mein
    empfohlenes Muster ist feature.type.js. Für die meisten
    Assets gibt es 2 Namen :

    • der Dateiname (avengers.controller.js)
    • den registrierten Komponentennamen mit Angular (AvengersController)

Zweitens können Sie Ordner-nach-Typ- und Ordner-nach-Feature-Stile in Ordner-nach-Feature-nach-Typ-Stile kombinieren:

com.example
├── pet
|   ├── Controllers
│   |   ├── PetController1.java
|   |   └── PetController2.java
|   └── Services
│       ├── PetService1.java
│       └── PetService2.java
├── user
|   ├── Controllers
│   |   ├── UserController1.java
│   |   └── UserController2.java
|   └── Services
│       ├── UserService1.java
│       └── UserService2.java
Setzen Sie Monica wieder ein
quelle
1
Der Johnpapa-Styleguide war genau der, über den ich gefälscht habe :-)
Jelle
1
Manchmal (öfter als wir denken) fügen wir den Dingen, die eigentlich einfach sein sollten, zu viel Komplexität hinzu. Benennung und Verpackung sind einige dieser Dinge. Der beste Rat ist, es einfach zu halten. Beides zu mischen hat sowohl die Vor- als auch die Nachteile beider Ansätze.
Laiv
1
@Laiv In dem Beispiel, das ich gegeben habe, stimme ich dem Overkill zu, aber in den meisten Fällen, in denen jeder Typ-Ordner problemlos 10-20 Dateien enthalten kann, halte ich das für sehr nützlich, da der gesamte Feature-Ordner in der Größenordnung von 50 liegen würde Dateien anders.
Setzen Sie Monica
6
fakking, dank iPhone automatisch korrigieren! Ich meinte "reden".
Jelle
2
@Chaotic Dieses Beispiel ist zu trivial, um Einzelheiten zu besprechen, aber in solchen Fällen, in denen Sie Teile haben, die über mehrere Komponenten hinweg verwendet werden, sollte dies wahrscheinlich eine eigene Komponente sein, von der andere Komponenten abhängen.
Setzen Sie Monica
26

Dies hat wirklich nichts mit der fraglichen Technologie zu tun, es sei denn, Sie verwenden ein Framework, das Sie im Rahmen eines Konventions-über-Konfigurations-Ansatzes nach Ordnern sortiert.

Persönlich bin ich der festen Überzeugung, dass die Funktion "Ordner für Ordner" weit überlegen ist und so oft wie möglich überall verwendet werden sollte. Es gruppiert Klassen, die tatsächlich zusammenarbeiten, während ordnerweise nur etwas dupliziert, das normalerweise bereits im Klassennamen vorhanden ist.

Michael Borgwardt
quelle
10
Ich würde hinzufügen, dass in Ordner-nach-Merkmalen das Spielen mit Klassen- und Methodenbereichen (protected, package, ...) einfacher wird.
Laiv
Für kleinere Projekte steht möglicherweise nur eine Funktion zur Verfügung. In diesem Szenario ist es viel einfacher, nach Typ zu organisieren.
aaaaaa
Als Beispiel Grails tut Ordner-by-Typ erzwingen für Ihre Domains, Steuerungen, Dienstleistungen usw.
tylerwal
17

Die Arbeit mit Paketen nach Merkmalen zeichnet sich durch hohe Modularität und Kohäsion aus . Es ermöglicht uns, mit dem Umfang der Komponenten zu spielen. Zum Beispiel können wir die Zugriffsmodifikatoren verwenden , um LoD und die Abhängigkeitsinversion für Integrationen oder / und Erweiterungen zu erzwingen .

Andere Gründe sind:

  • Einfachere Code-Navigation
  • Eine höhere Abstraktionsebene
  • Bereiche minimieren (begrenzende Kontexte)
  • Vertikale Modularisierung

Ordner- für -Schicht legt zu viel Gewicht auf die Details der Implementierung , (wie @ David erwähnt) was nicht zu viel erzählt über die Anwendung , die wir gerade arbeiten. Im Gegensatz zu Paket-by-Funktion , Paket- für -Schicht fördert horizontale Modularisierung. Diese Art der Modularisierung macht das Arbeiten mit Querschnittsteilen mühsam und mühsam.

Schließlich gibt es eine dritte Option. " Package by component ", was, in Worten von Onkel Bob, besser mit seinen Paketprinzipien in Einklang zu stehen scheint . Ob die Meinung von Onkel Bob zählt oder nicht, überlasse ich es Ihnen zu entscheiden. Ich finde es interessant, da diese Konvention mit seiner Clean Architecture in Einklang steht, die mir gefällt.

Laiv
quelle