اذهب إلى المحتوى

استخدام وسوم البناء لتخصيص الملفات التنفيذية Binaries في لغة جو Go


هدى جبور

وسم البناء Build tag أو قيد البناء Build constraint هو مُعرّف يُضاف إلى التعليمات البرمجية لتحديد متى يجب تضمين ملف ما في حزمة أثناء عملية البناء build، ويتيح لك إمكانية بناء إصدارات مُختلفة لتطبيقك من نفس التعليمات البرمجية المصدرية والتبديل بينها بطريقة سريعة ومنظمة.

يستخدم العديد من المطورين وسوم البناء لتحسين سير العمل Workflow عند بناء تطبيقات متوافقة مع جميع أنظمة تشغيل الأساسية Cross-platform، مثل البرامج التي تتطلب تغييرات في التعليمات البرمجية لمراعاة الفروقات بين أنظمة التشغيل المختلفة. تُستخدم وسوم البناء أيضًا من أجل اختبار التكامل Integration testing، مما يسمح لك بالتبديل بسرعة بين الشيفرة المتكاملة والشيفرة باستخدام خادم زائف Mock server أو شيفرة اختبارية بديلة Stub، وبين المستويات المختلفة لمجموعات الميزات التي يتضمنها تطبيقك.

لنأخذ مثلًا، مشكلة اختلاف مجموعات الميزات التي تُمنح للعملاء، فعند كتابة بعض التطبيقات، قد ترغب في التحكم بالمميزات التي يجب تضمينها في الثنائي binary، مثل التطبيق الذي يوفّر مستويات مجانية واحترافية Pro ومتقدمة Enterprise. كلما رفع العميل من مستوى اشتراكه في هذه التطبيقات، توفّرت له المزيد من الميزات وأصبحت غير مقفلة.

يمكنك حل هذه المشكلة من خلال الاحتفاظ بمشاريع منفصلة ومحاولة إبقائها متزامنةً مع بعضها بعضًا من خلال استخدام تعليمات الاستيراد import، وعلى الرغم من أن هذا النهج سيعمل، لكنه سيصبح مملًا بمرور الوقت وعرضةً للخطأ، وقد يكون النهج البديل هو استخدام وسوم البناء.

ستستخدم في هذه المقالة وسوم البناء في لغة جو، لإنشاء ملفات تنفيذية مختلفة تُقدم مجموعات ميزات مجانية واحترافية ومتقدمة لتطبيقك. سيكون لكل من هذه الملفات التنفيذية مجموعةٌ مختلفةٌ من الميزات المتاحة، إضافةً للإصدار المجاني، الذي هو الخيار الافتراضي.

ملاحظات:

  • التوافق مع أنظمة التشغيل الأساسية Cross-platform: ‏ هو مصطلح يستخدم في علم الحوسبة يشير إلى برامج الحاسوب أو أنظمة التشغيل أو لغات الحاسوب أو لغات البرمجة وتطبيقاتها التي يمكنها العمل على عدة منصات حاسوبية. هناك نوعان رئيسيان من البرمجيات المتوافقة مع أنظمة التشغيل الأساسية، إذ يستلزم الأول بناءه لكل منصة يمكنه العمل عليها، والثاني يمكنه العمل مباشرةً على أي منصة تدعمه.

  • اختبار التكامل Integration testing: يمثّل مرحلة اختبار البرامج التي تتكامل فيها الوحدات البرمجية وتُختبر مثل وحدة واحدة متكاملة. يُجرى اختبار التكامل لتقييم مدى امتثال نظام أو مكون برمجي لمتطلبات وظيفية محددة، وغالبًا ما تكون هذه المتطلبات مدونة في توثيق الخاصيات والمتطلبات.

  • خادم زائف Mock server: هو إطار عمل يهدف إلى تبسيط اختبار التكامل. تعتمد هذه الأُطر على مفهوم الكائنات الزائفة، وهي كائنات محاكاة تحاكي سلوك الكائنات الحقيقية بطرق خاضعة للرقابة، وتكون غالبًا بمثابة جزء من عملية اختبار البرنامج. يُنشئ المبرمج عادةً كائنًا زائفًا لاختبار سلوك بعض الأشياء الأخرى، بنفس الطريقة التي يستخدم بها مصمم السيارة دمية اختبار التصادم لمحاكاة السلوك الديناميكي للإنسان في اصطدام السيارة. هذه التقنية قابلة للتطبيق أيضًا في البرمجة العامة.

  • شيفرة اختبارية بديلة Stub: برنامج صغير يُستبدل ببرنامج أطول، ربما يُحمّل لاحقًا، أو يكون موجودًا عن بُعد في مكان ما، إذ يكون بديلًا مؤقتًا للشيفرة التي لم تُطوّر بعد، وهذه الشيفرة مفيدة جدًا في نقل البيانات والحوسبة الموزعة وكذلك تطوير البرمجيات واختبارها عمومًا.

