بناء محرك ترتيب أولويات خارطة الطريق
التعليمات
نظرة عامة
في هذا المعمل، ستبني محرك ترتيب أولويات خارطة الطريق بلغة Python يمكن لمدير الهندسة استخدامه لتقييم وترتيب وجدولة مقترحات المشاريع بشكل موضوعي في خارطة طريق ربع سنوية. يستخدم المحرك إطار RICE (الوصول x الأثر x الثقة / الجهد)، ويتعامل مع قيود سعة الفريق، ويحترم التبعيات بين المشاريع، وينتج خارطة طريق واضحة مع مبررات لكل إدراج واستبعاد.
المفاهيم الأساسية
تقييم RICE (ابتكره شون ماكبرايد في Intercom):
- الوصول (Reach): عدد المستخدمين أو العملاء المتأثرين لكل ربع
- الأثر (Impact): مقدار تأثر كل مستخدم (مقياس: 0.25 = أدنى، 0.5 = منخفض، 1 = متوسط، 2 = عالٍ، 3 = ضخم)
- الثقة (Confidence): مدى يقينك في التقديرات (0.0 إلى 1.0، حيث 1.0 = 100%)
- الجهد (Effort): أسابيع العمل الهندسي المطلوبة. صيغة RICE الأصلية من Intercom ودرس الوحدة الخامسة كلاهما يعبّر عن الجهد بـ أشهر-شخص؛ وهذا المختبر يستخدم أسابيع-شخص لتوحيد وحدة الجهد مع وحدة سعة الفريق. ولذلك تكون الدرجات هنا أكبر بنحو أربعة أضعاف من درجات الدرس للمشروع نفسه، وهذا غير ضار لأن درجات RICE لا تُقارن إلا ببعضها -- لكنه يعني أن درجة RICE بلا وحدتها بلا معنى، وذكر الوحدة جزء من عرض أي ترتيب أولويات.
درجة RICE = (الوصول x الأثر x الثقة) / الجهد
المتطلبات
الجزء 1: مقترحات المشاريع
أنشئ فئة PrioritizationEngine بالطرق التالية:
add_project(project) -- تقبل قاموساً بالمفاتيح المطلوبة التالية:
name(str): اسم المشروعreach(int أو float): عدد المستخدمين/العملاء المتأثرين لكل ربع (يجب أن يكون > 0)impact(float): درجة الأثر، يجب أن تكون إحدى: 0.25، 0.5، 1، 2، 3confidence(float): نسبة الثقة كعدد عشري (0.0 إلى 1.0)effort(float): أسابيع العمل المطلوبة (يجب أن تكون > 0)dependencies(list of str): أسماء المشاريع التي يجب إكمالها أولاً (يمكن أن تكون فارغة)category(str): إحدى "feature"، "tech_debt"، "infrastructure"، "experiment"
يجب أن تقوم الطريقة بـ:
- التحقق من جميع الحقول المطلوبة ونطاقات القيم
- حساب وتخزين درجة RICE للمشروع
- تخزين المشروع داخلياً وإرجاع درجة RICE المحسوبة
- رفع
ValueErrorللمدخلات غير الصالحة (حقول مفقودة، قيم خارج النطاق، فئة غير صالحة)
get_project(name) -- تُرجع قاموس المشروع بالاسم (بما في ذلك rice_score المحسوبة)، أو ترفع KeyError إذا لم يُوجد.
list_projects(sort_by="rice_score", category=None) -- تُرجع قائمة بجميع المشاريع مرتبة حسب الحقل المحدد (تنازلياً للدرجات، تصاعدياً للجهد). إذا تم توفير category، تُرشّح لتعرض فقط مشاريع تلك الفئة.
الجزء 2: تخصيص السعة
set_capacity(total_weeks, tech_debt_percentage=20) -- تُعيّن إجمالي أسابيع العمل الهندسي المتاحة للفريق للربع والنسبة المئوية المحجوزة للدين التقني (افتراضياً 20%).
يجب أن تقوم الطريقة بـ:
- تخزين
total_weeksكسعة الفريق الإجمالية - حساب
feature_weeksكـtotal_weeks * (1 - tech_debt_percentage / 100) - حساب
tech_debt_weeksكـtotal_weeks * (tech_debt_percentage / 100) - رفع
ValueErrorإذا كانtotal_weeks<= 0 أوtech_debt_percentageليس بين 0 و 100
get_capacity() -- تُرجع قاموساً يحتوي على total_weeks، feature_weeks، tech_debt_weeks، وremaining_weeks (يساوي total_weeks مبدئياً).
الجزء 3: حل التبعيات
validate_dependencies() -- تفحص جميع المشاريع بحثاً عن مشاكل التبعيات وتُرجع قاموساً يحتوي على:
valid(bool): True إذا كان يمكن حل جميع التبعياتmissing(list of str): أسماء المشاريع المشار إليها كتبعيات غير موجودةcircular(list of list of str): قوائم أسماء المشاريع المشاركة في تبعيات دائرية
يجب على المحرك اكتشاف:
- التبعيات المفقودة: مشروع يعتمد على مشروع لم يُضاف
- التبعيات الدائرية: المشروع أ يعتمد على ب، وب يعتمد على أ (أو دورات أطول)
الجزء 4: توليد خارطة الطريق
generate_roadmap() -- تنتج خارطة طريق ربع سنوية. هذه هي الطريقة الأساسية. يجب أن:
- تتحقق من التبعيات (ترفع
ValueErrorإذا كانت هناك تبعيات مفقودة) - تتحقق من تعيين السعة (ترفع
ValueErrorإذا لم يتم استدعاءset_capacity()) - تفصل المشاريع إلى مجموعتين: مشاريع فئة
tech_debtتستخدمtech_debt_weeks؛ جميع الفئات الأخرى تستخدمfeature_weeks - داخل كل مجموعة، ترتب المشاريع حسب درجة RICE (الأعلى أولاً)
- تعيّن المشاريع لخارطة الطريق بترتيب درجة RICE، مع مراعاة:
- السعة: يُدرج المشروع فقط إذا كان جهده يناسب الأسابيع المتبقية لمجموعته
- التبعيات: يُدرج المشروع فقط إذا كانت جميع تبعياته مُدرجة بالفعل في خارطة الطريق
- تُرجع قاموساً يحتوي على:
included(list of dict): المشاريع المُدرجة في خارطة الطريق، كل منها يحتوي علىname،rice_score،effort،category، وjustification(نص يشرح سبب الإدراج، مثل "RICE score: 5714. Fits within feature capacity.")excluded(list of dict): المشاريع غير المُدرجة، كل منها يحتوي علىname،rice_score،effort،category، وreason(نص يشرح السبب، مثل "Insufficient remaining capacity (needs 8 weeks, 3 available)" أو "Dependency 'Auth Rewrite' not included in roadmap")capacity_summary(dict):total_weeks،feature_weeks_used،feature_weeks_remaining،tech_debt_weeks_used،tech_debt_weeks_remaining
format_roadmap() -- تُرجع تمثيلاً نصياً مقروءاً لخارطة الطريق. يجب أن تستدعي generate_roadmap() داخلياً. التنسيق:
================================================
QUARTERLY ROADMAP
================================================
--- السعة ---
الإجمالي: 60 أسبوع | الميزات: 48 أسبوع | الدين التقني: 12 أسبوع
--- المشاريع المُدرجة (حسب الأولوية) ---
1. Auth Rewrite [infrastructure]
RICE: 6,000 | الجهد: 8 أسابيع
المبرر: RICE score: 6000. Fits within feature capacity.
2. Search Improvement [feature]
RICE: 5,714 | الجهد: 14 أسبوع
المبرر: RICE score: 5714. Fits within feature capacity.
3. Cache Layer Rebuild [tech_debt]
RICE: 4,500 | الجهد: 6 أسابيع
المبرر: RICE score: 4500. Fits within tech debt capacity.
4. Payment V2 [feature]
RICE: 4,200 | الجهد: 10 أسابيع
المبرر: RICE score: 4200. Fits within feature capacity.
--- المشاريع المُستبعدة ---
* Design System Refresh [feature]
RICE: 2,000 | الجهد: 4 أسابيع
السبب: Dependency 'Mobile Redesign' not included in roadmap
* Mobile Redesign [feature]
RICE: 1,800 | الجهد: 20 أسبوع
السبب: Insufficient remaining capacity (needs 20 weeks, 16 available)
--- الملخص ---
مُدرج: 4 مشاريع | مُستبعد: 2 مشاريع
سعة الميزات: 32/48 أسبوع مُستخدم (67%)
سعة الدين التقني: 6/12 أسبوع مُستخدم (50%)
================================================
اقرأ الاستبعادين معاً، فهما سبب بناء هذا المحرك أصلاً. مشروع Design System Refresh درجته أعلى من Mobile Redesign ومع ذلك استُبعد -- بسبب المشروع الذي تحته، الذي يعتمد عليه ولا تتسع له السعة. القائمة المرتبة وحدها لا تستطيع التعبير عن ذلك؛ لا يظهر إلا بتشغيل فحص السعة وفحص التبعيات معاً. وهو أيضاً شكل النقاش الذي ستخوضه مع صاحب مصلحة: مشروعه لم يُحذف لأنه غير مهم، بل لأنه يقع خلف شيء آخر حُذف.
مثال على الاستخدام
engine = PrioritizationEngine()
# إضافة مشاريع
engine.add_project({
"name": "Search Improvement",
"reach": 50000,
"impact": 2,
"confidence": 0.8,
"effort": 14,
"dependencies": [],
"category": "feature",
})
engine.add_project({
"name": "Cache Layer Rebuild",
"reach": 30000,
"impact": 1,
"confidence": 0.9,
"effort": 6,
"dependencies": [],
"category": "tech_debt",
})
engine.add_project({
"name": "Payment V2",
"reach": 20000,
"impact": 3,
"confidence": 0.7,
"effort": 10,
"dependencies": ["Auth Rewrite"],
"category": "feature",
})
engine.add_project({
"name": "Auth Rewrite",
"reach": 40000,
"impact": 2,
"confidence": 0.6,
"effort": 8,
"dependencies": [],
"category": "infrastructure",
})
engine.add_project({
"name": "Mobile Redesign",
"reach": 60000,
"impact": 1,
"confidence": 0.6,
"effort": 20,
"dependencies": [],
"category": "feature",
})
engine.add_project({
"name": "Design System Refresh",
"reach": 20000,
"impact": 0.5,
"confidence": 0.8,
"effort": 4,
"dependencies": ["Mobile Redesign"],
"category": "feature",
})
# تعيين سعة الفريق: 5 مهندسين x 12 أسبوع = 60 أسبوع عمل
engine.set_capacity(total_weeks=60, tech_debt_percentage=20)
# التحقق من التبعيات
dep_check = engine.validate_dependencies()
print(f"التبعيات صالحة: {dep_check['valid']}")
# توليد وعرض خارطة الطريق
roadmap = engine.generate_roadmap()
print(engine.format_roadmap())