
كلما كانت عملية التطوير أسرع ، كانت شركة التكنولوجيا تتطور بشكل أسرع.
لسوء الحظ ، تعمل التطبيقات الحديثة ضدنا - يجب تحديث أنظمتنا في الوقت الفعلي وفي الوقت نفسه لا تزعج أي شخص ولا تؤدي إلى التوقف والانقطاع. يصبح النشر في مثل هذه الأنظمة مهمة معقدة ويتطلب خطوط أنابيب توصيل مستمرة معقدة حتى في فرق صغيرة.
عادة ما يكون لخطوط الأنابيب هذه تطبيق ضيق ، تعمل ببطء ولا يمكن الاعتماد عليها. يجب على المطورين أولاً إنشائها يدويًا ، ثم إدارتها ، وغالبًا ما تقوم الشركات بتوظيف فرق DevOps بأكملها لهذا الغرض.
تعتمد سرعة التطوير على سرعة خطوط الأنابيب هذه. بالنسبة لأفضل الفرق ، يستغرق النشر من 5 إلى 10 دقائق ، ولكن عادة ما يستغرق وقتًا أطول بكثير ، وبالنسبة للنشر الواحد فإنه يستغرق عدة ساعات.
في الظلام ، يستغرق 50 مللي ثانية. خمسون. ميلي ثانية. Dark هو حل كامل مع لغة برمجة ومحرر وبنية تحتية مصممة خصيصًا للتسليم المستمر ، ويتم تصميم جميع جوانب Dark ، بما في ذلك اللغة نفسها ، بهدف النشر الفوري الآمن.
لماذا ناقلات مستمرة بطيئة جدا؟
دعنا نقول أن لدينا تطبيق ويب Python وقمنا بالفعل بإنشاء خط أنابيب توصيل مستمر رائع وحديث. بالنسبة إلى مطور مشغول بهذا المشروع كل يوم ، سيبدو نشر تغيير بسيط واحدًا كما يلي:
إجراء تغييرات
- إنشاء فرع جديد في بوابة
- جعل التغييرات وراء تبديل وظيفة
- اختبار وحدة للتحقق من التغييرات مع وبدون تبديل وظيفة
طلب بركة
- ارتكاب ارتكاب
- نشر التغييرات إلى مستودع بعيد على جيثب
- طلب بركة
- CI يبني تلقائيا في الخلفية
- مراجعة الكود
- وهناك عدد قليل من الاستعراضات ، إذا لزم الأمر
- دمج التغييرات مع معالج بوابة.
يعمل CI على المعالج
- تحديد تبعيات الواجهة الأمامية عبر npm
- بناء وتحسين موارد HTML + CSS + JS
- تشغيل في الواجهة الأمامية من اختبارات الوحدة والوظيفة
- تثبيت تبعيات Python من PyPI
- تشغيل في الخلفية من وحدة واختبارات وظيفية
- اختبار التكامل في كلا الطرفين
- إرسال موارد الواجهة الأمامية إلى CDN
- بناء حاوية لبرنامج بيثون
- إرسال حاوية إلى التسجيل
- Kubernetes بيان التحديث
استبدال الكود القديم بالجديد
- Kubernetes تطلق حالات متعددة من حاوية جديدة
- Kubernetes تنتظر تشغيل المثيلات
- يضيف Kubernetes مثيلات إلى موازن تحميل HTTP
- ينتظر Kubernetes حتى يتم استخدام المثيلات القديمة
- Kubernetes توقف الحالات القديمة
- يكرر Kubernetes هذه العمليات حتى تحل الحالات الجديدة محل الحالات القديمة
قم بتشغيل مفتاح الوظيفة الجديد
- يتم تضمين الرمز الجديد فقط لنفسي ، للتأكد من أن كل شيء على ما يرام
- يتم تضمين رمز جديد لـ 10٪ من المستخدمين ؛ يتم تتبع مقاييس التشغيل والأعمال
- يتم تضمين رمز جديد لـ 50٪ من المستخدمين ؛ يتم تتبع مقاييس التشغيل والأعمال
- يتم تضمين الرمز الجديد لـ 100٪ من المستخدمين ، ويتم تتبع مقاييس التشغيل والأعمال
- أخيرًا ، يمكنك تكرار الإجراء بأكمله لإزالة الرمز القديم والتبديل
تعتمد العملية على الأدوات واللغة واستخدام البنى الموجهة للخدمات ، ولكن بشكل عام ، يبدو الأمر كذلك. لم أذكر عمليات نشر ترحيل قاعدة البيانات لأن هذا يتطلب تخطيطًا دقيقًا ، لكن أدناه سأصف كيف يتعامل Dark مع هذا.
هناك العديد من المكونات هنا ، والكثير منها يمكن أن يبطئ بسهولة ، أو يتعطل ، أو يسبب منافسة مؤقتة أو يهدم نظام العمل.
وبما أن خطوط الأنابيب هذه يتم إنشاؤها دائمًا تقريبًا لمناسبة خاصة ، فمن الصعب الاعتماد عليها. كثير من الناس لديهم أيام لا يمكن فيها نشر الكود ، لأن هناك مشاكل في Dockerfile ، واحدة من العشرات من الخدمات التي تحطمت أو المختص المناسب في إجازة.
والأسوأ من ذلك ، أن العديد من هذه الخطوات لا تفعل شيئًا على الإطلاق. لقد احتجنا إليها من قبل عندما نشرنا الشفرة فورًا للمستخدمين ، ولكن الآن لدينا مفاتيح للرمز الجديد ، وهذه العمليات مقسمة. نتيجة لذلك ، أصبحت الخطوة التي يتم عندها نشر الكود (يتم استبدال الكود القديم بالآخر الجديد) مجرد خطر إضافي.
بالطبع ، هذا خط أنابيب مدروس للغاية. استغرق الفريق الذي أنشأه الوقت والمال لنشر بسرعة. عادة ما تكون خطوط أنابيب النشر أبطأ بكثير ولا يمكن الاعتماد عليها.
تنفيذ التسليم المستمر في الظلام
التسليم المستمر مهم جدًا لـ Dark لدرجة أننا حددنا أنظارنا في الوقت المحدد في أقل من ثانية. لقد مررنا بجميع خطوات خط الأنابيب لإزالة كل شيء غير ضروري ، وأخذنا الباقي في الاعتبار. هذه هي الطريقة التي أزلنا بها الخطوات.
صاغت جيسي فرازيل الكلمة الجديدة التي لم تنشر في مؤتمر تطوير البرمجيات في ريكيافيك
قررنا على الفور أن Dark سيعتمد على مفهوم "لا يمكن نشره" (بفضل جيسي فرازيل على المذهب الجديد ). يعني Deployless أن يتم نشر أي رمز على الفور وجاهزة للاستخدام في الإنتاج. بالطبع ، لن نفتقد رمزًا خاطئًا أو غير كامل (سأصف مبادئ السلامة أدناه).
في العرض التوضيحي Dark ، سُئلنا غالبًا كيف تمكنا من تسريع عملية النشر. سؤال غريب. ربما يعتقد الناس أننا توصلنا إلى نوع من التكنولوجيا الفائقة تقارن الشفرة وتجميعها وتعبئتها في حاوية وإطلاق جهاز افتراضي وإطلاق حاوية على حاوية باردة وأشياء من هذا القبيل - وكل هذا في 50 مللي ثانية. هذا بالكاد ممكن. لكننا أنشأنا محرك نشر خاص ، والذي لا يحتاج إلى كل هذا.
الظلام تطلق المترجمين الفوريين في السحابة. افترض أنك تكتب رمزًا في دالة أو معالج لـ HTTP أو الأحداث. نرسل فرقًا إلى شجرة بناء الجملة المجردة (تطبيق الكود المستخدم داخليًا بواسطة المحرر والخوادم الخاصة بنا) إلى خوادمنا ، ثم نقوم بتشغيل هذا الرمز عند تلقي الطلبات. لذا فإن النشر يشبه تمامًا سجل متواضع في قاعدة البيانات - فوري ومبدئي. النشر سريع للغاية لأنه يتضمن الحد الأدنى المجرد.
في المستقبل ، نخطط لإنشاء مترجم للبنية التحتية من Dark ، مما سيؤدي إلى إنشاء وتشغيل بنية تحتية مثالية للأداء العالي وموثوقية التطبيقات. النشر الفوري ، بالطبع ، لن يذهب إلى أي مكان.
نشر آمن
محرر منظم
الرمز في الظلام مكتوب في محرر الظلام. المحرر المهيكل لا يرتكب أخطاء في بناء الجملة. في الواقع ، لا يوجد لدى Dark محلل. أثناء الكتابة ، نحن نعمل مباشرةً مع Abstract Syntax Tree (AST) مثل Paredit و Sketch-n-Sketch و Tofu و Prune و MPS .
أي رمز غير مكتمل في Dark له دلالات تنفيذ صالحة ، يشبه إلى حد كبير الثقوب المكتوبة في عسلي . على سبيل المثال ، إذا قمت بتغيير استدعاء دالة ، فإننا نحتفظ بالوظيفة القديمة حتى تصبح الوظيفة الجديدة قابلة للاستخدام.
كل برنامج في Dark له معناه الخاص ، لذلك لا يتداخل الكود غير المكتمل مع العمل النهائي.
أوضاع التحرير
تكتب رمز في الظلام في حالتين. أولاً: تكتب رمزًا جديدًا وأنت المستخدم الوحيد. على سبيل المثال ، إنه موجود في REPL ، ولن يتمكن المستخدمون الآخرون من الوصول إليه مطلقًا ، أو إنه مسار HTTP جديد لا تشير إليه في أي مكان. يمكنك العمل هنا دون أي احتياطات ، والآن أنت تعمل تقريبًا في بيئة التطوير.
الحالة الثانية: الرمز قيد الاستخدام بالفعل. إذا مرت حركة المرور عبر الكود (الوظائف ، معالجات الأحداث ، قواعد البيانات ، النوع) ، فيجب توخي الحذر. للقيام بذلك ، نقوم بحظر جميع التعليمات البرمجية المستخدمة ونطلب استخدام أدوات أكثر تنظيماً لتحريرها. سأتحدث عن الأدوات الهيكلية أدناه: مفاتيح الوظائف لمعالجات HTTP ومعالجات الأحداث ، ومنصة ترحيل قوية لقواعد البيانات ، وطريقة جديدة للتحكم في الإصدار للوظائف والأنواع.
مفاتيح الوظائف
طريقة واحدة لإزالة التعقيد الزائد في Dark هي إصلاح العديد من المشاكل مع حل واحد. تؤدي مفاتيح الوظائف العديد من المهام المختلفة: استبدال بيئة التطوير المحلية ، وفروع git ، ونشر الكود ، وبالطبع الإصدار البطيء والتحكم التقليدي لرمز جديد.
يتم إنشاء ونشر مفتاح الوظيفة في محررنا في عملية واحدة. يقوم بإنشاء مساحة فارغة للرمز الجديد ويوفر عناصر تحكم في الوصول للرمز القديم والجديد ، وكذلك أزرار وأوامر للانتقال التدريجي إلى رمز جديد أو استبعاده.
يتم تضمين رموز التبديل الوظيفية في اللغة المظلمة ، وحتى المفاتيح غير المكتملة تؤدي مهمتها - إذا لم يتم استيفاء الشرط الموجود في المحول ، فسيتم تنفيذ الرمز المحظور القديم.
بيئة التطوير
وظيفة التبديل تحل محل بيئة التطوير المحلية. اليوم ، من الصعب على الفرق التأكد من أن كل شخص يستخدم نفس الإصدارات من الأدوات والمكتبات (منسقي الأكواد ، اللينتر ، مديري الحزم ، المجمعين ، المعالجين ، أدوات الاختبار ، إلخ.) مع Dark ، لا تحتاج إلى تثبيت التبعيات محليًا ، والتحكم في التثبيت المحلي لـ Docker أو اتخاذ تدابير أخرى لضمان ما لا يقل عن ما يشبه المساواة بين بيئة التنمية والإنتاج. بالنظر إلى أن هذه المساواة لا تزال مستحيلة ، فإننا لن ندعي أننا نسعى جاهدين لتحقيقها.
بدلاً من إنشاء بيئة محلية مستنسخة ، تقوم مفاتيح التبديل في Dark بإنشاء صندوق رمل جديد في الإنتاج يحل محل بيئة التطوير. في المستقبل ، نخطط أيضًا لإنشاء صندوق رمل لأجزاء أخرى من التطبيق (على سبيل المثال ، استنساخ قاعدة البيانات الفورية) ، على الرغم من أن هذا لا يبدو مهمًا في الوقت الحالي.
الفروع وعمليات النشر
هناك الآن عدة طرق لإدخال رمز جديد في الأنظمة: فروع git ، ومرحلة النشر ، ومفاتيح الوظائف. إنها تحل مشكلة واحدة في أجزاء مختلفة من سير العمل: git - في المراحل السابقة للنشر ، والنشر - في وقت الانتقال من الكود القديم إلى الجديد ، ومفاتيح الوظائف - للإصدار الخاضع للرقابة من الكود الجديد.
الطريقة الأكثر فاعلية هي مفاتيح الوظائف (في نفس الوقت أسهل للفهم والاستخدام). معهم ، يمكنك التخلي تماما عن طريقتين أخرى. من المفيد بشكل خاص إزالة النشر - إذا استخدمنا مفاتيح الوظائف لتضمين الكود على أي حال ، فإن خطوة نقل الخوادم إلى الكود الجديد تخلق فقط مخاطر غير ضرورية.
Git صعب الاستخدام ، خاصة بالنسبة للمبتدئين ، وهو يحده حقًا ، لكن لديه فروع مريحة. نحن تخلص من العديد من العيوب بوابة. يتم تحرير Dark في الوقت الفعلي ويوفر القدرة على العمل معًا في أسلوب مُحرر مستندات Google ، بحيث لا يتعين عليك إرسال الشفرة ويمكنك في كثير من الأحيان إجراء النقل والاندماج.
ميزة التبديل تدعم نشر آمن. بالإضافة إلى عمليات النشر الفوري ، فهي تتيح لك اختبار المفاهيم بسرعة في الأجزاء الصغيرة ذات المخاطر المنخفضة ، بدلاً من تطبيق تغيير رئيسي واحد يمكن أن يؤدي إلى إسقاط النظام.
الإصدارات
لتغيير وظائف وأنواع نستخدم الإصدار. إذا كنت ترغب في تغيير دالة ، فإن Dark ينشئ إصدارًا جديدًا من هذه الوظيفة. ثم يمكنك استدعاء هذا الإصدار باستخدام رمز التبديل في HTTP أو معالج الأحداث. (إذا كانت هذه الوظيفة عميقة في الرسم البياني للمكالمات ، فسيتم إنشاء نسخة جديدة من كل وظيفة في هذه العملية. قد يبدو أنها أكثر من اللازم ، ولكن لا تتداخل هذه الوظائف إذا لم تستخدمها ، لذلك فلن تلاحظها حتى.)
لنفس الأسباب ، نحن أنواع الإصدارات. تحدثنا عن نظامنا النوعي بالتفصيل في منشور سابق .
من خلال وظائف وأنواع الإصدارات ، يمكنك إجراء تغييرات على التطبيق تدريجياً. يمكنك التحقق من أن كل معالج فردي يعمل مع الإصدار الجديد ، فلن تحتاج إلى إجراء جميع التغييرات على التطبيقات فورًا (ولكن لدينا أدوات للقيام بذلك بسرعة إذا كنت تريد).
هذا أكثر أمانًا من النشر الكامل لكل شيء دفعة واحدة ، كما هو الآن.
إصدارات الحزمة الجديدة والمكتبة القياسية
عندما تقوم بتحديث حزمة في Dark ، فإننا لا نستبدل على الفور استخدام كل وظيفة أو كتابة في قاعدة الشفرة بأكملها. هذه ليست آمنة. يستمر الرمز في استخدام نفس الإصدار الذي استخدمته ، وتحديث استخدام الوظائف والأنواع إلى إصدار جديد لكل حالة على حدة باستخدام رموز التبديل.