المتطلبات الأساسية

أن يكون لديك مساحة عمل خاصة في لغة جو، وإذا لم يكن لديك مساحة عمل، اتبع سلسلة المقالات التالية: تثبيت لغة جو Go وإعداد بيئة برمجة محلية على أبونتو Ubuntu، وتثبيت لغة جو وإعداد بيئة برمجة محلية على نظام ماك macOS، وتثبيت لغة جو وإعداد بيئة برمجة محلية على ويندوز.

بناء النسخة المجانية

سنبدأ ببناء الإصدار المجاني من التطبيق، إذ سيكون هو الإصدار الافتراضي عند تنفيذ الأمر go build دون أي وسوم بناء. سنستخدم لاحقًا وسوم البناء لإضافة أجزاء أخرى إلى برنامجنا.

أنشئ مجلدًا باسم التطبيق الخاص بك في مجلد src، وسنستخدم هنا الاسم "app":

$ mkdir app

انتقل إلى المجلد "app" الذي أنشأته:

$ cd app

أنشئ الآن ملف "main.go" داخل مجلد المشروع. استخدمنا هنا محرر النصوص نانو nano لفتح وإنشاء الملف:

$ nano main.go

سنعرّف الآن الإصدار المجاني من التطبيق. انسخ المحتويات التالية إلى ملف main.go:

package main

import "fmt"

var features = []string{
  "Free Feature #1",
  "Free Feature #2",
}

func main() {
  for _, f := range features {
    fmt.Println(">", f)
  }
}

أنشأنا برنامجًا يُصرّح عن شريحة Slice باسم features، تحتوي على سلسلتين نصيتين strings تمثلان ميزات إصدار تطبيقنا المجاني. تستخدم الدالة ()main حلقة for لتنتقل عبر عناصر شريحة الميزات من أجل طباعة جميع الميزات المتاحة على الشاشة.

احفظ الملف واخرج منه، وبعد حفظ الملف لن نضطر إلى تحريره مرةً أخرى خلال هذا المقال، إذ سنستخدم وسوم البناء لتغيير ميزات الثنائيات التي سنبنيها منها.

اِبنِ وشغّل البرنامج:

$ go build
$ ./app

ستحصل على الخرج التالي:

> Free Feature #1
> Free Feature #2

طبع البرنامج ميزتين مجانيتين تكملان ميزات الإصدار المجاني من تطبيقنا.

أكملنا الآن الإصدار المجاني المُتمثّل بتطبيق يحتوي على مجموعة ميزات أساسية جدًا. سنبني بعد ذلك شيفرة تمكننا من إضافة مزيدٍ من الميزات إلى التطبيق عند البناء.

إضافة ميزات احترافية باستخدام go build

تجنّبنا حتى الآن إجراء تغييرات على الملف main.go، وذلك لمحاكاة بيئة إنتاج عامة ينبغي فيها إضافة الشيفرة دون تغيير الشيفرة الرئيسية أو كسرها.

ونظرًا لإمكانية تعديل ملف main.go، سنحتاج إلى استخدام آلية أخرى لإدخال المزيد من الميزات إلى شريحة features باستخدام وسوم البناء.

سننشئ ملفًا جديدًا باسم "pro.go"، والذي سيستخدم الدالة ()init لإضافة المزيد من الميزات إلى شريحة features:

