مستودع واحد مع Go: تنظيم الكود عمليًا

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

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

ابدأ الدورة

مستودع واحد مع Go: تنظيم الكود عمليًا

\n\n

المستودع الواحد (monorepo) هو نهج لإدارة الكود المصدري، حيث يتم تخزين جميع المشاريع والمكتبات والخدمات في مستودع واحد. في عالم Go، أصبح هذا النهج شائعًا بشكل خاص بفضل الدعم المدمج للوحدات ونظام الحزم المرن. في هذه المقالة، سنشرح كيفية تنظيم مستودع واحد في Go عمليًا، وسنستعرض الهيكل النموذجي، وأمثلة الكود، وأفضل الممارسات.

\n\n

لماذا نحتاج إلى مستودع واحد في Go؟

\n\n

يحل المستودع الواحد عدة مهام رئيسية:

\n
    \n
  • تبسيط إدارة التبعيات — جميع الحزم الداخلية موجودة في مكان واحد، مما يسهل تحديثها وإعادة هيكلتها.
  • \n
  • سجل تغييرات موحد — التزامات ذرية تؤثر على عدة خدمات في وقت واحد تعمل دون مزامنة إضافية.
  • \n
  • تسريع CI/CD — يمكن إعداد خطوط أنابيب تقوم ببناء الأجزاء المتغيرة فقط من المشروع.
  • \n
  • تحسين جودة الكود — من الأسهل تطبيق معايير موحدة، وأدوات التحليل، ومراجعة الكود.
  • \n
\n\n

هيكل المستودع الواحد Go: مخطط أساسي

\n\n

لنستعرض هيكلًا نموذجيًا للمستودع الواحد في Go. على سبيل المثال، لنأخذ مشروعًا يتكون من خدمتين صغيرتين (api و worker) ومكتبة مشتركة lib:

\n\n
my-monorepo/\n├── go.work\n├── go.work.sum\n├── apps/\n│   ├── api/\n│   │   ├── go.mod\n│   │   ├── main.go\n│   │   └── handler.go\n│   └── worker/\n│       ├── go.mod\n│       ├── main.go\n│       └── process.go\n├── lib/\n│   ├── go.mod\n│   ├── auth/\n│   │   └── auth.go\n│   └── db/\n│       └── db.go\n├── scripts/\n│   ├── build.sh\n│   └── test.sh\n└── Makefile
\n\n

العناصر الرئيسية:

\n
    \n
  • go.work — ملف مساحة العمل Go (Workspace)، الذي يربط جميع الوحدات.
  • \n
  • apps/ — دليل التطبيقات (الخدمات الصغيرة، أدوات CLI، إلخ).
  • \n
  • lib/ — المكتبات المشتركة التي تستخدمها جميع التطبيقات.
  • \n
  • scripts/ — البرامج النصية المساعدة للبناء والاختبار والنشر.
  • \n
\n\n

إعداد Go Workspace (go.work)

\n\n

يوفر Go 1.18+ آلية workspace، التي تسمح بالعمل مع عدة وحدات في وقت واحد. لننشئ ملف go.work في الجذر:

\n\n
go 1.22\n\nuse (\n    ./apps/api\n    ./apps/worker\n    ./lib\n)
\n\n

الآن، أثناء التطوير، يمكن تشغيل الأوامر من جذر المشروع، وسيرى Go جميع الوحدات ككيان واحد. على سبيل المثال، لتشغيل الاختبارات لجميع الوحدات:

\n\n
go test ./...
\n\n

ولبناء خدمة معينة:

\n\n
cd apps/api && go build -o bin/api .
\n\n

مثال كود: مكتبة مشتركة وخدمة صغيرة

\n\n

لننشئ مكتبة بسيطة للمصادقة في lib/auth/auth.go:

\n\n
package auth\n\nimport "errors"\n\nvar (\n    ErrInvalidToken = errors.New("invalid token")\n)\n\n// ValidateToken تتحقق من الرمز وتعيد معرف المستخدم.\nfunc ValidateToken(token string) (string, error) {\n    if token == "" {\n        return "", ErrInvalidToken\n    }\n    // هنا يمكن أن يكون التحقق الفعلي من JWT أو استدعاء خدمة خارجية\n    return "user-123", nil\n}
\n\n

الآن نستخدم هذه المكتبة في الخدمة الصغيرة apps/api/handler.go:

\n\n
package main\n\nimport (\n    "encoding/json"\n    "net/http"\n    "my-monorepo/lib/auth"\n)\n\ntype UserResponse struct {\n    UserID string `json:"user_id"`\n}\n\nfunc UserHandler(w http.ResponseWriter, r *http.Request) {\n    token := r.Header.Get("Authorization")\n    userID, err := auth.ValidateToken(token)\n    if err != nil {\n        http.Error(w, "Unauthorized", http.StatusUnauthorized)\n        return\n    }\n\n    resp := UserResponse{UserID: user                

المدونات

توصيات الكتب