Go في الأعمال الكبيرة: لماذا لم يعد مجرد "لغة للخدمات المصغرة"
\n\nعندما تسمع "Enterprise Go"، ما الذي يتبادر إلى ذهنك؟ لوائح الشركات المملة؟ مراجعات كود لا نهائية؟ أم ربما شعور بأن Go مخصص فقط للشركات الناشئة و DevOps؟
\n\nفي الواقع، Go في المؤسسات هو مستوى مختلف تمامًا من الانضباط والثقافة الهندسية. في الشركات الكبرى (Uber، Dropbox، Salesforce، Twitch) لا يكتبون باستخدام Go مجرد خدمات مصغرة، بل منصات كاملة تعالج ملايين الطلبات في الثانية. وهنا "مجرد أنه يعمل" ليس كافيًا.
\n\nفي هذه المقالة، سنحلل الميزات الرئيسية لـ التطوير باستخدام Go في المؤسسات: من تصميم الحزم إلى تسجيل الإنتاج. سيكون هناك الكثير من الكود والحد الأدنى من الحشو.
\n\n1. الهندسة المعمارية: لا تكرر خطأ "المونوليث في الخدمات المصغرة"
\n\nالمشكلة الأكثر شيوعًا التي أراها في مشاريع Go على مستوى المؤسسات هي محاولة نقل بنية Java-style إلى Go. النتيجة: مئات الواجهات غير الضرورية وطبقات تجريدية تبطئ التطوير فقط.
\n\nقاعدة "الحزمة حسب الميزة، وليس حسب الطبقة"
\n\nبدلاً من إنشاء مجلدات /models، /handlers، /services — قم بالتجميع حسب مجالات الأعمال:
myapp/\n├── cmd/\n│ └── server/\n│ └── main.go\n├── internal/\n│ ├── user/ # كل ما يتعلق بالمستخدمين\n│ │ ├── handler.go\n│ │ ├── service.go\n│ │ ├── repository.go\n│ │ └── user.go # نموذج البيانات\n│ ├── payment/ # كل ما يتعلق بالمدفوعات\n│ │ ├── handler.go\n│ │ ├── service.go\n│ │ ├── gateway.go\n│ │ └── payment.go\n│ └── pkg/ # الأدوات المساعدة العامة\n└── go.mod\n\nهذا النهج هو أحد أفضل ممارسات Go للمؤسسات. إنه يقلل من الاقتران ويجعل الكود قابلاً للتنبؤ. عندما يفتح مطور جديد المشروع، يرى على الفور منطق الأعمال، وليس طبقات التجريد.
\n\nالواجهات: استقبل الواجهات، وأعد الهياكل
\n\nهذه نصيحة كلاسيكية من مجتمع Go، لكنها حاسمة في المؤسسات. يجب أن تكون الواجهات صغيرة (1-2 طريقة) ويتم تعريفها حيث تُستخدم، وليس حيث تُنفذ.
\n\n// سيء: الواجهة محددة بجانب التنفيذ\npackage user\n\ntype UserRepository interface {\n FindByID(id string) (*User, error)\n Save(user *User) error\n}\n\ntype postgresRepo struct { ... }\n\n// جيد: الواجهة حيثما تكون مطلوبة\npackage user\n\ntype Storage interface {\n Get(id string) (*User, error)\n Put(user *User) error\n}\n\ntype service struct {\n db Storage\n}\n\nfunc NewService(db Storage) *service {\n return &service{db: db}\n}\n\nلماذا هذا مهم؟ لأنه في المؤسسات، غالبًا ما تغير الأنظمة الخلفية (PostgreSQL -> CockroachDB، Redis -> KeyDB). الواجهات المحددة من جانب المستهلك تسمح بذلك دون ألم.
\n\n2. معالجة الأخطاء: توقف عن تجاهل _
\n\nلا توجد استثناءات في Go، وهذا رائع. لكن في مشاريع المؤسسات، الأخطاء ليست مجرد if err != nil. إنها ثقافة كاملة.
التغليف أم لا؟
\n\nاستخدم fmt.Errorf مع %w لإنشاء سلاسل من الأخطاء. هذا يسمح بالحفاظ على مكدس الاستدعاءات ويبسط التصحيح.
func (s *service) ProcessOrder(ctx context.Context, orderID string) error {\n order, err := s.orderRepo.Get(ctx, orderID)\n if err != nil {\n return fmt.Errorf("getting order %s: %w", orderID, err)\n }\n\n if err := s.paymentGateway.Charge(ctx, order.Amount); err != nil {\n return fmt.Errorf("charging for order %s: %w", orderID, err)\n }\n\n return nil\n}\n\nعلى المستوى الأعلى (في handler/middleware) استخدم errors.Is() و errors.As() للتحقق من أنواع الأخطاء:
if errors.Is(err, ErrNotFo