ما هو المستودع الواحد (monorepo) ولماذا هو مفيد في Go؟
المستودع الواحد (monorepo) هو نهج لإدارة الكود يتم فيه تخزين جميع المشاريع والمكتبات والخدمات في مستودع واحد. في نظام Go البيئي، أصبح هذا النهج شائعًا بشكل خاص بفضل الدعم المدمج للوحدات (modules) ومساحات العمل (workspaces).
للمطورين المبتدئين، يوفر المستودع الواحد عدة مزايا رئيسية:
- إصدار موحد للكود — جميع التبعيات متزامنة
- إعادة هيكلة مبسطة — التغييرات تظهر فورًا في جميع المشاريع
- توحيد المعايير — إعدادات موحدة لأدوات التحليل (linters) و CI/CD والاختبارات
- الشفافية — سهولة فهم كيفية ارتباط الأجزاء المختلفة من النظام
في هذه المقالة، سنشرح كيفية تنظيم مستودع واحد بلغة Go بشكل صحيح، بدءًا من الهيكل الأساسي وصولاً إلى الأمثلة العملية.
الهيكل الأساسي للمستودع الواحد بلغة Go
التنظيم الصحيح للكود هو أساس نجاح المستودع الواحد. دعنا نلقي نظرة على الهيكل النموذجي:
my-monorepo/├── apps/│ ├── web-api/ # التطبيق الرئيسي│ │ ├── main.go│ │ ├── go.mod│ │ └── internal/│ └── worker/ # معالج الخلفية│ ├── main.go│ └── go.mod├── libs/│ ├── config/ # الإعدادات المشتركة│ │ ├── config.go│ │ └── go.mod│ └── logger/ # التسجيل│ ├── logger.go│ └── go.mod├── scripts/ # البرامج النصية المساعدة├── docs/ # التوثيق├── go.work # مساحة عمل Go└── README.mdالمبادئ الأساسية لهذا الهيكل:
- apps/ — التطبيقات القابلة للتنفيذ (الملفات الثنائية)
- libs/ — المكتبات القابلة لإعادة الاستخدام
- scripts/ — الأتمتة والأدوات المساعدة
- docs/ — توثيق المشروع
إعداد مساحة عمل Go (Go Workspace) للمستودع الواحد
بدءًا من Go 1.18، أصبح هناك دعم رسمي لمساحات العمل من خلال ملف go.work. يتيح ذلك العمل مع عدة وحدات في وقت واحد دون الحاجة إلى نشرها في مستودع بعيد.
لنقم بإنشاء مساحة عمل لمستودعنا الواحد:
// go.workgo 1.22
use ( ./apps/web-api ./apps/worker ./libs/config ./libs/logger)بعد إنشاء go.work، ستكون جميع الوحدات من قائمة use متاحة لبعضها البعض محليًا. هذا مناسب بشكل خاص أثناء التطوير — التغييرات في المكتبة تظهر فورًا في التطبيقات.
تهيئة الوحدات
لكل مكون، يجب إنشاء ملف go.mod خاص به. مثال لمكتبة الإعدادات:
// libs/config/go.modmodule github.com/your-org/libs/config
go 1.22وللتطبيق web-api:
// apps/web-api/go.modmodule github.com/your-org/apps/web-api
go 1.22
require github.com/your-org/libs/config v0.0.0
replace github.com/your-org/libs/config => ../../libs/configلاحظ استخدام replace — فهو يوجه Go لاستخدام النسخة المحلية من المكتبة بدلاً من البحث عنها على الإنترنت.
مثال كود: مكتبة وتطبيق
لنقم بإنشاء مكتبة بسيطة للإعدادات وتطبيق يستخدمها.
مكتبة libs/config
// libs/config/config.gopackage config
import ( "fmt" "os")
type Config struct { Port string Env string}
func Load() (*Config, error) { port := os.Getenv("PORT") if port == "" { port = "8080" }
env := os.Getenv("ENV") if env == "" { env = "development" }
return &Config{ Port: port, Env: env, }, nil}
func (c *Config) String() string { return fmt.Sprintf("Config{