Go 語言整潔架構(gòu)實(shí)踐
01 介紹
Bob 大叔在他的一篇標(biāo)題為「整潔架構(gòu)」的博客中提及,現(xiàn)在一些流行的系統(tǒng)架構(gòu),都采用軟件分層設(shè)計(jì),都主張以下 5 個(gè)規(guī)則:
- 獨(dú)立于框架
- 可測試的
- 獨(dú)立于用戶界面
- 獨(dú)立于數(shù)據(jù)庫
- 獨(dú)立于任何外部依賴
Bob 大叔的架構(gòu)設(shè)計(jì)遵循依賴規(guī)則,他畫了一張同心圓的圖,共分為 4 層,同心圓由內(nèi)向外依次為 Entities、Use Cases、Interface Adapters 和 Frameworks and Drivers,該規(guī)則規(guī)定依賴只能是由外向內(nèi),內(nèi)圈不關(guān)心外圈,外圈不要影響內(nèi)圈。
但是,不要認(rèn)為必須是分為這四層,這里描述的四層只是一個(gè)示例,也許你會發(fā)現(xiàn)你的業(yè)務(wù)不僅僅需要這四層,重點(diǎn)是要遵循由外向內(nèi)的依賴規(guī)則。
本文我們介紹整潔架構(gòu)在 Go 語言中的實(shí)踐。
02 整潔架構(gòu)分層設(shè)計(jì)
參照 Bob 大叔的整潔架構(gòu)軟件分層設(shè)計(jì),我們將架構(gòu)分層分為以下 4 層:
- Models
- Repository
- Usecase
- Delivery
其中,Models 與 Entities 相同,將在所有層中使用,我們可以將所有對象的結(jié)構(gòu)體和方法,以及其他需要在所有層中使用的變量、常量和函數(shù)放在 Models 層。這也可以避免遇到循環(huán)導(dǎo)入的問題。
Repository 層,我們可以將處理數(shù)據(jù)庫的程序和調(diào)用微服務(wù)的程序放在該層,僅處理數(shù)據(jù)輸入和輸出,不要有其它關(guān)于業(yè)務(wù)邏輯的代碼。該層依賴操作的數(shù)據(jù)庫或調(diào)用的微服務(wù)。
Usecase 層,我們可以將業(yè)務(wù)邏輯代碼放在該層,它負(fù)責(zé)接收表示層的輸入數(shù)據(jù),將數(shù)據(jù)處理之后,調(diào)用 Repository 層,將處理后的數(shù)據(jù)存儲在數(shù)據(jù)庫或傳遞給調(diào)用的微服務(wù)。反之,將數(shù)據(jù)庫中的數(shù)據(jù)或調(diào)用微服務(wù)的返回?cái)?shù)據(jù),處理之后,返回給 Delivery 層。該層依賴 Repository 層。
Delivery 層,負(fù)責(zé)將處理后的數(shù)據(jù)展示出來,可以采用 RESTful、HTML 或 gRPC 等各種形式。同時(shí),它也負(fù)責(zé)接收用戶輸入的數(shù)據(jù),將數(shù)據(jù)傳遞給 Usecase 層。該層依賴 Usecase 層。
實(shí)踐應(yīng)用的目錄:
.
├── app
│ └── main.go
├── go.mod
├── go.sum
└── todoList
├── delivery
│ └── http
│ └── todoList.go
├── models
│ └── todoList.go
├── repository
│ └── mysql
│ └── todoList.go
└── usecase
└── todoList.go
03 分層之間通信
分層之間是怎么通信的,除了 Models 層之外,其它層之間通過接口通信,例如 Usecase 層與 Repository 層之間通信,Repository 層定義接口,并實(shí)現(xiàn)接口中的所有方法。Usecase 層通過接口與 Repository 層通信。
示例代碼:
type TodoListRepository interface {
Create(ctx context.Context, t *Todolist) (err error)
}
同理,Delivery 層與 Usecase 層之間通信,Usecase 層定義接口,并實(shí)現(xiàn)接口中的所有方法。Delivery 層通過接口與 Usecase 層通信。
示例代碼:
type TodoListUsecase interface {
Create(context.Context, *Todolist) (err error)
}
04 總結(jié)
本文我們介紹整潔架構(gòu)的軟件分層設(shè)計(jì),并且通過一個(gè)簡單的 TodoList 項(xiàng)目,在 Go 語言中實(shí)踐「整潔架構(gòu)」的架構(gòu)設(shè)計(jì)。但是,在 Go 語言中實(shí)際上并沒有標(biāo)準(zhǔn)的架構(gòu)設(shè)計(jì),我們可以嘗試構(gòu)建自己的標(biāo)準(zhǔn)。
完整代碼,請查閱 github。