← Software design practices guides

How to avoid god objects and god modules

How-To Software design practices Intermediate 1101008HOWTO-1101008

HOWTO-1101008Software design practicesIntermediate

This guide shows you how to avoid god objects and god modules with SpecDD in a spec-driven development workflow.

A god object or god module is the place where unrelated behavior accumulates because it is convenient, familiar, or already central. It might validate input, render UI state, persist data, call external services, apply policy, send events, and format reports. At first this feels efficient. Later every change becomes risky because too many concerns share one owner.

SpecDD helps by making ownership visible. If one spec owns too many unrelated paths, rules, and tasks, the spec itself shows the design smell. You can then split responsibilities into smaller local specs and use non-goals to prevent the old unit from absorbing them again.

Short answer

Look for specs with broad ownership, mixed responsibilities, unrelated Must rules, and tasks that require many layers. Split the god unit into smaller specs at the right levels: model, service, adapter, component, API, job, event, policy, module, or package. Move each rule to the owning spec, add Must not boundaries to prevent relapse, and keep future tasks inside local Owns or Can modify authority.

When to use this guide

Use this guide when:

The design idea

God units are usually created by success, not neglect. A central module is useful, so more work goes there. A service already sees the data, so more decisions move into it. A component already handles the user action, so it starts saving data and enforcing policy too.

The fix is not merely “make files smaller.” The fix is to make ownership smaller and more coherent. Specs give you a place to draw those new ownership lines.

Steps

1. Recognize the god unit

Warning signs in a spec:

If the spec is hard to summarize, the code it governs is probably hard to change safely.

2. Identify separate responsibilities

Take a broad spec:

Spec: Trip Manager

Purpose:
  Manage trip creation, itinerary validation, storage, destination search, booking, and reporting.

Split the responsibilities:

Each responsibility can become its own local spec if it has durable behavior worth protecting.

3. Create smaller owning specs

Examples:

Spec: Itinerary Validation

Purpose:
  Decide whether an itinerary item can be saved.
Spec: Trip Storage

Purpose:
  Persist and retrieve trips and itinerary items.
Spec: Destination Search Adapter

Purpose:
  Translate destination search requests between trip planning and the external destination provider.

The new specs should be placed beside the code they govern.

4. Move rules to the owner

If the old broad spec says:

Must:
  Reject itinerary items without a place name.
  Save trip changes.
  Normalize destination provider results.

move those rules:

Do not leave duplicate copies behind. Duplicates drift.

5. Add non-goals to the old unit

If a coordinating service remains, narrow it:

Spec: Itinerary Service

Purpose:
  Coordinate itinerary validation and storage when itinerary items are added.

Depends on:
  ItineraryValidation
  TripStorage

Must:
  Validate itinerary input before storage is called.
  Save itinerary changes only after validation succeeds.

Must not:
  Own itinerary validation rules.
  Persist trips directly.
  Fetch destination search results.

The old central point can still coordinate, but it no longer owns every decision.

6. Review future tasks

Reject tasks that recreate the god unit:

Tasks:
  [ ] Add validation, storage, search, and reporting for the new itinerary workflow.

Split them:

Tasks:
  [ ] Add missing-place validation.
Tasks:
  [ ] Save accepted itinerary items.
Tasks:
  [ ] Normalize destination search results.

Each task belongs in the spec that owns the behavior.

Common mistakes

How to verify the result

The design has moved away from a god unit when:

← Software design practices guides