لقطة شاشة لجزء من عملية تلقائية في Dark تعرض نسختين من وظيفة Dict :: get. Dict :: get_v0 ارجاع اكتب أي (الذي نرفضه) ، و Dict :: get_v1 عاد نوع الخيار
غالبًا ما نوفر ميزة جديدة في المكتبة القياسية ونستبعد الإصدارات القديمة. سيحتفظ المستخدمون الذين لديهم إصدارات قديمة في الشفرة بالوصول إليها ، ولكن لن يتمكن المستخدمون الجدد من الحصول عليها. سنوفر أدوات لنقل المستخدمين من الإصدارات القديمة إلى الإصدارات الجديدة في خطوة واحدة ، ومرة أخرى باستخدام مفاتيح الوظائف.
يوفر Dark أيضًا فرصة فريدة: بمجرد تنفيذ رمز العمل الخاص بك ، يمكننا اختبار الإصدارات الجديدة بأنفسنا ، ومقارنة إخراج الطلبات الجديدة والقديمة لإبلاغك بالتغييرات. نتيجة لذلك ، فإن تحديثات الحزمة ، والتي يتم إجراؤها غالبًا على نحو أعمى (أو تتطلب اختبارات أمان صارمة) ، تشكل مخاطر أقل بكثير وقد تحدث تلقائيًا.
إصدارات مظلمة جديدة
امتد الانتقال من بيثون 2 إلى بيثون 3 على مدى عقد وما زال يمثل مشكلة. بمجرد إنشاء Dark للتسليم المستمر ، يجب مراعاة هذه التغييرات اللغوية.
عندما نجري تغييرات طفيفة على اللغة ، نقوم بإنشاء إصدار جديد من Dark. يبقى الرمز القديم في الإصدار القديم من Dark ، ويتم استخدام الرمز الجديد في الإصدار الجديد. للتبديل إلى الإصدار الجديد من Dark ، يمكنك استخدام رموز التبديل أو إصدارات الوظائف.
هذا مفيد بشكل خاص بالنظر إلى أن Dark قد ظهر مؤخرًا. قد تفشل العديد من التغييرات في اللغة أو المكتبة. يتيح لنا الإصدار التدريجي للغة إجراء تحديثات بسيطة ، وهذا يعني أنه لا يمكننا التسرع في اتخاذ العديد من القرارات بشأن اللغة أو تأجيلها إلى أن يصبح لدينا المزيد من المستخدمين ، وبالتالي المزيد من المعلومات.
هجرة قاعدة البيانات
هناك صيغة قياسية لترحيل قاعدة البيانات الآمنة:
- أعد كتابة التعليمات البرمجية لدعم التنسيقات الجديدة والقديمة
- تحويل جميع البيانات إلى تنسيق جديد
- حذف الوصول إلى البيانات القديمة
نتيجة لذلك ، يتم تأخير ترحيل قاعدة البيانات ويتطلب الكثير من الموارد. ونحن نراكم مخططات قديمة ، حتى المهام البسيطة ، مثل تصحيح اسم الجدول أو العمود ، لا تستحق الجهد المبذول.
يحتوي Dark على نظام أساسي فعال لترحيل قاعدة البيانات (نأمل) أن يسهل العملية كثيرًا لدرجة أنك لن تخاف منها. جميع مخازن البيانات في الظلام (أزواج القيمة الرئيسية أو جداول التجزئة المستمرة) هي من النوع. لترحيل مستودع بيانات ، يمكنك ببساطة تعيين نوع جديد له وخاصية الاستعادة والتراجع لتحويل القيم بين النوعين.
يتم الوصول إلى مستودعات البيانات في Dark من خلال أسماء المتغيرات التي تم إصدارها. على سبيل المثال ، سيتم تسمية مخزن بيانات المستخدمين في البداية باسم المستخدمين - v0. عند إنشاء إصدار جديد بنوع مختلف ، يتغير الاسم إلى Users-v1. إذا تم حفظ البيانات من خلال Users-v0 ، وقمت بالوصول إليها من خلال Users-v1 ، يتم تطبيق وظيفة التمرير. إذا تم حفظ البيانات من خلال Users-v1 ، ويمكنك الوصول إليها من خلال Users-v0 ، يتم استخدام وظيفة الاستعادة.

