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

Build an Org Design Simulator

35 min
Intermediate
3 Free Attempts

Instructions

Overview

In this lab, you will build an Org Design Simulator in Python that models engineering organizations using concepts from Module 3: Conway's Law, Team Topologies, span of control, cognitive load thresholds, and communication overhead. The tool will help an Engineering Manager analyze their organization's structure and receive data-driven recommendations.

Core Concepts

This lab applies the organizational design principles from Module 3:

  • Conway's Law simulation — modeling how team structure maps to system architecture
  • Team Topologies — classifying teams as stream-aligned, platform, enabling, or complicated-subsystem
  • Span of control — validating that managers have 5-9 direct reports
  • Communication overhead — calculating channels using the formula n*(n-1)/2
  • Cognitive load — detecting when teams own too many services relative to their size

Requirements

Part 1: Team and Org Management

Create a function create_org(org_name) that:

  • Creates and returns an org dictionary with the given name, an empty teams dictionary, and an empty managers dictionary
  • The org dictionary must include keys: name, teams, managers

Create a function add_team(org, team_name, team_type, members, services) that:

  • Adds a team to the org's teams dictionary
  • team_type must be one of: "stream_aligned", "platform", "enabling", "complicated_subsystem"
  • members is a list of member name strings
  • services is a list of service/component name strings the team owns
  • Raises ValueError if the team name already exists or the team type is invalid

Create a function add_manager(org, manager_name, team_names) that:

  • Adds a manager to the org's managers dictionary
  • team_names is a list of team names this manager oversees
  • Raises ValueError if the manager name already exists
  • Raises KeyError if any team name does not exist in the org

Part 2: Communication Overhead Calculations

Create a function calculate_communication_channels(team_size) that:

  • Returns the number of communication channels using the formula: n * (n - 1) / 2
  • Returns an integer
  • Raises ValueError if team_size is less than 0

Create a function calculate_org_communication_overhead(org) that:

  • Returns a dictionary where each key is a team name and the value is a dictionary containing:
    • team_size: number of members
    • internal_channels: communication channels within the team (n*(n-1)/2)
    • overhead_level: "low" if channels <= 10, "medium" if channels <= 28, "high" if channels > 28

Part 3: Span of Control Analysis

Create a function analyze_span_of_control(org) that:

  • Returns a dictionary where each key is a manager name and the value is a dictionary containing:
    • direct_reports: total number of unique members across all teams the manager oversees
    • teams_managed: number of teams managed
    • status: "too_narrow" if direct_reports < 5, "optimal" if 5-9, "too_wide" if > 9
    • recommendation: a string with actionable advice based on the status

Part 4: Cognitive Load and Team Split Recommendations

Create a function assess_cognitive_load(org) that:

  • Evaluates each team's cognitive load based on services-per-member ratio
  • Returns a list of dictionaries for teams that may be overloaded, each containing:
    • team_name: name of the team
    • team_size: number of members
    • services_owned: number of services
    • services_per_member: ratio rounded to 2 decimal places
    • cognitive_load: "sustainable" if ratio <= 1.5, "elevated" if ratio <= 2.5, "overloaded" if ratio > 2.5
    • recommendation: a string — if overloaded, recommend splitting; if elevated, recommend monitoring
  • Returns all teams sorted by services_per_member descending (most loaded first)

Create a function recommend_team_split(org, team_name) that:

  • Takes a team name and recommends how to split it
  • Returns a dictionary with:
    • original_team: the team name
    • current_size: number of members
    • current_services: list of services
    • should_split: True if the team has more than 8 members OR more than 2 services per member
    • recommended_teams: if should_split is True, a list of 2 dictionaries, each with suggested_name (string) and suggested_services (list), splitting services roughly in half; if should_split is False, an empty list
  • Raises KeyError if the team does not exist

Part 5: Conway's Law Simulation

Create a function simulate_conway_mapping(org) that:

  • Maps each team to the system components it would naturally produce (its services list), demonstrating Conway's Law
  • Returns a dictionary with:
    • teams_to_components: a dictionary mapping team names to their list of services
    • component_coupling: a list of dictionaries describing potential coupling between teams that share no services but are managed by the same manager, each containing team_a, team_b, and shared_manager
    • conway_warnings: a list of warning strings for potential architectural issues (e.g., a single team owning more than 4 services may produce a monolithic component)

Part 6: Org Chart Report Generation

Create a function generate_org_report(org) that:

  • Returns a formatted string containing:
    • A header with the organization name
    • A Team Topologies summary showing counts of each team type
    • A section for each manager showing their span of control status and the teams they manage
    • A section for each team showing members, services, team type, and communication channels
    • A cognitive load summary with recommendations
    • A Conway's Law analysis section
  • The output must be clean, readable, and well-structured

Example Usage

org = create_org("Acme Engineering")

# Add teams with topologies
add_team(org, "Payments", "stream_aligned",
         ["Alice", "Bob", "Carol", "Dave", "Eve"],
         ["payment-api", "billing-service", "invoice-generator"])

add_team(org, "Platform Infra", "platform",
         ["Frank", "Grace", "Heidi"],
         ["ci-cd-pipeline", "monitoring-stack", "dev-portal"])

