Closing · Lesson 93 of 94

Using what you learned

Watch this lesson

View full playlist ↗

Read the lesson

What you'll learn

Concept

A portfolio is evidence. Nobody hires from a certificate; they hire from proof that you can take a problem to a working, maintained result. Three projects are enough if each is complete: it runs from a clean clone, it has tests and CI, it has a README that explains what and why, and it solves a problem someone actually had. Quality over quantity: three finished projects with green checks beat twelve half-built ones, and the capstone from this course is already one of the three.

Using what you learned: capstone: expenses-cli (packaged, CI, Docker) → portfolio → one project on your chosen path → one real project for a real user → evidence: clean clone → tests pass → README explains why
Using what you learned · Figure 1 · Open for full size

The README is the page every reviewer reads and most stop at, so it carries the weight. In order: one sentence saying what the project does and for whom; a screenshot or a short terminal transcript; how to install and run it in three commands; the decisions you made and why, in a short paragraph, because that is what separates a developer from a tutorial follower; the status, what works and what does not; and how to run the tests. Green badges for CI and tests, pinned versions, a changelog, and a license signal that you know how software is maintained.

README section Answers the reader's question Signal it sends
one-line summary + audience what is this, is it for me? you can explain a product
screenshot / transcript what does it look like? it actually runs
install + run (3 commands) can I try it now? you care about the user's first minute
decisions and trade-offs why is it built this way? you think like an engineer
status and known gaps can I trust it? what is missing? honesty; you know what done means
tests, CI badge, changelog is it maintained? production habits

The most convincing project is one built for a real person. Find someone with a small, concrete problem: a friend's spreadsheet ritual, a local organization's manual report, a colleague's weekly export. Scope it to two weekends, agree in writing what done means, build it with the production shell from the capstone, deliver it with a README and a five-minute walkthrough, and fix the first two bugs they find. That is a production project: a real user, a real deployment, real feedback. Do it free the first time if you must; the second one can be paid, and the story of the first is what wins it.

Using what you learned: find one person with a small real problem → scope it: two weekends, 'done' in writing → build with the capstone shell: tests, CI, README → deliver: walkthrough + README; fix the first two bugs → testimonial and a story for the next one → the next one is paid
Using what you learned · Figure 2 · Open for full size

Translate the course into the words job posts and clients use. You did not "learn Python"; you can "build, test, package, and deploy Python services and command-line tools". You know "type-annotated code checked with mypy", "pytest with fixtures and mocking", "async HTTP clients", "SQL with sqlite and parameterized queries", "Docker and GitHub Actions CI", "dependency management with uv and lockfiles", and "secure handling of configuration and secrets". Put those phrases in the profile and the README, and let the repositories back them up. For a first role, a portfolio with green CI and a clear README is rarer than you think.

Code

A README checker: it scores a README against the sections reviewers look for and tells you what is missing. Run it on your own before anyone else does.

# readme_check.py
import re
from pathlib import Path

REQUIRED = {
    "one-line summary": lambda t: len(t.splitlines()) > 2 and 20 < len(t.splitlines()[2]) < 200,
    "install/run commands": lambda t: t.count("    ") >= 3 or t.count("```") >= 2,
    "decisions section": lambda t: re.search(r"^##.*(decision|design|why|trade)", t, re.I | re.M) is not None,
    "status or roadmap": lambda t: re.search(r"^##.*(status|roadmap|known|limitations)", t, re.I | re.M) is not None,
    "tests mentioned": lambda t: "pytest" in t or "tests" in t.lower(),
    "CI badge": lambda t: "![" in t and ("workflows" in t or "badge" in t),
    "license": lambda t: "license" in t.lower(),
}

Path("README.md").write_text('''# expenses-cli
![ci](https://github.com/you/expenses-cli/actions/workflows/ci.yml/badge.svg)
Per-category expense reports from CSV files, for anyone who tracks spending in spreadsheets.

    pip install expenses-cli
    export EXPENSES_DATA_DIR=./data
    expenses report sept.csv --format json

## Decisions
A library core with a thin CLI so the same code can back a web API later; sqlite over JSON once
files passed a few thousand rows; `uv` lockfile so every machine installs the same versions.

## Status
Reports and summaries work; budgets and charts are planned. Run `uv run pytest` for the tests.

MIT license.
''', encoding="utf-8")

