وسم البناء 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.
أفضل التعليقات
لا توجد أية تعليقات بعد
انضم إلى النقاش
يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.