AI EngineeringZero to ProductionHome·About·Contact
Career & Interview Prep · Project CR

Land the role & grow to tech-lead

The final capstone: a structured job-search plan, the first-90-days playbook, and the map from engineer → senior → tech-lead — turning everything you built into a career. Runnable planning tools.

⏱️ ~2 hours🏗️ Capstone project🎯 Beginner→Tech-lead
What you'll buildYour personal launch plan: a concrete job-search campaign, then the first-90-days playbook and the map from engineer → senior → tech-lead. This turns everything you've built in this course into a career, with runnable planning tools.

Learning objectives

  • Run a structured job search, not a scattershot one.
  • Execute a strong first 90 days.
  • Understand the engineer→senior→lead progression.
  • Own your growth deliberately.
▶ Runnable companionThe tools here are saved under code/proj-cr-launch/ — run them against your own resume, stories, and offers.

Applying randomly wastes effort. Run it like a pipeline: target roles, tailor materials (CR1), track applications, prep per-company (CR2–CR5). Volume × quality, measured.

Example code for learning — review, test, and adapt it before running against real or production systems. Commands can create, change, or delete resources. See the Terms & Disclaimer.
Python · a job-search tracker (runs)
job_tracker.pyfrom collections import Counter

applications = [
    {"company": "A", "stage": "offer"},
    {"company": "B", "stage": "onsite"},
    {"company": "C", "stage": "rejected"},
    {"company": "D", "stage": "phone screen"},
    {"company": "E", "stage": "applied"},
    {"company": "F", "stage": "onsite"},
]
funnel = Counter(a["stage"] for a in applications)
total = len(applications)
print("pipeline:", dict(funnel))
advanced = sum(1 for a in applications if a["stage"] not in ("applied", "rejected"))
print(f"response rate: {round(100*advanced/total)}% ({advanced}/{total} advancing)")
# healthy: keep enough in early stages to backfill as some drop
pipeline: {'offer': 1, 'onsite': 2, 'rejected': 1, 'phone screen': 1, 'applied': 1}
response rate: 83% (5/6 advancing)
▶ How this works

A job search works best run like a pipeline: many applications, each moving through stages (applied → phone screen → onsite → offer). This little tracker counts how many of your applications are at each stage and works out your response rate, so you can see the search's health at a glance.

  1. from collections import Counter brings in a handy tool that tallies how often each value appears in a list.
  2. applications is a list of small dictionaries, one per company, each recording its current stage. This is your search represented as data.
  3. funnel = Counter(a["stage"] for a in applications) counts how many applications sit in each stage. total = len(applications) is the overall count.
  4. advanced = sum(1 for a in applications if a["stage"] not in ("applied", "rejected")) counts the ones that got past the first step and weren't rejected — i.e. still alive. The last print turns that into a percentage response rate.

What the output means: pipeline: {...} shows the count at each stage, and response rate: 83% (5/6 advancing) means 5 of 6 applications moved forward. A low rate is a signal to improve your resume or targeting (CR1); a high rate means keep the volume up.

Try this: Replace the sample applications with your own list and update each stage as things progress. Re-run whenever something changes to watch your real funnel.

2 · The first 90 days intermediate

Land well in a new role

  1. Weeks 1-2: set up, read the code, get the app running (DF/CD skills), meet the team, ask questions.
  2. Weeks 3-6: ship small, safe changes (a bug fix, a test) to learn the pipeline and build trust.
  3. Weeks 7-12: take a real feature end-to-end; understand the domain and the users.
  4. Throughout: write things down, over-communicate, and find the person who explains the 'why'.
First impressions compoundShipping a small, well-tested, cleanly-deployed change in week 2 (exactly the DF→TQ→CD loop) signals competence fast. Don't try to rewrite everything — earn trust with reliable small wins first.

3 · Advanced — engineer → senior advanced

The jump to senior is about scope and autonomy: you own features/systems end to end, make sound tradeoffs without hand-holding, and your code raises the team's bar. It's less "can you code" and more "can you own outcomes."

4 · Professional — the impact ladder professional

LevelScope of impact
Juniorcompletes well-defined tasks
Midowns features with some guidance
Seniorowns systems; makes tradeoffs; mentors
Staff/Leaddrives cross-team technical direction & multiplies others

5 · Tech-lead — multiply, don't just build tech-lead

The tech-lead shift is from your output to the team's: you set technical direction, unblock people, uphold quality standards (the DF/TQ/CD/SD tech-lead tiers you learned), mentor, and translate between business and engineering. Your success is measured by what the team ships, not just you.

