When Style, readability and refactoring came to a close, only one thing was still pending, and it was the most important of all: building something whole from scratch, on your own. This module is exactly that. For eight modules, every piece of EasyTask came pre-packaged — the exercise told you which class was needed, which method was missing, which test to write; from here on the decisions are yours. And the first decision, the one that conditions all the others, is what you are going to build and how far you are going to take it. This lesson does not write a single line of code: it is here to help you pick an idea worth pursuing, trim it down to a size you can actually finish, and write it up in a one-page document that will become your contract with yourself. That sounds unglamorous next to programming, but it is the difference between a finished project and yet another half-built folder on your hard drive.

Contents

  1. What is expected of the final project
  2. How you will assess yourself: the rubric
  3. Choosing the idea: five criteria
  4. A catalogue of six project ideas
  5. Setting the scope with MoSCoW
  6. Functional and non-functional requirements
  7. Acceptance criteria
  8. Use cases and edge cases
  9. The definition document
  10. Worked example: MyExpenses
  11. How EasyTask was defined back in the day
  12. Common mistakes and tips
  13. Exercises
  14. Conclusion

  1. What is expected of the final project

The final project is a command-line application, written by you, that solves a specific problem from beginning to end. It is not trying to be original or impressive: it is trying to show that you can walk the whole road from an idea to a program that somebody else can download, run and understand.

These are the characteristics it must have:

  • It works without you standing next to it. Somebody clones the repository, reads the README.md, runs one command and the program starts.
  • It keeps data between runs. You close the program, open it again and your data is still there (module 5).
  • It is organised into modules and functions, not a single 600-line file (modules 4 and 7).
  • It does not break on odd input. Typing "thirty" where a number is expected must not produce a traceback (module 8).
  • It has automated tests for the things that genuinely matter (08-04).
  • It lives in Git, with a readable history and a README.md that explains it (08-01 and 08-03).

And a note on size: a project of this kind is somewhere between 300 and 800 lines of code, spread over four or five files, and between 15 and 25 hours of work for somebody who has just finished this course. EasyTask, in its v1.0, is of that order of magnitude. If your idea seems to need a great deal more, it is not that you are slow: it is that the idea is too big and needs trimming, which is precisely what section 5 does.

The whole module follows this path, and this lesson is only the first square:

flowchart LR
    A["09-01 Definition<br/>what and how far"] --> B["09-02 Design<br/>how it will be built"]
    B --> C["09-03 Implementation<br/>code and tests"]
    C --> D["09-04 Presentation<br/>explain it and publish it"]
    D --> E["09-05 Next steps"]

It is worth understanding why the order is that one. Each square reduces the uncertainty of the next: without a definition you do not know what to design, without a design you code blind and rewrite three times, and without a finished project there is nothing to present. This is not bureaucracy: it is the cheapest way to be wrong, because changing a sentence in a document takes a minute and changing a decision you have already coded takes an afternoon.

  1. How you will assess yourself: the rubric

There is no teacher handing out marks, so the mark is yours to give — and for that to mean anything you need a rubric written before you start, not afterwards. Read it now, keep it, and come back to it in Project presentation, where you will actually use it.

Criterion Weight Inadequate (1) Adequate (2) Good (3) Excellent (4)
Functionality 25 % Starts but fails on the main flow Does the essentials Does the essentials plus some of the "should" Everything essential works flawlessly and there are useful extras
Code structure 20 % A single file, everything in main() Separate functions Modules by responsibility Clear layers: model, logic, storage and interface
Robustness 15 % Any odd input knocks it over Validates the obvious try/except on input and files Systematic validation, custom exceptions and logging
Documentation 15 % No README Minimal README Complete README with installation and usage README, docstrings, type annotations and CHANGELOG
Tests 15 % None Two or three scattered tests Model and logic covered Model, logic and persistence, with edge cases
Use of Git 10 % No repository, or a single commit Commits, but with vague messages Small, descriptive commits Readable history, .gitignore and a v1.0 tag

To work out the mark, multiply each row's score by its weight and add them up. A project averaging 2.5 is already a worthy project for somebody starting out; aiming for a 4 in everything on the first attempt is the fastest way never to finish. And notice something important: only 25 % is "functionality". The rest is how it is built. That is a deliberate pedagogical decision too.

  1. Choosing the idea: five criteria

