التسمية ليست البحث
أنت الآن تعرف سبعة أنماط MOAD. معرفة الأسماء مهمة: فهي تسمح لك بالتعرف على نمط عندما تراه. لكن الاعتراف في درس محكوم يختلف عن الكشف في قاعدة كود لم تفتحها من قبل.
قاعدة الكود لا تصنف عيوبها. لا يأتي MOAD الرسوبي مع تعليق يقول // O(N²) — اصلح هذا. لا يعلن القطيع الرعد عن نفسه كانهيار فقدان الذاكرة. تجدها بقراءة الكود بسؤال محدد في الذهن: ما هيكل البيانات الذي يحتفظ بهذه القيم، وما العمليات التي تعمل ضده داخل حلقة؟
الكشف مهارة منفصلة عن الاعتراف. الاعتراف يقول: نعم، هذا النمط هو MOAD-0001. الكشف يقول: اسمح لي بالعثور على جميع الأماكن في قاعدة الكود هذه حيث قد يكون هذا النمط موجوداً، سواء كان بإمكاني رؤية الكود الكامل أم لا.
المسح الأول
يستخدم المسح الأول grep. لكل MOAD ركيزة: هيكل بيانات أو واجهة برمجية وجودها، بالقرب من عمليات معينة، إشارة تستحق التحقيق.
MOAD-0001 (Sedimentary): List.contains في حلقة
# Signal: membership test on a list variable inside a loop
grep -rn '.contains(' src/ | grep -v HashSet | grep -v TreeSet
grep -rn 'visited =' src/ | grep -v set | grep -v Set
MOAD-0002 (Intertangle): علم مشترك قابل للتغيير عبر المراحل
# Signal: static mutable field written by one subsystem, read by another
grep -rn 'static ' src/ | grep -v final | grep -v class | grep -v void
MOAD-0003 (Leaked Context): ThreadLocal في محرك تنفيذ مجمّع
# Signal: ThreadLocal.set() without guaranteed ThreadLocal.remove()
grep -rn 'ThreadLocal' src/
grep -rn 'ThreadLocal.set' src/ -l
MOAD-0004 (Logged Secret): رؤوس HTTP في مخرجات السجل
# Signal: log call with headers variable near auth endpoints
grep -rn 'log.*header' src/
grep -rn 'Authorization' src/ --include='*.log'
MOAD-0005 (Thundering Herd): فقدان الذاكرة بدون مزامنة
# Signal: cache.get() + null check + cache.put() without lock
grep -rn 'cache.get' src/ -A4 | grep 'cache.put'
تنتج هذه الأنماط مرشحين، وليس عيوباً مؤكدة. كل مرشح يحتاج فرز: اقرأ الكود المحيط، تحقق من نوع هيكل البيانات، أكد أن العملية تعمل بحجم كبير.
قراءة الكود للتعقيد
يجد Grep المرشحين. القراءة تؤكدها. عندما تفتح ملف مرشح، تقرأ بسؤال واحد: هل تنمو تكلفة العملية هذه مع حجم الإدخال؟
بالنسبة إلى MOAD-0001، بروتوكول التأكيد:
1. ابحث عن الحلقة الخارجية. ما الذي يحدد عدد التكرارات الخاصة به؟
2. ابحث عن العملية الداخلية (.contains, .indexOf, 'in'). ما هيكل البيانات الذي تعمل عليه؟
3. هل ينمو هيكل البيانات هذا مع نفس الإدخال الذي يقود الحلقة الخارجية؟
4. إذا نعم: التكلفة هي O(N²) حيث N = حجم الإدخال. العيب المؤكد.
5. إذا لا: الهيكل الداخلي مقيد (config، enum، ثابت صغير). إيجابية كاذبة.
يزور الرسم البياني N عقدة، يفحص قائمة visited على كل خطوة: تنمو كل من الحلقة وهيكل البيانات الداخلي مع N. مؤكد.
معالج الطلب التحقق من قائمة بيضاء من 5 عناوين IP للمسؤول: قائمة البيضاء لا تنمو أبداً مع حجم الطلب. إيجابية كاذبة.
ينطبق نفس البروتوكول على كل MOAD: حدد المحرك الخارجي، حدد الهيكل الداخلي، اسأل ما إذا كان كلاهما يتسع معاً.
درجة الموجة: إعطاء الأولوية لنتائجك
ليست جميع العيوب المؤكدة تستحق الإصلاح الفوري. MOAD في مكتبة بها 10000 معتمد منحدر له درجة موجة أعلى من نفس MOAD في أداة داخلية خاصة.
درجة الموجة = التسريع × درجة الدخول. التسريع: كم مرة أسرع يعمل الإصلاح بحجم الإنتاج النموذجي؟ درجة الدخول: كم عدد المكتبات أو الخدمات المنحدرة التي ستحصل على الإصلاح تلقائياً عند دمج المشروع الأصلي؟
A confirmed MOAD-0001 في معالج الاعتماديات Apache Maven، يعمل على رسوم بيانية بـ 50000 عقدة، مع 1000+ من مكونات إضافية Maven التي ترث التغييرات تلقائياً: درجة الموجة عالية جداً. هذا الإصلاح ينتمي إلى مقدمة طابورك.
A confirmed MOAD-0001 في أداة سطر أوامر للمستخدم الواحد بدون معتمدين: درجة الموجة قريبة من الصفر. تستحق الإصلاح، لكن ليست عاجلة.
عقد workaholic مقابل عقد glutton. عقدة بها betweenness عالية & speedup عالية هي workaholic: تتعامل مع التدفق الحرج & ستشطف قوائم الانتظار التالية عند فتحها. صححها فقط بعد التأكد من قدرة المشروع الأصلي. عقدة بها out-degree عالية & speedup منخفضة glutton: تستهلك كل شيء يتم تغذيته لها ولا تشعر بالألم. إصلاح workaholic بدون قدرة المشروع الأصلي ينشئ MOAD-0005 (thundering herd) بحجم البنية الأساسية.
الفحص إلى الدمج: خط أنابيب MOAD
يمر عيب مؤكد بدرجة موجة عالية عبر خط الأنابيب. تنتج كل مرحلة قطعة عمل. لا مرحلة اختيارية.
scan → قائمة المرشحين (مخرجات grep، نتائج التحليل الثابت)
ticket → وصف العيب (رقم MOAD، الموقع، تحليل التعقيد)
patch → تغيير الكود (مقايضة هيكل البيانات، تبني الكائن)
test → اختبار الوحدة (إثبات O(1): الوقت الإصلاح عند N=100 و N=10000)
UNDF → منشور كشف عام (undefect.com، النطاق العام)
disclose → CVE أو مرجع CWE إذا كان ذا صلة بالأمان
PR → طلب سحب المشروع الأصلي مع الإصلاح + الاختبار + رابط UNDF
merge → قبول المسؤول؛ الإصلاح ينتشر عبر ارتقاء الإصدار
تغذي كل قطعة عمل المرحلة التالية. لا يمكن التحقق من الإصلاح بدون اختبار. لا يمكن أن ينتشر الاختبار إلى حالات أخرى من نفس النمط بدون كشف. لا يمكن لكشف بدون طلب سحب المشروع الأصلي أن يترك الإصلاح في fork.
منشور MOAD (UNDF) هو المرحلة التي يغفل عنها معظم المهندسين. يصلحون العيب، يقدمون طلب سحب، ويعتبرون أنفسهم انتهوا. لكن الإصلاح بدون منشور معنون يعني أن كل مهندس مستقبلي يواجه نفس النمط يجب أن يعيد اكتشاف المشكلة والإصلاح بشكل مستقل. منشور MOAD يغلق حلقة المعرفة: يسمي النمط، يظهر طريقة الكشف، & يربط بالإصلاح. يجد الباحثون المستقبليون الإصلاح بالبحث عن اسم النمط.
إصلاح الكوكب بحجم كبير. إصلاح MOAD-0001 في مكتبة مستخدمة على نطاق واسع ينتشر إلى كل مشروع يستورده. يضمن منشور MOAD أن المهندسين في المشاريع الذين لن يرقوا هذه المكتبة أبداً يتعلمون الإصلاح أيضاً. كلا المسارين يعملان بالتوازي.
كتابة تذكرة عيب
تذكرة عيب جيدة تجيب على خمسة أسئلة:
1. الأين: ملف دقيق، فئة، دالة، ونطاق الأسطر
2. الماذا: نوع هيكل البيانات والعملية ضده
3. لماذا: تحليل التعقيد (O(N²) أو أسوأ، مع تحديد N)
4. التأثير: ما المدخلات التي تشغل سلوك الحالة الأسوأ، وفي أي حجم
5. الإصلاح: هيكل البيانات أو الكائن للاستبدال
تذكرة تجيب على الخمسة مكتفية بذاتها: يمكن لمسؤول لم يقرأ تحليلك أن يعيد إنتاج اكتشافك ويتحقق من إصلاحك. التذاكر التي تفقد (3) أو (4) تتطلب من المسؤول إعادة تحليل التعقيد قبل الدمج. هذا الاحتكاك يقلل من احتمال الدمج.
تتراكم المصداقية. طلب سحب أول يتضمن تذكرة واضحة، إصلاح موجه، & اختبار معيار يتم دمجه. طلب سحب ثاني من نفس المؤلف يتم مراجعته باحتكاك أقل. ثالث يتم مراجعته من قبل المسؤول الذي دمج الأول والثاني. السمعة في المصدر المفتوح دفتر من القطع: كل رقعة مقبولة تكسب ثقة للقادم.
قراءة مرشح حقيقي
هنا مرشح MOAD-0001 حقيقي في Python. اقرأه و أكمل بروتوكول الفرز.
class DependencyResolver:
def resolve(self, package, resolved=None, seen=None):
if resolved is None:
resolved = []
if seen is None:
seen = []
if package in seen:
return
seen.append(package)
for dep in self.registry.get_dependencies(package):
self.resolve(dep, resolved, seen)
resolved.append(package)
return resolved
أسئلة الفرز:
1. ما هيكل البيانات `seen`؟
2. ما العملية التي تعمل ضده في السطر 6؟
3. هل ينمو `seen` مع حجم الإدخال؟
4. هل تنمو الحلقة التي تقود الاستدعاءات المتكررة أيضاً مع حجم الإدخال؟
5. هل هذا عيب MOAD-0001 مؤكد أو إيجابية كاذبة؟
إصلاحك
عيب مؤكد بدرجة موجة عالية يحتاج رقعة كاملة: إصلاح الكود، اختبار يثبت التحسن، & ملخص منشور MOAD.
يجب أن يكون الاختبار اختبار أداء، وليس اختبار صحة. اختبار الصحة يمر قبل الإصلاح وبعده - تلك هي النقطة؛ المخرجات لا تتغير. اختبار الأداء عند حجمي إدخال يثبت التحسن:
import time
def build_graph(n):
# n packages, each depending on the previous one
return {f'pkg{i}': [f'pkg{i-1}'] if i > 0 else [] for i in range(n)}
for n in [100, 1000, 5000]:
registry = build_graph(n)
resolver = DependencyResolver(registry)
start = time.perf_counter()
resolver.resolve(f'pkg{n-1}')
elapsed = time.perf_counter() - start
print(f'n={n}: {elapsed:.4f}s')
قبل الإصلاح، ينمو الوقت المنقضي تربيعياً مع n. بعد الإصلاح، ينمو خطياً. اطبع كليهما و أدرج الأرقام في وصف طلب السحب.
ملخص MOAD يغطي: اسم النمط، الركيزة (معالج اعتماديات Python)، طريقة الكشف (grep بحثاً عن in seen حيث seen يبدأ كـ [])، الإصلاح، & رابط إلى طلب السحب. ينشر المنشور إلى undefect.com كنطاق عام. المهندسون المستقبليون الذين يبحثون عن 'اختبار العضوية في قائمة Python في حلقة بطيء' سيجدونه.