← Back to overview

Blob (God Object)

This is a bloated thing that does everything. Usually a class that first grew into a universal problem-solver for the whole project, and then almost became an operating system.

It can appear because of bad architectural decisions or simply from encapsulating everything in a terrible hurry. Or from the gradual "improvement" of some class by several generations of developers who just wanted to slap on a workaround and move on.

This thing stops being fully object-oriented and takes us back to the dark ages of programming. In practice, I have seen such constructs in banking legacy. Everything designed roughly after the 2000s was already done with care — whether object-oriented or functional. Even old monoliths can be split into functions in a way that yields a modular structure that easily survives changes (it only ships together, but is developed independently).

Symptoms

  • The class is huge and has a dozen responsibilities: business logic, validation, data access, logging, formatting.
  • The module "knows everyone": it calls services, hits the database, builds reports.
  • Almost every method takes and returns "everything under the sun".
  • Any change has to go through this class.

Why it happens

Again, very often the blob is just the first symptom of deeper problems. I have seen brave people try to refactor it (and I took part a couple of times myself). Behind that pile-up there are usually dozens of specific bad practices.

I think I won't be far off the mark saying that every bank in Russia's top-10 has a system older than 15 years with a business-logic construct the size of a framework, around which handlers and various external interfaces are neatly arranged. The system itself resists decomposition and cannot be rewritten in the coming years.

Example

The "bad" version: one class that does everything:

class OrderService:
    def create_order(self, cart):
        ...
    def apply_discount(self, order, code):
        ...
    def calculate_total(self, order):
        ...
    def save_order(self, order):           # data access
        ...
    def build_invoice_pdf(self, order):    # reports
        ...
    def send_email(self, order):           # notifications
        ...
    def validate_customer(self, c):        # business rules
        ...

The "good" version: the class delegates responsibilities to services:

class CreateOrderHandler:      # orchestration
    def __init__(self, pricing, storage, notifier):
        ...
    def handle(self, cart):
        order = Order(cart.items)
        pricing.apply_discounts(order)
        storage.save(order)
        notifier.order_created(order)

How to fix it

  • Split responsibilities by what changes together (the single responsibility principle).
  • Break it into services and modules without touching external interfaces.
  • First add characterization tests, then extract methods and classes one by one.
  • Don't try to rewrite it all at once — refactoring proceeds in iterations.