ما هو Wire ولماذا تحتاجه؟
Wire هي مكتبة لحقن التبعيات (Dependency Injection - DI) للغة Go، طورتها فريق Google. على عكس العديد من أطر DI الأخرى التي تعمل أثناء وقت التشغيل (runtime)، يستخدم Wire توليد الكود في مرحلة الترجمة (compile-time). هذا هو الفرق الجوهري: يقوم Wire بتحليل الكود الخاص بك ويُنشئ ملف wire_gen.go الذي يحتوي على كل منطق ربط التبعيات. هذا النهج يزيل الأخطاء المرتبطة بالانعكاس (reflect) ويجعل الكود مُنمّطًا بالكامل (fully typed).
لماذا تحتاج Wire؟
- تبسيط الإعداد: بدلاً من إنشاء جميع التبعيات يدويًا في
main.go، يقوم Wire بذلك تلقائيًا. - الاختبار: يمكنك بسهولة استبدال التطبيقات الحقيقية بنماذج وهمية (mocks) لاختبارات الوحدة (unit tests).
- نظافة الكود: يصبح الكود أكثر نمطية وأقل ترابطًا (low coupling).
- أمان الأنواع: يتم اكتشاف أخطاء الإعداد في مرحلة الترجمة، وليس في وقت التشغيل.
Wire مثالي للمشاريع الكبيرة حيث يصل عدد التبعيات إلى عشرات أو مئات.
التثبيت
Wire ليس مكتبة بالمعنى التقليدي (مثل حزمة تستوردها). إنها أداة سطر أوامر (CLI). يتم التثبيت عبر مدير الحزم القياسي لـ Go:
go install github.com/google/wire/cmd/wire@latest
بعد تنفيذ هذا الأمر، سيكون الملف الثنائي wire متاحًا في $GOPATH/bin (أو $GOBIN). تأكد من إضافة هذا المسار إلى متغير البيئة PATH.
تحقق من التثبيت:
wire help
إذا رأيت قائمة المساعدة بالأوامر، فكل شيء جاهز للعمل.
بداية سريعة مع مثال كود
لننشئ تطبيقًا بسيطًا يُرحّب بالمستخدم. سيكون لدينا ثلاثة مكونات: Message و Greeter (المُرحّب) و Event (الحدث).
الخطوة 1: هيكل المشروع
myapp/
├── main.go
├── wire.go
└── wire_gen.go (سيتم إنشاؤه)
الخطوة 2: إنشاء المكونات (main.go)
package main
import "fmt"
// Message — هيكل بسيط يحتوي على نص.
type Message struct {
Text string
}
// NewMessage — المُنشئ لـ Message.
func NewMessage(text string) Message {
return Message{Text: text}
}
// Greeter — هيكل يُرحّب باستخدام Message.
type Greeter struct {
Message Message
}
// NewGreeter — المُنشئ لـ Greeter.
func NewGreeter(m Message) Greeter {
return Greeter{Message: m}
}
// Greet — دالة تُرجع التحية.
func (g Greeter) Greet() Message {
return g.Message
}
// Event — هيكل يمثل حدثًا.
type Event struct {
Greeter Greeter
}
// NewEvent — المُنشئ لـ Event.
func NewEvent(g Greeter) Event {
return Event{Greeter: g}
}
// Start — دالة تبدأ الحدث.
func (e Event) Start() {
msg := e.Greeter.Greet()
fmt.Println(msg.Text)
}
func main() {
// إنشاء التبعيات يدويًا (بدون Wire)
message := NewMessage("مرحبًا، Wire!")
greeter := NewGreeter(message)
event := NewEvent(greeter)
event.Start()
}
الخطوة 3: إنشاء ملف wire.go
هذا الملف هو "المزوّد" لـ Wire. يحتوي على دوال التهيئة (providers) ودالة تُخبر Wire بما يجب تجميعه.
//go:build wireinject
// +build wireinject
package main
import "github.com/google/wire"
// InitializeEvent — الدالة التي سيستخدمها Wire لتوليد الكود.
// تُعلن أننا بحاجة إلى Event، وسيقوم Wire ببناء شجرة التبعيات بنفسه.
func InitializeEvent(text string) Event {
wire.Build(NewEvent, NewGreeter, NewMessage)
return Event{} // هذا السطر لن يُنفّذ، هو فقط لـ