Skip to content
FollowtheDamnCode

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

SmellWhat it looks likeUsual fix
Long MethodA function you have to scroll; comments that act as section headingsExtract Method at each heading (Composing Methods)
Large ClassDozens of fields and methods; a name like Manager or HelperExtract Class by responsibility (Moving Features)
Primitive ObsessionMoney as a float, phone numbers as strings, status as magic intsReplace Primitive with Object (Organizing Data)
Long Parameter ListFour or more parameters, several of the same typeIntroduce Parameter Object, Preserve Whole Object (Method Calls)
Data ClumpsThe 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.
From a long parameter list to a parameter object

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.

Fix it: five positional parameters, two of them swapped
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 rates
output
web:    136.80 EUR
mobile: 136.80 EUR

Run 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.

Fix it: a bare number with two meanings
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 min

Run 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

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.