SaaSLaravelFastCaisseالبنية البرمجية

ما تعلّمته من بناء برمجيات لمطابخ مطاعم حقيقية

العمل على نظام FastCaisse من نقطة البيع إلى الكشك ومنصة الطلب أونلاين علّمني أن برمجيات المطاعم لا تتعلق بالميزات بقدر ما تتعلق بألا تنهار وقت ذروة عشاء يوم الجمعة.

عزّام عزيز علي··8 دقيقة قراءة

قضيت جزءًا كبيرًا من السنوات الماضية في العمل على FastCaisse، وهو نظام للمطاعم يشمل نقطة البيع على الكاونتر، وكشك الطلب الذاتي، والطلب أونلاين، والربط مع منصات التوصيل مثل Deliveroo وUber Eats. أغلب عملائنا مطاعم في بلجيكا.

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

هذه بعض الأشياء التي غيّرت طريقتي في بناء البرمجيات.

1. الشبكة ستنقطع، فخطّط لذلك

الـ Wi-Fi في المطاعم سيئ. مشترك مع الزبائن، والراوتر خلف البرّاد، وأحدهم يطفئه "ليصلح الإنترنت". إذا توقفت نقطة البيع عن العمل عند انقطاع الاتصال، لا يستطيع المطعم أخذ الطلبات. وهذا مال حقيقي يضيع كل دقيقة.

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

2. كل طلب يحتاج مفتاح idempotency

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

الآن كل طلب يُنشأ بمفتاح يُولَّد على جهاز العميل. إذا وصل المفتاح نفسه مرتين، يعيد الـ backend الطلب الموجود بدل إنشاء طلب جديد. التغيير صغير في Laravel: فهرس unique على العمود، وبحث قبل الإدخال. لكنه أزال نوعًا كاملًا من شكاوى "لماذا طبخنا هذا مرتين".

والـ webhooks القادمة من منصات التوصيل تحتاج المعاملة نفسها. ستُرسل لك الحدث نفسه أكثر من مرة.

3. أخطاء تعدد المستأجرين هي الأخطر

منصة الطلب أونلاين تخدم مطاعم كثيرة من كود واحد وقاعدة بيانات واحدة. كل استعلام يجب أن يكون مقيّدًا بالمطعم الصحيح. انسَ ذلك مرة واحدة، وسيرى المطعم A طلبات المطعم B.

لا أثق بنفسي لأتذكر where('restaurant_id', ...) في كل استعلام، لذلك يتم التقييد عبر global scope على الـ models، ويُضبط من سياق الطلب مبكرًا في الـ middleware. كتابة استعلام غير مقيّد يجب أن تكون قرارًا مقصودًا، لا سهوًا.

4. الدفع آلة حالات، وليس قيمة صح/خطأ

النسخة الأولى عندي كان فيها عمود is_paid. صمد حوالي أسبوع.

مع Stripe وMollie، يمكن أن تكون الدفعة معلّقة، أو مُصرّحًا بها، أو مدفوعة، أو فاشلة، أو منتهية، أو ملغاة، أو مستردة جزئيًا، أو مستردة بالكامل... والـ webhook الذي يخبرك بذلك قد يصل قبل عودة الزبون إلى موقعك أو بعدها. التعامل مع الدفع كآلة حالات حقيقية، مع انتقالات مسموحة وسجل لكل تغيير، جعل الكود أطول لكن تتبّع الأخطاء أسهل بكثير عندما يحدث خلل.

وسيحدث خلل. غالبًا يوم السبت.

5. تجربة المستخدم في الكشك علم قائم بذاته

الكشك مبني بـ Next.js ويعمل على شاشات لمس كبيرة. أشياء لم أتوقعها:

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

6. تحدّث مع من يستخدمون النظام

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

لن ترى هذا من خلف مكتبك.

ما كنت سأقوله لنفسي في البداية

ابنِ لليوم السيئ، لا للعرض التجريبي. افترض أن الشبكة ستنقطع، وأن الطلبات ستصل مرتين، وأن الـ webhooks ستصل بترتيب خاطئ، وأن المستخدمين مستعجلون. إذا صمد نظامك في هذه الظروف، فالأيام الجيدة ستتدبّر نفسها.