شاشة ترحيل قاعدة البيانات مع أسماء الحقول لقاعدة البيانات القديمة ، وتعبيرات العودة والتراجع ، وإرشادات لتمكين الترحيل.
استخدم مفاتيح الوظائف لتوجيه المكالمات إلى Users-v0 إلى Users-v1. يمكنك القيام بمعالج HTTP واحد في كل مرة لتقليل المخاطر ، وتعمل المحولات أيضًا للمستخدمين الفرديين بحيث يمكنك التحقق من أن كل شيء يعمل كما هو متوقع. عندما لا يتم ترك Users-v0 ، يحول Dark جميع البيانات المتبقية في الخلفية من التنسيق القديم إلى التنسيق الجديد. لن تلاحظ ذلك حتى.
تجريب
Dark لغة برمجة وظيفية ذات كتابة ثابتة وقيم ثابتة ؛ وبالتالي ، فإن سطح الاختبار الخاص بها أصغر بكثير مقارنة باللغات الموجهة للكائنات ذات الكتابة الديناميكية. لكنك لا تزال بحاجة للاختبار.
في الظلام ، يقوم المحرر تلقائيًا بإجراء اختبارات للوحدات في الخلفية للحصول على تعليمات برمجية قابلة للتحرير ويقوم افتراضيًا بإجراء هذه الاختبارات لجميع مفاتيح الوظائف. في المستقبل ، نرغب في استخدام الأنواع الثابتة لإدخال الشفرة تلقائيًا للعثور على الأخطاء.
بالإضافة إلى ذلك ، يدير Dark البنية الأساسية الخاصة بك في الإنتاج ، وهذا يفتح إمكانيات جديدة. نقوم تلقائيًا بحفظ طلبات HTTP في البنية الأساسية المظلمة (في الوقت الحالي ، نقوم بحفظ جميع الطلبات ، ولكن بعد ذلك نريد التبديل إلى جلب). نحن نختبر كودًا جديدًا ونجري اختبارات للوحدات ، وإذا كنت ترغب في ذلك ، يمكنك بسهولة تحويل استعلامات شيقة إلى اختبارات وحدة.
ما تخلصنا منه
نظرًا لعدم وجود نشر لدينا ، ولكن توجد مفاتيح الوظائف ، فإن حوالي 60٪ من خط أنابيب النشر لا يزال في الخارج. لا نحتاج إلى فروع git أو طلبات تجمع ، وبناء موارد الخلفية والحاويات ، وإرسال الموارد والحاويات إلى السجلات أو خطوات النشر في Kubernetes.

