حاوية حقن التبعية لـ Go (Golang): Wire و Dig و Uber FX

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

حاوية حقن التبعية لـ Go (Golang): Wire و Dig و Uber FX

\n\n

حقن التبعية (DI) هو نمط تصميم يحصل فيه الكائن على تبعياته من الخارج بدلاً من إنشائها بنفسه. في Go (Golang) يكون DI مفيدًا بشكل خاص لإنشاء كود معياري وقابل للاختبار وقابل للتوسع. أشهر أدوات DI لـ Go هي Google Wire و Uber Dig و Uber FX. في هذه المقالة سنستعرض كلًا منها، مميزاتها وأمثلة على استخدامها.

\n\n

لماذا نحتاج حقن التبعية في Go؟

\n

Go هي لغة ثابتة الكتابة مع تمرير صريح للمعلمات. بدون DI، غالبًا ما ينشئ المطورون متغيرات عامة أو مصانع، مما يعقد الاختبار والصيانة. حاويات DI تحل هذه المشكلات:

\n
    \n
  • الاقتران الضعيف — تعتمد المكونات على الواجهات وليس على التطبيقات الملموسة.
  • \n
  • قابلية الاختبار — سهولة استبدال التبعيات بالكائنات الوهمية (mocks).
  • \n
  • تبسيط التكوين — تقوم الحاوية تلقائيًا بحل شبكة التبعيات.
  • \n
\n\n

Google Wire — توليد الكود أثناء التجميع

\n

Wire من Google ليست حاوية وقت تشغيل، بل هي مولد كود. تقوم بتحليل دوال البناء وتوليد كود لربط التبعيات في مرحلة التجميع. وهذا يعطي حمولة صفرية أثناء التنفيذ واكتشاف مبكر للأخطاء.

\n\n

تثبيت Wire

\n
go 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:

\n
// 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

لنشغل التوليد:

\n
wire
\n

سينشئ Wire ملف wire_gen.go مع كود تهيئة جاهز:

\n
// 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
\n

عيوب Wire:

\n
    \n
  • يتطلب خطوة توليد منفصلة.
  • \n
  • صعب الاستخدام مع التبعيات الديناميكية.
  • \n
\n\n

Uber Dig — حاوية وقت تشغيل مع الانعكاس

\n

Dig من Uber هي حاوية تعمل أثناء وقت التشغيل. تستخدم الانعكاس (reflection) لتحليل الأنواع وحل التبعيات تلقائيًا. توفر Dig واجهة برمجة تطبيقات بسيطة لتسجيل الدوال البنّاءة واستخراج الكائنات.

\n\n

تثبيت Dig

\n
go get go.uber.org/dig
\n\n

مثال على استخدام Dig

\n
package 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                    

توصيات