$ nano pro.go

أضف المحتويات التالية إلى الملف بعد فتحه:

package main

func init() {
  features = append(features,
    "Pro Feature #1",
    "Pro Feature #2",
  )
}

استخدمنا الدالة ()init لتشغيل الشيفرة قبل الدالة ()main في التطبيق، ثم استخدمنا الدالة ()append لإضافة ميزات احترافية إلى شريحة features.

احفظ الملف واخرج منه، ثم صرّف التطبيق وشغّله باستخدام الأمر التالي:

$ go build

نظرًا لوجود ملفين الآن في المجلد الحالي، هما "pro.go" و "main.go"، سينشئ الأمر go build ملفًا ثنائيًا من كليهما:

$ ./app

ستحصل على الخرج التالي:

> Free Feature #1
> Free Feature #2
> Pro Feature #1
> Pro Feature #2

يتضمن التطبيق الآن كلًا من الميزات الاحترافية والمجانية، وهذا غير مرغوب بالوضع الحالي للتطبيق؛ فلا يوجد تمييز بين الإصدارات، إذ يتضمن الإصدار المجاني الميزات التي من المفترض أن تكون متوفرة فقط في الإصدار الاحترافي. يمكنك حل المشكلة عن طريق إضافة المزيد من التعليمات البرمجية لإدارة المستويات المختلفة للتطبيق، أو استخدام وسوم البناء لإخبار أدوات جو عن الملفات التي تكون بامتداد "go."،التي يجب بناؤها وتلك التي يجب تجاهلها. سنضيف في الخطوة التالية وسوم البناء.

إضافة وسوم البناء

يمكنك الآن استخدام وسوم البناء لتمييز الإصدار الاحترافي عن المجاني. يكون شكل الوسم كما يلي:

// +build tag_name

من خلال وضع هذا السطر البرمجي في بداية الحزمة الخاصة بك (في أول سطر) وتبديل tag_name إلى اسم وسم البناء الذي تريده، ستُوسّم هذه الحزمة لتصبح شيفرةً يمكن تضمينها اختياريًّا في الثنائي النهائي. دعنا نرى هذا عمليًا عن طريق إضافة وسم البناء إلى ملف pro.go لإخبار الأمر go build بتجاهلها ما لم يُحدّد الوسم. افتح الملف في محرر النصوص الخاص بك:

$ nano pro.go

ضِف مايلي:

// +build pro

package main

func init() {
  features = append(features,
    "Pro Feature #1",
    "Pro Feature #2",
  )
}

أضفنا في بداية الملف pro.go السطر ‎// +build proمتبوعًا بسطر جديد فارغ؛ وهذا السطر الجديد ضروري، وبدونه سيفسّر جو السطر السابق على أنه تعليق. يجب أن تكون تصريحات وسوم البناء أيضًا في أعلى الملف ذي الامتداد "go." دومًا، لا تضع أي شيء، ولا حتى التعليقات قبلها.

يُخبِر التصريح build+ الأمر go build أن هذا ليس تعليقًا، بل هو وسم بناء. الجزء الثاني هو الوسم pro، فبإضافة هذا الوسم في الجزء العلوي من ملف pro.go، سيُضمّن الأمر go build ملف pro.go في حال وجود الوسم pro فقط. صرّف التطبيق الآن وشغّله:

$ go build
$ ./app

ستحصل على الخرج التالي:

> Free Feature #1
> Free Feature #2

بما أن ملف pro.go يتطلب وجود الوسم pro، سيجري تجاهل الملف وسيُصرّف التطبيق دونه.

عند استخدام الأمر go build، يمكننا استخدام الراية tags- لتضمين شيفرة محددة لكي تُصرّف مع التطبيق عن طريق إضافة وسم الشيفرة مثل وسيط. سنجرّب ذلك مع الوسم pro:

$ go build -tags pro

ستحصل على الخرج التالي:

> Free Feature #1
> Free Feature #2
> Pro Feature #1
> Pro Feature #2

سنحصل الآن على الميزات الاحترافية فقط إذا أضفنا الوسم pro.