Python · a growth self-assessment (runs)
growth.pydef growth_stage(signals):
    """signals: dict of bool — what you're consistently doing."""
    score = sum(signals.values())
    if signals.get("multiplies_team") and signals.get("sets_direction"):
        return "tech-lead track"
    if signals.get("owns_systems") and signals.get("mentors"):
        return "senior"
    if signals.get("owns_features"):
        return "mid"
    return "growing toward mid"

me = {
    "owns_features": True, "owns_systems": True, "mentors": True,
    "sets_direction": False, "multiplies_team": False,
}
print("current stage:", growth_stage(me))
print("next: build 'sets_direction' + 'multiplies_team' -> tech-lead")
current stage: senior
next: build 'sets_direction' + 'multiplies_team' -> tech-lead
▶ How this works

This is a self-assessment: you tick off which senior/lead behaviours you're consistently doing, and it tells you roughly what career stage that puts you at — and what to build next to reach the following rung.

  1. signals is a dictionary of True/False facts about your habits — do you own features, own systems, mentor, set technical direction, multiply the team?
  2. The function checks them from the top down, strongest first: if you both multiplies_team and sets_direction, you're on the "tech-lead track"; else if you owns_systems and mentors, you're "senior"; and so on. The first matching rule wins, so it reports your highest solid level.
  3. me fills in the honest current picture — here owning features and systems and mentoring, but not yet setting direction or multiplying the team.
  4. The two print lines report the stage and spell out the exact two signals to develop next to move up.

What the output means: current stage: senior — the True signals matched the "senior" rule but not the tech-lead one. The next line names the gap: build sets_direction and multiplies_team to reach the tech-lead track.

Try this: Set the flags to your own honest yes/no. Whatever two are False just below your current stage are your concrete goals for the next 6–12 months.

This is the whole journey, closedYou started at "never used a terminal" and end with a plan to reach tech-lead. Every section's essential→tech-lead ladder was preparing you for this: the skills, the leadership habits, and now the map to apply them. That's a complete path.

🪜 Practice ladder beginner → industry

Six graded exercises, easy to real-world. Try each before opening its solution.

Exercise 1 · A job-search pipeline trackerBeginner

Context: Run the job search like a funnel you can measure, not a black box you guess at. The response rate tells you where to intervene — a weak resume, or interviews you're not converting.

Your task: Build job_tracker.py that counts applications by stage and computes a response rate.

Requirements:

  • Count applications at each funnel stage (applied → screen → onsite → offer)
  • Compute a response rate = anything past 'applied' over the total
  • Handle an empty pipeline without dividing by zero
  • Return the per-stage counts alongside the rate
  • Runs offline over a list of furthest-stage-reached values

💡 Hint: A Counter over the furthest stage each application reached gives the funnel; a low response rate says fix targeting, not interview prep.

Show solution

Treat the search as a measurable pipeline — the response rate tells you where to intervene:

from collections import Counter

STAGES = ["applied", "screen", "onsite", "offer"]

def funnel(applications):
    # applications: list of the furthest stage each reached
    c = Counter(applications)
    counts = {s: c.get(s, 0) for s in STAGES}
    total = sum(counts.values())
    responded = total - counts["applied"]        # anything past 'applied'
    return {"counts": counts, "total": total,
            "response_rate": round(responded/total, 2) if total else 0.0}

apps = ["applied","applied","screen","onsite","applied","offer"]
print(funnel(apps))
# response_rate ~0.5 -> half your applications got a reply

A low response rate means fix the resume/targeting; strong responses but no offers means fix interview prep. The funnel tells you which, so effort goes where it moves the needle.

Exercise 2 · A first-90-days plan with staged goalsIntermediate

Context: A new role needs a plan, not vibes. Staged goals turn 'make a good impression' into concrete milestones — buying trust with small safe wins before taking on risk.

Your task: Build plan_90_days() returning the goal for a given week band.

Requirements:

  • Weeks 1–2: setup (env, access, read the codebase, meet the team)
  • Weeks 3–6: ship small, safe changes to build trust
  • Weeks 7–12: own a feature end-to-end
  • Beyond ramp: higher-scope, more ambiguous work
  • Runs offline for any week number

💡 Hint: Map week ranges to goals; by week 12 you should own something end-to-end, which is the evidence a review looks for.

Show solution

Staged goals turn "make a good impression" into concrete, checkable milestones:

def plan_90_days(week):
    if 1 <= week <= 2:
        return "setup: env, access, read the codebase, meet the team"
    if 3 <= week <= 6:
        return "ship small safe changes: build trust with low-risk PRs"
    if 7 <= week <= 12:
        return "own a feature end-to-end: design, build, ship, measure"
    return "beyond ramp: take on ambiguous, higher-scope work"

for w in (1, 4, 9, 14):
    print(f"week {w:>2}: {plan_90_days(w)}")