The temptation is to pick the most ambitious idea you can think of. Resist it. A good final project meets these five criteria:

  1. It solves a problem you actually have. If the program is going to be genuinely useful to you, you will finish it; if it is an abstract exercise, you will abandon it at the first difficulty. Think about what you write down today on a piece of paper, in a note on your phone or in a messy spreadsheet.
  2. It is manageable. It should fit into four or five entities at most and a handful of operations. If describing it takes more than five sentences, it is too big.
  3. It uses data you can make up. No depending on an external API, a corporate database or a file you do not have. You must be able to create twenty test records in ten minutes.
  4. It can be finished. There is an identifiable minimum version that is already useful. If the project only makes sense "once everything is there", it is a bad project.
  5. It fits what you know. This course has given you files, collections, classes and the command line. A project needing charts, the web or audio will force you to learn something else before you can apply what you have learned, and that is for later on.

A useful contrast: "a social network for photography enthusiasts" fails every criterion; "a record of the plants at home and when each one needs watering" meets them all and, on top of that, gets used.

  1. A catalogue of six project ideas

If nothing comes to mind, pick from here. All of them are sized for section 1 and all of them exercise the whole course, but each one leans on different things:

Idea What it does Entities Course concepts it exercises
Personal expense tracker Records income and expenses by category and produces monthly reports Expense, Category Aggregation with dictionaries (05-03), sorted with key (06-02), formatting amounts and f-strings (02-03), JSON (05-05)
Library or film catalogue Records books or films, marks them read/watched and lends them to friends Book, Loan Searching by title and author (06-01), sets for genres (05-03), inheritance if you mix media (07-04)
Time tracker Records sessions by project and client and works out the billable total Session, Project Dates and durations, range validation (02-04), CSV to export to a spreadsheet (05-05)
Contact book Stores people with phone numbers and emails, searches and groups them by tag Contact Format validation (02-04), strings and normalisation (05-02), nested structures (05-04)
Weekly menu generator Proposes a seven-day menu and produces a grouped shopping list Recipe, Ingredient Randomness with constraints, nested structures (05-04), sets and totals by category (05-03)
EasyTask for another domain The same design applied to a different context: workshop incidents, physiotherapy exercises, house plants Item, Collection The whole of module 7 on familiar ground, with the example in front of you as a reference

That last row deserves a clarification, because it is the most honest of the six: copying EasyTask's structure and changing the domain is a perfectly valid final project. You do not learn less for having a map; translating a design into another domain is exactly what professional life consists of. That said, change it for real — your own entities, your own fields, your own reports — do not just rename variables.

And a warning about the fifth one: the menu generator is the most fun and the most treacherous, because generation with constraints (no repeated dish, balanced categories) gets complicated very quickly. Only choose it if you start with the silly version: picking at random with no constraints at all.

  1. Setting the scope with MoSCoW

The biggest danger in your first project is not that it is hard: it is that it never gets finished. And it does not get finished because the scope grows while you code. You are implementing the expense list, it occurs to you that filtering by date range would be nice, and since you are filtering, exporting to Excel, and since you are exporting, a chart... Three weeks later there is neither a chart nor a list. This is called scope creep, and the antidote is to write the scope down beforehand and refuse to negotiate with it.

The MoSCoW technique sorts everything you can think of into four boxes:

Box Meaning Rule of thumb
M — Must (essential) Without this the program is useless 5 or 6 items at most
S — Should Adds a lot, but the program works without it 3 or 4 items, for after the Musts are done
C — Could Would be nice if there is time to spare As much as you like; you probably will not do it
W — Won't (not now) You explicitly decide not to do it The most important box of the four

Box W looks like a bin and is precisely the opposite: it is the one that protects you. Writing "there will be no graphical interface", "there will be no multi-user support", "there will be no cloud sync" turns a shortcoming into a decision. When somebody asks in your presentation why there is no graphical interface, the answer "I deliberately left it out to focus on the data model" is professional; "I ran out of time" is not. And during development, every time a new idea occurs to you, you do not implement it: you write it down in box C and carry on.

An example, for an expense tracker:

  • Must: record an expense, list the month's expenses, total by category, save and load, delete an expense.
  • Should: edit an expense, filter by date range, export to CSV.
  • Could: monthly budget with a warning when exceeded, recurring expenses.
  • Won't: graphical interface, multiple users, multi-currency, bank imports, charts.

  1. Functional and non-functional requirements

With the boxes full, it is time to turn the Musts and Shoulds into requirements: precise, verifiable sentences. There are two kinds and it pays not to mix them up:

Type Answers Examples
Functional (FR) What does the program do? Record an expense, list by month, calculate totals
Non-functional (NFR) How must it behave? Speed, robustness, data format, ease of use

