Back to Course|Engineering Manager Interviews: Leadership, Org Design & Strategic Execution
Lab

Build a Roadmap Prioritization Engine

30 min
Advanced
3 Free Attempts

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 name
  • reach (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, 3
  • confidence (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 ValueError for 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_weeks as the team's total capacity
  • Calculate feature_weeks as total_weeks * (1 - tech_debt_percentage / 100)
  • Calculate tech_debt_weeks as total_weeks * (tech_debt_percentage / 100)
  • Raise a ValueError if total_weeks <= 0 or tech_debt_percentage is 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 resolved
  • missing (list of str): Project names referenced as dependencies that do not exist
  • circular (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:

  1. Validate dependencies (raise a ValueError if there are missing dependencies)
  2. Validate that capacity has been set (raise a ValueError if set_capacity() has not been called)
  3. Separate projects into two pools: tech_debt category projects use tech_debt_weeks; all other categories use feature_weeks
  4. Within each pool, sort projects by RICE score (highest first)
  5. 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
  6. Return a dictionary with:
    • included (list of dict): Projects included in the roadmap, each with name, rice_score, effort, category, and justification (a string explaining why it was included, e.g., "RICE score: 26667. Fits within feature capacity.")
    • excluded (list of dict): Projects not included, each with name, rice_score, effort, category, and reason (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())

Grading Rubric

Project management and RICE scoring -- PrioritizationEngine correctly stores projects with all required fields (name, reach, impact, confidence, effort, dependencies, category); add_project() validates all fields including that impact is one of [0.25, 0.5, 1, 2, 3], confidence is between 0 and 1, effort and reach are positive, and category is one of the four valid types; correctly calculates RICE score as (reach * impact * confidence) / effort; get_project() retrieves by name including the calculated rice_score and raises KeyError for missing projects; list_projects() supports sorting by rice_score or effort and filtering by category25 points
Capacity allocation and the 20% tech debt rule -- set_capacity() correctly splits total engineering weeks between feature work and tech debt using the provided percentage (default 20%); validates that total_weeks is positive and tech_debt_percentage is between 0 and 100; get_capacity() returns accurate total_weeks, feature_weeks, tech_debt_weeks, and remaining_weeks values; the capacity system correctly tracks remaining capacity as projects are assigned to the roadmap; tech_debt category projects draw from tech_debt_weeks while all other categories draw from feature_weeks25 points
Dependency resolution -- validate_dependencies() correctly identifies missing dependencies (projects referenced that have not been added) and circular dependencies (A depends on B and B depends on A, or longer cycles); returns a structured result with valid boolean, missing list, and circular list; generate_roadmap() raises ValueError when missing dependencies exist; the roadmap respects dependency ordering by only including a project when all of its dependencies are already included; excluded projects that fail dependency checks receive an appropriate reason string25 points
Roadmap generation and formatted output -- generate_roadmap() produces a complete roadmap with included projects (sorted by RICE score within their capacity pool), excluded projects with clear reasons, and an accurate capacity_summary; justifications for included projects reference the RICE score and capacity pool; reasons for excluded projects specify whether it was a capacity issue (with specific numbers) or a dependency issue (naming the missing dependency); format_roadmap() produces a well-structured human-readable output with capacity breakdown, numbered included projects, excluded projects with reasons, and a summary showing utilization percentages; handles edge cases cleanly (no projects, all projects fit, no projects fit)25 points

Checklist

0/11

Your Solution

3 free attempts remaining
FREE WEEKLY NEWSLETTER

Stay on the Nerd Track

One email per week — courses, deep dives, tools, and AI experiments.

No spam. Unsubscribe anytime.