Early wins are small and safe by design — you're buying trust and context before taking on risk. By week 12 you should own something end-to-end, which is the evidence a review looks for.

Exercise 3 · Map contributions to the impact ladderAdvanced

Context: Promotion is about scope of ownership, not effort. Effort is invisible; owned scope is not — a feature, then a system, then a direction.

Your task: Build impact_tier(signals) that classifies work as junior/mid/senior/staff-lead from what the person owns.

Requirements:

  • Classify from ownership signals, not hours worked
  • Owning features → mid
  • Owning systems and mentoring → senior
  • Setting direction and multiplying the team → staff/tech-lead
  • Runs offline over a signals dict

💡 Hint: Check the highest-scope signals first so the tier reflects the largest surface the person demonstrably owns.

Show solution

The ladder is defined by scope of ownership — naming your tier honestly shows you what to reach for next:

def impact_tier(signals):
    # signals: booleans about what you demonstrably own
    if signals.get("sets_direction") and signals.get("multiplies_team"):
        return "staff/tech-lead"
    if signals.get("owns_systems") and signals.get("mentors"):
        return "senior"
    if signals.get("owns_features"):
        return "mid"
    return "junior"

print(impact_tier({"owns_features": True}))                       # mid
print(impact_tier({"owns_systems": True, "mentors": True}))       # senior
print(impact_tier({"sets_direction": True, "multiplies_team": True}))  # staff

Effort is invisible; owned scope is not. Moving up means owning larger, more ambiguous surface area — a feature, then a system, then a direction — and having the artifacts to prove it.

Exercise 4 · A growth self-assessment that names the next two signalsExpert

Context: Growth stalls when you don't know what to build next. The useful output isn't your current tier — it's the next two concrete signals to develop, the shortest path up.

Your task: Build growth.py that reads current signals and returns the two nearest unmet signals to develop.

Requirements:

  • An ordered ladder of signals so gaps surface in a sensible sequence
  • Return the person's current strengths
  • Return the next two unmet signals to develop
  • Two concrete targets beat a vague 'grow more'
  • Runs offline over a signals dict

💡 Hint: Order the ladder (feature ownership and mentoring before system ownership and direction) and take the first two signals not yet met.

Show solution

The useful output isn't your current tier — it's the next two things to work on:

LADDER = ["owns_features", "mentors", "owns_systems",
          "sets_direction", "multiplies_team"]

def next_signals(signals, n=2):
    unmet = [s for s in LADDER if not signals.get(s)]
    return unmet[:n]

def assess(signals):
    have = [s for s in LADDER if signals.get(s)]
    return {"strengths": have, "develop_next": next_signals(signals)}

print(assess({"owns_features": True, "mentors": True}))
# develop_next: ['owns_systems', 'sets_direction']

Ordering the ladder means the gaps come out in a sensible sequence: master feature ownership and mentoring before reaching for system ownership and direction-setting. Two concrete targets beat a vague "grow more".

Exercise 5 · Score yourself against a role rubricProfessional

Context: Interviews score you on dimensions, and averages hide the gap that sinks you. Scoring yourself against the same rubric surfaces the one dimension to fix before applying widely.

Your task: Build a rubric scorer over portfolio, resume evidence, search execution, interview readiness, and first-90-days plan, flagging any dimension below bar.

Requirements:

  • Score all five dimensions
  • Flag every dimension below a bar (e.g. 3 of 5)
  • Report the average and a ready/not-ready verdict
  • Name the specific below-bar dimensions, not just the average
  • Runs offline over a scores dict

💡 Hint: Return the below-bar map, not just the mean — a strong portfolio can't rescue a search you're not running consistently.

Show solution

Self-scoring against the same rubric interviewers use surfaces your weakest dimension before they do:

DIMENSIONS = ["portfolio", "resume_evidence", "search_execution",
              "interview_readiness", "first_90_plan"]
BAR = 3   # out of 5

def score_readiness(scores):
    weak = {d: s for d, s in scores.items() if s < BAR}
    avg = sum(scores.values()) / len(scores)
    return {"avg": round(avg, 1), "below_bar": weak,
            "ready": len(weak) == 0}

s = {"portfolio": 4, "resume_evidence": 3, "search_execution": 2,
     "interview_readiness": 4, "first_90_plan": 3}
print(score_readiness(s))
# below_bar: {'search_execution': 2} -> fix this before applying widely

Averages hide the gap that sinks you; the below_bar map names the one dimension to fix first. A strong portfolio can't rescue a search you're not running consistently.

Exercise 6 · Evaluate a real offer beyond the headline numberIndustry scenario

Context: An offer is more than base salary. A weighted comparator stops the biggest base number from dominating a decision that growth and risk should shape.