Functional ones are best written with the user story template:

As a <role> I want <action> so that <benefit>.

All three parts serve a purpose. The role forces you to think about who uses this (even if it is you). The action must be a concrete verb: "record", "list", "export", never "manage" or "handle", which mean nothing. And the benefit is what justifies the requirement: if you cannot finish the sentence, the requirement is probably surplus. Number them — FR-1, FR-2... — because you will be citing them in commits, in tests and in the README.

Write between five and eight functional requirements and three or four non-functional ones. Fewer than five functional ones usually means a project that is too small; more than eight, one you will not finish.

  1. Acceptance criteria

A requirement without an acceptance criterion is an intention. The acceptance criterion answers: how do I know, beyond argument, that this is done? It is written as a list of observable checks, and its great virtue is that it turns almost literally into tests when you get to 09-03.

Compare:

Vague version Version with acceptance criteria
"Expenses can be recorded" 1. Asks for description, amount, category and date.
2. Rejects non-numeric amounts or amounts ≤ 0 without breaking.
3. If the date is left blank, uses today's.
4. After recording, the expense appears in the month's list.
5. The expense is still there after closing and reopening the program.

The second column is checkable by anyone, including you two weeks from now. A good acceptance criterion has between three and five points, describes what is observed from the outside (not how it is implemented) and includes at least one error case.

  1. Use cases and edge cases

A use case is the complete journey of a user task, from beginning to end, told as a sequence. It exists to reveal steps the requirements do not mention:

UC-1: Record an expense
  1. The user starts the program.
  2. The program loads the saved data and shows the menu.
  3. The user chooses "1. Record expense".
  4. The program asks for description, amount, category and date.
  5. The user enters them.
  6. The program validates, saves and confirms: "Expense recorded (id 24)."
  7. The program returns to the menu.

Written out like that you can see things that were not in the requirement: that data has to be loaded at startup, that an identifier is needed, that confirming with a message is a good idea. Two or three use cases covering the main flows are enough.

Edge cases are the odd situations that break the program if you did not anticipate them. Think about them now, not when they turn up:

Family Questions you must answer
Empty What does the list show if there are no records at all? What happens when you average zero items?
One Does it look right with a single item? And deleting the last one?
Many What happens with 500 records on screen? Do you need pagination or filtering?
Invalid input Text where a number is expected, a negative amount, an impossible date (31/02), an empty field
Duplicates Are two identical records allowed? Two categories with the same name but different capitalisation?
Files Missing data file (first run), empty, corrupt or without permissions
Extremes Enormously long strings, huge amounts, accents and ñ, dates from last year

The files row is the one beginners forget most often, and it is the one that guarantees a traceback in the first demo: the program was always tested with data that already existed and nobody ever ran the first startup.

  1. The definition document

Everything above fits on one page. Copy this template into a DEFINITION.md file inside the repository and fill it in; it is your contract with yourself and the reference you will come back to whenever you wonder whether something belongs in the project.

# <Project name>

## 1. Problem
Two or three sentences: what real problem it solves and for whom.

## 2. Proposed solution
One sentence: what the program is. "A command-line application that..."

## 3. Scope (MoSCoW)
- Must: ...
- Should: ...
- Could: ...
- Won't: ...   <- explicit and without regrets

## 4. Functional requirements
FR-1. As a <role> I want <action> so that <benefit>.
      Acceptance: 1) ... 2) ... 3) ...
FR-2. ...

## 5. Non-functional requirements
NFR-1. ...

## 6. Main use cases
UC-1: ...

## 7. Anticipated edge cases
- ...

## 8. Sample data
How the 15-20 test records are generated.

## 9. Definition of done
The project is finished when: ...

Section 9 deserves special attention. Write down today, in writing, what "done" means: "Every FR marked as Must works, there are tests for the model and the storage layer, the README explains how to install and use it, and the v1.0 tag exists". Without that sentence written down, "done" shifts every week.

  1. Worked example: MyExpenses

This is the complete definition document for the sample project that will accompany lessons 09-02, 09-03 and 09-04. We will call it MyExpenses.

1. Problem. I get to the end of the month with no idea where my money went. I jot expenses down in phone notes I never review and I have no way of seeing how much I spend on food versus transport.

2. Proposed solution. A command-line application that records expenses and income with a category and a date, saves them in a JSON file and shows monthly reports by category.

3. Scope (MoSCoW).

