Apply, review, or refactor code using the Observer design pattern. Use this skill when the problem matches the pattern's structural forces, especially in Kotlin/JVM backend systems. Do not force the pattern when a simpler language or framework feature is sufficient.
Apply, review, or refactor code using the Observer design pattern. Use this skill when the problem matches the pattern's structural forces, especially in Kotlin/JVM backend systems. Do not force the pattern when a simpler language or framework feature is sufficient.
Observer
Objective
Notify multiple subscribers when a subject changes without tightly coupling the subject to concrete observers.
Trigger conditions
Use this skill when at least two of these signals are present:
One state change has multiple independent reactions.
Subscribers join or leave dynamically.
The publisher should depend only on a stable event contract.
Do not select the pattern from its name alone. First identify the design forces,
the axis of change, the ownership of state, and the required lifecycle.
Do not use when
Strong consistency requires all reactions in the same aggregate transaction.
Event ordering, retries, or delivery guarantees are unspecified.
An event bus would conceal critical control flow inside a small codebase.
The example is intentionally minimal. Adapt naming and boundaries to the domain;
do not copy it as production architecture without evaluating lifecycle, failures,
observability, and concurrency.
Review checklist
The problem contains the forces this pattern is intended to resolve.
The abstraction is stable and meaningful to clients.
Concrete implementations remain substitutable.
Domain logic has not leaked into infrastructure wrappers.
Error handling and lifecycle semantics are explicit.
Tests cover each concrete participant and the client contract.
The implementation is simpler than the conditional or coupling it replaces.
A standard Kotlin, Spring, or library mechanism would not be clearer.
Testing strategy
Contract-test every interchangeable implementation.
Test client behavior against fakes through the abstraction.
Verify invalid state, ordering, and failure propagation.
Add concurrency tests where instances or shared state cross coroutine boundaries.
Use integration tests only for adapter/framework behavior; keep pattern semantics unit-testable.
Common failure modes
Pattern-first design: selecting a named pattern before understanding the problem.
Ceremony without variability: interfaces and classes that have only one permanent implementation.
Leaky abstractions: clients depend on concrete implementation details.
Hidden operational semantics: latency, retries, transactions, or thread safety are obscured.
Misplaced business rules: orchestration wrappers become the actual domain model.
Output expected from the agent
When applying this skill, produce:
A force analysis.
A pattern-fit verdict: APPLY, CONSIDER, or REJECT.
The proposed participants mapped to domain names.
A minimal implementation plan.
Kotlin code or a patch.
Tests.
Trade-offs and rejected alternatives.
Migration and rollback notes when refactoring existing code.
Related patterns and alternatives
Mediator, Domain Events, Reactive Streams
Source basis
Derived from the classic GoF pattern catalog and the public pattern description at:
https://refactoring.guru/design-patterns/observer.
Do not reproduce proprietary diagrams or paid content. Use the source for conceptual
orientation and create original domain-specific explanations and examples.