حاوية حقن التبعية لـ Go (Golang): Wire و Dig و Uber FX
\n\nحقن التبعية (DI) هو نمط تصميم يحصل فيه الكائن على تبعياته من الخارج بدلاً من إنشائها بنفسه. في Go (Golang) يكون DI مفيدًا بشكل خاص لإنشاء كود معياري وقابل للاختبار وقابل للتوسع. أشهر أدوات DI لـ Go هي Google Wire و Uber Dig و Uber FX. في هذه المقالة سنستعرض كلًا منها، مميزاتها وأمثلة على استخدامها.
\n\nلماذا نحتاج حقن التبعية في Go؟
\nGo هي لغة ثابتة الكتابة مع تمرير صريح للمعلمات. بدون DI، غالبًا ما ينشئ المطورون متغيرات عامة أو مصانع، مما يعقد الاختبار والصيانة. حاويات DI تحل هذه المشكلات:
\n- \n
- الاقتران الضعيف — تعتمد المكونات على الواجهات وليس على التطبيقات الملموسة. \n
- قابلية الاختبار — سهولة استبدال التبعيات بالكائنات الوهمية (mocks). \n
- تبسيط التكوين — تقوم الحاوية تلقائيًا بحل شبكة التبعيات. \n
Google Wire — توليد الكود أثناء التجميع
\nWire من Google ليست حاوية وقت تشغيل، بل هي مولد كود. تقوم بتحليل دوال البناء وتوليد كود لربط التبعيات في مرحلة التجميع. وهذا يعطي حمولة صفرية أثناء التنفيذ واكتشاف مبكر للأخطاء.
\n\nتثبيت Wire
\ngo install github.com/google/wire/cmd/wire@latest\n\nمثال على استخدام Wire
\nلنفترض أن لدينا خدمة تعتمد على قاعدة بيانات ومسجل:
\n// main.go\npackage main\n\nimport "fmt"\n\ntype Logger struct{}\n\nfunc NewLogger() Logger { return Logger{} }\n\nfunc (l Logger) Log(msg string) { fmt.Println(msg) }\n\ntype Database struct {\n logger Logger\n}\n\nfunc NewDatabase(logger Logger) Database {\n return Database{logger: logger}\n}\n\ntype Service struct {\n db Database\n log Logger\n}\n\nfunc NewService(db Database, log Logger) Service {\n return Service{db: db, log: log}\n}\nالآن لننشئ ملف wire.go مع تعليمات لـ Wire:
// wire.go\n//go:build wireinject\n// +build wireinject\n\npackage main\n\nimport "github.com/google/wire"\n\nfunc InitializeService() Service {\n wire.Build(NewLogger, NewDatabase, NewService)\n return Service{}\n}\nلنشغل التوليد:
\nwire\nسينشئ Wire ملف wire_gen.go مع كود تهيئة جاهز:
// wire_gen.go\n// Code generated by Wire. DO NOT EDIT.\n\npackage main\n\nfunc InitializeService() Service {\n logger := NewLogger()\n database := NewDatabase(logger)\n service := NewService(database, logger)\n return service\n}\nمزايا Wire:
\n- \n
- أخطاء في مرحلة التجميع. \n
- لا يوجد انعكاس (reflection)، أداء عالي. \n
- كود بسيط وقابل للتنبؤ. \n
عيوب Wire:
\n- \n
- يتطلب خطوة توليد منفصلة. \n
- صعب الاستخدام مع التبعيات الديناميكية. \n
Uber Dig — حاوية وقت تشغيل مع الانعكاس
\nDig من Uber هي حاوية تعمل أثناء وقت التشغيل. تستخدم الانعكاس (reflection) لتحليل الأنواع وحل التبعيات تلقائيًا. توفر Dig واجهة برمجة تطبيقات بسيطة لتسجيل الدوال البنّاءة واستخراج الكائنات.
\n\nتثبيت Dig
\ngo get go.uber.org/dig\n\nمثال على استخدام Dig
\npackage main\n\nimport (\n "fmt"\n "go.uber.org/dig"\n)\n\ntype Config struct {\n Port int\n}\n\nfunc NewConfig() *Config {\n return &Config{Port: 8080}\n}\n\ntype Server struct {\n config *Config\n}\n\nfunc NewServer(c *Config) *Server {\n return &Server{config: c}\n}\n\nfunc (s *Server) Start() {\n fmt.Print