หนึ่งในหัวข้อสำคัญในการพัฒนาแอปพลิเคชันขนาดกลางถึงใหญ่ คือเรื่องของการจัดการ 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