Build a Roadmap Prioritization Engine
Instructions
Overview
In this lab, you will build a Python Roadmap Prioritization Engine that an Engineering Manager can use to objectively score, rank, and schedule project proposals into a quarterly roadmap. The engine uses the RICE framework (Reach x Impact x Confidence / Effort), handles team capacity constraints, respects inter-project dependencies, and produces a clear roadmap with justifications for every inclusion and exclusion.
Core Concepts
RICE Scoring (created by Sean McBride at Intercom):
- Reach: Number of users or customers affected per quarter
- Impact: How much each user is affected (scale: 0.25 = minimal, 0.5 = low, 1 = medium, 2 = high, 3 = massive)
- Confidence: How certain you are in the estimates (0.0 to 1.0, where 1.0 = 100%)
- Effort: Person-weeks of engineering work required
RICE Score = (Reach x Impact x Confidence) / Effort
Requirements
Part 1: Project Proposals
Create a class PrioritizationEngine with the following methods:
add_project(project) -- Accepts a dictionary with these required keys:
name(str): The project namereach(int or float): Number of users/customers affected per quarter (must be > 0)impact(float): Impact score, must be one of: 0.25, 0.5, 1, 2, 3confidence(float): Confidence percentage as a decimal (0.0 to 1.0)effort(float): Person-weeks required (must be > 0)dependencies(list of str): Names of projects that must be completed first (can be empty)category(str): One of "feature", "tech_debt", "infrastructure", "experiment"
The method must:
- Validate all required fields and value ranges
- Calculate and store the RICE score for the project
- Store the project internally and return the calculated RICE score
- Raise a
ValueErrorfor invalid input (missing fields, out-of-range values, invalid category)
get_project(name) -- Returns the project dictionary by name (including its calculated rice_score), or raises a KeyError if not found.
list_projects(sort_by="rice_score", category=None) -- Returns a list of all projects sorted by the specified field (descending for scores, ascending for effort). If category is provided, filters to only projects of that category.
Part 2: Capacity Allocation
set_capacity(total_weeks, tech_debt_percentage=20) -- Sets the team's total available engineering weeks for the quarter and the percentage reserved for tech debt (default 20%).
The method must:
- Store
total_weeksas the team's total capacity - Calculate
feature_weeksastotal_weeks * (1 - tech_debt_percentage / 100) - Calculate
tech_debt_weeksastotal_weeks * (tech_debt_percentage / 100) - Raise a
ValueErroriftotal_weeks<= 0 ortech_debt_percentageis not between 0 and 100
get_capacity() -- Returns a dictionary with total_weeks, feature_weeks, tech_debt_weeks, and remaining_weeks (initially equal to total_weeks).
Part 3: Dependency Resolution
validate_dependencies() -- Checks all projects for dependency issues and returns a dictionary with:
valid(bool): True if all dependencies can be resolvedmissing(list of str): Project names referenced as dependencies that do not existcircular(list of list of str): Lists of project names involved in circular dependencies
The engine must detect:
- Missing dependencies: A project depends on a project that has not been added
- Circular dependencies: Project A depends on B, and B depends on A (or longer cycles)
Part 4: Roadmap Generation
generate_roadmap() -- Produces a quarterly roadmap. This is the core method. It must:
- Validate dependencies (raise a
ValueErrorif there are missing dependencies) - Validate that capacity has been set (raise a
ValueErrorifset_capacity()has not been called) - Separate projects into two pools:
tech_debtcategory projects usetech_debt_weeks; all other categories usefeature_weeks - Within each pool, sort projects by RICE score (highest first)
- Assign projects to the roadmap in RICE-score order, respecting:
- Capacity: A project is only included if its effort fits within the remaining weeks for its pool
- Dependencies: A project is only included if all its dependencies are already included in the roadmap
- Return a dictionary with:
included(list of dict): Projects included in the roadmap, each withname,rice_score,effort,category, andjustification(a string explaining why it was included, e.g., "RICE score: 26667. Fits within feature capacity.")excluded(list of dict): Projects not included, each withname,rice_score,effort,category, andreason(a string explaining why, e.g., "Insufficient remaining capacity (needs 8 weeks, 3 available)" or "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() -- Returns a human-readable string representation of the roadmap. Must call generate_roadmap() internally. Format:
================================================
QUARTERLY ROADMAP
================================================
--- Capacity ---
Total: 60 weeks | Features: 48 weeks | Tech Debt: 12 weeks
--- Included Projects (by priority) ---
1. Search Improvement [feature]
RICE: 26,667 | Effort: 12 weeks
Justification: RICE score: 26667. Fits within feature capacity.
2. Cache Layer Rebuild [tech_debt]
RICE: 15,000 | Effort: 6 weeks
Justification: RICE score: 15000. Fits within tech debt capacity.
--- Excluded Projects ---
* Mobile Redesign [feature]
RICE: 8,000 | Effort: 20 weeks
Reason: Insufficient remaining capacity (needs 20 weeks, 16 available)
* Payment V2 [feature]
RICE: 12,000 | Effort: 10 weeks
Reason: Dependency 'Auth Rewrite' not included in roadmap
--- Summary ---
Included: 4 projects | Excluded: 2 projects
Feature capacity: 44/48 weeks used (92%)
Tech debt capacity: 10/12 weeks used (83%)
================================================
Example Usage
engine = PrioritizationEngine()
engine.add_project({
"name": "Search Improvement",
"reach": 50000,
"impact": 2,
"confidence": 0.8,
"effort": 12,
"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",
})
# Set team capacity: 5 engineers x 12 weeks = 60 person-weeks
engine.set_capacity(total_weeks=60, tech_debt_percentage=20)
# Check dependencies
dep_check = engine.validate_dependencies()
print(f"Dependencies valid: {dep_check['valid']}")
# Generate and display roadmap
roadmap = engine.generate_roadmap()
print(engine.format_roadmap())