Your task: Build an offer comparator scoring comp, growth, and risk so you decide on total value, not just the headline number.

Requirements:

  • Comp combines base, equity, and bonus (normalized)
  • Growth captures scope and mentorship
  • Risk penalizes short runway and unclear role
  • A weighted score combines all three; weights are tunable to your priorities
  • Compare two contrasting offers offline (e.g. startup vs big-co)

💡 Hint: Normalize comp to a comparable scale and subtract a risk penalty; let the score check your gut, not replace it — tune the weights to what you value.

Show solution

A weighted comparator stops the biggest base number from dominating a decision it shouldn't:

def offer_value(o, weights=None):
    w = weights or {"comp": 0.5, "growth": 0.3, "risk": 0.2}
    comp = (o["base"] + o["equity_annual"] + o["bonus"]) / 100_000  # normalize
    growth = o["scope"] * 0.5 + o["mentorship"] * 0.5               # 0-5 each
    risk_penalty = (5 - o["runway_years"]) + (5 - o["role_clarity"])
    score = w["comp"]*comp + w["growth"]*growth - w["risk"]*risk_penalty
    return round(score, 2)

startup = {"base":150_000,"equity_annual":60_000,"bonus":0,"scope":5,
           "mentorship":2,"runway_years":2,"role_clarity":3}
bigco   = {"base":200_000,"equity_annual":40_000,"bonus":30_000,"scope":3,
           "mentorship":4,"runway_years":5,"role_clarity":5}
print("startup:", offer_value(startup), " bigco:", offer_value(bigco))

Comp is half the story: growth (will you own real scope, get mentored?) and risk (runway, role clarity) can flip the decision. Tune the weights to your own priorities and let the score check your gut, not replace it.

✓ Checkpoint — you can move on when you can…

  • Run a structured, measured job search.
  • Execute a strong first 90 days.
  • Explain the engineer→senior→lead progression.
  • Assess your stage and plan the next rung deliberately.
📋 Grade your launch plan — is this a campaign or a scattershot?
DimensionMeets the barAbove the bar (staff)
Portfolio qualityYou have 1–2 shipped, runnable projects with a README that states the problem, the approach, and how it was verified.Projects are deployed/live with evidence (metrics, before/after, tests) that a stranger can evaluate in five minutes without you present.
Resume evidenceBullets are outcome-oriented (impact + number), not task lists; each claim maps to something you can demo or discuss.Every bullet is defensible under drill-down: you can explain the tradeoff, the alternative, and what you'd do differently.
Search executionThe search is run as a tracked pipeline (targets, applications, stages) with a measured response rate, not random applying.You keep enough volume in early stages to backfill drop-off, tailor materials per target, and iterate the funnel when the rate is low.
Interview readinessYou have STAR stories prepared (CR2) and can pass the coding/system-design bars (CR3/CR4) for your target level.Stories are calibrated to the level you're targeting, and you can turn any resume line into a 2-minute structured answer on demand.
First-90-days planYou have a concrete ramp: set up + read code (weeks 1–2), ship small safe changes (3–6), own a feature (7–12).The plan names how you'll earn trust with a well-tested, cleanly-deployed early win and how you'll find the person who explains the 'why'.
Growth self-awarenessYou can place yourself honestly on the impact ladder (junior→staff) and name the two signals to build next.You have a deliberate 6–12 month plan to develop the next rung's signals (owns systems, mentors, sets direction, multiplies the team).

Score each dimension 0 (missing), 1 (meets bar), or 2 (above bar). 0–4: keep building. 5–8: a solid, defensible submission. 9–12: staff-level — you could hand this to a reviewer and defend every call. Any dimension at 0 blocks shipping regardless of the total.

Knowledge check check yourself

✓ Knowledge check

Why does the project frame the job search as a measured pipeline (tracking stages and response rate) instead of applying widely?

Show answer
Applying randomly wastes effort; running it as a funnel with volume × quality lets you see the search's health — a low response rate signals fixing the resume or targeting, a high one signals keeping volume up — so you improve deliberately rather than guess.
✓ Knowledge check

According to the impact ladder, what actually distinguishes the tech-lead shift from strong senior work?

Show answer
The shift is from your output to the team's: you set technical direction, unblock and mentor others, and are measured by what the team ships — not just your own code. The self-assessment gates tech-lead on sets_direction + multiplies_team, not just owning systems.
© 2026 studybydoing.in · AI Engineering: Zero to Production · All rights reserved. · About · Privacy Policy · Terms · Contact
Educational content, provided as-is and without warranty. Code samples are examples — review, test, and adapt them before using in production. See the Terms of Use & Disclaimer. Use at your own risk.
© studybydoing.in