add_team(org, "Search", "stream_aligned",
         ["Ivan", "Judy", "Karl", "Liam", "Mia", "Noah", "Olivia", "Pat", "Quinn", "Rosa"],
         ["search-api", "indexer", "ranking-engine", "autocomplete", "search-analytics"])

add_team(org, "ML Core", "complicated_subsystem",
         ["Sam", "Tina"],
         ["recommendation-engine", "fraud-detection", "nlp-pipeline"])

# Add managers
add_manager(org, "VP Alice", ["Payments", "Search"])
add_manager(org, "Director Bob", ["Platform Infra", "ML Core"])

# Analyze
channels = calculate_communication_channels(10)
print(f"Channels for 10 people: {channels}")  # 45

span = analyze_span_of_control(org)
print(span)

load = assess_cognitive_load(org)
print(load)

report = generate_org_report(org)
print(report)

Expected Output Format

================================================================
ORG DESIGN REPORT: Acme Engineering
================================================================

TEAM TOPOLOGIES SUMMARY
----------------------------------------------------------------
  Stream-aligned teams:       2
  Platform teams:             1
  Enabling teams:             0
  Complicated subsystem teams: 1
  Total teams:                4
  Total engineers:            20

================================================================
MANAGER SPAN OF CONTROL
================================================================

VP Alice
  Teams: Payments, Search
  Direct reports: 15
  Status: TOO WIDE
  Recommendation: Consider splitting into two management roles.

Director Bob
  Teams: Platform Infra, ML Core
  Direct reports: 5
  Status: OPTIMAL
  Recommendation: Span of control is within the recommended 5-9 range.

================================================================
TEAM DETAILS
================================================================

Payments [stream_aligned]
  Members (5): Alice, Bob, Carol, Dave, Eve
  Services (3): payment-api, billing-service, invoice-generator
  Communication channels: 10 (medium)
  Services per member: 0.60

Platform Infra [platform]
  Members (3): Frank, Grace, Heidi
  Services (3): ci-cd-pipeline, monitoring-stack, dev-portal
  Communication channels: 3 (low)
  Services per member: 1.00

Search [stream_aligned]
  Members (10): Ivan, Judy, Karl, Liam, Mia, Noah, Olivia, Pat, Quinn, Rosa
  Services (5): search-api, indexer, ranking-engine, autocomplete, search-analytics
  Communication channels: 45 (high)
  Services per member: 0.50

ML Core [complicated_subsystem]
  Members (2): Sam, Tina
  Services (3): recommendation-engine, fraud-detection, nlp-pipeline
  Communication channels: 1 (low)
  Services per member: 1.50

================================================================
COGNITIVE LOAD ASSESSMENT
================================================================

1. ML Core — 1.50 services/member — ELEVATED
   Monitor closely; consider adding team members or reducing scope.

2. Platform Infra — 1.00 services/member — SUSTAINABLE
   Cognitive load is within healthy bounds.

3. Payments — 0.60 services/member — SUSTAINABLE
   Cognitive load is within healthy bounds.

4. Search — 0.50 services/member — SUSTAINABLE
   Cognitive load is within healthy bounds.

================================================================
CONWAY'S LAW ANALYSIS
================================================================

Team-to-Component Mapping:
  Payments -> payment-api, billing-service, invoice-generator
  Platform Infra -> ci-cd-pipeline, monitoring-stack, dev-portal
  Search -> search-api, indexer, ranking-engine, autocomplete, search-analytics
  ML Core -> recommendation-engine, fraud-detection, nlp-pipeline

Potential Coupling (shared manager):
  Payments <-> Search (via VP Alice)
  Platform Infra <-> ML Core (via Director Bob)

Warnings:
  - Search owns 5 services — risk of producing a monolithic component.
    Consider splitting into focused sub-teams.

================================================================

Grading Rubric

Org and team management — create_org() returns a properly structured dictionary; add_team() validates team_type against the four Team Topologies types and raises ValueError for duplicates or invalid types; add_manager() correctly links managers to teams and raises KeyError for non-existent teams and ValueError for duplicate managers; all data structures are consistent and well-organized20 points
Communication overhead and span of control — calculate_communication_channels() correctly implements n*(n-1)/2 and handles edge cases (0, 1, negative); calculate_org_communication_overhead() correctly classifies levels (low/medium/high); analyze_span_of_control() accurately counts unique direct reports across teams, correctly classifies spans as too_narrow/optimal/too_wide, and provides meaningful recommendations25 points
Cognitive load and team split — assess_cognitive_load() correctly calculates services-per-member ratio, classifies load levels (sustainable/elevated/overloaded), and returns results sorted by ratio descending; recommend_team_split() correctly identifies when splits are needed (>8 members or >2 services per member), divides services roughly in half, and generates sensible suggested team names25 points
Conway's Law simulation and report generation — simulate_conway_mapping() correctly maps teams to components, identifies coupling through shared managers, and generates warnings for teams owning too many services; generate_org_report() produces a clean, well-formatted report covering all analysis areas (topologies summary, span of control, team details, cognitive load, Conway analysis) and handles edge cases without crashing30 points

Checklist

0/12

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.