Grade by Grade
B. Software Development · Software Development: Managing a Team Software Project

Design Documents: Architecture, Data, Interfaces and Traceability

B1.2 B1.3About 75 minutes
Learning goals
  • I can list the sections of a software design document and explain what each is for.
  • I can design a program's architecture as modules with clear responsibilities and draw it.
  • I can specify data formats and module interfaces (function names, parameters, return values, docstrings with examples) before coding.
  • I can build a traceability matrix that links requirements to design and tests, and use it to find gaps.
  • I can run a design review that checks the design against user needs, quality standards, budget and schedule.

Words to know

software design document (SDD)
The development-stage document that explains how the software will meet the requirements: architecture, data, interfaces, user interface, error handling and standards.
architecture
The big-picture structure of a program: its modules, what each is responsible for, and how they connect.
interface (of a module)
What other code needs to know to use a module: function names, parameters, return values and the rules for using them, but not the code inside.
type hint
An annotation such as borrowed: date (a parameter) or -> date (the return value) that documents what type a parameter or return value should be. Python does not enforce it, but tools and readers use it.
doctest
An example written inside a docstring in the form of an interactive Python session; Python's doctest module can run it as a test.
traceability matrix
A table linking each requirement to the design elements that meet it and the tests that check it.
coding standard
The team's agreed rules for code style, naming and comments (for Python, usually based on PEP 8).
design review
A meeting where the team (and sometimes the client) checks a design against the requirements before coding begins.

Why write the design down?

When you code alone, the design lives in your head. When four people code at once, it cannot. If Jordan's loans module expects dates as text like "Jan 4" and Priya's storage module hands it date objects, the program breaks the first time the pieces meet, perhaps two days before delivery.

The software design document (SDD) prevents this. It is written at the start of the development stage and says how the software will meet each requirement, precisely enough that team members can code different modules at the same time and have them fit together. B1.2 asks you to develop the software product according to the project plan, making sure it meets end-user needs, works as intended and can be produced within quality standards, budget and timelines. The design document and the design review are where you check all of that before the expensive part (coding) begins.

What goes in a design document

A design document for a student project is usually 3 to 8 pages. Typical sections:

  1. Overview: purpose, and a link to the scope document and requirements.
  2. Architecture: the modules, each one's responsibility and owner, and a diagram of how they connect.
  3. Data design: the data structures in memory and the exact file formats.
  4. Interface specifications: for each module, every public function's name, parameters, return value, and what it does, with examples.
  5. User interface design: screen or menu mock-ups, the wording of prompts and error messages.
  6. Error handling: what happens with bad input, missing files, full disks.
  7. Coding standards: naming, comments, docstrings, how code is reviewed.
  8. Traceability matrix: which part of the design meets each requirement, and which tests check it.

The sibling unit Modular and Object-Oriented Design teaches how to choose modules and classes (with tools such as CRC cards and UML class diagrams). This lesson is about writing the design down so that a team can build it.

Architecture

Jordan, the lead developer, splits LendIt into four modules, each with one job (high cohesion) and as few connections as possible (low coupling):

  • main.py shows the menu, reads choices, prints messages and calls the other modules. It contains no business rules.
  • items.py adds, finds and searches items.
  • loans.py holds the loan rules: due dates, fees, overdue checks, the 3-item limit.
  • storage.py is the only module that reads and writes files.

Each module has an owner who codes it and a second person who reviews it.

main.pymenu and messages (Luc)items.pyadd, find, search (Luc)loans.pylend, return, fees (Jordan)storage.pyload and save files (Priya)items.csvmembers.csvloans.csvreads, writesmain.py calls the three modules.Only storage.py touches files,so a format change stays in one place.
LendIt's architecture. Arrows show which module calls which. Because only storage.py touches the files, changing the file format later affects one module, not four.

Data design

The data design gives exact formats, so that no one has to guess. LendIt stores three CSV (comma-separated values) files:

  • items.csv: item_id,name,category, for example SS-01,Snowshoes (adult),snowshoes
  • members.csv: member_no,name, for example 1042,A. Singh
  • loans.csv: item_id,member_no,borrowed,due,returned, for example SS-01,1042,2027-01-04,2027-01-18, (an empty returned field means the item is still out)

Dates are stored in ISO 8601 form, YYYY-MM-DD. This avoids the classic confusion over whether 01/04 means January 4 or April 1, and ISO dates sort correctly even as plain text. In memory, dates are Python date objects, converted by storage.py on loading and saving. Notice that members.csv stores only a number and a name, exactly as privacy requirement N4 says.

Interface specifications

An interface is everything another programmer needs to use a module without reading its code. Write each public function's signature, with type hints and a docstring that gives the requirement it meets, its rules and some examples. If the examples are written as a Python session, the doctest module can run them as tests, so the specification checks itself.

Here is the design-stage version of part of loans.py. Jordan writes the docstrings first, gets them reviewed, then writes the bodies.

