Smells: Bloaters
Code that has grown too big to handle — long methods, huge classes, long parameter lists, and data that should have been an object.
Big idea
A code smell is a surface sign that a design is drifting — not a bug yet, but a place bugs like to breed. Bloaters are the smells of size: methods, classes, and parameter lists that grew a little at a time until nobody can hold them in their head. Each has a standard refactoring that shrinks it back.
The bloaters
| Smell | What it looks like | Usual fix |
|---|---|---|
| Long Method | A function you have to scroll; comments that act as section headings | Extract Method at each heading (Composing Methods) |
| Large Class | Dozens of fields and methods; a name like Manager or Helper | Extract Class by responsibility (Moving Features) |
| Primitive Obsession | Money as a float, phone numbers as strings, status as magic ints | Replace Primitive with Object (Organizing Data) |
| Long Parameter List | Four or more parameters, several of the same type | Introduce Parameter Object, Preserve Whole Object (Method Calls) |
| Data Clumps | The same three values travel together everywhere (street, city, postcode) | Make them a class |
Think of it like
A junk drawer. It started as "the drawer for batteries". Then scissors went in, then takeaway menus, then a spare key. Each addition was reasonable; now nobody can find anything and the drawer won't close. The fix is the same every time: take things out and give each group its own place.
Why size causes bugs
- A long method mixes several levels of detail, so a change in one part silently affects another that shares a variable.
- A large class has many fields that only some methods use; it's unclear which ones matter where.
- Primitives carry no rules: a float doesn't know it's euros, a string doesn't know it must be a valid email.
- Positional parameters of the same type can be swapped and nothing complains.
Hands on: a long parameter list breeds a swapped argument
quote() takes five positional values, two of them rates. One caller passed tax and discount in the wrong order and the quote is wrong — nothing caught it. Refactor so that mistake can't happen (a small PriceTerms object with named fields is the classic move), keeping the output shown.
def quote(qty, unit_price, discount_rate, tax_rate, currency):
subtotal = qty * unit_price
discounted = subtotal * (1 - discount_rate)
return f"{discounted * (1 + tax_rate):.2f} {currency}"
# standard terms: 5% discount, 20% tax
print("web: ", quote(3, 40.0, 0.05, 0.20, "EUR"))
print("mobile:", quote(3, 40.0, 0.20, 0.05, "EUR")) # someone swapped the ratesoutput
web: 136.80 EUR
mobile: 136.80 EURRun and edit it in the app.
The parameter object names the values and makes "standard terms" a single thing callers share, so there's nothing left to swap.
Hands on: primitive obsession mixes units
Durations are passed around as bare numbers. One module meant minutes, another seconds. Replace the primitive with a small Duration type so the units can't be confused, keeping the output shown.
def video_length():
return 90 # minutes
def ad_break():
return 120 # seconds
def total_runtime_minutes():
return video_length() + ad_break() # adds minutes to seconds
print(f"runtime: {total_runtime_minutes()} min")output
runtime: 92 minRun and edit it in the app.
start_lat, start_lng, end_lat, end_lng appear together in a dozen function signatures. Which smell, and the usual fix?
A 120-line function has comments like "# --- validate ---", "# --- compute totals ---", "# --- send email ---". What's the natural first refactoring?
When a bloater is fine
Size alone isn't a crime: a long but flat match that maps 40 error codes to messages is easy to read; a big class that's all one responsibility (a Matrix with many maths methods) is cohesive. Refactor when size hides structure — mixed levels of detail, fields used by only some methods, values that need rules.
How it relates
- Large Class is the textbook violation of Single Responsibility.
- Primitive Obsession is why Encapsulation matters for small values, not just big objects.
- Builder is a heavier cure for long constructor parameter lists.
- Next family: OO Abusers.
Key terms
- Code smell — A surface symptom that usually points to a deeper design problem.
- Bloater — A smell of excessive size in a method, class, or parameter list.
- Primitive obsession — Using raw strings and numbers for domain concepts that deserve their own types.
- Data clump — A group of values that always appear together and should be an object.
- Parameter object — A small class that bundles related parameters into one named argument.