Image: AI generated
يعود من حيث أُصلح
بنيتُ أداة تُغلق الانحراف.
أطروحة yongol بسيطة. إذا لم تستقرّ القرارات في مصدر وحيد موثوق (SSOT)، فإنها تنجرف. لذلك وضعنا القرارات في SSOT، وجعلنا الشيفرة إسقاطًا مؤقتًا (projection) يُعاد رسمه مع كل عملية توليد. عمود حُدِّد بـ BIGINT كان ينزلق خلسةً إلى INT بعد إعادة هيكلة واحدة — هذا النوع من انحراف منطق الأعمال أُغلق بهذه الطريقة.
لكن قبل فترة، وأنا أحلّل مجموعة عيوب في الشيفرة التي ولّدها yongol، لاحظتُ شيئًا غريبًا. كانت العيوب تعترف بنفسها ببنية جملة واحدة. “جمع import منفصل عن ‘هل يستخدم المعالج time فعلًا’.” “استنتاج requiredness منفصل عن ‘هل تطلب واجهة الـ API هذا المعامل كـ required حقًّا’.” معامل المسار دائمًا required، وimport يُضاف فقط عند استخدام الرمز فعليًّا. قرارات بنيوية متماثلة كانت مدفونة كوكلاء محليين مريحين داخل شيفرة المولّد، دون أن تُسجَّل في أي SSOT.
لم يختفِ الانحراف. صعد طبقة إلى أعلى. منطق الأعمال أُغلق بـ SSOT، لكن القرارات البنيوية للمولّد نفسه — الذي يقرأ تلك الـ SSOT ويُنتج الشيفرة — لم يكن لها SSOT خاص بها. أطروحة yongol ارتدّت على yongol ذاته. في الموضع الذي تنبّأت به النظرية بالضبط.
لذا يتغيّر السؤال. الجميع يعرف لماذا يحدث الانحراف. السؤال الحقيقي هو: لماذا يعود حتى بعد الإصلاح.
الجذر: القرار والتفصيل شيئان مختلفان
لنعُد إلى الفيزياء ونبنِ من جديد.
القرار معلومة. ومعلومة منخفضة الإنتروبيا تحديدًا. “هذا العمود يجب أن يكون 64 بت” هو اختيار مقصود لحالة واحدة من بين حالات لا تُحصى. الطبيعة تكره الإنتروبيا المنخفضة. إذا تُركت المعلومة وحدها، تنتشر في ضوضاء محيطها وتتلاشى. القانون الثاني للديناميكا الحرارية ينطبق على القرارات أيضًا.
رصدت هندسة البرمجيات هذا التآكل منذ زمن بعيد. تقول قوانين ليمان (Lehman) لتطوّر البرمجيات إن تعقيد أنظمة E-type يزداد ما لم يُبذَل جهد صريح لتقليله (1980). فيزياء المعلومات تنزل أعمق. أثبت لانداور (Landauer) عام 1961 أن محو بت واحد يتطلّب تكلفة ديناميكية حرارية لا تقل عن kT ln 2. تغيير المعلومة والاحتفاظ بها ليس مجانيًّا من حيث المبدأ. إبقاء القرار في مكانه يتطلّب إنفاق طاقة مستمرًّا.
لكي تبقى المعلومة حيّة، تحتاج إلى أمرين: تخزين موثوق (authoritative store)، وإعادة إسقاط نشطة ومستمرة منه (error correction). الحمض النووي في أجسامنا يعمل هكذا، وبتات التكافؤ في التخزين الرقمي كذلك. نحتفظ بالأصل في مكان منفصل، ونعيد الاستعادة منه في كل مرة.
يحدث الانحراف عندما تنكسر هذه الاستعادة. الآلية واحدة. أسمّيها الربط بالوكيل (proxy binding). عندما لا يستطيع الوسيط التمييز بين القرار والتفصيل والحفاظ على كلّ منهما، فإن الشخص التالي (أو الوكيل التالي) لا يقرأ القرار من المصدر الموثوق، بل يعيد استنتاجه من إشارة مترابطة مجاورة ومريحة. “هذا العمود من نوع timestamptz، إذن يجب import الحزمة time” — تخمين. صحيح في الغالب. ولذلك خطير. يخطئ أحيانًا، وعندما يخطئ يختفي القرار بصمت.
الشيفرة raw هي بالضبط هذا النوع من الوسائط. لا تميّز الشيفرة بين “هذا قرار” و"هذا صحيح مصادفةً في هذا الموضع". لذلك لا يُحلّ الأمر بنموذج أكبر. الوسيط نفسه عاجز عن حمل القرار، فمهما ازدادت ذكاء القارئ، لا يوجد ما يُقرأ.
لم تكن هذه الظاهرة بلا اسم. في هندسة البرمجيات، ميّز بيري وولف بين انتهاك المبادئ (erosion) وفقدان الحساسية تجاه البنية (drift) (1992)، وسمّى كانينغهام الفائدة المتراكمة على الشيفرة غير المُتقنة “الدين التقني” (1992). كل مجال سمّى الأعراض جيدًا. ما أضيفه هو الآلية الواحدة الكامنة تحتها (الربط بالوكيل)، وأن هذه الآلية تتكرّر صعودًا كلما أُغلقت طبقة. أسأل عن السببية، لا عن التسمية.
لماذا يصعد إلى أعلى
حتى هنا القصة معروفة. الجديد يأتي بعدها.
لإغلاق الانحراف تحتاج إلى شيئين: مستودع يحمل القرارات بسلطة (SSOT)، وفاعل إغلاق يقرأه ويُنتج المخرجات (المولّد). لكن فاعل الإغلاق نفسه يتّخذ قرارات. قرارات بنيوية مثل “معامل المسار يُعامَل كـ required”. والوسيط الذي تعيش فيه تلك القرارات — شيفرة المولّد — لا يميّز هو أيضًا بين القرار والتفصيل.
الآلية ذاتها تتكرّر طبقة أعلى. فعل الإغلاق نفسه يخلق طبقة غير مُغلقة فوقه. الانحراف لم يُباد، بل انتقل. إلى طبقة بلا سلطة.
إذا دفعنا هذا إلى نهايته، نصل إلى استنتاج مزعج. إذا أعطينا المولّد SSOT خاصًّا به؟ فإن ما يبني ذلك الـ SSOT سيُخزّن قراراته بدوره في وسيط غير مُغلق. كلما صعدنا طبقة تقلّصت المساحة المكشوفة، لكن في القمة تبقى دائمًا طبقة بلا سلطة. سواء كانت إنسانًا، أو مولّدًا لمولّد. الانحراف مستحيل الإبادة تقاربيًّا. (هذا أقرب إلى تخمين قوي منه إلى برهان. لكن كل طبقة أغلقتها حتى الآن فتحت الطبقة التي فوقها لحظة إغلاقها.)
هذا هو الجواب على “لماذا يعود بعد الإصلاح”. إنه لا يعود. بل حين نُغلق طبقة، تفتح أداة الإغلاق الطبقة التالية. النهر ذاته يتسرّب من سدّ أعلى.
لا تماثل العلاج: ما يمكن التصريح به، وما لا يُغلَق إلا بالتحقّق
كيف نُغلق الطبقة العليا إذن؟ هنا تبرز لا تماثلية حاسمة.
قرارات منطق الأعمال هي في الغالب قيم. العمود 64 بت، الوصول للمالك فقط، التصفّح بنظام المؤشّر. القيم يمكن التصريح بها. اكتبها في DDL أو OpenAPI أو ملف مواصفات، وهذا يصبح الـ SSOT. تُغلق بالتصريح.
القرارات البنيوية للمولّد مختلفة. “معامل المسار required”، “import مرتبط بمرجع الرمز الفعلي”، “required (وجود المفتاح) يختلف عن عدم الفراغ.” هذه ليست قيمًا بل خصائص سلوكية لدالّة على كل المدخلات الممكنة. خصائص السلوك لا يمكن حصرها بالتصريح. لأن المدخلات لا نهائية. لا توجد طريقة لكتابة “يجب أن يتصرّف هذا التحويل هكذا في كل الحالات” في خانة YAML واحدة.
لذلك قرارات هذه الطبقة لا تُغلق بالتصريح بل بالتحقّق فقط. مدقّق الأنواع، اختبارات الخصائص، بوّابات الترجمة. لا نُثبّت القرار كبيانات، بل نُثبّت بوّابة تكشف الانتهاك آليًّا في كل مرة.
ما كتبته في مقال آخر عن “حوّل المراجعة البشرية إلى شيفرة” يقع هنا تحديدًا. بعض الوعود يمكن التصريح بها فيحرسها الـ SSOT، وبعضها لا يمكن التصريح بها فتحرسها البوّابة. ما إذا كانت الشيفرة التي أنتجها المولّد تُترجَم بنجاح لا يمكن كتابته في أي SSOT. يُثبَت فقط بتشغيل الترجمة في كل مرة. بدون تلك البوّابة، يطفو وعد “نجاح التوليد = إمكانية البناء” خارج البنية، وvalidate يمرّ 0/0 بينما المخرجات معطوبة.
الانحراف القابل للتصريح يُغلق بـ SSOT، والانحراف الذي لا يُغلق إلا بالتحقّق يُغلق بالبوّابة. الخلط بينهما يعني ملاحقة أبدية للخلد بالتصريح.
النهر ذاته، سدود مختلفة
هذه البنية تتكرّر خارج الشيفرة أيضًا.
في المعرفة، الانحراف هو ضياع المصدر. حين يُفقد من قال ادّعاءً ما، ومتى، وبأي دليل، ينتشر ذلك الادّعاء كضوضاء تُسمّى “حقيقة”. الشخص التالي لا يقرأ من السلطة (المصدر الأصلي) بل يعيد الاستنتاج من السياق المحيط. لهذا صمّمتُ GEUL لغةً تفرض المصدر والزمن ودرجة الموثوقية على كل معلومة. الفلسفة المعرفية القائلة بأنه لا توجد حقائق بل ادّعاءات فحسب هي صمّام أمان ضدّ الربط بالوكيل في طبقة المعرفة.
في القانون، الانحراف هو انحراف السوابق القضائية عن القرار الأصلي. لم تترك الحضارة هذا لضمير القاضي في كل قضية، بل دوّنت القواعد، وعرّفت الانتهاك، وأضافت آلية إنفاذ. القاضي الجيد ليس SSOT بل وكيل. القانون المكتوب هو الـ SSOT.
إنه النهر ذاته. إذا لم يستقرّ القرار في مكانه الموثوق، وإذا لم يميّز الوسيط بين القرار والتفصيل، فإنه ينجرف. سواء كان شيفرة، أو معرفة، أو قانونًا.
الخاتمة: ليس إبادة بل دفع إلى أعلى
الحرب ضدّ الانحراف لا يمكن أن تكون إبادة هدفها. الإبادة مستحيلة. لأن أداة الإغلاق تفتح الطبقة التالية دائمًا.
الهدف شيء آخر. دفع الانحراف إلى طبقة أعلى ذات مساحة مكشوفة أصغر، ثم تسليح تلك الطبقة بالتحقّق الآلي. حين نجمع القرارات المبعثرة في عشرات الآلاف من أسطر الشيفرة raw في SSOT واحد، تتقلّص المساحة القابلة للانجراف تقلّصًا هائلًا. المساحة المتبقّية — ثوابت سلوك المولّد — تُسدّ بالبوّابات. ومع ذلك تبقى في القمة طبقة أخيرة لا يمكن تفويضها: حكم الإنسان. هناك نتحقّق من جديد في كل مرة ونعيد تثبيت الوعود.
هذا هو الـ Ratchet. يدور في اتجاه واحد فقط. السنّ الذي صعد لا ينزلق إلى الأسفل. الإنتروبيا تجرّ القرارات نحو الأسفل، والـ Ratchet يرفعها درجة في كل مرة. لا توازن. التوقّف يعني الانجراف.
الانحراف لا يموت. لذلك نحن لا نتوقّف. بناء الوعود في مواجهة الإنتروبيا ليس انتصارًا واحدًا، بل Ratchet دائم.
مقالات ذات صلة
- Ratchet Pattern — كيف تجعل الوكيل يصل إلى النهاية
- لماذا تتباعد حلقة وكيلك
- Reins Engineering — ذكاء اصطناعي بلجام
للمزيد من القراءة (مصادر خارجية)
- Lehman’s laws of software evolution — نظرة عامة على القاعدة التجريبية القائلة بأن البرمجيات تزداد تعقيدًا إذا لم تُعالَج.
- Landauer’s principle — التكلفة الديناميكية الحرارية لمحو المعلومات.
المراجع
- Perry, D. E. & Wolf, A. L. (1992). Foundations for the Study of Software Architecture. ACM SIGSOFT Software Engineering Notes, 17(4), 40-52. ACM — التمييز بين التآكل (erosion) والانحراف (drift).
- De Silva, L. & Balasubramaniam, D. (2012). Controlling software architecture erosion: A survey. Journal of Systems and Software, 85(1), 132-151. ScienceDirect
- Lehman, M. M. (1980). Programs, Life Cycles, and Laws of Software Evolution. Proceedings of the IEEE, 68(9), 1060-1076. IEEE — قانون تزايد التعقيد وقانون التغيير المستمر.
- Landauer, R. (1961). Irreversibility and Heat Generation in the Computing Process. IBM Journal of Research and Development, 5(3), 183-191. IBM — الحدّ الأدنى من التكلفة الديناميكية الحرارية لمحو المعلومات.
- Shannon, C. E. (1948). A Mathematical Theory of Communication. Bell System Technical Journal, 27, 379-423. DOI — أساس المعلومات والإنتروبيا وتصحيح الأخطاء.
- Cunningham, W. (1992). The WyCash Portfolio Management System. OOPSLA ‘92 Experience Report. c2.com — الدين التقني و"فائدة الشيفرة غير المُتقنة".