Skip to content
Part IA Michaelmas Term

The God Class Anti-Pattern

The Rookie Error

The God class (also called a “blob” or “monolith”) is a single class that attempts to do everything in the system. It parses input, performs computation, manages state, renders output, logs diagnostics, and handles all edge cases — all in one enormous file. It “works” in the narrow sense that the program produces correct output, but it is low-quality design.

Signs of a God Class

A class is likely a God class if:

  • It has many unrelated fields: a BankingSystem class that contains customerName, interestRate, filePath, graphicsContext, and errorLogger is mixing concerns that belong in separate classes
  • The name contains “Manager”, “Utils”, “System”, “Processor”, or “Handler”: these are often signs that the class does not represent a single well-defined concept but rather a grab-bag of operations
  • It exceeds a few hundred lines of code: a well-designed class typically fits on one screen; a God class scrolls through dozens of pages
  • Methods within it do not share state: parseConfig() and renderChart() both live in the same class but operate on entirely different data
  • Changing one feature risks breaking unrelated features: modifying the database code corrupts the UI because everything is tangled together

Why It Happens

God classes arise naturally when a developer starts by writing a few lines of procedural code, and then keeps adding to the same class as new requirements arrive. Without deliberate decomposition, the class absorbs responsibility after responsibility until it becomes unmanageable.

The main method is a common birthplace: a developer puts the control flow logic directly in main, then adds helper methods to the same class, then adds fields that those methods need. The result is a class that is at once the entry point, the business logic, and the I/O layer.

Why It Is Bad

Hard to Understand

A new developer (or the original developer, six months later) must read the entire class to understand any single part of it. The class’s responsibilities are tangled; you cannot reason about parsing logic without also seeing rendering code interleaved.

Hard to Test

Testing a God class requires setting up every dependency it touches, even the ones irrelevant to the feature under test. If the class reads a file, writes to a database, and sends emails, then testing the calculation logic forces you to mock files, databases, and email services — or to write fragile integration tests.

Hard to Reuse

If you need the parsing logic in another program, you cannot extract it cleanly — it is coupled to rendering and database code through shared fields and helper methods. You must either copy-paste (creating duplication) or pull in the entire God class (bringing all its unrelated dependencies).

Hard to Modify

A change to one feature risks breaking others because the code is not separated by concern. The methods share mutable state through fields, and a seemingly innocent addition of a field can have cascading effects through methods that were never meant to see it.

The Alternative: Decomposition

Good OOP design distributes responsibility across small, focused, cooperating classes. Each class represents a single concept from the problem domain and communicates with others through well-defined interfaces.

Instead of one BankingSystem class that does everything:

┌─────────────────┐
│   God Class     │
│  - parseCSV()   │
│  - calculate()  │
│  - renderHTML() │
│  - logErrors()  │
│  - sendEmail()  │
└─────────────────┘

Decompose into cooperating classes:

┌──────────┐     ┌──────────────┐     ┌──────────────┐
│ CSVParser│────→│ BankAccount  │────→│ HTMLRenderer │
└──────────┘     └──────────────┘     └──────────────┘

                 ┌─────┴──────┐
                 │ ErrorLogger │
                 └────────────┘

Each class now has:

  • A clear, single purpose
  • Its own set of fields relevant only to its purpose
  • Methods that all operate on those fields
  • Independence from unrelated concerns

Benefits of Decomposition

  • Easier to understand: you can read and comprehend one small class in isolation
  • Easier to test: you can unit-test CSVParser with a string input, without involving databases or renderers
  • Easier to reuse: CSVParser can be dropped into any project that needs CSV parsing
  • Easier to modify: changing the HTML rendering does not touch the parsing or calculation code

The Principle

The antidote to the God class is the Single Responsibility Principle (SRP): a class should have one, and only one, reason to change. If you can identify multiple distinct reasons why a class might need modification, it has multiple responsibilities and should be split.

A useful heuristic: can you describe what the class does in one sentence without using the word “and”? “This class parses CSV files” — good. “This class parses CSV files, calculates account balances, renders HTML, and logs errors” — God class.

Is It Ever Acceptable?

In very small programs (under ~200 lines total), a single class may be pragmatic. The overhead of decomposition — extra files, interface definitions, wiring code — may not justify itself for a script that fits on one screen. But as soon as the program grows beyond a few hundred lines, or as soon as another person needs to read it, the God class becomes a liability.

The key insight: “works correctly” is not the same as “well-designed.” A God class may pass its tests today, but it creates maintenance debt that will be paid with interest every time the code is touched.