تبدو معالجة الملفات في لغة كوبول بسيطة ظاهريًا، لكنها خادعة. تُعرّف الملف في قسم البيئة، وتصف بنية سجلاته في قسم البيانات، وتستخدم أوامر الفتح والقراءة والكتابة، ثم أمر الإغلاق في قسم الإجراءات. أربعة أوامر، دورة حياة واحدة. تكمن المشكلة في أن برامج كوبول نادرًا ما تبقى بسيطة، إذ تتراكم فيها المنطق، ومسارات الاستثناءات، والفروع الشرطية، واستدعاءات أمر التنفيذ على مدى عقود من الصيانة. ما يبدأ كنمط فتح وإغلاق بسيط يتحول تدريجيًا إلى شيء أكثر تعقيدًا: ملفات تُفتح مرتين في مسار تنفيذ واحد، وعبارات إغلاق تُنفذ حتى في غياب أي ملف مفتوح، وخروج بسبب أخطاء يتجاوز أمر الإغلاق تمامًا.
لا تظهر أي من هذه المشاكل فورًا. يُجمَّع البرنامج بنجاح، وغالبًا ما يعمل دون أخطاء على المدخلات التي تختبرها. لكنه يفشل بصمت عند استخدام تركيبات مدخلات لم تتوقعها أبدًا، أو يُضعف أداء نافذة المعالجة الدفعية تدريجيًا لدرجة أن لا أحد يربط السبب بالنتيجة. يكشف التحليل الثابت هذه المشاكل قبل حدوث أي من ذلك.
كشف التسربات بجميع اللغات
SMART TS XL يرسم سلاسل المراجع طويلة الأمد وهياكل البيانات غير المحدودة عبر قاعدة التعليمات البرمجية الكاملة الخاصة بك.
المزيد من المعلوماتعيوب حالة الملفات الأربعة التي تستحق البحث عنها
قبل الخوض في آليات الكشف، إليك تصنيف واضح لما تبحث عنه. ليست كل مشاكل ملفات COBOL متساوية.
| خلل | ما يحدث أثناء التشغيل | خطورة |
|---|---|---|
| مفتوح مزدوج | فتح ملف مفتوح مسبقًا ← حالة الملف 41 أو توقف غير طبيعي | مرتفع |
| يُغلق دون فتح مسبق | إغلاق ملف لم يتم فتحه مطلقًا ← حالة الملف 42 أو إنهاء غير طبيعي | مرتفع |
| لا يوجد زر إغلاق عند المخرج العادي | ترك الملف مفتوحًا عند إيقاف التشغيل ← يقوم نظام التشغيل بإغلاقه، ولكن قد يؤدي عدم مسح المخازن المؤقتة إلى فقدان البيانات | متوسط |
| تم حذف أمر الإغلاق (CLOSE) عند الخروج بسبب خطأ. | توقف البرنامج بشكل غير طبيعي أثناء فتح الملف ← احتمال تلف السجلات في ملفات VSAM | مرتفع |
| فتح/إغلاق متكرر في حلقة | يتم فتح الملف وإغلاقه في كل تكرار ← زيادة كبيرة في عمليات الإدخال/الإخراج | متوسطة عالية |
الخلاصة الرئيسية: العيوب الأكثر خطورة، مثل عمليات الفتح والإغلاق المزدوجة بدون فتح، تُسبب أعطالاً فورية أثناء التشغيل أو مخاطر على سلامة البيانات. أما عيوب الأداء (فتح/إغلاق على مستوى الحلقة) فلا تُسبب أي خطأ على الإطلاق، بل تُؤدي فقط إلى بطء في عمليات المعالجة الدفعية لم يتمكن أحد من تحديد سببها.
ما الذي يجعل العثور على هذا الأمر يدوياً صعباً؟
لا يكمن التحدي في تحديد النمط، فكل مطور يعلم أنه لا ينبغي فتح ملف مرتين. يكمن التحدي في أن تدفق التحكم في لغة كوبول غير خطي بطرق تجعل التتبع اليدوي غير موثوق.
لنفترض برنامجًا بهذا الهيكل:
كوبول
PROCEDURE DIVISION.
MAIN-LOGIC.
PERFORM INITIALIZATION
PERFORM PROCESS-RECORDS
PERFORM TERMINATION
STOP RUN.
INITIALIZATION.
OPEN INPUT CUSTOMER-FILE
OPEN OUTPUT REPORT-FILE
MOVE 0 TO WS-ERROR-FLAG.
PROCESS-RECORDS.
READ CUSTOMER-FILE INTO WS-CUSTOMER-REC
AT END MOVE 1 TO WS-EOF-FLAG
END-READ
IF WS-ERROR-FLAG = 1
PERFORM ERROR-EXIT
END-IF
PERFORM UNTIL WS-EOF-FLAG = 1
PERFORM PROCESS-ONE-RECORD
READ CUSTOMER-FILE INTO WS-CUSTOMER-REC
AT END MOVE 1 TO WS-EOF-FLAG
END-EXEC
END-PERFORM.
ERROR-EXIT.
DISPLAY 'Error in processing'
CLOSE CUSTOMER-FILE *> CLOSE here...
STOP RUN.
TERMINATION.
CLOSE CUSTOMER-FILE *> ...and CLOSE here too
CLOSE REPORT-FILE
STOP RUN.
هل يمكنك اكتشاف الخلل دون تتبع كل مسار تنفيذي؟ WS-ERROR-FLAG يتم ضبطه على 1 في الداخل PROCESS-ONE-RECORD (ربما عن طريق برنامج فرعي مُستدعى)، تتدفق عناصر التحكم إلى ERROR-EXITوهذا يُغلق الملف ويتوقف. هذا صحيح. ولكن إذا WS-ERROR-FLAG is لست عند الضبط، تكتمل الحلقة. PROCESS-RECORDS يعود، و TERMINATION يستأنف التشغيل، والذي يغلق أيضًا CUSTOMER-FILEإغلاقان، وفتح واحد. حالة ملف وقت التشغيل 42.
هذا برنامج بسيط من ثلاثة أقسام. أما البرامج الحقيقية فتتكون من عشرين قسمًا، واستدعاءات شرطية لـ PERFORM، وعبارات GO TO في البرامج القديمة، وروتينات لمعالجة الاستثناءات تستدعي بدورها روتينات أخرى. إن التتبع اليدوي ليس فقط عرضة للأخطاء، بل إنه غير عملي أيضًا.
كيفية نمذجة التحليل الثابت لحالة الملف
يكشف التحليل الثابت عن هذه العيوب من خلال إنشاء مخطط تدفق التحكم للبرنامج ونشر حالة الملف على طول كل مسار.
يُخصص التحليل لكل ملف متغير حالة بثلاث قيم محتملة:
CLOSEDلم يتم فتح الملف، أو تم إغلاقه بنجاحOPENتم فتح الملف ولم يتم إغلاقه بعدUNKNOWN، لا يمكن تحديد الحالة بشكل ثابت (على سبيل المثال، فتح مشروط في فرع لم يتم تحليله بالكامل)
في كل عبارة OPEN، يتحقق التحليل مما يلي: هل هذا الملف موجود بالفعل في حالة OPEN؟ إذا كانت الإجابة بنعم ← عيب فتح مزدوج.
في كل عبارة إغلاق: هل هذا الملف في حالة CLOSED or UNKNOWN؟ إذا كان مغلقًا ← أغلق بدون عيب مفتوح.
في كل مسار لإيقاف التشغيل أو الخروج من البرنامج: هل لا يزال أي ملف في حالة OPEN؟ إذا كانت الإجابة بنعم ← عيب إغلاق مفقود.
بالنسبة لحلقات التكرار، يتحقق التحليل مما إذا كانت عبارة OPEN أو CLOSE تهيمن عليها رأس الحلقة، مما يعني أنها تنفذ في كل تكرار.
احترس: أصعب الحالات التي تواجه أي محلل هي استدعاءات PERFORM في الإجراءات المشتركة. إذا
ERROR-HANDLERإذا تم استدعاء الدالة من اثني عشر مكانًا مختلفًا في البرنامج، فإن حالة الملف عند نقطة استدعاء الدالة PERFORM تحدد ما إذا كان سيتم الإغلاق داخلERROR-HANDLERصحيح أم خاطئ. سينتج عن المحلل الذي لا ينشر الحالة عبر سلاسل PERFORM نتائج سلبية خاطئة (إغفال عيوب حقيقية) أو نتائج إيجابية خاطئة (الإشارة إلى رمز صحيح).
فتح/إغلاق الحلقة: خلل في الأداء بدون رمز خطأ
لا ينتج عن هذا النمط أي خطأ أثناء التشغيل ولا أي خلل في حالة الملف. إنه ببساطة يعمل ببطء، وربما أبطأ بكثير من اللازم.
كوبول
*> PROBLEMATIC: file opened and closed on every iteration
PROCESS-ALL-REGIONS.
PERFORM VARYING WS-REGION-ID FROM 1 BY 1
UNTIL WS-REGION-ID > 10
OPEN INPUT CUSTOMER-FILE
PERFORM PROCESS-REGION-RECORDS
CLOSE CUSTOMER-FILE
END-PERFORM.
ما لم يتم تقسيم الملف فعليًا حسب المنطقة، فإن هذه الطريقة تتسبب في عبء إضافي غير ضروري. عمليًا، من الأفضل فتح الملف مرة واحدة، وقراءة جميع السجلات، ثم تطبيق التصفية في الذاكرة أو من خلال منطق برمجي.
تتضمن كل عملية فتح (OPEN) لملف VSAM البحث في الفهرس، وتهيئة وحدة التحكم بالوصول (ACB)، وتخصيص مساحة التخزين المؤقت. بينما تقوم كل عملية إغلاق (CLOSE) بتفريغ المخازن المؤقتة، وتحديث الفهرس، وتحرير وحدة التحكم بالوصول. بالنسبة لملف يحتوي على عشر مناطق، يحدث هذا عشر مرات بدلاً من مرة واحدة. أما بالنسبة لملف يحتوي على 10,000 سجل وألف منطقة، فإن الحسابات تصبح معقدة للغاية.
كوبول
*> CORRECT: open once, filter inside the loop
PROCESS-ALL-REGIONS.
OPEN INPUT CUSTOMER-FILE
PERFORM VARYING WS-REGION-ID FROM 1 BY 1
UNTIL WS-REGION-ID > 10
PERFORM PROCESS-REGION-RECORDS
END-PERFORM
CLOSE CUSTOMER-FILE.
يكشف التحليل الثابت عن ذلك من خلال تحديد عبارات الفتح والإغلاق التي يهيمن عليها تنفيذ الحلقة، أي أن كل تنفيذ لجسم الحلقة يُنفذ عبارة الفتح أو الإغلاق. ويتطلب هذا الكشف أن يُمثل مخطط تدفق التحكم بنية الحلقة، وليس مجرد تسلسل العبارات.
حالة الملف: إشارة حالة ملف برنامجك، إذا قمت بتحديدها
تُحدِّث كل عملية معالجة ملفات في لغة كوبول حقل حالة الملف (FILE STATUS) المُعرَّف في مدخل التحكم بالملف (FILE-CONTROL). يستطيع البرنامج الذي يتحقق من حالة الملف بعد كل عملية فتح (OPEN) أو قراءة (READ) أو كتابة (WRITE) أو إغلاق (CLOSE) اكتشاف أي خلل في حالة الملف والاستجابة له أثناء التشغيل. أما البرنامج الذي يتجاهل حالة الملف فهو يعمل بشكل عشوائي.
قائمة التحقق: رموز حالة الملف التي يجب على كل مطور COBOL معرفتها
00إتمام ناجح10نهاية الملف (قراءة: لا توجد سجلات أخرى)35لم يتم العثور على الملف (فتح الإدخال: الملف غير موجود)41الملف مفتوح بالفعل (OPEN على ملف في حالة OPEN)42، الملف غير مفتوح (أغلق أو اقرأ ملفًا في حالة مغلقة)47محاولة قراءة ملف لم يتم فتحه (إدخال/إخراج)48محاولة كتابة على ملف غير مفتوح (إخراج، إدخال/إخراج، أو توسيع)97تم فتح الملف بنجاح (خاص بشركة IBM، في بعض البيئات)
كوبول
FILE-CONTROL.
SELECT CUSTOMER-FILE
ASSIGN TO CUSTFILE
FILE STATUS IS WS-CUST-FILE-STATUS.
WORKING-STORAGE SECTION.
01 WS-CUST-FILE-STATUS PIC XX.
PROCEDURE DIVISION.
OPEN INPUT CUSTOMER-FILE
IF WS-CUST-FILE-STATUS NOT = '00'
DISPLAY 'OPEN failed: ' WS-CUST-FILE-STATUS
PERFORM ABEND-ROUTINE
END-IF.
احترس: من الأخطاء الشائعة في الصيانة تحديد حالة الملف في إدخال التحكم في الملف دون الإشارة إليها مطلقًا.
WS-CUST-FILE-STATUSفي قسم الإجراءات. يتم ملء الحقل بعد كل عملية على الملف، ولكن إذا لم يتحقق منه أي كود، فسيتجاوز البرنامج الأخطاء دون تنبيه. يمكن للتحليل الثابت رصد هذا النمط: حالة الملف مُعلنة ولكن لم يتم الرجوع إليها مطلقًا في المنطق الشرطي.
ثلاثة أنماط برمجة كوبول واقعية تسبب عيوبًا
النمط 1: مشكلة الخروج من الخطأ المشترك
يحتوي البرنامج على عدة أقسام معالجة، لكل منها معالج أخطاء خاص بها. تقوم عدة معالجات أخطاء بإغلاق الملف قبل العودة. كما يقوم روتين الإنهاء العادي بإغلاق الملف أيضًا. في حال حدوث خطأ واستمرت عملية الاسترداد بعد معالج الأخطاء، يتم إغلاق الملف مرتين.
كوبول
VALIDATE-RECORDS.
READ CUSTOMER-FILE INTO WS-REC
AT END MOVE 1 TO WS-EOF
END-READ
IF WS-CUST-FILE-STATUS NOT = '00' AND '10'
CLOSE CUSTOMER-FILE *> closes here on read error
PERFORM WRITE-ERROR-LOG
GO TO TERMINATION *> skips to close in TERMINATION?
END-IF.
TERMINATION.
CLOSE CUSTOMER-FILE *> double close if GO TO reached here
CLOSE REPORT-FILE
STOP RUN.
استخدم GO TO TERMINATION ينقل السيطرة مباشرة إلى TERMINATIONوالتي تنفذ بنفسها CLOSE CUSTOMER-FILE. حالة الملف 42.
الحل: استخدام روتين إغلاق مركزي واحد. يستدعي كل مسار خروج نفس الروتين، الذي يتحقق مما إذا كان الملف مفتوحًا قبل إغلاقه.
النمط الثاني: الشرط المفتوح
يُفتح الملف بشكل مشروط، فقط عندما يكون وضع معالجة معين نشطًا. أما أمر الإغلاق (CLOSE) فهو غير مشروط، ويحدث في كل مسار تنفيذي بما في ذلك المسارات التي لم يُفتح فيها الملف مطلقًا.
كوبول
INITIALIZATION.
IF WS-PROCESSING-MODE = 'FULL'
OPEN OUTPUT AUDIT-FILE *> only opened in FULL mode
END-IF.
TERMINATION.
CLOSE AUDIT-FILE *> ALWAYS closes -- FILE STATUS 42 in PARTIAL mode
STOP RUN.
هذا العيب غير مرئي في الاختبارات إذا تم تشغيلها دائمًا في الوضع الكامل. ويظهر في بيئة الإنتاج عند تشغيل الاختبار لأول مرة في الوضع الجزئي.
النمط 3: التنفيذ عبر وحدات التجميع
في البرامج التي تستخدم CALL لاستدعاء البرامج الفرعية، يمكن تمرير ملف مفتوح في البرنامج الرئيسي إلى برنامج فرعي يقوم بإغلاقه، ثم يقوم البرنامج الرئيسي بإغلاقه مرة أخرى.
كوبول
*> Main program
CALL 'SUBPROG1' USING CUSTOMER-FILE-STATUS
*> SUBPROG1 closes CUSTOMER-FILE internally
CLOSE CUSTOMER-FILE *> double close
يتطلب هذا النمط تحليلًا بين الإجراءات ، وتتبع حالة الملف عبر حدود استدعاء البرنامج الفرعي إلى سلوك البرنامج الفرعي، وهو ما لا يمكن للتحليل البسيط داخل البرنامج اكتشافه.
ما يحتاجه جهاز التحليل الثابت للقيام بذلك بشكل جيد
لا تتعامل جميع أدوات التحليل الثابت مع تحليل حالة ملفات COBOL بنفس العمق. إليك قائمة مرجعية لاتخاذ القرار لتقييم هذه الإمكانية:
هل تدعم الأداة سلاسل أوامر PERFORM؟ تستخدم برامج COBOL أمر PERFORM لاستدعاء الفقرات والأقسام المسماة. يجب أن تكون عمليات الملفات داخل هدف PERFORM مرئية لتتبع حالة البرنامج المُستدعي.
هل تتعامل الأداة مع عمليات PERFORM VARYING المضمنة (الحلقات)؟ يُعد اكتشاف الحلقات ضروريًا لتحديد عمليات OPEN/CLOSE التي تهيمن عليها الحلقات.
هل يتتبع البرنامج حالة البرنامج عبر عبارة GO TO؟ تستخدم برامج COBOL القديمة عبارة GO TO بكثرة. سيُفوّت محلل لا يستطيع تتبع حواف GO TO في مخطط تدفق التحكم فئات كاملة من العيوب.
هل يدعم البرنامج عمليات النسخ والاستبدال؟ غالبًا ما يكون كود معالجة الملفات موجودًا ضمن عناصر النسخ. سيُغفل المحلل الذي لا يُوسّع عناصر النسخ قبل التحليل العمليات المُعرّفة في الكود المُضمّن.
هل يتحقق من استخدام حالة الملف؟ لا يقتصر التحليل الكامل على التحقق مما إذا تم الإعلان عن حالة الملف فحسب، بل يتحقق أيضًا مما إذا كان يتم التحقق منها فعليًا بعد كل عملية.
هل يُجري تحليلًا بين الإجراءات؟ تُنشئ البرامج الفرعية المُستدعاة التي تُجري عمليات على الملفات تبعيات حالة بين البرامج. يتطلب التغطية الحقيقية اتباع سلاسل الاستدعاء.
الخلاصة الرئيسية: إن أداة تفحص فقرة أو قسماً واحداً فقط ستغفل معظم العيوب في الواقع العملي. أما العيوب المهمة في بيئة الإنتاج، والتي استغرقت سنوات للظهور وساعات لتشخيصها، فهي تلك التي تمتد عبر أقسام متعددة، وفروع شرطية، وروتينات مُستدعاة.
كيفية التعامل مع النتائج: إطار عمل لتحديد الأولويات
عندما يكشف التحليل الثابت عن عيوب في الملفات، لا تكون جميع النتائج متساوية. إليك كيفية تصنيفها:
قم بإصلاحها فوراً (قبل تشغيل الدفعة التالية):
- افتح الملف مرتين في أي مسار تنفيذ حيث قد يتسبب رمز حالة الملف 41 في حدوث إنهاء غير طبيعي.
- أغلق بدون فتح في المسارات التي يتم تنفيذها في بيئة الإنتاج
- مسارات الخروج المفقودة عند حدوث خطأ في إغلاق ملفات VSAM (خطر على سلامة الكتابة)
جدول أعمال المرحلة القادمة:
- عملية فتح/إغلاق مهيمنة على الحلقات مع تأثير قابل للقياس على نافذة الدفعة
- فحص حالة الملف مفقود في الملفات الهامة (التدقيق، المعاملات، التقارير)
- فتح مشروط مع إغلاق غير مشروط في البرامج متعددة الأوضاع
تتبع ومعالجة البيانات خلال عملية التحديث القادمة:
- بيانات حالة الملف مفقودة
- أغلق فقط على مسارات الخروج العادية (نظام التشغيل يتعامل مع ذلك، لكنها ممارسة سيئة)
- العيوب بين الإجراءات التي يتطلب إصلاحها تنسيق التغييرات عبر برامج متعددة
كيفية SMART TS XL يحلل حالة ملف COBOL
SMART TS XLالصورة تحليل الكود الثابت يبني نموذجًا لتدفق التحكم لكل برنامج COBOL في البيئة، موسعًا أعضاء COPY، ومتتبعًا سلاسل PERFORM، ومتتبعًا حواف GO TO، وناقلًا حالة الملف عبر كل فرع من فروع كل شرط. إنه ليس مسحًا لمطابقة الأنماط؛ بل هو نموذج هيكلي لما يفعله البرنامج فعليًا في كل نقطة يمكن الوصول إليها أثناء تنفيذه.
تُوسّع إمكانية رسم خرائط تبعيات التطبيقات هذا النطاق ليشمل البُعد بين الإجراءات: فعندما يستدعي برنامج COBOL برنامجًا فرعيًا يُنفّذ عمليات على الملفات، تُمثّل خريطة التبعيات تلك العلاقة، مما يُتيح إجراء تحليل يتجاوز حدود وحدات الترجمة. وتظهر عيوب الفتح المزدوج التي تمتد بين البرنامج الرئيسي والبرنامج الفرعي المُستدعى في النموذج الهيكلي بطريقة لا تظهر في أي تحليل داخل البرنامج.
تتيح إمكانية البحث المؤسسي إمكانية تنفيذ النتائج على نطاق واسع: العثور على كل برنامج في المحفظة يفتح مجموعة بيانات محددة، وكل عنصر COPY يحتوي على عبارة CLOSE، وكل برنامج يحتوي على هدف PERFORM يتضمن عبارة OPEN، عبر ملايين أسطر لغة COBOL في ثوانٍ. بالنسبة لفريق التحديث الذي يستعد لنقل عبء عمل دفعي إلى السحابة، تحوّل إمكانية البحث هذه عملية تدقيق يدوية تستغرق أسابيع إلى استعلام مُوجّه.
تُضيف إمكانية توسيع JCL السياق التشغيلي: أي خطوات JCL التي تستدعي كل برنامج، وأي مجموعات البيانات التي تشير إليها كل عبارة DD، وكيفية ربط معالجة الملفات في كود COBOL بمجموعات البيانات الفعلية المُعرّفة في JCL. يُعتبر عيب CLOSE في ملف يُعرّفه JCL على أنه مجموعة بيانات إخراج حرجة ذا أولوية أعلى من نفس العيب في ملف عمل مؤقت، ويتطلب تحديد هذه الأولوية معرفة سياق JCL لكل برنامج COBOL.
الدرس الأوسع: حالة الملف ليست سوى بُعد واحد
تُعد عمليات الملفات الزائدة حالة خاصة لمشكلة أكثر عمومية: برامج COBOL التي تطورت على مدى عقود تحتوي على سلوكيات تعتمد على الحالة، وحالة الملف، وحالات التبديل، وحالات العداد، والتي لا يمكن فهمها بشكل صحيح إلا من خلال تتبع كل مسار تنفيذ ممكن عبر الرسم البياني الكامل لتدفق التحكم.
مراجعة هذا النوع من التعليمات البرمجية من قِبل البشر بطيئة وغير مكتملة وغير متسقة. يكتشف المطورون المختلفون عيوبًا مختلفة، حتى أن المطور نفسه الذي يراجع البرنامج نفسه مرتين يكتشف عيوبًا مختلفة. أما التحليل الثابت فهو منهجي: إذ يطبق القواعد نفسها على كل مسار في كل برنامج، في كل مرة، دون إرهاق أو افتراضات.
بالنسبة للفرق التي تدير محافظ كبيرة من برامج COBOL، سواءً لأغراض الصيانة الدورية، أو برامج تحديث الأنظمة القديمة ، أو عمليات تدقيق الامتثال، فإنّ فائدة التحليل المنهجي لحالة الملفات لا تقتصر على اكتشاف العيوب فحسب، بل تتعداها إلى ضمان تحليل المحفظة بشكل كامل، ومعرفة العيوب المتبقية بدلاً من إخفائها.


