ما هي الـ Migration وما علاقتها بالـ Database ؟
السلام عليكم ورحمة الله وبركاته
الفهرس
المقدمة
اليوم سنتحدث عن مفهوم الـ Migration
في الـ Database
وكيفية استخدامها بشكل صحيح
سأكتفي بشرح الفكرة العامة للـ Migration
وكيفية استخدامها ولن أدخل في تفاصيل تقنية كثيرة
لأن الهدف من هذا المقال هو توضيح الفكرة العامة للـ Migration
وفائدتها وكيفية استخدامها لا أكثر
تخيل معي أنك تعمل وحدك في تطوير مشروعك الخاص وقمت ببناء قاعدة بيانات
ومع مرور الوقت أثناء تطويرك للمشروع تقوم بإضافة أو تعديل أو حذف حقول أو عناصر جديدة في الجداول أو تقوم بحذف جداول بأكملها
أو إضافة علاقات جديدة بين الجداول وهكذا
وتستمر في هذه العمليات طوال فترة تطويرك للمشروع وهذه أمور طبيعية ومتوقعة ودائمًا ما نقوم بتعديل الكثير من الأمور في قاعدة البيانات خلال تطويرنا لأي مشروع
وعلى مقياس شخصي ومشروع صغير وبسيط لا توجد مشكلة في ذلك
لكن ماذا لو كان لديك فريق عمل كبير وكل عضو في الفريق يقوم بتعديلات على قاعدة البيانات الخاصة بالمشروع
كيف سيتم تتبع هذه التعديلات ؟ وكيف ستقومون بتنسيق هذه التعديلات بينكم ؟
بمعنى لنفترض أنك تعمل في مشروع مع بلال مشروع صغير وبسيط وقمت أنت بإنشاء قاعدة بيانات لهذا المشروع
الآن أنت قمت بتشغيل المشروع على جهازك وقام بلال بتشغيل المشروع على جهازه
وكل شخص بالطبع قام بإنشاء Database
خاصة به على جهازه كـ LocalHost
لنفترض أنك كنت المسؤول عن اضافة ميزة جديدة وهذه الميزة تتطلب إضافة حقل جديد لجدول معين
لنفترض أنك أضفت حقل يسمى phone
لجدول users
وبعد أن قمت بإضافته واختبرت الميزة وعملت بشكل جيد قمت برفع التعديلات على الـ Repository
الخاص بالمشروع
الآن سيقوم بلال بتنزيل التعديلات الجديدة من الـ Repository
وسيقوم بتشغيل المشروع على جهازه الخاص
لكن سؤال كيف سيعرف بلال أنه يجب عليه إضافة حقل phone
لجدول users
؟
هل تقوم أنت بإرسال له رسالة تقول له "مرحبًا بلال آسف على الإزعاج لكن تذكر أن تضيف phone
لجدول users
"
ولنقل أنك أخبرته، لكن هل سيتذكر ذلك ؟ وهل سيقوم بإضافته بشكل صحيح من الأساس ؟
بمعنى حتى لو أخبرته كيف يمكنك التأكد من أنه قام بإضافته بشكل صحيح ؟
هل ستقوم بارسال ملف SQL
له يحتوي على الأوامر اللازمة لإضافة الحقل وتقول له "قم بتشغيل هذا الملف رجاءًا قبل أن تفعل أي شيء آخر"
قد تظن أن اضافة بسيطة مثل اضافة phone
لجدول users
ليست مشكلة ولكن ماذا لو كانت هناك تعديلات كبيرة وكثيرة ؟
لنقل أنك قمت بعمل جدول جديد وضخم وأضفت Relation
بينه وبين جدول آخر أو Polymorphic Relation
هل ستقوم بإرسال له ملف SQL
يحتوي على الأوامر اللازمة لإنشاء الجدول والعلاقات ؟
وطبعًا لن يكون هناك بلال بل سيكون هناك عبدالله وأشرف وفريق كامل يعمل على المشروع هل ستقوم بفتح اذاعة داخل الشركة تخبرهم وكل شخص يخبر الآخر
وإليك حوار تخيلي قد يحدث بينكم:
- أنت: يا عبدالله، هل أضفت تعديلاتي الجديدة على الـ
Database
الخاصة بك ؟ - عبدالله: لا، أنا أضفت تعديلات بلال وأشرف
- أنت: يا بلال، هل تستطيع ارسال ملف الـ
SQL
الجديد لعبدالله - بلال: أنا لدي
Database
قديمة وحدثت مشكلة وتعارض مع تعديلات أشرف - أشرف: شباب، هل قمتم بعمل هذه التعديلات الجديدة على الـ
Server
من الأساس ؟ - ... وهكذا
ويمكنك أن تتخيل الفوضى التي ستحدث والأخطاء والتعارض بين البيانات والتأخير
هنا يأتي دور الـ Database Migration
لحل هذه المشكلة وتنظيم عملية التعديل على قاعدة البيانات بشكل صحيح ومنظم
لكن سؤال قبل أن نكمل، هل هذا يعني أنني أستعمل الـ Migration
فقط داخل فريق كبير ؟
الإجابة لا، الـ Migration
مفيد حتى وإن كنت تعمل وحدك على مشروع صغير وبسيط
الفكرة أنه يكون مكان واحد يكون فيه كل الجداول والتعديلات التي تمت على الـ Database
والتي يحتاجها أي شخص ليبدأ بالعمل على المشروع
ويستطيع إنشاء قاعدة بيانات جديدة والتعديلات الجديدة بسهولة
وأيضًا وقد يكون أهم شيء وهو تطبيق التعديلات على الـ Server
نفسه الذي ترفع عليه المشروع
بمعنى وإن كنت تعمل وحدك على المشروع وتستخدم LocalHost
لتشغيل المشروع وتعمل على تعديلات على قاعدة البيانات
ستضطر لاحقًا لرفعه على الـ Server
كيف ستقوم بتطبيق التعديلات على الـ Server
؟
هل في كل مرة ستقوم بالدخول لداخل الـ Server
في الـ Terminal
وتقوم بتنفيذ أوامر الـ SQL
والتعديلات يدويًا ؟
هنا أيضًا نستفيد من الـ Migration
واستخدامها في الـ CI/CD
والـ Deployment
لتطبيق التعديلات بشكل تلقائي عند رفع المشروع على الـ Server
حسنًا أعتذر، أعرف أنني تكلمت بشكل نظري عن الـ Migration
ولم أشرح ما هو الـ Migration
بالضبط وكيفية استخدامها
الآن سأقوم بشرح الـ Migration
بالتفصيل وكيفية استخدامها
ما هي الـ Migration ؟
الـ Migration
بكل بساطة هي مجموعة من الملفات التي تستخدم لبناء وتعديل قاعدة البيانات
فعلى سبيل المثال لنقول أنك بدأت مشروع جديد مع فريقك وأنت كنت المسؤول عن بناء قاعدة البيانات المبدئية
فأنت الآن قمت بإنشاء جدول يدعى Users
ليمثل المستخدمين ويحتوي على id
, name
, email
, password
عندما تنشيء شيء جديد أو تعديل جديد على الـ Database
ستقوم بإنشاء ملف يحتوى على التعديلات وتضعه على سبيل المثال في مجلد يدعى migrations
هذه الملف ما رأيك بأن نسميه باسم معبر مثل 2024_10_01_123000_create_users_table.php
حيث يحتوى على تاريخ الانشاء ثم الوصف لتوضح متى تمت الاضافة او التعديل وماذا يفعل هذا الملف بالتحديد
ونحن فقط قمنا بإضافة جدول جديد لا أكثر
وبالمناسبة التاريخ غالبًا ما يكون بصيغة YYYY_MM_DD_HHMMSS
أي سنة_شهر_يوم_ساعة_دقيقة_ثانية
بالتالي فالتاريخ هنا هو 2024_10_01_123000
وهو يعني أن الملف تم إنشاؤه في الأول من أكتوبر 2024
الساعة 12:30:00
ما محتوى وشكل الملف بالتحديد ؟
الملف يحتوى على دالتين أساسيتين وهما up
و down
حيث أن up
تحتوي على الأوامر التي تقوم بإنشاء الجدول أو تعديله
و down
تحتوي على الأوامر التي تقوم بالتراجع عن التغيرات التي في up
في حالة الجدول الذي أنشأناه Users
سيكون الملف كالتالي:
class CreateUsersTable
{
public function up()
{
DB::raw('CREATE TABLE users (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(255),
email VARCHAR(255),
password VARCHAR(255)
)');
}
public function down()
{
DB::raw('DROP TABLE users');
}
}
لاحظ هنا أن في دالة up
نقوم بإنشاء الجدول users
بالطريقة التي نريدها
وفي دالة down
نقوم بحذف الجدول users
ملحوظة
: لاحظ أنني كتبت أوامر الـSQL
بشكل مباشر أيraw
لكن غالبًا ويفضل أن تعتمد على المكاتب والـORM
أوODM
ليهتم بأمر الـSQL
بداخلها بشكل أفضل وأكثر أمانًا
فعلى سبيل المثال في لغة مثل PHP
ستكون هناك مكتبات تسهل عليك عملية الـ Migration
ففي الـ Laravel
على سبيل المثال ستقوم بكتابة الملف كهذا
class CreateUsersTable
{
public function up()
{
Schema::create('users', function ($table) {
$table->id();
$table->string('name');
$table->string('email');
$table->string('password');
});
}
public function down()
{
Schema::dropIfExists('users');
}
}
وكذلك مع جميع اللغات والـ Frameworks
ستجد مكتبات تسهل عليك عملية الـ Migration
وتعتمد على نفس المبدأ حيث أن هناك دالة up
بها الأوامر التي نريد تنفيذها ودالة down
بها الأوامر التي تقوم بالتراجع عن التغييرات
الآن أصبح لدينا ملف يحتوي على التعديلات والإضافات التي قمنا بها في الـ Database
الآن ما الخطوة التالية ؟
الخطوة التالية هي تنفيذ هذا الملف على الـ Database
كيفية تنفيذ الـ Migration ؟
بكل بساطة بعد أن قمت بكتابة الملف ووضعته في مجلد الـ migrations
يمكنك تنفيذه بسهولة
وغالبًا الـ Framework
الذي تستخدمه يوفر لك أوامر لتنفيذ الـ Migration
بسهولة
وإن كنت لا تستخدم Framework
يمكنك أن تمر على ملفات الـ Migration
وتنفذ دالة up
بكل بساطة
في الـ Laravel
يمكنك تنفيذ الـ Migration
بكل بساطة عن طريق الأمر
php artisan migrate
هكذا سيتم المرور على ملفات الـ Migration
وتنفيذها على الـ Database
بشكل مباشر
بالتالي سيتم إنشاء جدول users
التي أنشأناه داخل ملف الـ Migration
وسيتم تنفيذ الأوامر التي في دالة up
وفي حالة أردت التراجع عن التعديلات يمكنك استخدام الأمر
php artisan migrate:rollback
هكذا سيتم التراجع عن آخر تعديل تم على الـ Database
وسيتم تنفيذ الأوامر التي في دالة down
لكن هناك ملحوظة مهمة عن موضوع التراجع عن التعديلات سأتحدث عنها لاحقًا في الفقرة القادمة
ملحوظة
: أنا أستخدمLaravel
لتوضيح لا أكثر وكل شيء يمكنك تنفيذه في أيFramework
أو بدونFramework
بنفس الطريقة
طالمًا فهمت الفكرة العامة
الآن نحن قمنا بإنشاء جدول users
ونفذناه على الـ Database
واختبرناه وكل شيء سار بشكل جيد
الآن غالبًا ستقوم برفع تعديلات وملف الـ Migration
على الـ Repository
الخاص بالمشروع
ثم يأتي أعضاء فريق كل واحد على جهازه الخاص سيقوم فقط بتنفيذ الـ Migration
على الـ Database
الخاص به
وهكذا سيتم تطبيق التعديلات على الـ Database
بشكل سليم ومنظم وبدون أخطاء كما كتبتها أنت في ملف الـ Migration
تنفيذ الـ Migration مع الفريق
الآن لنفترض أن كل واحد في الفريق يقوم بتنفيذ شيء معين في المشروع
فمثًلا :
- أنت: تقوم بإضافة
phone
لجدولusers
- عبدالله: يقوم بإضافة جدول جديد يسمى
posts
- بلال: يقوم بإضافة جدول جديد
permissions
ويقوم بربطه بجدولusers
في جدول ثالث يسمىuser_permissions
- أشرف: .... ااا .. امم .. يقوم بشيء ما في المشروع
كل شخص يقوم بتعديلاته في جهازه بشكل مستقل ويكتب أي تغيرات يقوم بها على الـ Database
في ملف داخل مجلد الـ migrations
فغالبًا أنت انتهيت من تعديلك وأنشأت ملف يدعى 2024_10_02_123000_add_phone_to_users_table.php
وقمت برفعه على الـ Repository
ثم عبدالله انتهى وأنشأ ملف يدعى 2024_10_03_123000_create_posts_table.php
وقام برفعه على الـ Repository
وبلال قام بإنشاء ملف يدعى 2024_10_04_123000_create_permissions_table.php
و 2024_10_04_135000_create_user_permissions_table.php
وقام أيضًا برفعهما
وأشرف حسنًا قام .. ااا .. بعمل ملف يدعى 2024_10_05_123000_add_something_to_something_table.php
وقام برفعه
الآن كل شخص رفع تعديلاته وكل شخص قام بتنزيل الملفات التي أنشأها الآخرين من الـ Repository
والآن مجلد الـ migrations
الخاص بكل شخص سيكون بهذا الشكل
migrations
├── 2024_10_01_123000_create_users_table.php
├── 2024_10_02_123000_add_phone_to_users_table.php
├── 2024_10_03_123000_create_posts_table.php
├── 2024_10_04_123000_create_permissions_table.php
├── 2024_10_04_135000_create_user_permissions_table.php
└── 2024_10_05_123000_add_something_to_something_table.php
الآن كل شخص سيقوم فقط بتنفيذ الـ Migration
لتتطبق كل هذه التغيرات والإضافات على الـ Database
وبهذه الطريقة يمكنك تنظيم عملية التعديل على الـ Database
بشكل جيد ومنظم وتجنب النسيان أو الأخطاء
ولا مزيد من يا بلال ابعت الملف أو يا عبدالله هل نفذت التعديلات التي ارسلتها لك منذ يومين وهكذا
وأيضًا غالبًا عندما تقوم برفع هذه التعديلات على الـ Server
تستطيع جعله تلقائيًا ينفذ الـ Migration
عند رفع أي تعديل
بعض الملحوظات التي عليك الانتباه لها
أثناء استخدام الـ Migration
هناك بعض الأمور التي يجب عليك الانتباه لها
أي ملف أنشأته ورفعته على الـ Repository
لا تقم بتعديله مرة أخرى
لأن تم تنفيذه ولن يتم تنفيذ مرة أخرى
├── 2024_10_01_123000_create_users_table.php
├── 2024_10_02_123000_add_phone_to_users_table.php
فعلى سبيل المثال لاحظ أننا قمنا بإنشاء جدول users
وأضفنا phone
له
ولكن لما لم نقم بتعديل ملف 2024_10_01_123000_create_users_table.php
وإضافة phone
للجدول
السبب لأن الملف تم رفعه و تم تنفيذه عند باقي أعضاء الفريق والأهم من هذه أنه تم تنفيذه على الـ Server
بالتالي المشكلة أنك إذا قمت بتعديل الملف وأضفت phone
للجدول ورفعته على الـ Repository
وطالما أنه تم تنفيذه من قبل فلن يتم تنفيذه مرة أخرى ولن يتم إضافة phone
للجدول users
لأن الـ Framework
أو الـ Migration
سيقوم بالتحقق من الملفات التي تم تنفيذها ولن يقوم بتنفيذ أي ملف تم تنفيذه من قبل
وهذا يعتبر من الأمور الجيدة لأنه يمنع تنفيذ نفس التعديلات مرتين
وأيضًا لو افترضنا أنك قمت بتعديل الملف وأضفت phone
للجدول ورفعته على الـ Repository
ستحتاج لعمل rollback
للتراجع عن التعديلات التي قمت بها في الـ Migration
السابقة والتراجع عنها في الـ Server
وعند كل أعضاء الفريق بشكل يدوي
وهذه العملية تعتبر كارثة لأنك غالبًا ستفقد البيانات المتواجدة في الـ Database
لأن في حالتنا هذه التراجع يعني حذف الجدول users
بأكمله وإعادة إنشائه من جديد بالتعديلات الجديدة
بالتالي البيانات التي به سيتم فقدها
لذا يجب عليك الانتباه لهذه النقطة وعدم تعديل الملفات التي تم تنفيذها من قبل
اعتبر أن الملفات التي تم تنفيذها أصبحت من المضي وأصبح كتاريخ للتعديلات التي تمت على الـ Database
على مر الزمن
وأي تعديل جديد يجب أن يكون في ملف جديد
لذا فكما رأيت هنا :
├── 2024_10_01_123000_create_users_table.php
├── 2024_10_02_123000_add_phone_to_users_table.php
لو أردت أن تضيف phone
للجدول users
مرة أخرى يجب عليك إنشاء ملف جديد يحتوي على التعديلات الجديدة
كما فعلنا في الملف 2024_10_02_123000_add_phone_to_users_table.php
ولا نقم أبدًا بتعديل ملف تم رفعه وتم تنفيذه من قبل عند الآخرين وفي الـ Server
لذا طالما رفعت ملفًا وتم تنفيذه فلا تقم بعمل rollback
ولا تقم بتعديله مرة أخرى
فكرة دالة down
والـ rollback
هي للتراجع عن التعديلات التي تقوم باختبارها على جهازك الخاص وليس للتعديل على التعديلات التي تم تنفيذها من قبل
فمثلًا أنت قمت بإنشاء جدول users
وأضفت phone
ثم قمت بعمل migration
وتم تنفيذه على الـ Database
الخاصة بك فقط
ثم قررت أن تغير phone
إلى mobile
تستطيع عمل rollback
وتنفيذ الـ Migration
الجديدة وتجربتها على جهازك الخاص
لأنك في هذه الحالة تختبرها على جهازك الخاص ولم تقم برفعها بعد على الـ Repository
ولم يتم تنفيذها على الـ Server
بالتالي يمكنك فعل ما تشاء وتجربة التعديلات الجديدة على الـ Database
الخاصة بك كما تشاء قبل أن ترفعها
الختام
هذا هو شرح بسيط للـ Migration
وكيفية استخدامها وفائدتها وكيفية تنظيم عملية التعديل على الـ Database
بشكل جيد
المقالة قصيرة لأنني لم أرد أن أطيل عليكم مثل كل مرة لذا يكفي أننا فهمنا الفكرة العامة للـ Migration
وكيفية استخدامها
وفهمنا فائدتها وكيفية تنظيم عملية التعديل على الـ Database
بشكل جيد ومنظم وكيفية تطبيق التعديلات على الـ Server
بشكل تلقائي
وعند الآخرين بكل بساطة