liveBook · Manning

Humble object pattern

As explained in Unit Testing Principles, Practices, and Patterns

A design pattern that moves complex logic into a testable component while leaving a thin component responsible for difficult-to-test interactions with external systems.

The humble object pattern separates complex, important business logic from difficult-to-test interactions such as frameworks, asynchronous execution, user interfaces, and external systems. The extracted component remains testable; the surrounding wrapper coordinates dependencies while containing little or no logic. section 7.1

Use collaborator count and complexity to decide where logic and tests belong:

  • Keep domain models and algorithms complex but narrow, with few collaborators; they offer the strongest return from unit testing. section 7.3
  • Leave trivial constructors and similarly insignificant code untested when tests would add little regression protection. section 7.3
  • Keep controllers wide but simple: orchestrate collaborators and defer complex decisions to extracted components. section 7.6
  • Refactor code that is both complex and collaborator-heavy; it combines high maintenance cost with poor testability. section 7.6

Refactoring customer email changes

An initial User class loads users and company data, determines employee status, updates employee counts, and sends messages. Extract the domain operation so User changes email and Company maintains its employee count; use factories to reconstruct objects from database data; then let UserController load objects, invoke the operation, save them, and send the message. Unit-test the extracted behavior with cases for corporate transitions, non-corporate transitions, unchanged types, and unchanged emails. section 7.2 section 7.3

Figure 7.4. The Humble Object pattern extracts the logic out of the overcomplicated code, making that code so humble that it doesn’t need to be tested. The extracted logic is moved into another class, decoupled from the hard-to-test dependency.

Use the figure to contrast overcomplicated code with a thin wrapper and a separate component decoupled from the difficult dependency. section 7.1

How Unit Testing Principles, Practices, and Patterns covers it

How deep it goes
Explains extraction, controller thinness, code categories, and testing choices, while deferring detailed controller integration-test treatment.
Examples
Uses a customer-management email change, User and Company classes, factories, a controller, database access, and a message bus.
What you can do after
Apply it via refactoring to extract testable domain logic from coupled code and target high-value unit tests.
How it connects
Connects business logic and orchestration with hexagonal architecture, functional architecture, domain models, controllers, and unit testing.

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Unit Testing Principles, Practices, and Patterns. The section links point to the parts of the book it draws on.