هندسة SaaS
تحديث البنية التقنية دون إعادة كتابة كل شيء: الترحيل التدريجي وGo وNext.js
تحديث البنية التقنية يعني أن تستبدل تدريجيًا ما يعيق التسليم أو الأمان أو النمو، دون إيقاف الخدمة ودون إعادة كتابة كل شيء دفعة واحدة. والطريقة الأكثر أمانًا هي الترحيل التدريجي: واجهة وسيطة أمام النظام القائم، ثم وحدة تلو الأخرى. وفي بنية SaaS، يشكّل Go للخدمات، وNext.js وTypeScript للواجهة، وPython للذكاء الاصطناعي والبيانات، تركيبة متينة، بشرط أن يكون الفريق قادرًا على تشغيلها واستثمارها، وهو أمر لا يتحقق دائمًا.
باختصار
- حدّث بنيتك التقنية حين تعيق التسليم أو الأمان أو النمو، لا لمجرد أن تقنية ما أصبحت قديمة.
- فضّل الترحيل التدريجي (strangler pattern) على إعادة الكتابة الكاملة: كل مرحلة تقدّم قيمة ويمكن التراجع عنها.
- Go لخدمات الواجهة الخلفية، وNext.js وTypeScript للواجهة الأمامية، وPython للذكاء الاصطناعي والبيانات: كل لغة في مجالها.
- إذا كانت منصة SaaS تستهدف السوق الدولية، فاختر مبكرًا نموذج عزل المستأجرين وعالج حماية المعطيات الشخصية (القانون 09-08 في المغرب) منذ مرحلة التصميم.
- ابدأ بالتدقيق وبأساس التسليم المستمر، واترك ترحيل البيانات إلى النهاية.
ما المؤشرات التي تدل على أن البنية التقنية تحتاج إلى تحديث؟
قِدم التقنية ليس مشكلة في حد ذاته. تصبح البنية التقنية مشكلة حين تكلّف أكثر مما تُدرّ: كل تطوير يستغرق وقتًا أطول من المتوقع، ويقضي الفريق في الالتفاف على النظام وقتًا أطول مما يقضيه في تطويره. والمؤشرات المهمة قابلة للملاحظة:
- عمليات نشر بطيئة ومحفوفة بالمخاطر: كل إطلاق في بيئة الإنتاج يتم يدويًا، غالبًا في المساء، مع الخوف من إفساد جزء آخر من النظام.
- تبعيات منتهية الدعم: إطار عمل أو لغة برمجة أو نظام تشغيل لم يعد يتلقى تحديثات أمنية.
- معرفة محصورة: شخص أو شخصان فقط يفهمان قلب النظام، ويصبح التوظيف على هذه التقنية صعبًا.
- توسّع مكلف: الحل الوحيد لاستقبال مستخدمين أكثر هو خادم أكبر، وذروات الاستخدام تتحول إلى أعطال.
- عوائق أمام تطوير المنتج: يستحيل فتح API لشريك، أو إضافة لغة، أو استقبال عميل ثانٍ على المنصة نفسها، أو ربط نموذج ذكاء اصطناعي بطريقة سليمة.
المؤشر المنفرد يُعالج غالبًا معالجة موضعية. أما حين تتراكم عدة مؤشرات، فلا يعود السؤال هل يجب التحديث، بل بأي ترتيب. وقبل اختيار التقنيات، صُغ أهداف الأعمال والقيود بوضوح: وهذا هو دور دفتر تحملات برمجي جيد.
إعادة بناء التطبيق: لماذا تتجنب إعادة الكتابة الكاملة؟
الإغراء كبير بأن تتخلص من كل شيء وتبدأ من الصفر. لكن عمليًا، تُجمّد إعادة الكتابة الشاملة («big bang») المنتجَ لأشهر: يستمر النظام القديم في التطور لتلبية حاجات العملاء، ويلهث النظام الجديد خلف هدف متحرك، ويُركّز الانتقال النهائي كل المخاطر في عطلة نهاية أسبوع واحدة. كما أن قواعد العمل الضمنية، التي لم تُوثّق قط لكنها حاضرة في الشيفرة، هي أول ما يضيع.
البديل المجرَّب هو الترحيل التدريجي، المعروف غالبًا باسم strangler pattern (نسبةً إلى التين الخانق، وهي صورة نشرها Martin Fowler): ينمو النظام الجديد حول القديم ويحل محله وظيفة بعد وظيفة.
- وضع واجهة وسيطة (reverse proxy أو بوابة API) أمام التطبيق القائم، دون أي تغيير بالنسبة للمستخدمين.
- اختيار نطاق أول محدود ومفيد وقليل المخاطر: البحث أو الإشعارات أو وحدة التقارير مثلًا.
- إعادة بنائه بالتقنيات الجديدة، ثم توجيه هذه الحركة إليه عبر الواجهة الوسيطة.
- القياس والتصحيح، ثم تكرار العملية مع النطاق التالي.
- حذف الشيفرة القديمة أولًا بأول، وإلا ظل الفريق يصون نظامين إلى ما لا نهاية.
كل مرحلة تقدّم قيمة ويمكن التراجع عنها: إذا أساءت الخدمة الجديدة التصرف، تعيد الواجهة الوسيطة توجيه الحركة إلى النظام القديم ريثما يتم التصحيح. أما النقطة الحساسة فهي في مكان آخر: خلال المرحلة الانتقالية، كثيرًا ما تتقاسم الشيفرة القديمة والجديدة البيانات نفسها. حدّد منذ البداية أي نظام هو المرجع لكل معطى، واعزل الشيفرة الجديدة عن خصوصيات النموذج القديم بطبقة ترجمة («طبقة مضادة للفساد» anti-corruption layer)، وإلا انتقل الدين التقني مع الشيفرة.
لماذا Go وNext.js لبنية SaaS؟
تشكّل Next.js وGo وPython وTypeScript البنية التقنية الرئيسية لدى Codevista Innovations. والأسباب تشغيلية، وتصلح لأي فريق يقيّم هذه التركيبة.
Go لخدمات الواجهة الخلفية
- تزامن بسيط: تتيح goroutines وchannels معالجة الطلبات وطوابير الرسائل والاستدعاءات الخارجية بالتوازي، دون إدارة الخيوط (threads) يدويًا.
- ملف تنفيذي واحد: تُترجَم خدمة Go إلى ملف تنفيذي مستقل يمكن أن يكون ثابتًا بالكامل. تبقى الحاوية خفيفة، ولا حاجة إلى تثبيت أي بيئة تشغيل على الخادم.
- أداء يمكن التنبؤ به: لغة مُترجَمة، وإقلاع سريع، واستهلاك ذاكرة متواضع عمومًا. ويصبح تحجيم البنية التحتية أسهل.
- تشغيل سهل: مكتبة قياسية غنية (HTTP وJSON والتشفير)، وأدوات مدمجة للاختبار والتنسيق وتحليل الأداء، وترجمة متقاطعة نحو أنظمة أخرى.
- شيفرة مقروءة من الفريق كله: اللغة محدودة عن قصد، مما يسهّل مراجعة الشيفرة وإدماج مطورين جدد.
يناسب Go بشكل خاص واجهات API، وخدمات التكامل (الدفع، أنظمة ERP، المراسلة)، والمعالجات غير المتزامنة، والمكونات التي يجب أن تتحمل الضغط.
Next.js وTypeScript للواجهة الأمامية
يضيف Next.js إلى React العرض من جهة الخادم والتوليد الثابت للصفحات. تصل الصفحات العامة إلى المتصفح مبنيةً مسبقًا، وهذا مهم للإحالة الطبيعية (SEO)، ولسرعة العرض على الهاتف، وللمشاركة على الشبكات الاجتماعية. كما توفّر منظومة React، وهي من أكثر منظومات الواجهة الأمامية انتشارًا، مكونات ومكتبات للواجهة، وتسهّل التوظيف.
يضيف TypeScript عقودًا مُنمَّطة: توصف البيانات المتبادلة مع الواجهة الخلفية مرة واحدة، انطلاقًا مثلًا من مخطط OpenAPI تنتجه خدمات Go. فإذا أُعيدت تسمية حقل في الـAPI، يفشل البناء (build) لا بيئة الإنتاج. وأخيرًا، يسهّل Next.js الترحيل التدريجي: قواعد إعادة الكتابة (rewrites) فيه تقدّم الصفحات الجديدة وتحيل الباقي إلى التطبيق القديم، صفحة بصفحة.
Python حيث يوجد الذكاء الاصطناعي والبيانات
تظل Python اللغة المرجعية للبيانات والذكاء الاصطناعي: معالجة البيانات، والتعلم الآلي، وحزم SDK لمزوّدي النماذج اللغوية. وبدل فرض هذه الأعمال على Go، الأفضل عزلها في خدمات Python مخصصة تُستدعى عبر API داخلية أو طابور رسائل. هذا التقسيم يُبقي كل لغة في مجالها، ويسمح بتطبيق قواعد أمان أكثر صرامة على النطاق الذي يعالج بيانات حساسة، كما في حالة تنسيق وكلاء الذكاء الاصطناعي. والثمن: لغة إضافية يجب صيانتها واختبارها ومراقبتها. وإذا اقتصر الذكاء الاصطناعي على بضعة استدعاءات API نحو مزوّد نماذج، فخدمة Go أو TypeScript تكفي غالبًا.
متى لا يكون Go وNext.js الخيار المناسب؟
لا توجد بنية تقنية صالحة لكل الحالات. وفي ما يلي الحالات التي تكون فيها خيارات أخرى، أو الإبقاء على الوضع القائم، أكثر حكمة:
- الفريق يتقن أصلًا بنية سليمة. تطبيق Laravel أو Django أو Java أو .NET يُصان جيدًا ويُختبر ويُنشر بانتظام لا يبرر تغيير اللغة. حدّث الممارسات قبل التقنيات.
- واجهة إدارة داخلية بسيطة. لأداة تسيير لا تواجه ضغطًا كبيرًا، كثيرًا ما يُسلّم إطار عمل «متكامل» يولّد واجهة الإدارة تلقائيًا أسرع من خدمات Go.
- تطبيق كامل خلف المصادقة. في غياب صفحات عامة، تسقط حجة SEO لصالح Next.js؛ وقد يكفي تطبيق React تقليدي، وهو أبسط استضافةً.
- مجال عمل غني جدًا بالقواعد. يفضّل Go البساطة ولو على حساب شيء من التكرار؛ وبعض الفرق تفضّل لغة أكثر تعبيرًا لنمذجة مجال معقد.
- غياب القدرة على التشغيل. تعدد الخدمات يستلزم المراقبة وسجلات مركزية ونشرًا آليًا. وبدون هذا الأساس، يكون نظام أحادي (monolith) حسن الهيكلة أكثر أمانًا من خدمات مصغّرة (microservices) سيئة المراقبة.
ضع في الحسبان أيضًا وتيرة Next.js: إصداراته الرئيسية تتطور بسرعة، ومواكبة هذه التحديثات تتطلب وقتًا مخططًا له.
بنية متعددة المستأجرين (multi-tenant): الاستعداد للنمو الدولي
منصة SaaS متعددة المستأجرين تخدم عددًا كبيرًا من المؤسسات العميلة، أي المستأجرين (tenants)، على منصة واحدة. واستهداف عدة بلدان يضاعف عدد المستأجرين ومتطلبات الفصل بينهم. ويُختار نموذج العزل مبكرًا، لأن تغييره لاحقًا صعب:
- قاعدة بيانات مشتركة مع معرّف للمستأجر: النموذج الأقل تكلفة، لكن كل استعلام يجب أن يُصفّي البيانات بشكل صحيح؛ وتضيف ميزة الأمان على مستوى الأسطر (Row-Level Security) في PostgreSQL صمّام أمان مفيدًا.
- مخطط (schema) لكل مستأجر: فصل أفضل، لكن عمليات ترحيل أثقل في التنسيق.
- قاعدة بيانات لكل مستأجر: عزل قوي وإمكانية توطين البيانات بلدًا بلدًا، مقابل تشغيل أكثر تعقيدًا.
أبعد من قاعدة البيانات، تفرض السوق الدولية اختيارات ملموسة: عدة لغات منها العربية التي تُكتب من اليمين إلى اليسار، والمناطق الزمنية، والعملات، ووسائل الأداء (مركز النقديات ما بين البنوك، CMI، للأداء بالبطاقة في المغرب، ومزوّدون آخرون مثل Stripe بحسب البلدان التي توجد فيها الجهة المُصدِرة للفواتير)، والامتثال. وفي المغرب، يؤطّر القانون 09-08 معالجة المعطيات ذات الطابع الشخصي، بما في ذلك نقلها إلى الخارج؛ واللجنة الوطنية لمراقبة حماية المعطيات ذات الطابع الشخصي (CNDP) هي سلطة المراقبة التي ينبغي الرجوع إليها. وقد يضيف كل بلد مستهدف قواعده الخاصة: تحقّق منها قبل اختيار مكان استضافة البيانات. ويفصّل دليلنا حول تطوير SaaS حسب الطلب في المغرب هذه المفاضلات.
كيف ترتّب مراحل تحديث التطبيق؟
ترتيب المراحل لا يقل أهمية عن التقنيات المختارة. وهذا تسلسل يحدّ من المخاطر:
- التدقيق ورسم الخريطة: جرد المكونات والتبعيات وتدفقات البيانات ونقاط الألم، مرتبةً حسب قيمتها بالنسبة للأعمال وحسب المخاطر.
- أساس التسليم: التكامل والنشر المستمران، واختبارات آلية على المسارات الحرجة، والمراقبة. فبدون شبكة الأمان هذه، يصبح كل ترحيل مجازفة.
- الواجهة الوسيطة والنطاق الأول: إعداد الـproxy، ثم ترحيل وحدة عالية القيمة وقليلة المخاطر للتحقق من صلاحية المقاربة.
- واجهة Next.js تدريجية: الصفحات العامة أولًا، حيث يؤثر العرض من جهة الخادم في الإحالة الطبيعية وسرعة العرض، ثم شاشات التطبيق.
- البيانات في النهاية: قاعدة البيانات هي الجزء الأكثر خطورة؛ رحّلها مجالًا بمجال، مع سكربتات للتحقق وخطة للتراجع.
- إيقاف النظام القديم ونقل المعرفة: كل وحدة يتم استبدالها تختفي من النظام القديم، ويكتسب الفريق الداخلي الكفاءة في النظام الجديد على امتداد الورش، لا في نهايته.
أدِر هذا الورش عبر دورات قصيرة، بمنهجية مثل Scrum: كل sprint يسلّم نطاقًا قابلًا للتحقق على بيئة ما قبل الإنتاج (staging) قبل إطلاقه في الإنتاج. وإذا عهدت بالعمل كله أو بجزء منه إلى مزوّد خدمات، فستساعدك معاييرنا لـاختيار وكالة تطوير في الدار البيضاء على طرح الأسئلة الصحيحة، لا سيما بشأن أمن البيانات.
ترافق Codevista Innovations هذا المسار، من تشخيص بنيتك التقنية الحالية إلى تصميم بنيات متعددة المستأجرين بـGo وNext.js، انطلاقًا من الدار البيضاء نحو المغرب والسوق الدولية. تنطلق مشاريعنا بمرحلة استكشاف وتصميم، ثم تتقدّم عبر sprints مدة كل منها أسبوعان، تُسلَّم على بيئة staging لتصادق عليها. ولتقييم وضعيتك، حدّثنا عن مشروعك.
أسئلة شائعة
كم يستغرق تحديث تطبيق قائم؟
يتوقف ذلك على حجم النظام، وجودة الشيفرة الحالية، ومدى توفر الفريق: لا يوجد رقم عام يمكن الوثوق به. وميزة الترحيل التدريجي تحديدًا أنه لا يرتهن بتاريخ انتقال واحد. يمكن إطلاق نطاق أول في الإنتاج قبل نهاية الورش بوقت طويل، ثم تتوالى الوحدات التالية حسب قيمتها. ويتيح تدقيق أولي وضع تسلسل وتقدير واقعيين.
هل يمكن الاحتفاظ بقاعدة البيانات الحالية عند الانتقال إلى Go وNext.js؟
نعم، وغالبًا ما يُنصح بذلك في البداية. يتوفر Go على مشغّلات (drivers) ناضجة لقواعد البيانات العلائقية الرئيسية، ومنها PostgreSQL وMySQL وSQL Server. ويمكن إذن للخدمات الجديدة القراءة من القاعدة الحالية والكتابة فيها خلال المرحلة الانتقالية. ثم يُرحَّل المخطط مجالًا بمجال، بعد استقرار الخدمات، مع سكربتات للتحقق من الاتساق وخطة للتراجع.
Go أم Node.js للواجهة الخلفية لمنصة SaaS؟
لكليهما ما يبرره. يتيح Node.js استخدام TypeScript في الواجهتين الأمامية والخلفية، مما يبسّط عمل الفريق الصغير. ويقدّم Go ملفًا تنفيذيًا واحدًا وتزامنًا أصيلًا يستثمر كل أنوية المعالج دون إعدادات خاصة، وهما ميزتان مفيدتان لواجهات API ذات الضغط العالي وخدمات التكامل. ويبقى المعيار الحاسم في الغالب كفاءات الفريق وقيود التشغيل، أكثر من الأداء الخام.
هل Next.js مفيد لتطبيق أعمال لا يحتاج إلى SEO؟
بدرجة أقل. فالعرض من جهة الخادم في Next.js يخدم أساسًا الصفحات العامة: الإحالة الطبيعية، وسرعة العرض، والمشاركة على الشبكات الاجتماعية. أما لأداة داخلية موجودة بالكامل خلف المصادقة، فقد يكفي تطبيق React تقليدي. ويظل Next.js مناسبًا إذا كان المنتج نفسه يجمع بين موقع عام وفضاء للعملاء، أو إذا أردت إطار عمل واحدًا للتوجيه (routing) والتدويل والاستدعاءات من جهة الخادم.