การจัดการ Dependency Injection ใน Golang

Sharing is caring!

หนึ่งในหัวข้อสำคัญในการพัฒนาแอปพลิเคชันขนาดกลางถึงใหญ่ คือเรื่องของการจัดการ 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 WireStatic compile-time safetyต้อง regenerate ทุกครั้งที่แก้โค้ด
Uber Fxใช้งาน runtime พร้อม log ดีมากDebug ยาก, learning curve สูง

สรุป

Dependency Injection ใน Go มีหลายแนวทางให้เลือก ตั้งแต่ manual แบบดั้งเดิมไปจนถึงการใช้เครื่องมือช่วยเช่น Wire หรือ Fx ขึ้นอยู่กับขนาดระบบและทีมงานของคุณ หากเริ่มต้นใหม่ แนะนำเริ่มจาก manual และค่อยพัฒนาไปใช้เครื่องมือเพื่อช่วยจัดการ graph ได้สะดวกยิ่งขึ้น


เผยแพร่โดย: poolsawat.com | เขียนโดย: King Pool

Leave a Reply

อีเมลของคุณจะไม่แสดงให้คนอื่นเห็น ช่องข้อมูลจำเป็นถูกทำเครื่องหมาย *