مقارنة خط أنابيب التوصيل المستمر القياسي (يسار) والإمداد المستمر بـ Dark (يمين). في Dark ، يتكون التسليم من 6 خطوات ودورة واحدة ، بينما يتضمن الإصدار التقليدي 35 خطوة و 3 دورات.
في Dark ، لا يوجد سوى 6 خطوات ودورة واحدة في النشر (الخطوات التي يتم تكرارها عدة مرات) ، في حين يتكون خط أنابيب الإمداد المستمر الحديث من 35 خطوة و 3 دورات. في الظلام ، تعمل الاختبارات تلقائيًا ، حتى أنك لا ترى ذلك ؛ يتم تثبيت التبعيات تلقائيا. لم يعد هناك حاجة إلى أي شيء متعلق ب git أو github ؛ ليس من الضروري جمع حاويات Docker واختبارها وإرسالها ؛ لم يعد نشر Kubernet مطلوبًا.
حتى الخطوات المتبقية في الظلام أصبحت أسهل. نظرًا لأنه يمكن التحكم في مفاتيح الوظائف في إجراء واحد ، فلن تضطر إلى المرور عبر خط أنابيب النشر بالكامل مرة ثانية لإزالة الرمز القديم.
لقد قمنا بتبسيط تسليم الأكواد قدر الإمكان ، مما يقلل من وقت ومخاطر التسليم المستمر. لقد قمنا أيضًا بتبسيط تحديثات الحزمة ، وترحيل قواعد البيانات ، والاختبار ، والتحكم في الإصدار ، وتثبيت التبعية ، والمساواة بين بيئة التطوير والإنتاج ، وترقيات إصدار اللغات السريعة والآمنة.
أجيب على أسئلة حول هذا الموضوع على HackerNews .
لمعرفة المزيد حول جهاز Dark ، اقرأ مقالة Dark ، تابعنا على Twitter (أو أنا ) ، أو قم بالتسجيل للحصول على نسخة تجريبية وتلقي إعلامات المنشورات التالية . إذا كنت قادماً إلى StrangeLoop في سبتمبر ، تعال إلى إطلاقنا .