Resume, Portfolio & GitHub Profile Module 6 – Portfolio projects
Writing a project case study
How to write a portfolio case study that a reader takes in within two minutes: the problem, constraints, approach, trade-offs, results and credits.
What you will learn
- Structure a case study: problem, constraints, approach, trade-offs, results, next steps
- Add diagrams and screenshots with alt text that says what they show
- Name teammates, libraries and AI help, and claim only your own part
- Write in layers for a reader who has two minutes
Before you start
What you’ll learn · Before you start
What you will learn
- Structure a case study: problem, constraints, approach, trade-offs, results, next steps
- Add diagrams and screenshots with alt text that says what they show
- Name teammates, libraries and AI help, and claim only your own part
- Write in layers for a reader who has two minutes
Before you start
On this page
GitHub’s tutorial for job seekers expects a hiring manager to look at a project for a couple of minutes, and a case study of 700 words takes three and a half minutes to read at 200 words a minute. Many readers stop before the end, so a case study has to work for them too.
This lesson writes one for Meera’s canteen queue tracker: the parts a case study needs and the question each part answers, written in layers so that its first 30 words already hold the result.
A case study tells the reasoning a README leaves out
Open the canteen tracker’s repository and its README does what GitHub’s tutorial asks of one: it lists what the project can do, gives the steps to install and start it, shows a demo and explains how to run its tests. An interviewer’s questions start where it stops. Why a token queue and not a second counter? Why SQLite? How was the wait measured? A case study: A short account of one project for a reader deciding whether to interview you: the problem and who had it, the constraints, the approach, the trade-offs, the results against a baseline and the next steps. answers them: it is the project’s reasoning, written down for a reader who was not there.
MySmartCoPilot’s template has seven parts, in this order, in 400 to 900 words:
| Part | The question it answers |
|---|---|
| Summary line | What is it, and what did it achieve? |
| Problem | Who had which problem, and how big was it? |
| Constraints | What limited the solution: hardware, time, money, data? |
| Approach | What was built, how does it fit together, and which part was yours? |
| Trade-offs | Which choices were made, against which alternatives, and at what cost? |
| Results | What changed, against what baseline, in which unit? |
| Next steps | What would you really do next, and why? |
Four things travel with the parts. Every image gets alt text: A short text that stands in for an image: screen readers read it aloud, and it shows when the image cannot load. It says what the image shows. that says what it shows. A credits section names each teammate’s part, every library and any AI help. Work you cannot show, such as an internship’s internal system, is described in general terms, with ranges in place of confidential figures. And the last line links the code.
Key idea
A README says how to run a project; a case study says why it was built that way and what it changed, in seven parts that a reader can scan in order.
Checkpoint
Check: The seven parts of a case study
Write it in layers, because readers stop early
At a reading pace of 200 words a minute, a reader who gives your project two minutes reads 400 words. Write for that reader first, in three layers: a summary line of at most 30 words with the result; a card of up to 120 words for your portfolio page, with the problem, your part, the result and the link; and the full case study for the reader who stays. Step through what each reader takes away:
The drawing shows the whole scene; its 5 steps are listed below.
Every step as text
- The summary line. A reader scanning Meera's portfolio page meets the summary line first, 29 words read in about 9 seconds. It names the project and its result, the wait falling from 14 to 6 minutes, so even this reader leaves with the point.
- The card. A reader who wants more reads the card, 102 words in about 31 seconds. It adds the problem, Meera's own part and the link, which is enough to decide whether the project is worth opening.
- A reader with less time. A reader with less time stops after the card and goes back to the list. Everything they needed to remember was already in the first two layers.
- The full case study. A reader who stays opens the full case study. At 200 words a minute, two minutes cover 400 words, so the problem, the constraints and the approach come first and the details later.
- The code. The case study ends with the link. The reader opens the repository with the questions the case study raised, such as how the wait was measured, and the README and tests answer them.
The program measures Meera’s first two layers, and checks that each one carries the result with its unit and that the card carries the link:
# The first two layers of a case study for Meera's canteen queue tracker: a summary line and a card for her portfolio
# page. The program counts the words of each layer, gives its reading time at an assumed pace of 200 words a
# minute and checks that the layer carries the result, with its unit, and, on the card, the link.
# Meera, her project and its address are invented. Press Edit, write your own layers in LAYERS, and run it again.
import re
WORDS_A_MINUTE = 200
RESULT = re.compile(r"\b\d+(?:\.\d+)? to \d+(?:\.\d+)? (?:minutes|seconds|ms|%)")
LINK = re.compile(r"github\.com/[\w.-]+/[\w.-]+")
LAYERS = { # name: (most words, needs the link, text)
"summary line": (30, False, "Canteen queue tracker: a token queue for my college canteen, built with two "
"classmates in Flask and SQLite, that cut the average lunch-hour wait from 14 to 6 "
"minutes."),
"card": (120, True, "Canteen queue tracker · Flask, SQLite · with two classmates. The college canteen sells about "
"450 lunches a day from one counter, and at lunch the queue took 14 minutes. We built a token "
"queue: students take a numbered token on a tablet and sit down until the counter screen "
"calls them. My part was the queue itself and its 31 tests. Over four weeks of use, the "
"average lunch-hour wait fell from 14 to 6 minutes, measured from the app's own log against "
"a week of timing by hand before it. Next: a pause button the staff asked for. Code and "
"demo: github.com/meera-iyer-example/canteen-queue"),
}
def words(text):
return re.findall(r"[\w'’./:-]+", text)
for name, (most, needs_link, text) in LAYERS.items():
n = len(words(text))
checks = [f"result with its unit: {'yes' if RESULT.search(text) else 'missing'}"]
if needs_link:
checks.append(f"link: {'yes' if LINK.search(text) else 'missing'}")
over = "" if n <= most else f" (over the limit of {most})"
print(f"{name}: {n} words{over}, {round(n * 60 / WORDS_A_MINUTE)} s to read · {' · '.join(checks)}")
print(f"full case study: 400 to 900 words, {400 / WORDS_A_MINUTE} to {900 / WORDS_A_MINUTE} min to read")
print(f"what a reader gets through in two minutes: {2 * WORDS_A_MINUTE} words") Output
summary line: 29 words, 9 s to read · result with its unit: yes card: 102 words, 31 s to read · result with its unit: yes · link: yes full case study: 400 to 900 words, 2.0 to 4.5 min to read what a reader gets through in two minutes: 400 words
Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 layers.py
Runs on this device, in your browser. The first run downloads Python (about 13.5 MB), which is kept for the next runs.
Your run, in this browser
Both layers fit their limits: 29 words in about 9 seconds, and 102 words in about 31. The summary line names the result, the wait falling from 14 to 6 minutes, so a reader who stops there still has it. The full 400 to 900 words take 2 to 4.5 minutes, so the problem and the approach come before the detail.
Saving the result for the end
Wrong: a case study that opens with the tech stack and states the result in its last paragraph. Right: the result in the summary line, then again in Results with its baseline and how it was measured. A reader who stops after two minutes never reaches the last paragraph.
Checkpoint
Check: Writing in layers for readers who stop early
The canteen tracker's case study, written section by section Pro: opens with a Pro, Premium or Ultimate pass
This part writes the full case study of the canteen queue tracker from the records the project left behind. Each section gets the version a hurried writer produces, the version a reader can check, and the record behind its numbers.
In this part:
- From the records to a problem and an approach a reader believes
- Trade-offs written as decisions with a cost
- Results with a baseline, a unit and their limits
1 diagram · 1 runnable example (Python, case_study.md, draft.md) · about 6 minutes
Opening this part with your pass…
This part opens with any MySmartCoPilot pass.
- Pro pass · 1 week₹79$2.99
- 30 days₹179$5.99
- 1 year₹1,699$45
One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.
Passes can’t be bought right now, so this part can’t be opened at the moment. The free part above stands on its own. If you have a pass, enter your licence key.
It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).
Alt text, credits and work you cannot show Pro: opens with a Pro, Premium or Ultimate pass
Three things decide whether a reader trusts the rest of a case study: what its images say to someone who cannot see them, who it says did the work, and how it handles work it cannot show. This part writes each one, the weak version beside the one a reader can trust.
In this part:
- Alt text that says what an image shows and why it matters
- Credits that name each person’s part, every library and any AI help
- Work you cannot show: the problem in general terms, figures as ranges
about 5 minutes
Opening this part with your pass…Pro part. It opens with the same pass as the part above.
A rubric for judging a case study, level by level Pro: opens with a Pro, Premium or Ultimate pass
A rubric turns “it reads well” into marks a writer can act on. This part scores the hurried draft and the finished canteen case study against five criteria, and names the edit that moved each mark.
In this part:
- Five criteria, each marked from 0 to 2
- The two drafts scored, and the edit behind each mark
about 3 minutes
Opening this part with your pass…Pro part. It opens with the same pass as the part above.
Practise: fix a case study draft
Arjun, the invented student of this track’s project entries, wrote a hurried case study for his library seat booker. Fix it from his records; the sample tests check the summary line, the seven sections, the length, the numbers, the result, the alt text, the credits and the link:
Exercise · Medium · Python
Fix a case study draft from the project's records
Arjun, the invented student of this track's project entries, wrote a case study for his library seat booker in a hurry. It is the Markdown text in CASE_STUDY in case_study.py. His records say what is true:
- The problem: the college library's reading room has 120 seats, booked by writing a name in a register at the desk. In the semester before the project, 31 % of booked seats were never used, while students were turned away.
- The constraints: one desk computer in the library, students on their phones, no budget, and the librarian wanted no phone numbers stored.
- The approach: a Django site with a PostgreSQL database. A student books a seat for a 2-hour slot, checks in by scanning a code on the desk, and a booking with no check-in is released 15 minutes after its slot starts.
- One trade-off: a seat is released after 15 minutes rather than 30, so empty seats come back quickly; the cost is that a student who is more than 15 minutes late loses the seat.
- The result: over one semester, no-shows fell from 31 % to 12 %, counted from the site's check-in log against the register of the semester before.
- Credits: he built it alone with Django and PostgreSQL, and used no AI help. Code: https://github.com/arjun-mehta-example/seat-booker
Fix the draft so that:
- it opens with a summary line of at most 30 words, before the first heading, that names the result with its unit;
- it has the seven sections of this lesson as
##headings, in order: Problem, Constraints, Approach, Trade-offs, Results, Next steps, Credits; - its text, without the image and the link, is 400 to 900 words long, and every number in it comes from his records;
- the Results section gives the result with its baseline and its unit;
- every image has alt text of at least five words that says what the image shows;
- the Credits section has three lines that start "Team:", "Libraries:" and "AI help:";
- it links the code.
Starter code · case_study.py
# Arjun's case study draft, written in a hurry. Fix it from his records in the prompt.
CASE_STUDY = """# Library seat booker
A seat booking site I made for my college library. It works really well and students like it.
## Problem
The reading room of our college library was always full during exams, but many seats had a bag on them and nobody in
them. Students booked seats by writing their name in a register at the desk, and there was no way to know whether
anyone would come. Students who needed a seat were turned away at the door while booked seats stood empty for
hours, and the librarian spent a lot of time settling arguments about who had booked what. I wanted to see
whether a simple booking site could free up those seats without making more work for the library staff.
## Approach
I built a website where a student picks a seat and a time slot. When the student arrives, they check in at the desk,
and the site marks the seat as taken. If nobody checks in, the seat goes back into the pool so that someone else can
book it. The librarian has a page that shows every seat, its bookings for the day and which ones are checked in, and
can release a seat by hand if something goes wrong. I kept the pages simple so that they load quickly on a phone and
work on the old computer at the desk.

## Results
No-shows went down a lot and the librarian was happy with it. Students also stopped arguing at the desk about who
had booked a seat first.
## Next steps
I would like to add a waiting list, so that a student is told by e-mail when a seat comes free, and a weekly report
for the librarian that shows how full the reading room was at each hour of the day.
""" The sample tests · test_case_study.py
import re
from case_study import CASE_STUDY
SECTIONS = ["Problem", "Constraints", "Approach", "Trade-offs", "Results", "Next steps", "Credits"]
RECORDS = (
"120 seats; 31 % of booked seats never used; a 2-hour slot; released 15 minutes after its slot starts, rather "
"than 30; no-shows fell from 31 % to 12 % over one semester"
)
NUMBER = re.compile(r"(?<![\w.,/-])\d+(?:\.\d+)?(?![\w/])")
IMAGE = re.compile(r"!\[([^\]]*)\]\([^)]*\)")
LINK = "https://github.com/arjun-mehta-example/seat-booker"
RESULT = re.compile(r"from \d+(?:\.\d+)? ?(?:%|minutes|seconds)[^.]*?\bto \d+(?:\.\d+)? ?(?:%|minutes|seconds)")
def section(name):
parts = re.split(r"^## ", CASE_STUDY, flags=re.M)
for part in parts[1:]:
title, _, body = part.partition("\n")
if title.strip() == name:
return body
return ""
def prose():
text = IMAGE.sub(" ", CASE_STUDY).replace(LINK, " ")
return re.findall(r"[\w'’.-]+", text)
def test_summary_line_names_the_result():
"""opens with a summary line of at most 30 words that names the result with its unit"""
before = CASE_STUDY.split("\n## ", 1)[0]
lines = [line for line in before.splitlines() if line.strip() and not line.startswith("#")]
assert lines, "write a summary line before the first heading"
summary = " ".join(lines)
assert len(summary.split()) <= 30, f"the summary line has {len(summary.split())} words: at most 30"
assert re.search(r"\d+ ?%", summary), "the summary line names the result with its unit"
def test_seven_sections_in_order():
"""has the seven sections as ## headings, in order"""
headings = [h.strip() for h in re.findall(r"^## (.+)$", CASE_STUDY, flags=re.M)]
assert headings == SECTIONS, f"the headings are {headings}: they should be {SECTIONS}"
def test_length_and_numbers_from_the_records():
"""is 400 to 900 words long, and every number comes from the records"""
words = prose()
assert 400 <= len(words) <= 900, f"{len(words)} words: write 400 to 900"
allowed = set(NUMBER.findall(RECORDS))
found = set(NUMBER.findall(IMAGE.sub(" ", CASE_STUDY).replace(LINK, " ")))
assert found <= allowed, f"numbers that the records do not hold: {sorted(found - allowed)}"
def test_result_with_baseline_and_unit():
"""gives the result in Results with its baseline and its unit"""
assert RESULT.search(section("Results")), "write the result as 'from <baseline> to <result>', with the unit"
def test_alt_text_and_credits_and_link():
"""gives every image useful alt text, credits in three lines, and the link to the code"""
for alt in IMAGE.findall(CASE_STUDY):
assert len(alt.split()) >= 5, f"the alt text '{alt}' does not say what the image shows"
credits = section("Credits")
for start in ("Team:", "Libraries:", "AI help:"):
assert re.search(rf"^\s*(?:- )?{re.escape(start)}", credits, flags=re.M), f"the credits need a line '{start}'"
assert LINK in CASE_STUDY, "link the code" A hint
Work through the records one at a time and give each its section, in the order of the list. Two sections are missing, Constraints and Trade-offs, and so is Credits. For the summary line, start from the project's name and end with the result, as in "Library seat booker: … cut no-shows from 31 % to 12 % in one semester."
Results of the sample tests
| Test | Result | Details |
|---|
What your code printed
The sample tests run on this device, in your browser (Pyodide): nothing is sent to mysmartcopilot.com. The first run downloads Python (about 13.5 MB), which is kept for the next runs. A check in your browser is feedback for you, not proof that the code is right for every input.
Then answer questions on the parts and the layers of a case study, starting with the idea you have answered worst so far:
Practice that adapts to you
Practise this lesson
6 questions about 5 ideas of this lesson. Each answer is explained at once, and what you get right is kept in this browser.
Interview questions
Warm-up (fresher to mid-level): How does a project’s README differ from its case study?
The README tells a visitor how to use the project: what it does, how to install and start it, where to see it working, and how to test it. The case study tells a reader why it was built that way and what it changed: the problem, the constraints, the approach, the trade-offs with their costs, the results against a baseline and the next steps. The README serves someone who wants to run the code; the case study serves someone deciding whether to interview you, so it starts with the result and says which part was yours.
Three questions of this module’s bank go further:
-
Fresher to mid
Your strongest project was built during an internship, and its code, data and figures are confidential. How do you write a case study that a reader can trust, and what do you say when an interviewer asks for the numbers?
-
Fresher to senior
You used an AI assistant for parts of your project's code. How do you say so in the case study, and what do you answer when an interviewer asks which parts it wrote and how you checked them?
-
Fresher to mid
A hiring manager says they read your case study for two minutes and still could not tell what you built or what it achieved. How do you rewrite its first 150 words, and how do you check the rewrite?
Flashcards · 6 cards
Recall it, then check
Say the answer to yourself before you look: recalling it is what makes it stick.
-
How does a project's case study differ from its README?
The README tells a visitor how to use the project: what it does and how to install, start and test it. The case study tells someone deciding whether to interview you why it was built that way and what it changed.
-
What are the seven parts of a case study, in order?
A summary line, the problem, the constraints, the approach, the trade-offs, the results and the next steps, in about 400 to 900 words.
-
What should the trade-offs and results parts of a case study answer?
Trade-offs: which choices were made, against which alternatives, and at what cost. Results: what changed, against what baseline, and in which unit.
-
Which four things go with the parts of a case study?
Alt text on every image saying what it shows; credits naming each teammate's part, the libraries used and any AI help; general terms and ranges for work you cannot show; and a link to the code at the end.
-
What are the three layers of a case study, and how long is each?
A summary line of at most 30 words with the result; a card of up to 120 words with the problem, your part, the result and the link; and the full case study, 400 to 900 words, for readers who stay.
-
How much of a case study does a reader who gives it two minutes read?
About 400 words at 200 words a minute. The result belongs in the summary line, and the problem and approach before the detail, because a result kept for the last paragraph may never be seen.
Key takeaways
- A README says how to run a project; a case study says why it was built that way and what it changed, in seven parts from the summary line to the next steps.
- Write in layers: a summary line of at most 30 words with the result, a card of up to 120 words, then the full case study of 400 to 900 words.
- A reader who gives a project two minutes reads about 400 words, so the result and the problem come first.
Terms in this lesson
- alt text
- A short text that stands in for an image: screen readers read it aloud, and it shows when the image cannot load. It says what the image shows.
- case study
- A short account of one project for a reader deciding whether to interview you: the problem and who had it, the constraints, the approach, the trade-offs, the results against a baseline and the next steps.
References
- Using your GitHub profile to enhance your resume (GitHub Docs)
- Creating diagrams (GitHub Docs)
- 5 tips for making your GitHub profile page accessible (The GitHub Blog)
- Complex images (Images tutorial) (W3C Web Accessibility Initiative)
- Creating a commit with multiple authors (GitHub Docs)
Related tools
Report a problem with this lesson
Kept only in this browser. Your Learn progress