今天我們不會講太多關於 Clean Architecture
的概念,因為目前有許多文章都分享過了,今天主要是要跟大家分享當一個需求下來時,怎麼將需求拆分之後使用 Clean Architecture
的概念設計架構,就讓我們開始吧!
Clean Architecture 是由 Robert C. Martin
於 2000 年所提出的一種架構,此架構主要的精神著重於描述 分層
與 減少相依性
的重要性,詳細的介紹可以參考 這裡。
我目前所採用的 clean architecture
是採用 bxcodec
於 這個專案 所使用的架構,其架構的中心思想也是參考 Robert
所提出的原始版本,其改良的原因在這裡
如上圖,此架構主要分成四個階層依序為
以下會分別對這四個階層做介紹
用於定義資料格式與屬性,此階層所定義的物件會在其他三層都會用到。
用於與外部 service 互動的 adapter,例如要與 mariadb
、mongo
或是 redis
等 data storage 進行互動,就將方法封裝在此階層內。
用於封裝商業邏輯方法,在系統內有用到的邏輯判斷或是演算法都會放在此階層內。
用於封裝接口給外部使用者使用的方法,例如要提供 rest
、gRPC
或是 command line
的方法都會封裝在此階層內。
規劃一個簡單的 會員系統
,其中要包含 註冊
與 登入
的功能並且開放 RESTful API
給前端存取
首先,我們可以思考一個會員系統內最基本的單位為 使用者
,不管使用任何功能都會與使用者有關,因此可以得知 Model Layer
內一定會有 使用者
,因此在這邊我們可以將其抽離出來,接著思考基本的使用者會有什麼樣的資訊,最最最基本的使用者可以包含 id
、username
與 password
這三個資訊,其中 id
是唯一值,以下為 使用者的結構。
type User struct {
ID string `json:"id"`
Username string `json:"username"`
Password string `json:"password"`
Email string `json:"email"`
Phone string `json:"phone"`
}
接著可以思考看看,Model Layer
的資料要存放在哪裡與如何取得,我們可以透過封裝 使用者 CURD 的方法實現。
type Repository interface {
GetUserList(map[string]interface{}) ([]*User, error)
GetUser(in *User) (*User, error)
CreateUser(in *User) (*User, error)
ModifyUser(in *User, data map[string]interface{}) (*User, error)
DeleteUser(in *User) error
}
需求有定義的很清楚,要實現 註冊
與 登入
的功能,因此這邊可以將這兩個方法的邏輯封裝成 Register
與 Login
方法,可以在方法內存取 Repository Layer
的方法並進行運算。
type Service interface {
Login(id, password string) (*User, error)
Register(in *User) (*User, error)
}
在需求最後有提到要開放 RESTful API
給前端存取,因此我們可以呼叫 Service Layer
的 Register
與 Login
兩個方法並提供 POST /api/v1/user/register
與 POST /api/v1/user/login
的方法供前端存取。
type RestfulHandler interface {
Login(c *gin.Context) error
Register(c *gin.Context) error
}
透過以上的方法可以將整體需求實作完成,每一階層都有自己專門負責的事項。
今天透過範例理解了怎麼透過 clean architecture
將 需求
轉換為程式的架構,這也是我目前開發時所使用的方法,希望對大家有幫助!
明天就讓我們利用今天所描述的範例透過 golang 實作出來吧!