Reading Code Line by Line — ReportBuilder
How Thoughtful Design Turns Raw Data Into Structured Information
This code defines a small reporting system that collects numeric records and turns them into a structured summary.
Each record contains a category and an amount. The class stores those records, normalizes the data format, and then calculates useful information such as totals per category and percentage distribution.
In the end, the build_report() method combines everything into a single structured report that includes the total number of records, the totals per category, and the percentage distribution of the values.
from typing import Dict, List
from collections import defaultdict
class ReportBuilder:
"""
Build structured reports from raw numeric records.
Each record contains a category and an amount.
"""
def __init__(self) -> None:
self.records: List[Dict[str, float | str]] = []
def add_record(self, category: str, amount: float) -> None:
""" Store a normalized record."""
record = self._normalize_record(category, amount)
self.records.append(record)
def _normalize_record(self, category: str, amount: float) -> Dict[str, float | str]:
"""Ensure consistent data format."""
return {
"category": category.strip().lower(),
"amount": float(amount)
}
def totals_by_category(self) -> Dict[str, float]:
"""Aggregate totals per category."""
totals = defaultdict(float)
for record in self.records:
totals[record["category"]] += record["amount"]
return dict(totals)
def _sorted_totals(self, totals: Dict[str, float]) -> List[Dict[str, float | str]]:
"""Return category totals sorted from highest to lowest."""
rows = []
for category, amount in totals.items():
rows.append({
"category": category,
"total": round(amount, 2)
})
rows.sort(key=lambda row: row["total"], reverse=True)
return rows
def percentage_breakdown(self, totals: Dict[str, float]) -> List[Dict[str, float | str]]:
"""Calculate percentage share per category."""
overall_total = sum(totals.values())
breakdown = []
for category, amount in totals.items():
percentage = (amount / overall_total) * 100 if overall_total else 0
breakdown.append({
"category": category,
"percentage": round(percentage, 2)
})
breakdown.sort(key=lambda row: row["percentage"], reverse=True)
return breakdown
def build_report(self) -> Dict:
"""Produce the final report structure."""
totals = self.totals_by_category()
return {
"records": len(self.records),
"totals": self._sorted_totals(totals),
"distribution": self.percentage_breakdown(totals)
}
records = [
("books", 120.50),
("books", 35.20),
("food", 42.10),
("food", 15.90),
("tools", 210.00),
]
report = ReportBuilder()
for category, amount in records:
report.add_record(category, amount)
result = report.build_report()
print(result)What This Program Does
This class collects simple records consisting of a category and an amount. It then transforms those records into useful summaries.
The class performs several steps:
store records in memory
normalize incoming data
aggregate totals per category
calculate percentage distribution
build a structured report
In other words, the program turns raw input into structured information. Before looking at each line of code, it helps to understand this overall idea.
Reading the Code Line by Line
Now we examine how the program is structured. The goal is not only to understand what the code does, but also to see how the logic is organized.
Imports
from typing import Dict, List
from collections import defaultdictThe code imports Dict and List from Python’s typing module, and defaultdict from the collections module.
Dict and List are type hints. They do not change how the Python interpreter executes the program, but they help static analysis tools. By reading this line, we already know the program will likely store data as lists of dictionaries.
defaultdict is a specialized dictionary type. It automatically creates a default value when a missing key is first accessed.
For example:
defaultdict(float)means a new key automatically starts with:
0.0This makes it especially useful for counting, grouping, and aggregation tasks.
From these imports alone, we can already infer two things:
the program stores structured data in lists and dictionaries
the program likely uses automatic default values during aggregation
Defining the Class
class ReportBuilder:The class name clearly communicates its role. It does not simply hold data. It builds a report from records. Good naming is one of the first signs of well-designed code.
Class Documentation
"""
Build structured reports from raw numeric records.
Each record contains a category and an amount.
"""The docstring explains the responsibility of the class.
Two key ideas appear immediately:
input consists of raw records
each record contains a category and an amount
Example input might look like this:
("food", 12.5)
("rent", 800)
("food", 7.25)These incoming values are later normalized and stored internally as dictionaries like:
{"category": "food", "amount": 12.5}The rest of the program transforms these simple records into a structured report.
Object Initialization
def __init__(self) -> None:
self.records: List[Dict[str, float | str]] = []When a ReportBuilder object is created, the constructor initializes an empty list. This list will hold all records added to the system.
Each stored record will look like this:
{"category": "food", "amount": 12.5}At this stage, the class prepares an empty container where future records will be stored.
Adding a Record
def add_record(self, category: str, amount: float) -> None:This method is the public entry point for inserting data. The user provides a category and an amount. However, the program does not store these values immediately.
record = self._normalize_record(category, amount)
self.records.append(record)Before storing anything, the input is normalized. Centralizing this step keeps the rest of the program simple and ensures that all stored records follow the same format.
Data Normalization
def _normalize_record(self, category: str, amount: float) -> Dict[str, float | str]:The leading underscore indicates that the method is intended for internal use.
return {
"category": category.strip().lower(),
"amount": float(amount)
}Two normalization steps occur here. First, the category is cleaned.
" Food "
"FOOD"
"food"All become:
"food"Second, the amount is converted to a numeric value using float(). Normalization ensures that logically identical inputs are treated as the same category. Without this step, values like “Food”, “ food “, and “FOOD” would appear as separate categories during aggregation.
Calculating Totals
def totals_by_category(self) -> Dict[str, float]:This method aggregates all stored records.
The program uses:
totals = defaultdict(float)This means every new category automatically starts with the value 0.0.
Because of that, the loop can stay compact:
totals[record["category"]] += record["amount"]There is no need to manually check whether the category already exists in the dictionary.
At the end, the method returns a normal dictionary:
return dict(totals)So the outside world still receives a plain dict, while the method uses defaultdict internally to keep the logic concise.
Sorting Totals
def _sorted_totals(self, totals: Dict[str, float]) -> List[Dict[str, float | str]]:Dictionaries are convenient for aggregation and lookup, but converting the data into a list of rows makes it easier to sort and present in a predictable order.
The totals are converted into rows like this:
{"category": "food", "total": 35.5}The totals are rounded to two decimal places to make the report easier to read and avoid long floating-point representations. These rows are then sorted so that the largest category appears first.
Percentage Distribution
This method calculates how much each category contributes to the overall total.
def percentage_breakdown(self, totals: Dict[str, float]) -> List[Dict[str, float | str]]:The percentage is calculated using:
percentage = (amount / overall_total) * 100 if overall_total else 0The conditional prevents a division-by-zero error if the overall total equals zero. Each percentage value is rounded to two decimal places to keep the report readable.
Building the Final Report
def build_report(self) -> Dict:The final method assembles the report.
First the totals are calculated once:
totals = self.totals_by_category()Those totals are then reused when building the rest of the report.
The output structure looks like this:
{
"records": 3,
"totals": [...],
"distribution": [...]
}The result is a structured summary of the data.
Interesting Design Decisions
Several design choices make this code clear and maintainable.
Normalization before storage
Incoming data is cleaned before it enters the system. This prevents inconsistent values from spreading through the program.
Small focused methods
Each method performs one clear task.
add_record → receive input
_normalize_record → clean data
totals_by_category → aggregate values
_sorted_totals → organize totals
percentage_breakdown → analyze distribution
build_report → assemble the final outputBreaking logic into small methods makes the program easier to test and maintain.
Reusing existing logic
Both _sorted_totals() and percentage_breakdown() reuse the totals produced by totals_by_category()
Computing totals once and passing them to other methods avoids repeated work and follows the single-responsibility principle, where each method performs one specific task.
A cleaner aggregation pattern
Using defaultdict(float) removes manual key initialization and keeps the aggregation logic concise. Small design choices like this often make production Python code easier to read and maintain.
Behind the Camera
When I first read this code, I do not start by examining each line. Instead, I try to understand what story the code is trying to tell.
What problem is it solving?
What kind of data flows through the program?
What is the final result supposed to look like?
Once I understand that story, I break it into smaller pieces.
For this example, the story looks roughly like this:
receive records
clean the data
store the records
calculate totals
calculate percentages
build a final reportAfter that, I go back to the code and ask a simple question for each part of the story:
Which function is responsible for this step?
When you read code this way, the program stops looking like a wall of syntax.
It becomes a sequence of decisions made by the person who wrote it.
And that is the real goal of this series:
not just to read code — but to understand the thinking behind it.

