كتابة نصوص ترحيل قاعدة بيانات لن تعطل بيئة الإنتاج

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

هنا يأتي دور نصوص الترحيل. إنها ليست مجرد ملفات SQL. إنها طريقة منظمة لتطوير مخطط قاعدة البيانات الخاص بك دون تخمين، دون خطوات يدوية، ودون ذلك الشعور المزعج عندما يحدث خطأ في النشر.

النمط الأساسي: ملف واحد، تغيير واحد

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

لنفترض أنك بحاجة إلى إضافة عمود phone إلى جدول users. بدلاً من تسجيل الدخول إلى بيئة الإنتاج وتشغيل ALTER TABLE مباشرة، تقوم بإنشاء ملف باسم 20241101_add_phone_to_users.sql. بداخله، تكتب:

ALTER TABLE users ADD COLUMN phone VARCHAR(20);

ثم تقوم بإنشاء 20241101_add_phone_to_users_rollback.sql:

ALTER TABLE users DROP COLUMN phone;

كلا الملفين يذهبان إلى مستودعك بجانب كود التطبيق الخاص بك. يمران بمراجعة الكود. يتم دمجهما مثل أي تغيير آخر.

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

الترتيب أهم مما تعتقد

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

لا مزيد من "إنه يعمل على جهازي لكنه يفشل على الخادم" لأن ترتيب الترحيل كان مختلفًا. لا مزيد من التناقضات الصامتة حيث تخطت إحدى البيئات خطوة.

اجعل نصوصك قابلة للتكرار (Idempotent)

Idempotent هي كلمة فاخرة لفكرة بسيطة: تشغيل نفس البرنامج النصي مرتين يجب أن ينتج نفس النتيجة ولا يسبب خطأ.

قارن بين هاتين العبارتين:

-- غير قابل للتكرار: سيحدث خطأ إذا كان العمود موجودًا بالفعل
ALTER TABLE users ADD COLUMN phone VARCHAR(20);

-- قابل للتكرار: آمن للتشغيل عدة مرات
ALTER TABLE users ADD COLUMN IF NOT EXISTS phone VARCHAR(20);

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

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

التراجع ليس اختياريًا

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

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

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

بالنسبة للتغييرات المدمرة - حذف الأعمدة، إزالة الجداول، تغيير أنواع البيانات - تحتاج إلى استراتيجية منفصلة. سنغطي ذلك لاحقًا. في الوقت الحالي، القاعدة بسيطة: كل ترحيل يحصل على تراجع، حتى لو كان يستعيد الهيكل فقط.

كيف يظل العمل المتوازي آمنًا

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

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

جدول التتبع

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

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

قائمة تحقق عملية لكتابة نصوص الترحيل

قبل دمج ملف الترحيل، راجع هذه القائمة السريعة:

  • هل يحتوي النص على معرف فريد (طابع زمني أو تسلسل)؟
  • هل هناك نص تراجع مطابق؟
  • هل النص قابل للتكرار؟ هل يمكن تشغيله مرتين دون خطأ؟
  • هل يعيد التراجع الحالة السابقة بالفعل؟
  • هل قمت باختبار كل من الترحيل الأمامي والتراجع على نسخة من بيانات الإنتاج؟
  • هل يقوم الترحيل بقفل الجداول؟ إذا كان الأمر كذلك، هل يمكن تشغيله أثناء حركة المرور المنخفضة؟

الخلاصة

ترحيلات قاعدة البيانات ليست مجرد SQL. إنها عقد بين فريقك وبيانات الإنتاج الخاصة بك. كل ملف ترحيل يمثل قرارًا: ما الذي يتغير، وبأي ترتيب، وكيفية التراجع عنه إذا سارت الأمور بشكل خاطئ. تعامل مع كل ملف بنفس العناية التي توليها لكود التطبيق الخاص بك. راجعه. اختبره. تأكد من أن لديه تراجعًا. قاعدة بيانات الإنتاج الخاصة بك ستشكرك.