المنطق الذي يعيش خارج النماذج
داخل كل ملكية Oracle Forms تقريباً يجلس بناء محدد يُسمى متغير حالة الحزمة — قيمة شبه عامة تعيش في جسم حزمة PL/SQL وتستمر عبر الاستدعاءات داخل جلسة ولكن ليس عبر الجلسات. لن تجده في أي ملف .fmb. لن تراه في مصدر النموذج على الإطلاق. لن يظهر في تقدير الترحيل. عندما تُعيد خلفية TypeScript الجديدة استجابات عديمة الحالة لنفس العملية المنطقية، يصبح ذلك المتغير السبب الهادئ وراء بدء نصف قواعد العمل في إنتاج الإجابة الخاطئة. كانت لدى شركة تداول طاقة قمنا بتقديرها الربيع الماضي 96 منها مشتركاً عبر 184 نموذجاً. احتوى جانب قاعدة البيانات على 2.7 ضعف كود النماذج نفسها.
هذه النسبة نموذجية. النماذج هي القمة. الجبل الجليدي في قاعدة البيانات.
عُدت إلى عام 2011، تم استدعائي إلى عميل تصنيع في اليوم التالي لنشر ما اعتقد الجميع أنه وحدة تقارير بسيطة. خلال ساعات، بدأت أرقام المخزون عبر ثلاثة مصانع في الانحراف ببضع وحدات كل معاملة. قضينا عطلة نهاية أسبوع كاملة في مطاردتها، وتبين أن الجاني هو مُشغّل AFTER UPDATE على جدول المخزون يتسلسل عبر أربعة مُشغّلات أخرى قبل أن يستقر في حزمة تدقيق. كانت أداة التقارير الجديدة تُصدر UPDATE إضافياً يبدو غير ضار لتحديث علامة حالة، مما أشعل السلسلة بأكملها. أعدت كتابة قائمة تحقق تحليل التبعيات الخاصة بي على متن الطائرة في طريق العودة.
مُشغّلات قواعد البيانات ليست مُشغّلات النماذج
تُشغَّل مُشغّلات النماذج استجابةً لأحداث واجهة المستخدم. مُشغّلات قواعد البيانات، كما هي موثّقة في مرجع PL/SQL الخاص بـ Oracle، تُشغَّل استجابةً لـ DML — INSERT، UPDATE، DELETE — وتعمل داخل المعاملة التي أصدرت البيان. تفرض قواعد المرجعية، وتملأ أعمدة التدقيق، وتتسلسل الحذف، وتُشغّل منطق العمل الذي تفترض النماذج أنه سيحدث تلقائياً.
مُشغّل تدقيق تمثيلي:
CREATE OR REPLACE TRIGGER orders_audit_trg
AFTER INSERT OR UPDATE OR DELETE ON orders
FOR EACH ROW
BEGIN
INSERT INTO orders_audit (order_id, action, changed_by, changed_at,
old_amount, new_amount)
VALUES (COALESCE(:NEW.order_id, :OLD.order_id),
CASE WHEN INSERTING THEN 'I'
WHEN UPDATING THEN 'U' ELSE 'D' END,
USER, SYSDATE, :OLD.amount, :NEW.amount);
END;
عمليات الترحيل التي تنتقل إلى طبقة تطبيق جديدة غالباً ما تفترض أنها تستطيع استبدال هذا بتسجيل تدقيق على مستوى التطبيق. يتحطم هذا الافتراض في اللحظة التي تُعدّل فيها وظيفة مجمّعة أو نص SQL*Plus أو كاتب تقرير الجدول نفسه. التقط مُشغّل قاعدة البيانات جميع الكتّاب. يلتقط مُسجّل التطبيق واحداً فقط.
حالة الحزمة هي عقد خفي
يمكن لـ حزم PL/SQL في Oracle الاحتفاظ بحالة محدودة النطاق بالجلسة: متغيرات مُعلنة على مستوى الحزمة تستمر عبر الاستدعاءات داخل نفس جلسة قاعدة البيانات. تستخدم تطبيقات Forms هذا بكثرة — يسجّل المستخدم الدخول، تُشغّل الجلسة إجراء تسجيل الدخول، وتُملأ 40 متغيراً من متغيرات الحزمة بمعرف المستخدم، والدور، ومركز التكلفة، والتقويم المالي، وحدود الموافقة. تقرأ كل استدعاء نموذج لاحق من تلك الحالة دون إعادة تحميلها.
لقد أحصينا بين 20 و180 متغير حالة حزمة لكل تطبيق Forms. الوسيط هو 58. لا شيء منها مرئي في ملفات .fmb. ولا شيء منها ينجو من بنية REST عديمة الحالة دون إعادة نمذجة صريحة.
المزالق الأربع التي نراها بشكل متكرر
عبر 14 مشروع ترحيل، تمثّل نفس المشكلات الأربع معظم تأخرات الجدول الزمني على جانب قاعدة البيانات:
- نقاط الالتزام غير المرئية. تُصدر النماذج عمليات commit ضمنية على التنقل بين الكتل. تفترض مُشغّلات قواعد البيانات حدوث هذه الالتزامات. تكسر نقاط نهاية REST التي تجمع عمليات متعددة في معاملة واحدة افتراضات المُشغّل.
- انحراف حالة الجلسة. متغيرات الحزمة المُملوءة عند تسجيل الدخول تصبح قديمة عندما تُجمع البنية الجديدة اتصالات قاعدة البيانات. يخدم نفس الاتصال مستخدمين مختلفين عبر الطلبات.
- تسلسلات المُشغّل. UPDATE واحد يُطلق مُشغّلاً يُصدر UPDATE آخر يُطلق مُشغّلاً آخر. عمق التسلسل في عينتنا يصل إلى 7. تفوت البدائل على مستوى التطبيق الخطوات الوسيطة.
- تسريبات REF cursor. تُعيد الإجراءات المُخزّنة REF cursors التي تستهلكها النماذج صفاً بصف. يجب أن تجسّد نقطة نهاية REST مجموعة النتائج الكاملة، مما يُغيّر خصائص الذاكرة ويُطلق أحياناً ORA-04030 على الاستعلامات الكبيرة.
كل واحدة منها قابلة للإصلاح. لا شيء منها واضح من قراءة ملفات .fmb وحدها.
ما يجب أن يلتقطه تحليل التبعيات
قبل كتابة سطر من كود الترحيل، نستخرج رسم التبعيات الكامل: كل جدول، وعرض، وحزمة، وإجراء، ووظيفة، ومُشغّل، وتسلسل تلمسه النماذج، بالإضافة إلى كل ما تلمسه هذه الكائنات بدورها. يتراوح الرسم لتطبيق متوسط الحجم من 4,000 إلى 12,000 عقدة.
الرسم هو ما يخبرنا ما إذا كان يمكن استبدال حالة الحزمة بمخزن جلسة مُكتّب، وما إذا كانت مُشغّلات قاعدة البيانات يمكن تركها في مكانها، أو ما إذا كان منطق التدقيق يجب إعادة كتابته في طبقة التطبيق. تخطي هذه الخطوة هو الخطأ الأكثر تكلفة في ترحيل Oracle Forms. رأيناه يضيف ستة إلى تسعة أشهر لمشاريع بدت نظيفة في اليوم الأول.
ترك مُشغّلات قاعدة البيانات في مكانها
توصيتنا الافتراضية هي الحفاظ على تشغيل مُشغّلات قاعدة البيانات أثناء وبعد الترحيل. إنها مُختبرة في المعركة، وتلتقط الكتّاب غير التطبيقيين، وهي بالفعل في مصفوفة تحكم المدققين. إذا انتقل المشروع في النهاية من Oracle، فإن وثائق مُشغّل PostgreSQL تُظهر أن نفس نمط التحكم يُنقل بشكل نظيف إلى قواعد البيانات مفتوحة المصدر. يستدعي تطبيق TypeScript الجديد الإجراءات المُخزّنة للمعاملات المعقدة بدلاً من إعادة تنفيذ المنطق.
هذا ليس ممكناً دائماً — بعض المُشغّلات تستدعي DBMS_ALERT، أو UTL_HTTP، أو ميزات أخرى يجب إعادة كتابتها — ولكن عندما يكون كذلك، فإنه يُزيل فئة كاملة من مخاطر الترحيل. تستمر قاعدة البيانات في فرض ما كانت تفرضه دائماً. تتغير طبقة التطبيق حولها.
الخلاصة
عمليات ترحيل Oracle Forms هي عمليات ترحيل قواعد بيانات متنكّرة بواجهة مستخدم. ملفات .fmb هي السطح المرئي؛ العقد الحقيقي هو حزم PL/SQL، ومُشغّلات قاعدة البيانات، وحالة الحزمة التي اعتمدت عليها النماذج لعقود. كل مشروع شحنّاه في الوقت المحدد بدأ بتحليل تبعيات كامل لجانب قاعدة البيانات — قبل أن يفتح أي شخص نموذجاً. كل مشروع تأخر تخطّى هذه الخطوة.