GRASP — General Responsibility Assignment Software Patterns — is a set of nine principles introduced by Craig Larman in 'Applying UML and Patterns' (1997). Where SOLID tells you how to structure individual class relationships, GRASP addresses a more fundamental question that every developer faces at design time: which object should be responsible for this behavior? GRASP provides named heuristics for answering that question systematically rather than by intuition. The patterns are not algorithms — they are lenses that make the reasoning process explicit and communicable.
Information Expert is the most frequently applied GRASP pattern and the source of the most common design question: 'Where should I put this method?' The answer: in the class that has the data the method needs. If calculating an order total requires knowing the line items, the Order class (which holds the items) should calculate its own total — not an external service that reaches inside Order to extract the items.
The Controller pattern answers: who should handle a system event (a user action, an incoming message, a scheduled trigger)? Not the domain objects — they should be ignorant of delivery mechanisms. Not the UI — it should be ignorant of business logic. The Controller is a non-UI class that receives events and delegates to domain objects. It coordinates but does not compute. In practice: a REST controller is a GRASP Controller. So is a message consumer, a CLI command handler, or a batch job scheduler — all are controllers for different delivery mechanisms.
The Polymorphism pattern addresses type-based behavioral variation. When you see a switch or if/else on a type field, that is usually a signal that the Polymorphism pattern applies: each branch of the conditional should be a subtype, and the behavior should be dispatched by the type system — not by the caller. This is directly related to OCP: the switch grows with every new type; polymorphism means adding a new type adds a new class without touching existing code.
Larman called Protected Variations 'the most fundamental principle in software design' — and it is hard to argue otherwise. Every design pattern, every architectural style, every abstraction exists to protect stable code from volatile change. The practical application: identify the points of instability in your system (external APIs, business rules that change frequently, database technology, third-party libraries) and wrap each in a stable interface. The code that depends on the interface is protected — it will not change when the instability changes.
Pure Fabrication resolves the tension between high cohesion and the need to put infrastructure concerns somewhere. Consider persistence: the Order entity should not know how to save itself to a database — that would violate SRP and introduce infrastructure into the domain. But the persistence logic must live somewhere. A Repository is a Pure Fabrication: a class invented for design purposes that has no direct counterpart in the problem domain. It exists to give persistence behavior a high-cohesion, low-coupling home. Other examples: Mapper, Logger, EventPublisher, CacheManager. All are pure fabrications — invented for the design, not for the domain.