تطوير برمجيات مخصّصة
برمجيات مخصّصة بـ Next.js و PostgreSQL
ما يغيّره اختيار PostgreSQL في بناء Next.js - الضمانات التي يفرضها، والبحث الذي لم يبقَ له حاجة لخدمة، والفخّ الذي يقع فيه كل فريق مرة.
اختيار PostgreSQL لبناء مخصّص له نتائج محدّدة، وهي تستحق أن تُقال لا أن تُفترض. وهو الخيار الافتراضي في هذه المشاريع لا قاعدة، والسبب أنه ينقل العمل من التطبيق إلى مكان لا يمكن تجاوزه.
ضمانات لا يستطيع التطبيق نسيانها
أقوى حجّة لقاعدة بيانات علائقية في البرمجيات المخصّصة لا علاقة لها بالأداء.
التطبيق يكتبه عدة أشخاص على مدى سنوات، ولن يعرف جميعهم القواعد. والضمان المفروض في كود التطبيق يصمد في المسارات التي تذكّرها أحد - لا في سكربت الاستيراد ولا أمر الكونسول ولا المهمة المجدولة ولا شاشة الإدارة التي تُضاف في الربيع القادم.
أما الضمان المفروض في قاعدة البيانات فيصمد في كلها. المفتاح الأجنبي يعني أن أمرًا لا يستطيع الإشارة إلى عميل غير موجود. وقيد التفرّد يعني أن طلبين متزامنين لا يستطيعان إنشاء السجل نفسه، وهذا ما لا يحقّقه أي قدر من التحقّق-ثم-الإدراج في الكود. وقيد التحقّق يعني أن الكمية لا يمكن أن تكون سالبة في الصف لا في النموذج فقط.
ويمضي PostgreSQL أبعد من أكثرها على نحو يهمّ التطبيقات الحقيقية. فقيد الاستبعاد يستطيع رفض حجز يتقاطع نطاق تاريخه مع حجز قائم للمورد نفسه - وهو تنازع يصعب فعلًا إغلاقه في الكود ويسهل إغلاقه هنا. والفهارس الجزئية تفهرس الصفوف المهمة وحدها، فلا يدفع استعلام على السجلات النشطة ثمن الأرشيف.
ما يحذفه ذلك من الكود
كل واحد من تلك القيود كود تحقّق لا تكتبونه ولا تختبرونه ولا تحتاجون تذكّره عند إضافة سابع طريقة لإنشاء سجل.
وهو أيضًا الفرق بين خطأ مستحيل وخطأ غير مرجّح. وفي نظام يتعامل مع المال أو المخزون أو المواعيد، هذا الفرق هو المسألة كلها.
JSONB، وأين الخط
بعض البيانات تقاوم المخطّط فعلًا. حمولة webhook من طرف ثالث. نموذج يهيّئ العميل حقوله. إعدادات لكل عميل تختلف بين عميل وآخر.
وPostgreSQL يعامل ذلك بصدق: يُخزَّن JSONB بكفاءة ويُستعلَم بمعاملات حقيقية ويُفهرَس بـ GIN، فتكون البيانات غير المبنيّة خيارًا من الدرجة الأولى لا حلًّا ملتويًا.
والخط الذي يستحق الحفاظ عليه أن كل ما تُصفّون به أو ترتّبون أو تقرّرون أو تربطون أو تقيّدون يأخذ عمودًا. ونمط الفشل معروف وبطيء - يصير عمود JSON مكان الحقول الجديدة لأن إضافة ترحيل بدت ثقيلة، وبعد سنتين لا يستطيع أحد الإجابة عن سؤال حول البيانات دون قراءة الكود.
البحث، بلا نظام ثانٍ
قسم كبير من التطبيقات يضيف خدمة بحث وخط مزامنة واعتمادًا تشغيليًا ليفعل شيئًا تستطيع قاعدة البيانات فعله أصلًا.
والبحث في النص الكامل في PostgreSQL فيه تجذير وترتيب وتهيئات لعدة لغات، ويُفهرس جيدًا. ومع بضع مئات آلاف السجلات يكون سريعًا، وله ميزة كبيرة هي أن نتائج البحث لا يمكن أن تكون قديمة، لأنه لا شيء يُزامَن.
وحيث ينتهي أمر حقيقي يستحق الذكر - احتمال الأخطاء المطبعية، وضبط الصلة على نطاق واسع، والبحث المتعدّد الأوجه في ملايين المستندات. والوصول إلى تلك النقطة قياس لا تنبؤ، والوصول إليها لاحقًا أرخص بكثير من تشغيل عنقود بحث من الأسبوع الأول لمجموعة بيانات لم تحتجه يومًا.
الفخّ الواحد، وكيف يُعالَج
كل فريق يلقاه مرة. تطبيق Next.js على بيئة بلا خوادم يفتح اتصالًا بقاعدة البيانات لكل نسخة، وPostgreSQL يقبل عددًا ثابتًا. وتحت الزيارات لا يصير التطبيق أبطأ - بل يبدأ برفض الاتصالات، وهذا يُقرأ كفشل قاعدة بيانات وهو خطأ في الإعداد.
والجواب وسيط تجميع اتصالات بين التطبيق وقاعدة البيانات، والجزء الذي يُوقع الناس أن التجميع بنمط المعاملة لا يتوافق مع العبارات المُحضَّرة إلا إذا هُيّئ العميل لذلك. تجميع الاتصالات في بيئة بلا خوادم هو الشرح الكامل.
ويُحسَم ذلك في الأسبوع الأول في هذه الأعمال، وهو الفرق بين قيد معروف وحادثة.
كيف يسير العمل
على مراحل، كل واحدة تُثبَّت كتابةً قبل بدئها وتنتهي بشيء منشور تستطيعون استخدامه. والمرحلة الأولى تأخذ مسارًا واحدًا من أوله إلى آخره بدل مخطّط عدة مسارات، لأن ذلك ما يحسم المخطّط على بيانات حقيقية.
وقرارات قاعدة البيانات تُتخذ في تلك المرحلة الأولى لا بعدها. أي القيود تُفرض وأين، وما هو عمود وما هو JSONB، وكيف تعمل الترحيلات على جدول سيكبر لاحقًا، وما ترتيب التجميع. لا واحد منها مكلف مبكرًا، وكلها مكلفة التغيير بعد وجود بيانات إنتاج وراءها.
ما تحصلون عليه
تطبيق منشور في نهاية كل مرحلة، والمستودع بتاريخه سليمًا، والمخطّط ترحيلاتٍ لا حالةً راهنة - فيكون لقاعدة البيانات تاريخ يمكن إعادة تشغيله ومراجعته.
ومعه: ملاحظة مكتوبة عن نموذج البيانات ولماذا هو بهذا الشكل، والفهارس ولماذا كل واحد منها، وإعداد التجميع، والقيود مع سطر لكل واحد يوضح ما يمنعه. وهذا الأخير هو الوثيقة التي يعود إليها الناس فعلًا، لأن قيدًا لا يفهمه أحد قيدٌ يُزيله أحد في النهاية.
متى لا يكون PostgreSQL هو الجواب
إن كان التطبيق طبقة رقيقة فوق واجهة طرف آخر ولا يحفظ حالةً خاصة به تقريبًا، فأنتم تشغّلون مكوّنًا بلا سبب - ومخزن أبسط هو الجواب الأفضل.
وإن كان الحمل في حقيقته ذاكرة مؤقتة أو طابورًا، فليكن ذاكرة مؤقتة أو طابورًا. يستطيع PostgreSQL كليهما بشكل مقبول، وليس مصنوعًا لأي منهما.
وإن كانت البيانات قياسات عالية الحجم تُضاف فقط - قراءات حسّاسات أو قياسات عن بعد بحجم كبير - فسيستوعب جدول علائقي قدرًا مفاجئًا منها، لكن هناك نقطة يفوز بعدها مخزن مصمّم لذلك. وتلك النقطة ينبغي أن تُثبَت بالقياس لا بافتراض أنها بلغت.