"""loans.py: loan rules for LendIt (design-stage version)."""
from datetime import date, timedelta
LOAN_DAYS = 14
FEE_PER_DAY = 0.25
MAX_FEE = 5.00
def due_date(borrowed: date) -> date:
"""Return the date a loan is due (R2).
>>> due_date(date(2027, 1, 4))
datetime.date(2027, 1, 18)
"""
return borrowed + timedelta(days=LOAN_DAYS)
def late_fee(due: date, returned: date) -> float:
"""Return the late fee in dollars (R3): $0.25 per day late, at most $5.00.
>>> late_fee(date(2027, 1, 18), date(2027, 1, 18))
0.0
>>> late_fee(date(2027, 1, 18), date(2027, 1, 21))
0.75
>>> late_fee(date(2027, 1, 18), date(2027, 2, 17))
5.0
"""
days_late = (returned - due).days
if days_late <= 0:
return 0.0
return min(MAX_FEE, days_late * FEE_PER_DAY)
if __name__ == "__main__":
import doctest
print(doctest.testmod())

Output: TestResults(failed=0, attempted=4). The four examples in the docstrings were run and all produced exactly the shown result.

A few details are worth noticing:

  • due: date and -> float are type hints. Python does not check them while running, but they tell other team members exactly what to pass, and editors use them to warn about mistakes.
  • Each docstring names its requirement (R2, R3), which links the code to the traceability matrix.
  • The examples include the boundaries: returned on the due date (0.0), a normal late return (3 days, 0.75) and a return far past the cap (30 days late would be 7.50, capped at 5.0).
  • The named constants (LOAN_DAYS, FEE_PER_DAY, MAX_FEE) put every business rule in one place. If the centre changes its fee, one line changes.

The sibling unit Algorithm Design and Analysis adds preconditions and postconditions to specifications like these.

Worked example

Example 1: Specifying an interface

Write the interface (signature and docstring with examples) for can_borrow, which decides whether a member may take another item under requirement R7 (at most 3 items out at once).

  1. Choose the inputs the function needs: the member's number and the list of current loans. Choose the output: True or False.
  2. Decide the data shape: each loan is a dictionary with keys item_id, member_no, borrowed, due and returned (None while the item is out), matching the data design.
  3. Write the signature: def can_borrow(member_no: int, loans: list[dict]) -> bool:
  4. Write the docstring: "Return True if the member has fewer than 3 items out (R7). An item is out when its loan's returned value is None."
  5. Add examples at the boundary: a member with 2 items out gives True; with 3 items out gives False; with 3 loans of which one has been returned gives True.

Signature, rule, data format and boundary examples are all agreed before anyone writes the body, so Luc (who calls it from the menu) and Jordan (who writes it) can work at the same time.

User interface design

Luc designs the menu on paper first and shows it to Denise and two volunteers. Requirement N3 (usable after 15 minutes of training) shapes it: the commonest tasks come first, help is always one key away, and quitting always saves. The design document also lists the exact wording of every message, such as "Item SS-01 is already on loan to member 1042. Due back Monday, January 18."

LendIt 1.0 (mock-up)=== LendIt: Maple Grove Community Centre ===1. Lend an item2. Return an item3. Show overdue items4. Add a new item5. Search items6. Help7. Save and quitChoose 1 to 7:most common firsthelp always theresave before quit
Luc's menu mock-up, as it appears in the design document. Volunteers suggested putting Lend and Return at the top because they are used most.

The traceability matrix

How do you know the design covers every requirement, and that every requirement will be tested? A traceability matrix links them. Each row is a requirement; the columns give the design element that meets it and the tests that check it. Gaps jump out: a requirement with no test, or a test that checks no requirement (which may be testing something nobody asked for).

Req.Design elementTests
R1 add itemsitems.add_item(), menu option 4T1, T2
R2 record loans, due dateloans.due_date(), loans.lend()T3
R3 returns and late feesloans.late_fee(), loans.return_item()T4, T5, T6
R4 overdue listloans.overdue(), menu option 3(none yet)
R5 save and loadstorage.load_all(), storage.save_all()T8, T9
Part of LendIt's traceability matrix at the end of design. R4 has no test yet, which the design review must fix.

The same check as a program. A dictionary maps each requirement to its list of tests; a set collects every test that is used, so that unused tests can be found.

trace = { # requirement -> tests that check it
"R1": ["T1", "T2"],
"R2": ["T3"],
"R3": ["T4", "T5", "T6"],
"R4": [],
"R5": ["T8", "T9"],
}
all_tests = ["T1", "T2", "T3", "T4", "T5", "T6", "T7", "T8", "T9"]
untested = [r for r in trace if not trace[r]]
used = set()
for tests in trace.values():
used.update(tests)
orphans = [t for t in all_tests if t not in used]
print("Requirements with no test:", untested)
print("Tests that check no requirement:", orphans)
covered = len(trace) - len(untested)
print(f"Coverage: {covered}/{len(trace)} = {covered / len(trace):.0%}")

Output: Requirements with no test: ['R4'] / Tests that check no requirement: ['T7'] / Coverage: 4/5 = 80% (one line each)

Worked example

Example 2: A design review