Box Contents
Must Record an expense; record income; list a month's transactions; total and breakdown by category; delete a transaction; save and load automatically
Should Edit a transaction; filter by category; export the month to CSV
Could Budget per category with a warning; recurring transactions; comparison between two months
Won't Graphical interface; multiple users; multi-currency; bank imports; charts; cloud

4. Functional requirements.

Id Requirement Acceptance criteria
FR-1 As a user I want to record an expense with a description, amount, category and date so that I have a record of what I spend on Asks for the four values; rejects amounts ≤ 0 or non-numeric ones; blank date = today; confirms with the assigned id
FR-2 As a user I want to record income so that I can work out the month's balance Same as FR-1 but the transaction counts as positive; default category "income"
FR-3 As a user I want to list a month's transactions so that I can review what I did Asks for the month in YYYY-MM format; sorts by date; shows id, date, description, category and amount; if there is nothing, says "No transactions in 2026-08"
FR-4 As a user I want to see a month's total by category so that I know where my money goes One line per category with amount and percentage; sorted from highest to lowest; a final line with the total and the balance
FR-5 As a user I want to delete a transaction so that I can correct a mistake Asks for the id; if it does not exist, warns and does not break; asks for confirmation; after deleting it disappears from the list
FR-6 As a user I want my data to save itself so that I do not lose anything when I close the program Saved after every addition or deletion; loaded at startup; if the file does not exist, it starts empty without an error
FR-7 As a user I want to export a month to CSV so that I can open it in a spreadsheet Generates expenses-YYYY-MM.csv with a header row; ; separator; reports the path it created

5. Non-functional requirements.

  • NFR-1. No user input causes a traceback: every error is shown as a message and returns to the menu.
  • NFR-2. Data is stored in a single readable JSON file, editable by hand and encoded as UTF-8.
  • NFR-3. Any operation responds in under a second with up to 2,000 transactions.
  • NFR-4. The program runs on Python 3.10 or later without installing external dependencies.

6. Main use cases. UC-1 record an expense (the one in section 8); UC-2 check a month's breakdown; UC-3 fix a mistake by deleting and recording again.

7. Anticipated edge cases. First startup with no file; JSON corrupted by hand; a month with no transactions; an amount with a decimal comma (12,50); a non-existent id when deleting; a category typed as "Food" and as "food"; a badly written month (2026-13).

8. Sample data. A sample_data.json with 20 transactions spread over two months and five categories, generated by hand once and versioned in the repository.

9. Definition of done. All seven FRs work; there are tests for the model, the aggregation and the save/load cycle; the README explains installation, usage and limitations; the v1.0 tag exists.

  1. How EasyTask was defined back in the day

EasyTask went through this very process, even though you did not see it. Its definition document said: "Marta coordinates three people at Alba Studio and keeps track of who does what in a notebook; when somebody asks what they are supposed to be doing, it has to be looked up by hand". Its Musts were add a task, list, mark completed, delete and save. Its Won'ts were explicit and held to the end: no graphical interface, no simultaneous users, no notifications and no synchronisation. Everything else you learned with it — the priorities, RecurringTask, the summary by assignee, the CSV — were Shoulds that came in once the Musts were green.

Comparing the two documents teaches you something: they are almost identical in form and completely different in content. The process is always the same; the only thing that changes is the domain.

Common Mistakes and Tips

  • Choosing a project that is too big. This is mistake number one and there is no cure halfway through. Rule of thumb: if once you have finished defining it, it strikes you as "too easy", the size is probably right. A small, finished project teaches you ten times more than an ambitious, abandoned one.
  • Skipping the document out of "eagerness to code". The temptation is to start typing within the first hour. Writing the definition takes 45 minutes and saves days of rewriting, because you discover before you code that you needed an identifier or that two entities were really the same one.
  • Requirements that cannot be verified. "Make it intuitive", "make it fast", "make it pretty". Rewrite them as something observable: "the menu fits on screen without scrolling", "it responds in under a second with 2,000 records".
  • Leaving the Won't box empty. If there is nothing you are not going to do, then you have not decided anything. Force yourself to write at least four exclusions.
  • Confusing a requirement with a solution. "I want to save the data in JSON" is not a requirement, it is a design decision and it belongs to Planning and design. The requirement is "I want my data not to be lost when I close the program".
  • Tip: choose a domain you know. If you are a musician, a sheet-music catalogue; if you run, a training log. Knowing the domain saves you half the design doubts, because you already know which fields matter.
  • Tip: the 20-records rule. Before writing any code, picture 20 real records from your project. If you cannot make them up, the domain is not clear yet.

