หนึ่งในหัวข้อสำคัญในการพัฒนาแอปพลิเคชันขนาดกลางถึงใหญ่ คือเรื่องของการจัดการ Dependency Injection หรือ DI โดยเฉพาะในภาษา Go ที่ไม่มี framework ใหญ่มาช่วยเหมือนใน Java หรือ .NET
ในบทความนี้เราจะมาทำความเข้าใจพื้นฐานของ DI ใน Go ตั้งแต่แนวคิดพื้นฐาน ตัวอย่างจริง ไปจนถึงการใช้ tools เช่น uber-go/fx และ google/wire เพื่อเพิ่มความยืดหยุ่นในการเขียนโปรแกรม
Dependency Injection คืออะไร?
DI (Dependency Injection) คือแนวคิดการส่งพฤติกรรมหรือ dependency ของ object จากภายนอก แทนที่จะสร้างเองภายใน ทำให้สามารถเปลี่ยน พัฒนา ทดสอบ หรือ reuse ได้ง่ายขึ้น
เปรียบเทียบ: แทนที่ object A จะสร้าง object B ด้วยตัวเอง A ควร “รับ” object B มาจากภายนอกแทน
ประโยชน์ของ DI
- ทำให้โค้ดแยกส่วน (decoupled)
- ง่ายต่อการ test (mock dependencies ได้)
- รองรับการเปลี่ยนแปลงภายในระบบได้ดี
DI แบบพื้นฐานใน Go
เนื่องจาก Go ไม่รองรับ constructor injection โดยตรงเหมือน Java เราสามารถจัดการ DI ได้ด้วยการส่งผ่าน dependency ผ่าน constructor function
ตัวอย่าง 1: Manual Dependency Injection
type DB struct{}
func (db *DB) Query() string {
return "data from DB"
}
type Service struct {
db *DB
}
func NewService(db *DB) *Service {
return &Service{db: db}
}
func (s *Service) GetData() string {
return s.db.Query()
}
func main() {
db := &DB{}
service := NewService(db)
fmt.Println(service.GetData())
}
ข้อดีของวิธีนี้คือเรียบง่าย แต่พอระบบใหญ่ขึ้น การจัดการ dependency หลายชั้นจะยุ่งยาก
ใช้ Wire จาก Google
Wire เป็น code generation tool ที่ช่วย build dependency graph โดยอัตโนมัติ
ติดตั้ง Wire
go install github.com/google/wire/cmd/wire@latest
ตัวอย่างใช้ Wire
// provider.go
func ProvideDB() *DB {
return &DB{}
}
func ProvideService(db *DB) *Service {
return &Service{db: db}
}
// wire.go
var Set = wire.NewSet(ProvideDB, ProvideService)
func InitializeService() *Service {
wire.Build(Set)
return nil
}
หลังจากสร้างไฟล์ wire.go แล้ว ให้รันคำสั่ง:
wire
Wire จะสร้างไฟล์ wire_gen.go เพื่อให้คุณใช้ DI ได้แบบ auto-generated
ใช้ fx จาก Uber
fx เป็น Dependency Injection Framework ที่ build on top ของ dig โดย Uber
func NewDB() *DB {
return &DB{}
}
func NewService(db *DB) *Service {
return &Service{db: db}
}
func main() {
app := fx.New(
fx.Provide(NewDB, NewService),
fx.Invoke(func(s *Service) {
fmt.Println(s.GetData())
}),
)
app.Run()
}
ภาพประกอบการทำงานของ Dependency Injection ใน Go

ข้อเปรียบเทียบ Tools ที่ใช้ DI
| Tool | จุดเด่น | ข้อควรระวัง |
|---|---|---|
| Manual | เข้าใจง่าย, ไม่ต้องใช้ lib | ยุ่งยากเมื่อระบบใหญ่ |
| Google Wire | Static compile-time safety | ต้อง regenerate ทุกครั้งที่แก้โค้ด |
| Uber Fx | ใช้งาน runtime พร้อม log ดีมาก | Debug ยาก, learning curve สูง |
สรุป
Dependency Injection ใน Go มีหลายแนวทางให้เลือก ตั้งแต่ manual แบบดั้งเดิมไปจนถึงการใช้เครื่องมือช่วยเช่น Wire หรือ Fx ขึ้นอยู่กับขนาดระบบและทีมงานของคุณ หากเริ่มต้นใหม่ แนะนำเริ่มจาก manual และค่อยพัฒนาไปใช้เครื่องมือเพื่อช่วยจัดการ graph ได้สะดวกยิ่งขึ้น
เผยแพร่โดย: poolsawat.com | เขียนโดย: King Pool