أين تعيش القواعد فعلاً
ما الجزء من منطق أعمال تطبيق Oracle Forms الذي يعيش فعلاً في نوع محفز واحد؟ عبر 2,400 ملف .fmb حللناها، الإجابة هي 38%. محفزات WHEN-VALIDATE-ITEM هي أكبر مجموعة منفردة من PL/SQL المُضمَّن في معظم تطبيقات Forms — أكثر من جميع محفزات مستوى النموذج وأجسام الحزم ووحدات المكتبة مجتمعة. كتبنا بشكل منفصل عن ما هو فعلاً داخل ملف .fmb؛ يُركز هذا المنشور على المحفزات التي تحمل الجزء الأكبر من المنطق. كان لدى شركة تأمين عملنا معها 9,700 منها في نظام إدارة بوليصة نُشر لأول مرة في 2001.
تعيش الهجرات أو تموت بناءً على كيفية ترجمة هذه المحفزات.
كان أحد مشاريع Oracle الأولى لي في عام 2004 عبارة عن واجهة أمامية لفوترة اتصالات بولندية مع WHEN-VALIDATE-ITEM على رمز خطة المشترك الذي أجرى بحث جدول مشترك بالإضافة إلى استدعاء فحص ائتمان. عمل بشكل مثالي لأربع سنوات، حتى أضاف شخص ما مسافة لاحقة إلى قيمة مرجعية وبدأ المحفز في رفض كل عقد جديد بصمت صباح الاثنين. قدت 200 كيلومتر إلى موقع العميل لأشاهدهم يُعيدون إنتاج الخطأ شخصياً، لأن لا أحد يُصدق أنها لم تكن الشبكة. كان السبب الجذري هو RTRIM مفقود. لم أكتب مقارنة سلسلة دون تطبيع منذ ذلك الحين.
ما يُفترض أن يفعله WHEN-VALIDATE-ITEM
يُشغَّل المحفز عندما يفقد العنصر التركيز وقيمته قد تغيرت. وظيفته هي تحديد ما إذا كانت القيمة الجديدة مقبولة. إذا لم تكن، يرفع FORM_TRIGGER_FAILURE، والذي يُعيد التركيز إلى العنصر ويعرض رسالة. تختلف القواعد — فحوصات النطاق، والتبعيات بين الحقول، وعمليات البحث في قاعدة البيانات، والحدود التنظيمية.
-- Typical WHEN-VALIDATE-ITEM
IF :POLICY.COVERAGE_AMOUNT > 1000000
AND :POLICY.UNDERWRITER_LEVEL < 3 THEN
MESSAGE('Coverage above 1M requires senior underwriter');
RAISE FORM_TRIGGER_FAILURE;
END IF;
هذا المثال من أربعة أسطر يلمس عنصري نموذج، وعتبة مُرمَّزة ثابتة، ورسالة عرض. إنه تمثيلي. محفز WHEN-VALIDATE-ITEM المتوسط في عينتنا هو 11 سطراً. الشريحة الـ 95 هي 84.
هدف الترجمة
الشكل المستهدف لدينا هو دالة مُعتمِد TypeScript نقية تأخذ حالة النموذج الحالية وتُعيد إما null أو كائن خطأ. لا آثار جانبية، ولا وصول إلى DOM، ولا استدعاءات قاعدة بيانات مباشرة من المُعتمِد نفسه.
export const validateCoverageAmount: Validator<PolicyForm> = (state) => {
if (state.coverageAmount > 1_000_000 && state.underwriterLevel < 3) {
return { field: "coverageAmount",
message: "Coverage above 1M requires senior underwriter" };
}
return null;
};
تنتقل عمليات البحث في قاعدة البيانات إلى مُعتمِدات غير متزامنة تستدعي نقطة نهاية REST مُولَّدة. يبقى المُعتمِد نقياً؛ تمتلك نقطة النهاية الوصول إلى البيانات. هذا الانقسام هو القرار الأهم في الترجمة — إنه ما يجعل القواعد قابلة للاختبار والتخزين المؤقت والتدقيق. الشكل العام لـ ما يتغير وما يبقى كما هو عندما يصبح PL/SQL هو TypeScript ينطبق هنا أيضاً: ينجو منطق الأعمال ميكانيكياً، فقط وقت التشغيل يتغير.
التعامل مع الحالات الفوضوية
ليس كل محفز هو أربعة أسطر نظيفة. فهرسنا خمسة أنماط تُقاوم الترجمة الساذجة:
- الالتزامات الضمنية. المحفزات التي تستدعي
COMMITفي منتصف الاعتماد. تُعاد هيكلة هذه إلى خطوات حفظ صريحة. القائمة الكاملة لنقاط الالتزام غير المرئية والطريقة التي تتفاعل بها مع محفزات قاعدة البيانات مُغطاة في مقالنا حول محفزات قاعدة البيانات وحالة الحزمة. - المتغيرات العامة. الإشارات إلى
:GLOBAL.xyzالتي تُخزن حالة الجلسة عبر النماذج. تُصبح هذه مخزن جلسة مُكتَّب. - استدعاءات DO_KEY. المحفزات التي تُعيد تشغيل أحداث التنقل. تصبح هذه انتقالات حالة صريحة.
- SQL الديناميكي. استدعاءات
FORMS_DDLوEXEC_SQL. تُوسم هذه للمراجعة البشرية — حوالي 6% من المحفزات تقع هنا. - المراجع بين النماذج. قراءة العناصر من نموذج مفتوح آخر. تصبح هذه كائنات سياق ذات نطاق جلسة.
تقع حوالي 91% من محفزات WHEN-VALIDATE-ITEM في أنماط نظيفة تترجم تلقائياً. الـ 9% المتبقية تحتاج إلى مراجعة. معرفة أي 9% قبل بدء المشروع هو الفرق بين جدول زمني يمكن التنبؤ به وانزلاق ربع سنوي.
الحفاظ على الدلالات التي لا يستطيع المترجم رؤيتها
أصعب القواعد هي تلك التي تعتمد على نموذج تنفيذ Oracle Forms. يُشغَّل WHEN-VALIDATE-ITEM فقط عندما يتغير العنصر — ليس في كل حفظ، ولا في نتائج الاستعلام، ولا في التعيين البرمجي. الخطأ في هذا يعني أن المُعتمِدات تُشغَّل بشكل متكرر جداً وتكسر سير العمل الذي كان يعمل.
نعكس دلالات Forms صراحةً. يتتبع وقت تشغيل المُعتمِد حالة متسخة لكل حقل، ويقمع الاعتماد أثناء تعبئة الاستعلام، ويحترم التسلسل الهرمي الأصلي للمحفز (العنصر، الكتلة، النموذج). القاعدة المُترجَمة متطابقة؛ وقت التشغيل الذي يستدعيها هو ما يُطابق السلوك.
اختبار الترجمة
يحصل كل مُعتمِد مُهاجَر على اختبارين تلقائياً: واحد مُولَّد من تدفق التحكم PL/SQL الأصلي، وواحد مُلتقَط من حركة المرور الإنتاجية مقابل النظام القديم. الثاني يهم أكثر. نُعيد تشغيل ستة أشهر من تقديمات النماذج الحقيقية من خلال كل من المُعتمِدات القديمة والجديدة ونُقارن النتائج. أي انحراف هو عيب.
في المشاريع الأربعة الأخيرة، التقط هذا التكرار بين 14 و71 عيباً لكل 1,000 محفز — كلها تقريباً في أنماط الحالات الفوضوية أعلاه.
الخلاصة
WHEN-VALIDATE-ITEM هو المكان الذي تعيش فيه 25 عاماً من المعرفة المؤسسية. ترجمتها إلى TypeScript ليست تمريناً نحوياً — إنها تمرين دلالي، وتعتمد الدلالات على نموذج تنفيذ Forms بقدر ما تعتمد على الكود نفسه. الهجرات التي تحافظ على قواعد الأعمال بنظافة هي تلك التي تفصل الاعتماد النقي عن الوصول إلى البيانات، وتعكس نموذج التنفيذ الأصلي، وتُعيد تشغيل حركة المرور الحقيقية قبل التحويل. هذا الحفاظ الميكانيكي هو الحجة الكاملة وراء الهجرة المنظمة كطريق ثالث بين إعادة الكتابة اليدوية وترجمة الكود.