OOP Anti-Patterns

The design mistakes interviewers plant in code review questions, how to name each one, and the refactoring that fixes it.

Overview

An anti-pattern is a design that looks reasonable, gets used again and again, and reliably makes code harder to change. Most of the ones in this topic are code smells: surface signs that a deeper design problem is near. Kent Beck coined the term 'code smell' while helping Martin Fowler with *Refactoring* (1999; second edition 2018), and that book's smell catalog is where most of these names come from.

Interviewers use anti-patterns in two ways. In a code review question they hand you a class and ask what is wrong with it. In a design question they watch whether your own design drifts into one. In both cases the score comes from naming the problem precisely, saying why it hurts, and showing the fix.

A field guide

  • God class — One class that knows about everything and does most of the work — Extract classes, one responsibility each
  • Anemic domain model — Objects are only fields, getters and setters; all rules sit in service classes — Move the rules into the objects that own the data
  • Primitive obsession — Money as a float, an email as a string, an id as an int, validated in many places — A small value object per concept
  • Feature envy — A method reads another object's fields more than its own — Move the method to the object it envies
  • Data clumps — The same three fields travel together everywhere — Group them into one object
  • Switch on type — if kind == 'circle' ... elif kind == 'square' repeated in several places — Polymorphism: one class per kind, one method each
  • Shotgun surgery — One small change touches ten classes — Bring the scattered code together
  • Long parameter list — A method with eight arguments — Pass an object, or split the method
  • Refused bequest — A subclass overrides inherited methods to do nothing — Composition instead of inheritance
  • Global state — Singletons and static fields read from anywhere — Pass dependencies in

The god class

The god class is the anti-pattern interviewers ask about most, because it is what every codebase grows into without care. It starts as a helpful OrderManager and ends as three thousand lines that price orders, charge cards, send email and write reports. Every change touches it; every test needs all of it.

  • Many reasons to change — List the teams or features that would edit it
  • Imports from every layer — It talks to the database, the mailer and the payment API
  • Methods that do not share fields — Group methods by the fields they touch; each group is a class in hiding
  • Tests need everything mocked — A unit test builds five fakes to call one method

The anemic domain model

Martin Fowler described this one in a 2003 article that made the name common. The classes look object-oriented: Order, Customer, Invoice, each with fields and accessors. But none of them does anything. The rules live in OrderService, InvoiceService and friends, which read the fields, decide, and write the fields back. That is procedural code with an object-shaped skin, and it pays the cost of an object model without the benefit: any code can put an order into a state the business forbids.

  • order.status = "canceled" from anywhere — order.cancel() checks the rule and changes the state
  • Rules live in OrderService — Rules live in Order
  • Invalid states are possible — Invalid states are refused at the door
  • Tests need the service and its dependencies — Tests build an Order and call a method

What you will be able to do

  • Name ten anti-patterns from a description of the code and say what each one costs.
  • Refactor a god class by grouping its methods around the fields they share.
  • Turn an anemic model into a rich one by moving each rule next to its data.
  • Replace a primitive with a value object and a type switch with polymorphism, and show the tests that get simpler.
  • Explain how to refactor a large class safely, one extraction at a time, behind tests.

Interview questions

  • What is a god class, and how do you refactor one?
  • What is an anemic domain model, and how do you make it rich?
  • What is primitive obsession, and what does the fix look like?
  • What is feature envy, and where should the method go?
  • Why is a switch on a type field a smell, and what replaces it?
  • How do you refactor safely when the anti-pattern is in code with many callers and few tests?

Sign up free to read the full topic

More Low-Level Design topics

Start free on Cariara · Coding problems · System design studio