هذا جيد إذا كان هناك إصدارين فقط، ولكن الأمور تصبح معقدةً عند وجود مزيدٍ من الإصدارات وإضافة مزيدٍ من الوسوم. سنستخدم في الخطوة التالية وسوم بناء متعددة مع منطق بولياني Boolean logic، لإضافة إصدار مُتقدم.

استخدام المنطق البولياني مع وسوم البناء

عندما تكون هناك وسوم بناء متعددة في حزمة جو، تتفاعل الوسوم مع بعضها بعضًا باستخدام المنطق البولياني. لتوضيح ذلك، سنضيف المستوى "مُتقدم Enterprise" لتطبيقنا باستخدام الوسم pro والوسم enterprise.

سنحتاج من أجل بناء ثنائي للإصدار المتقدم إلى تضمين كل من الميزات الافتراضية والميزات الاحترافية، ومجموعة جديدة من الميزات الخاصة بالإصدار المتقدم. افتح محررًا وأنشئ ملفًا جديدًا enterprise.go، لنضع فيه الميزات الجديدة:

$ nano enterprise.go

ستبدو محتويات enterprise.go متطابقة تقريبًا مع pro.go ولكنها ستحتوي على ميزات جديدة. ضِف الأسطر التالية إلى الملف "enterprise.go":

package main

func init() {
  features = append(features,
    "Enterprise Feature #1",
    "Enterprise Feature #2",
  )
}

احفظ الملف واخرج.

لا يحتوي ملف enterprise.go حاليًا على أي وسوم بناء، وكما تعلّمت عندما أضفت pro.go، فهذا يعني أن هذه الميزات ستضاف إلى الإصدار المجاني عند تنفيذ go.build. بالنسبة إلى pro.go، أضفت build pro+ \\ متبوعًا بسطر فارغ في أعلى الملف لإخبار الأمر go build أنه يجب تضمينه فقط عند استخدام tags pro-. تحتاج في هذه الحالة فقط إلى وسم بناء واحد لتحقيق الهدف، لكن عند إضافة الميزات الجديدة المتقدمة، إذ يجب أن يكون لديك أولًا ميزات احترافية Pro.

سنجعل الآن ملف enterprise.go يدعم وسم البناء pro. افتح الملف باستخدام محرر النصوص الخاص بك:

$ nano enterprise.go

ضِف بعد ذلك وسم البناء قبل سطر التصريح package main وتأكد من إضافة سطر فارغ كما تحدثنا:

// +build pro

package main

func init() {
  features = append(features,
    "Enterprise Feature #1",
    "Enterprise Feature #2",
  )
}

احفظ الملف واغلقه، ثم صرّف التطبيق دون إضافة أي وسوم (الإصدار المجاني):

$ go build
$ ./app

ستحصل على الخرج التالي:

> Free Feature #1
> Free Feature #2

لاحظ أن الميزات المتقدمة لا تظهر في الإصدار المجاني. دعنا الآن نضيف وسم الإصدار المحترف pro ونبني التطبيق ونشغّله مرةً أخرى:

$ go build -tags pro
$ ./app

ستحصل على الخرج التالي:

> Free Feature #1
> Free Feature #2
> Enterprise Feature #1
> Enterprise Feature #2
> Pro Feature #1
> Pro Feature #2

ليس هذا فعلًا ما نحتاجه حتى الآن، لأن الميزات المتقدمة تظهر عندما نبني إصدار احترافي، وسنحتاج إلى استخدام وسم بناء آخر لحل هذه المشكلة. بالنسبة للوسم enterprise فهو على عكس الوسم pro، إذ نحتاج هنا إلى التأكد من توفُّر الميزات الاحترافية pro والمتقدمة enterprise في نفس الوقت.

يراعي نظام البناء في جو هذا الموقف من خلال السماح باستخدام بعض المنطق البولياني في نظام وسوم البناء.

لنفتح enterprise.go مرةً أخرى:

$ nano enterprise.go

سنضيف الآن وسمًا إلى هذا الملف باسم enterprise كما فعلنا سابقًا عند إضافة الوسم pro:

// +build pro enterprise

package main