At the design review, the team checks the design against the four things named in B1.2. What questions do they ask, and what did they find?

  1. End-user needs: Does every Must requirement have a design element? The matrix shows yes, but R4 has no test. Denise and two volunteers walk through the paper menu: they ask for the member's name, not only the number, in the overdue list. Added to the design.
  2. Functions as intended: Do the interfaces fit together? Jordan checks that every function main.py calls exists in an interface spec with matching parameters. One mismatch is found: the menu planned to pass the item name to lend(), but the interface takes the item ID. Fixed in the design, which costs minutes now instead of hours later.
  3. Quality standards: Is there a coding standard? The team adopts PEP 8 naming, a docstring on every public function with the requirement ID, and review of every change by a second member.
  4. Budget and timeline: Does the design fit the schedule? The modules match the WBS tasks E, F, G and H. The extra overdue column is small, so the schedule holds. Cost stays at $0 (Python's standard library only, no paid packages).

The review produced three changes, all cheap because no code existed yet. The design is approved and becomes the guide for the development stage.

Just for fun

A saying passed around programming teams for years: "Weeks of coding can save you hours of planning." Read it twice. It is a joke, and it is also a warning.

Hands-on activity

Project step 5: Write your design document

You need: your scope document and requirements, paper, and Python.

  1. Architecture: split your project into 3 to 6 modules. Give each a one-sentence responsibility and an owner (or a "hat" if you are working alone). Draw the diagram.
  2. Data design: write the exact format of every file and the main data structures. Use ISO dates if you store dates.
  3. Interfaces: for each module, write the signature and docstring of every public function, with at least two examples each, including a boundary. Put them in real .py files with the bodies replaced by pass or a simple placeholder, so that the files already run.
  4. User interface: sketch your menu or screens and write the exact wording of three error messages. Show the sketch to your client and note their reaction.
  5. Coding standard: write five rules your team will follow.
  6. Traceability matrix: link every requirement to a design element and to at least one planned test (give tests IDs now; you will write them in the testing lessons). Run the traceability program on it.
  7. Design review: go through the four questions from Example 2 with your team or client. Record changes. Save everything as docs/design.md and the stub .py files in your project folder.

What to look for: someone else could code any one of your modules from the document alone; no requirement without a test; no guessing about formats.

Your turn

1

Name five sections of a software design document.

2

Why is storage.py the only module allowed to read and write files?

3

Write the date January 4, 2027 in ISO 8601 form, and give one reason to store dates this way.

4

What does the type hint in def late_fee(due: date, returned: date) -> float: tell another programmer?

5

What is the output of late_fee(date(2027, 1, 18), date(2027, 1, 25))? Explain.

6

What two kinds of gap does a traceability matrix reveal?

7

Name the four things a B1.2 design review checks.

More practice: warm-up

1

What does SDD stand for?

2

What is a doctest?

3

In LendIt's loans.csv, what does an empty returned field mean?

4

What is a coding standard?

5

What is the design-review stage's big advantage?

More practice: on your own

1

Write the interface (signature and a docstring with two examples) for days_late(due, returned), which returns 0 if the item is on time or early.

2

Why do the doctest examples for late_fee include a return far past the cap?

3

In the traceability program, what would be printed if "R4": ["T7"] were used instead of "R4": []?

4

Jordan wants main.py to calculate the late fee itself "because it's only one line". Using the architecture, explain why this is a bad idea.

5

The design document says dates are date objects in memory and ISO strings in files. Which module converts between them, and what Python methods could it use?

Challenge

1

Write the body of can_borrow from Example 1 and give its result for member 1042 with loans of SS-01 (out), SK-07 (out), GM-12 (returned) and SK-02 (out).

2

Extend the traceability program so it also prints, for each requirement, how many tests check it, in the form R3: 3 test(s). Write the loop.

3

A teammate says, "Design documents are a waste of time in agile projects; the code is the documentation." Give a balanced response.

Check your understanding

Quiz

1.

Which section of a design document gives exact file formats?

2.

What is the main purpose of interface specifications?

3.

A traceability matrix shows that requirement R4 has no test. What should happen?

4.

Why does LendIt store dates as 2027-01-04 in its files?

5.

What does print(doctest.testmod()) print when all 4 docstring examples pass?

6.

At a design review, which question checks "budget and timeline"?

For parents and teachers

Big idea: B1.2 asks students to develop the software according to the project plan, making sure it meets user needs, works as intended and fits quality standards, budget and timelines. B1.3 asks them to produce software to specification. The design document is where those checks happen before coding: architecture, data formats, interfaces with examples, screen mock-ups, coding standards and a traceability matrix.

How to help: Take part in the design review as the client. Look at the menu sketch and say honestly what confuses you. Ask "Which part of the design does this requirement?" for two or three of their requirements.

Common difficulties:

  • Skipping the design and coding straight away; the cost appears later as modules that do not fit.
  • Vague data formats ("a file with the loans in it").
  • Docstrings without examples, or examples that miss the boundaries.
  • Putting business rules in the menu code instead of in their module.