Cara menyusun aplikasi Go, dirancang menurut arsitektur bersih


9

Saya mencoba membangun proyek menggunakan arsitektur bersih, seperti dijelaskan di sini . Saya menemukan artikel yang bagus tentang cara melakukan ini di Go .

Contohnya adalah yang sangat sederhana, dan penulis memasukkan kode mereka ke dalam paket-paket yang dinamai berdasarkan lapisan tempat mereka berada. Saya menyukai gagasan Paman Bob bahwa arsitektur suatu aplikasi harus dengan jelas mengomunikasikan maksudnya . Jadi saya ingin aplikasi saya memiliki paket tingkat atas berdasarkan area domain. Jadi struktur file saya akan terlihat seperti ini:

/Customers
    /domain.go
    /interactor.go
    /interface.go
    /repository.go
/... the same for other domain areas

Masalahnya adalah beberapa layer berbagi paket yang sama. Jadi tidak begitu jelas kapan aturan ketergantungan dilanggar, karena Anda tidak memiliki impor yang menunjukkan apa yang bergantung pada apa.

Saya berasal dari latar belakang Python, di mana ini tidak akan menjadi masalah besar, karena Anda dapat mengimpor file individual, sehingga customers.interactordapat mengimpor customers.domain.

Kita bisa mencapai sesuatu yang serupa di gO dengan paket bersarang, sehingga paket pelanggan berisi paket domain dan paket interaksor, dan sebagainya. Ini terasa kikuk, dan paket yang identik namanya bisa menjengkelkan untuk dihadapi.

Pilihan lain adalah membuat beberapa paket per area domain. Satu disebut customer_domain, satu disebut customer_interactor, dll. Tapi ini terasa kotor juga. Itu tidak cocok dengan pedoman penamaan paket Go, dan sepertinya semua paket terpisah ini entah bagaimana harus dikelompokkan, karena nama mereka memiliki awalan yang sama.

Jadi apa yang akan menjadi tata letak file yang bagus untuk ini?


Sebagai seseorang yang menderita di bawah arsitektur yang mengorganisir paket-paket secara eksklusif berdasarkan tingkat arsitektur, izinkan saya menyuarakan dukungan saya untuk paket-paket berbasis fitur . Saya semua untuk tujuan komunikasi tetapi jangan membuat saya merangkak melalui setiap sudut dan celah yang tidak jelas hanya untuk menambahkan satu fitur baru.
candied_orange

Dengan maksud, maksud saya bahwa paket harus mengkomunikasikan tentang aplikasi tersebut. Jadi jika Anda sedang membangun aplikasi perpustakaan, Anda akan memiliki paket buku, paket pemberi pinjaman, dll.
bigblind

Jawaban:


5

Ada beberapa solusi untuk ini:

  1. Pemisahan Paket
  2. Analisis Ulasan
  3. Analisis Statis
  4. Analisis Runtime

Masing-masing memiliki pro / kontra.

Pemisahan Paket

Ini adalah cara termudah yang tidak perlu membangun tambahan apa pun. Muncul dalam dua rasa:

// /app/user/model/model.go
package usermodel
type User struct {}

// /app/user/controller/controller.go
package usercontroller
import "app/user/model"
type Controller struct {}

Atau:

// /app/model/user.go
package model
type User struct {}

// /app/controller/user.go
package controller
import "app/user/model"

type User struct {}

Namun ini mematahkan keutuhan konsep User. Untuk memahami atau memodifikasi UserAnda perlu menyentuh beberapa paket.

Tapi, itu memang memiliki properti bagus yang lebih jelas ketika modelimpor controller, dan sampai batas tertentu itu diberlakukan oleh semantik bahasa.

Analisis Ulasan

Jika aplikasinya tidak besar (kurang dari 30KLOC) dan Anda memiliki programmer yang baik, biasanya tidak perlu membangun apa pun. Struktur pengorganisasian berdasarkan nilai akan cukup, misalnya:

// /app/user/user.go
package user
type User struct {}
type Controller struct {}

Seringkali "pelanggaran kendala" tidak begitu penting atau mudah diperbaiki. Ini merusak kejelasan dan pengertian - selama Anda tidak membiarkannya lepas kendali, Anda tidak perlu khawatir.

Analisis Statis / Runtime

Anda juga dapat menggunakan analisis statis atau runtime untuk menemukan kesalahan ini, melalui anotasi:

Statis:

// /app/user/user.go
package user

// architecture: model
type User struct {}

// architecture: controller
type Controller struct {}

Dinamis:

// /app/user/user.go
package user

import "app/constraint"

var _ = constraint.Model(&User{})
type User struct {}

var _ = constraint.Controller(&Controller{})
type Controller struct {}

// /app/main.go
package main

import "app/constraint"

func init() { constraint.Check() }

Keduanya statis / dinamis juga dapat dilakukan melalui bidang:

// /app/user/user.go
package user

import "app/constraint"

type User struct {   
    _ constraint.Model
}

type Controller struct {
    _ constraint.Controller
}

Tentu saja pencarian hal-hal seperti itu menjadi lebih rumit.

Versi lain

Pendekatan semacam itu dapat digunakan di tempat lain, tidak hanya tipe kendala, tetapi juga penamaan fungsi, API-s dll.

https://play.golang.org/p/4bCOV3tYz7

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.