Exercises

These exercises are the first real steps of your project. Do them in an actual DEFINITION.md file; you will be using it in the next four lessons.

Exercise 1: Choose and justify the idea

Write down three candidate ideas — at least one from the catalogue in section 4 and at least one of your own — and assess each against the five criteria in section 3 in a table scored from 1 to 3. Pick the winner and write a paragraph of three or four sentences explaining the real problem it solves and for whom.

Exercise 2: MoSCoW scope

For the winning idea, fill in the four boxes: 5 or 6 Musts, 3 or 4 Shoulds, as many Coulds as you like and a minimum of 4 Won'ts. Then run the acid test: cover up the Shoulds and the Coulds and ask yourself whether what is left would already be useful to you. If the answer is no, some Should needs promoting to Must; if the answer is "half of this is surplus", demote a Must.

Exercise 3: Requirements and edge cases

Turn the Musts and Shoulds into 5 to 8 numbered functional requirements using the "As a / I want / so that" template, each with three or more acceptance criteria, and add 3 or 4 non-functional requirements. Then go through the table of families in section 8 and write at least one edge case from each family applied to your project.

Solutions

Solution 1. Section 10 is the complete solution to the exercise for MyExpenses. The evaluation table that preceded it was this one:

Idea Own problem Manageable Data can be made up Finishable Fits the course Total
Expense tracker 3 3 3 3 3 15
Catalogue of films watched 2 3 3 3 3 14
Flight deal finder 3 1 1 1 1 7

The third one falls under its own weight: it depends on external data you do not control. The second was viable but the problem was less personal — "it would be nice to have" is not the same as "I need this" — and that nuance is what sustains motivation in week three. Self-assessment rubric: have you scored at least three ideas? Does the winner have a 3 in "finishable"? Could you explain the problem to an outsider in 30 seconds?

Solution 2. The MoSCoW for MyExpenses is in section 10. Notice two specific decisions: "edit a transaction" is in Should and not in Must because deleting and recording again already fixes a mistake — the added value of editing is convenience, not capability — and "charts" is in Won't even though it is the first thing anybody imagines in an expense application, because it requires an external library and a whole learning curve that is not the one in this course. Rubric: do you have 4 or more Won'ts? Does each Must fit into less than three hours of work? Do the Musts on their own already make up a useful program?

Solution 3. The seven FRs, the four NFRs and the edge cases for MyExpenses are in section 10. Compare your acceptance criteria with those of FR-3: notice that it includes the empty case ("No transactions in 2026-08") and the input format (YYYY-MM). Those two things are what later turn into two def test_... with barely any translation. Rubric: do all your FRs have a concrete verb? Does each one have three or more observable criteria? Does at least one criterion per requirement describe what happens when something goes wrong? Do you have an edge case from each of the seven families?

Conclusion

The final project is yours: a command-line application of between 300 and 800 lines that solves a real problem, keeps data, is organised into modules, does not break on odd input, has tests and lives in Git. You will assess yourself with the six-criterion rubric — functionality, structure, robustness, documentation, tests and Git — written before you start precisely so that it means something. The idea is chosen with five criteria: that it solves a problem of your own, that it is manageable, that it uses data you can make up, that it can be finished and that it fits what you have learned; and if none comes to mind, there is the catalogue of six, including the perfectly legitimate option of rebuilding EasyTask for a different domain.

Then comes what really decides whether the project gets finished: the scope. MoSCoW sorts everything into essential, should, could and not now, and the Won't box — explicit, written down, without regrets — is what stops the project from growing while you code it. The Musts and Shoulds become functional requirements with the "As a <role> I want <action> so that <benefit>" template and non-functional requirements describing how it must behave; each with its acceptance criteria, which answer beyond argument when something is done and which in 09-03 will turn almost literally into tests. Use cases reveal the steps the requirements forget, and the seven families of edge cases — empty, one, many, invalid input, duplicates, files and extremes — keep the traceback out of your first demo. All of it fits in a one-page DEFINITION.md that ends with the most useful sentence in the document: what exactly "done" means. MyExpenses, the expense tracker that will accompany the rest of the module, already has its own written out in full.

With the what settled, it is time for the how. In Planning and design we will turn this document into technical decisions: which entities there are and whether they are classes or dictionaries, what format the data is stored in, how the code is split into layers and modules, what the menu looks like, which algorithms you need written in pseudocode before you program them and in what order you are going to do it all, session by session.

© Copyright 2026. All rights reserved