Projektstruktur
Auf oberster Ebene enthalten Go-Projekte eine Reihe von Verzeichnissen für die unterschiedlichen Projekt-Artefakte. Beispiel:
cmd
> api
main.go
> web
main.go
config
config.json
pkg
> mysql
repository.go
> http
> record
channel.go
repository.go
scripts
sample.sh
Das Verzeichnis cmd enthält für jedes Target-Binary ein Unterverzeichnis mit je einem Main-Programm. Das Verzeichnis config enthält Konfigurationsdateien, pkg die eigentliche Anwendung und scripts eventuell benötigte Skripte. Die Top-Level-Directories werden je nach Projekterfordernissen erweitert oder reduziert (mehr dazu in [2]). Neben den Artefakt-Verzeichnissen unterscheidet das Modell drei Package-Arten: Root-, Sub- und Executable-Packages.
Root-Package: Domain Model
Das Root-Package pkg enthält das Domain Model der Anwendung, sowie Sub-Package-übergreifende Funktionen. Das Root-Package referenziert weder Sub-Packages noch externe Abhängigkeiten, wie z.B. Datenbank- oder HTTP-Code.
Sub-Packages: Usecase oder Adapter
Sub-Packages unterhalb von pkg enthalten Usecases oder Adapter. Im Beispiel ist das Sub-Package record ein Usecase-Package, das den Usecase „Aufzeichnen von Tests“ implementiert. Usecase-Packages nutzen Artefakte des Root-Packages und sind frei von externen Abhängigkeiten. Adapter-Packages enthalten Typen und Funktionen, die die Anwendung mit ihrem Kontext verbinden. Im Beispiel enthält das Sub-Package mysql Code für den Zugriff auf MySQL-Datenbanken.
Executable-Packages: Main
Executable-Packages enthalten eine Main-Datei pro Binärartefakt. Im Beispiel implementiert das Main-Package im Verzeichnis cmd/api eine HTTP-API und nutzt dafür Funktionen aus den Adapter-Sub-Packages mysql und http:
func main() {
r := mux.NewRouter()
repo := mysql.Repository{}
r.HandleFunc("/record", http.StartRecording(repo))
http.ListenAndServe(r)
}
Fazit
Das vorgeschlagene Package-Layout vereint Konzepte aus dem DDD und aus Hexagonalen Architekturen. Zyklische Abhängigkeiten werden vermieden. Das Domain-Modell ist frei von externen Abhängigkeiten und lässt sich einfach testen. Die Package-Struktur ist minimal verschachtelt. Package-Namen kommunizieren klar, was darin enthalten ist.
Referenzen