func init() {
  features = append(features,
    "Enterprise Feature #1",
    "Enterprise Feature #2",
  )
}

احفظ الملف واخرج، ثم صرّف التطبيق مع إضافة الوسم enterprise:

$ go build -tags enterprise
$ ./app

سيكون الخرج على النحو التالي:

> Free Feature #1
> Free Feature #2
> Enterprise Feature #1
> Enterprise Feature #2

لاحظ أننا خسرنا ميزات الإصدار الاحترافي، وسبب ذلك هو أنه عندما نضع عدة وسوم بناء ضمن نفس السطر في ملف "go."، سيفسر go build أن العلاقة بينهما هي OR المنطقية. إذًا، بإضافة السطر build pro enterprise+ \\ سيُبنى الملف enterprise.go في حال وجود إحدى الوسمين pro أو enterprise.

نحن الآن بحاجة إلى كتابة وسوم البناء بطريقة صحيحة مع استخدام المنطق AND، ولفعل ذلك سنكتب كلًا من الوسمين في سطر منفصل، وبهذا الشكل سيفسّر go build على أن العلاقة بينهما AND. افتح الملف enterprise.go مرةً أخرى وافصل وسوم البناء في أسطر منفصلة:

// +build pro
// +build enterprise

package main

func init() {
  features = append(features,
    "Enterprise Feature #1",
    "Enterprise Feature #2",
  )
}

الآن، صرّف تطبيقك مع الوسم enterprise:

$ go build -tags enterprise
$ ./app

ستحصل على الخرج التالي:

> Free Feature #1
> Free Feature #2

ما زال هذا غير كافي لأن منطق AND يتطلب أن يكون العنصران محققين "true"؛ إذًا نحتاج إلى وجود وسمي البناء pro و enterprise:

$ go build -tags "enterprise pro"
$ ./app

ستحصل على الخرج التالي:

> Free Feature #1
> Free Feature #2
> Enterprise Feature #1
> Enterprise Feature #2
> Pro Feature #1
> Pro Feature #2

يمكنك الآن بناء التطبيق من نفس شجرة المصدر بعدة طرق مختلفة وفقًا للميزات التي تريد توفيرها.

استخدمنا في هذا المثال وسم بناء جديد باستخدام وسم build+ // للدلالة على منطق AND، ولكن هناك طرق بديلة لتمثيل المنطق البولياني باستخدام وسوم البناء. يحتوي الجدول التالي على بعض الأمثلة على التنسيقات النحوية الأخرى لوسوم البناء، جنبًا إلى جنب مع مكافئها المنطقي:

قاعدة وسم البناء عينة عن الوسم التعليمة المنطقية
عناصر مفصولة بفراغ build pro enterprise+ \\ محترف أو متقدم pro OR enterprise
-------- -------- --------
عناصر مفصولة بفاصلة build pro,enterprise+ \\ محترف ومتقدم pro AND enterprise
-------- -------- --------
عناصر مفصولة بعلامة تعجب build !pro+ \\ ليس محترف NOT pro

خاتمة

تعرّفت في هذا المقال على كيفية استخدام وسوم البناء للتحكم في الملفات التي ستُصرّف إلى ملفات ثنائية في جو؛ إذ صرّحنا أولًا عن وسم البناء، ثم استخدمناها في go build ثم دمجنا عدة وسوم باستخدام المنطق البولياني. أخيرًا بنينا برنامجًا يتضمن مجموعات ميزات مختلفة كل منها يمثل إصدارًا (مجاني، احترافي، متقدم)، والذي أظهر قوة وسوم البناء التي تمثّل أداةً قوية جدًا بالتحكم بإصدارات المشروع.

ترجمة -وبتصرف- للمقال Customizing Go Binaries with Build Tags لصاحبه Gopher Guides.

اقرأ أيضًا


تفاعل الأعضاء

أفضل التعليقات

لا توجد أية تعليقات بعد



انضم إلى النقاش

يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.

زائر
أضف تعليق

×   لقد أضفت محتوى بخط أو تنسيق مختلف.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   جرى استعادة المحتوى السابق..   امسح المحرر

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • أضف...