前情提要
學習 Golang 一陣子了,最近開始使用在正式的產品上,
老實說我還不覺得有用到它的特色。
在學習程式語言上的一個現實是,我在台灣面臨的商業規模大多瓶頸並不在語言本身,
開發者的寫法(甚至稱不上演算法)、軟硬架構基本上可以解決大部份的問題。
我的背景是 C#、JavaScript(TypeScript) 為主要開發項目,
除此之外,也有寫過 C、C++、Java、Php、VB.NET、Ruby 與 Python
Go 的優勢常見如下:
- 讓人容易了解的語意:作為漢語母語者我感受不強烈,我的英文不夠好可以感受到這點(同樣我對 Python 的感受也不深)
- 容易上手的多緒:這個有感,相比 C# 的確易懂好寫
- 靜態語言: 原本寫 Python 的開發人員可能比較有感,對我來說這是基本(C# 開發者角度)
- 高效,快:目前的專案複雜性還未可以感到其差異,或許需要壓測用實際數據比較。
經驗上是,錯誤的架構或寫法往往才是瓶頸之所在。 - 編譯快:在 C# 的不好體驗,巨大單體專案,不包測試編譯就要 2~5 分鐘,不曉得 Go 在這樣情況的表現如何? 不過目前主流開發方式為雲原生,微服務,或許有生之年不會再看巨型單體專案了
- 原生測試:這點我覺得真是棒,我的學習之路就是由 Learn Go with tests 開始的
- IOP:介面導向程式設計,目前還無法體會其哲學,不過因為其語言的特性會促使人思考,這點我還在慢慢嚐試
一個新的語言我會從測試開始學,
這表示你通常會需要這些工具:測試框架、相依注入、Mocking、語意化 Assert,
本文會專注在使用相依注入的套件 WIRE
WIRE
一些 Q&A
為什麼選用 WIRE ?
google 官方推薦 Wire
還有哪些選擇 ?
有什麼不同
官方推薦,本質上更像代碼生成器(Code Generator)
Clear is better than clever ,Reflection is never clear.
— Rob Pike
示範
參考本篇文章
高耦合版本
1 | package main |
在上面的程式中,可以明顯看到 ConcatService
相依於 HttpClient
與 Logger
,
而 HttpClient
本身又與 Logger
耦合。
這是一種高耦合,在這個例子裡 Logger
還會產生兩份實體,但實際上我們只需要一份。
Golang 實際上不像 C# 有建構子(Constructor)的設計,不過常見的實踐會用大寫 New 開頭的方法作為一種類似建構子的應用,
比如說上面例子的 NewConcatService
與 NewHttpClient
。
我們可以透過這個方法來注入我們相依的服務。
相依注入
1 | package main |
我們把焦點放在 main
函數中,實作實體與注入會在這裡發生,當你的程式變得複雜時,這裡也變得更複雜。
一個簡單的思路是我們可以把重構這些邏輯,
到另一個檔案 container.go
的 CreateConcatService
方法中。
1 | // container.go |
1 | func main() { |
接下來我們看看怎麼透過 wire
實作
使用 Wire
安裝 wire
1 | go get github.com/google/wire/cmd/wire |
接下來改寫 container.go
1 | //go:build wireinject |
在專案中執行
1 | wire |
wire 將會產生 wire_gen.go
檔,裡面幫你實作 CreateConcatService
函數
1 | //wire_gen.go |
簡單回顧一下:
我們需要針對特定的 Service 寫出一個方法的殼
1
2
3func CreateConcatService() *ConcatService {
////skip
}在方法中透過
wire.Build
加入相依的類別,實際上我們不需要 return 實體,所以用panic
包起來1
2
3
4
5
6
7func CreateConcatService() *ConcatService {
panic(wire.Build(
wire.Struct(new(Logger), "*"),
NewHttpClient,
NewConcatService,
))
}執行 wire 建立檔案
實務上需要這個 Service 時,直接呼叫 Create 方法
1
service := CreateConcatService()
GoLand 設定
如果你跟我一樣使用 GoLand 作為主要編輯器,
應該會收到 customer tags 的警告
解決方法:
GoLand > Preferences > Build Tags & Vendoring > Editor Constraints > Custom Tags
設定為 wireinject
即可
參考
- go 语言 web 框架比较:gin vs iris vs echo
- The Pros And Cons Of Programming In Go
- Learn Go with tests
- Wire Tutorial
- [Golang] Struct
- Wire:Best Practices
- Defer, Panic, and Recover
- [wire] Google 官方推薦 DI Framework
- Go Dependency Injection with Wire
- Golang 簡潔架構實戰
- 理解一下依赖注入,以及如何用 wire
- Golang 依赖注入框架 wire 使用详解
- Go 依赖注入(DI)工具-wire 使用
- 一文讀懂 wire
(fin)