text = Path("README.md").read_text(encoding="utf-8")
results = {name: check(text) for name, check in REQUIRED.items()}
for name, ok in results.items():
    print(f"{'ok ' if ok else '-- '} {name}")
print(f"score {sum(results.values())}/{len(results)}")
Output
ok  one-line summary
ok  install/run commands
ok  decisions section
ok  status or roadmap
ok  tests mentioned
ok  CI badge
ok  license
score 7/7

A portfolio index: three projects with the evidence each carries, rendered as the table you would put on a personal site or a CV. Fill in yours; the shape is what matters.

# portfolio.py
from dataclasses import dataclass, field


@dataclass
class Project:
    name: str
    for_whom: str
    skills: list[str]
    evidence: list[str] = field(default_factory=list)

    def row(self):
        return f"| {self.name} | {self.for_whom} | {', '.join(self.skills)} | {', '.join(self.evidence)} |"


projects = [
    Project("expenses-cli", "anyone tracking spending",
            ["typing + mypy", "pytest", "packaging", "Docker", "CI"], ["PyPI", "CI badge", "Dockerfile"]),
    Project("link-checker", "site owners", ["asyncio", "httpx", "argparse"], ["tests", "README with transcript"]),
    Project("club-reports", "a local sports club (real user)",
            ["sqlite", "csv", "logging", "scheduling"], ["in use weekly", "testimonial"]),
]

print("| Project | For | Skills shown | Evidence |")
print("|---|---|---|---|")
for p in projects:
    print(p.row())
real = [p.name for p in projects if "real user" in p.for_whom]
print()
print("projects for a real user:", real, "| skills covered:", len({s for p in projects for s in p.skills}))
Output
| Project | For | Skills shown | Evidence |
|---|---|---|---|
| expenses-cli | anyone tracking spending | typing + mypy, pytest, packaging, Docker, CI | PyPI, CI badge, Dockerfile |
| link-checker | site owners | asyncio, httpx, argparse | tests, README with transcript |
| club-reports | a local sports club (real user) | sqlite, csv, logging, scheduling | in use weekly, testimonial |

projects for a real user: ['club-reports'] | skills covered: 12

The scope agreement for a first real project, generated as a one-page document. Agreeing on this before writing code is what makes a small project finish.

# scope.py
from datetime import date, timedelta

start = date(2026, 9, 13)
scope = {
    "client": "Riverside Running Club",
    "problem": "monthly membership report is assembled by hand from two spreadsheets (3 hours/month)",
    "done_when": "one command produces the report as PDF from the two exported CSVs, matching last month's numbers",
    "out_of_scope": ["editing memberships", "emailing the report", "a web interface"],
    "deliverables": ["the command with README", "a 5-minute walkthrough", "fixes for the first two bugs within two weeks"],
    "sessions": 4,
}
end = start + timedelta(weeks=2)
print(f"SCOPE: {scope['client']}")
print(f"Problem: {scope['problem']}")
print(f"Done when: {scope['done_when']}")
print("Not included:", "; ".join(scope["out_of_scope"]))
print("Deliverables:", "; ".join(scope["deliverables"]))
print(f"Timeline: {scope['sessions']} sessions between {start} and {end}")
Output
SCOPE: Riverside Running Club
Problem: monthly membership report is assembled by hand from two spreadsheets (3 hours/month)
Done when: one command produces the report as PDF from the two exported CSVs, matching last month's numbers
Not included: editing memberships; emailing the report; a web interface
Deliverables: the command with README; a 5-minute walkthrough; fixes for the first two bugs within two weeks
Timeline: 4 sessions between 2026-09-13 and 2026-09-27

Try it yourself

Run readme_check.py against the capstone's real README and fix every gap it reports. Fill in portfolio.py with your actual three projects, or the two you have and the one you will build, and put the table on a personal page or your profile. Write a scope document for one real person's problem using scope.py as the template, and send it to them this week.

Common mistakes

What's next

You can turn this into work. One lesson remains: a look back at the whole road from print("Hello, world!") to a deployed package, and a thank you.

Course overview