فيه جملة بتتقال في كل فريق برمجة وبتوقف الشغل نص يوم: «بس هو شغال عندي». الجملة دي مش سوء حظ ولا مزاج من السيرفر — دي نتيجة متوقعة لمشروع مافيهوش اتفاق مكتوب على النسخ والإعدادات والبيانات. والحلو في الموضوع إن الاتفاق ده تلات ملفات وأمر واحد، والفريق اللي بيمشي عليهم مابيقعش في الجملة دي أصلًا.
الحتة اللي بتضيع: ملف القفل
composer.json بيقول إيه اللي انت موافق عليه. composer.lock بيقول إيه اللي انت مركّبه فعلًا.
{
"require": {
"php": "^8.3",
"laravel/framework": "^12.0"
}
}
^12.0 معناها «أي نسخة 12 مهما كانت»، فممكن انت مركّب 12.4 وزميلك ركّب المشروع الشهر اللي بعده وجابت له 12.19. الاتنين موافقين نفس الشرط والاتنين عندهم كود مختلف. composer.lock بيسجّل الرقم بالظبط — النسخة الدقيقة لكل حزمة ولكل حزمة تابعة ليها.
عشان كده: composer.lock بيتحفظ في المستودع. مش استثناء ولا ملف مؤقت. ده ملف المشروع اللي بيخلي جهازك وجهاز زميلك وسيرفر الإنتاج شايفين نفس الكود بالحرف.
الأمرين اللي الناس بتخلط بينهم
composer install— بيقرا ملف القفل ويركّب النسخ المكتوبة فيه بالظبط. ده اللي انت بتعمله في 95% من المرات.composer update— بيتجاهل القفل، ويحل الشروط من أول وجديد، ويكتب قفل جديد.
يعني لما تعمل composer update عشان تركّب حزمة جديدة، انت مش بتضيف حزمة — انت بتحدّث كل حاجة في المشروع في نفس اللحظة. لو عايز حزمة واحدة بس:
composer require spatie/laravel-permission
ولو عايز تحدّث حزمة بعينها:
composer update spatie/laravel-permission --with-dependencies
القاعدة اللي بنمشي عليها: composer update قرار فريق، بيتاخد في وقت مخصص وبيتعمل معاه اختبار — مش حاجة حد يعملها الساعة اتنين بالليل عشان لقى خطأ.
اختلاف نسخة PHP بين الأجهزة
لو انت على PHP 8.4 وسيرفر الإنتاج على 8.3، Composer ممكن يركّب لك حزمة محتاجة 8.4 وتقع عند النشر. قول له يحل الشروط على نسخة الإنتاج مهما كان اللي عندك:
{
"config": {
"platform": {
"php": "8.3.0"
}
}
}
وعلى سيرفر الإنتاج نفسه، الأمر بيبقى:
composer install --no-dev --optimize-autoloader
--no-dev بيشيل أدوات التطوير زي بيئة الاختبار ومحلّلات الكود — دي مالهاش لازمة في الإنتاج، وكل حزمة زيادة هناك هي سطح هجوم زيادة.
الملف التاني: البيئة
.env فيه مفتاح التطبيق وبيانات قاعدة البيانات ومفاتيح الخدمات الخارجية. الملف ده مايدخلش المستودع أبدًا، وهو مستبعد افتراضيًا في لارافيل. اللي بيدخل المستودع هو .env.example.
خلّي بالك إن .env.example مش نسخة قديمة من ملفك — ده عقد بين أعضاء الفريق: أي مفتاح جديد تحتاجه في الكود، لازم يتضاف في .env.example بقيمة فاضية أو قيمة تجريبية في نفس اللحظة. الفريق اللي بينسى ده بيقضي نص يومه في «انت ناقصك المفتاح الفلاني».
وفيه قاعدة واحدة لو خالفتها هيتكسر عندك في الإنتاج بس ويشتغل عندك تمام: ماتنادي env() في أي مكان غير ملفات config/. السبب إن php artisan config:cache في الإنتاج بيخزّن الإعدادات كلها في ملف واحد، وبعدها env() بترجّع null في أي مكان تاني. الشكل الصح:
// config/services.php
return [
'whatsapp' => [
'token' => env('WHATSAPP_TOKEN'),
],
];
// وفي الكود، دايمًا كده
$token = config('services.whatsapp.token');
الملف التالت: الهجرات
الهجرات هي نظام إصدارات مخطط قاعدة البيانات. لو زميلك ضاف عمود وانت عملت git pull وشغّلت php artisan migrate، جدولك بقى زي جدوله. ده الاتفاق.
وفيه قاعدتين بتحافظوا على الاتفاق ده:
- ماتعدّلش هجرة اتنشرت خلاص. انت لو غيّرت ملف هجرة زميلك شغّله من أسبوع، جهازه مش هيشغّله تاني وهيفضل مختلف عنك للأبد. عايز تغيّر عمود؟ اعمل هجرة جديدة تعدّله.
migrate:freshممنوعة على أي بيئة فيها بيانات حقيقية. الأمر ده بيمسح كل الجداول. على جهازك عادي. على الإنتاج دي كارثة مالهاش رجوع، وفي الإنتاج بنستخدمphp artisan migrate --forceوبس.
والبيانات التجريبية المشتركة مكانها الـ seeders، مش «هبعتلك ملف SQL على واتساب». لما البذور تبقى في المستودع، أي واحد جديد في الفريق بيبقى عنده نفس البيانات اللي بتتكلموا عنها.
النتيجة: خمس دقايق بدل نص يوم
المشروع اللي ماشي بالكلام اللي فوق بيتشغّل عند أي حد بالخطوات دي، وبس:
git clone <repo> && cd <repo>
composer install
cp .env.example .env
php artisan key:generate
php artisan migrate --seed
php artisan serve
حط الست سطور دول في README.md بتاع المشروع. لو حد اشتغل بيهم وماشتغلش عنده، يبقى فيه خطوة انت عاملها على جهازك ومش مكتوبة — وده بالظبط اللي كان هيبقى «بس هو شغال عندي» بعد شهرين.
وقبل ما تقفل: النظافة الآلية
الفريق اللي بيتخانق على المسافات البادئة في مراجعة الكود بيضيّع وقته. سيبها لأداة:
composer require --dev laravel/pint
./vendor/bin/pint --test
--test بيقول لك الملفات المخالفة من غير ما يعدّلها — وده اللي بيتحط في التحقق الآلي قبل الدمج، فالمراجعة تبقى على المنطق مش على الشكل.
الخطوة الجاية
افتح أي مشروع شغال عليه دلوقتي، واسأل نفسك تلات أسئلة: هل composer.lock محفوظ في المستودع؟ هل .env.example فيه كل مفتاح الكود بيقراه؟ وهل الـ README فيه خطوات تشغيل حد جديد يقدر يمشي عليها من غير ما يسألك؟ لو إجابة واحدة منهم «لأ»، انت عندك «بيشتغل عندي» مستنية تحصل.
إحنا في أكاديمية أنوبت بنبدأ المستوى التاني من الباك إند بالشغل ده بالذات — استراتيجية الفروع وطلبات الدمج ومراجعة الكود والبذور الواقعية — قبل ما نكتب أي ميزة، لأن ده اللي بيفرق بين واحد بيبرمج وواحد بيشتغل في فريق. تقدر تشوف الترتيب كامل في [كورس الباك إند — المستوى التاني](/courses/back-end-2)، ولو لسه بتبني أول واجهة برمجية ليك ابدأ من [أول API بلارافيل](/blog/laravel-first-api).