GRASP Principles
Larman's nine patterns for the question object design keeps returning to: which class should own this responsibility? They are the reasoning behind decisions that otherwise sound arbitrary, so they are useful whenever an interviewer asks why you put a method where you put it.
part ofSoftware design & architectureoverview, primer and where to startread it →on this pageshowhide
explore
- Information Expert5 questions
- Creator6 questions
- Controller5 questions
- Low Coupling (GRASP)5 questions
- High Cohesion (GRASP)6 questions
- Polymorphism (GRASP)6 questions
- Pure Fabrication5 questions
- Indirection (GRASP)5 questions
- Protected Variations6 questions
questions
page 2 of 2How would you detect low cohesion in an existing class objectively, and what refactoring sequence would you apply to fix it without breaking clients?
basics
~20 sLook for method groups touching disjoint fields (the LCOM metric captures this), vague names, and files changed by many unrelated commits. Fix by extracting each concern into its own class, keeping the old class as a delegating facade until callers migrate.
Applying GRASP's Information Expert (assign a responsibility to the class that has the data needed) can grow a class into a God object. How do High Cohesion and Low Coupling act as a check on that, and what do you do instead?
basics
~20 sInformation Expert says 'put it where the data is', which keeps piling work onto data-rich classes. Cohesion is the veto: if the class stops having one clear purpose, move the responsibility to a new invented class — GRASP calls that Pure Fabrication.
"Any problem can be solved by adding a level of indirection — except too many levels of indirection." How do you decide when an indirection is worth adding, and what does an unjustified one cost?
basics
~20 sAdd it when you can name what it decouples: a real second implementation, an unstable external dependency, a test seam, or a place to put cross-cutting concerns. Otherwise you pay extra hops, harder debugging and more code for imagined flexibility.
When the information a responsibility needs is spread across several objects, how do you apply GRASP's Information Expert principle?
basics
~20 sSplit the job. Each object computes the part it knows and asks its neighbour for the rest — a chain of "partial experts". An order asks each line item for its subtotal; each line item asks its product for the price.
A polymorphic call selects an implementation from the runtime type of a single receiver object. How do you handle behavior that must vary on the runtime types of TWO objects — for example, collision resolution between `Asteroid`, `Ship`, and `Missile` — and what does each approach cost?
basics
~20 sOrdinary method calls pick an implementation from one object's type only. For two, you either chain two polymorphic calls (double dispatch, as in the Visitor pattern), or look the behavior up in a table keyed by the pair of types. Both trade simplicity for extensibility.
How does GRASP's Polymorphism principle relate to the Open–Closed Principle, the Liskov Substitution Principle, and GRASP's Protected Variations? Where can a design that uses polymorphism still violate them?
basics
~20 sPolymorphism is the usual way to achieve Protected Variations (hide a varying thing behind a stable interface) and to get Open–Closed behavior (add a class, don't edit existing code). Liskov is the condition that makes it safe: every implementation must be usable wherever the interface is expected.
You have wrapped a third-party service behind an interface, yet a provider change still forced edits across many callers. What went wrong, and how do you diagnose and fix a protective boundary that failed?
basics
~20 sThe interface probably wasn't stable: it exposed the provider's types, errors, or behaviour. If callers must know which implementation is behind the interface — for retries, error codes, ordering or quirks — the variation leaked and nothing was truly protected.
How does GRASP's Pure Fabrication relate to two other GRASP principles — Indirection and Protected Variations — and can you have one without the others?
basics
~20 sPure Fabrication invents a non-domain class to keep cohesion high. Indirection puts a middleman between two things so they don't touch. Protected Variations hides something unstable behind a stable interface. They overlap often, but each can occur alone.
How do you distinguish a legitimate GRASP Pure Fabrication from an abusive "OrderManager" god-service that has drained the domain model of behavior?
basics
~20 sA good fabrication has one clearly named job, a stated reason it can't live on a domain class, few dependencies, and leaves entities holding their own rules. A god-service has a vague name, many unrelated methods, and reduces entities to data bags.
How does the "put behavior where the data is" idea behind GRASP's Information Expert scale up to module and service boundaries in a distributed system?
basics
~20 sThe same rule applies to services: whichever service owns the data should own the logic and decisions about it. If one service constantly fetches another's data to decide something, the responsibility is in the wrong place — move the behavior to the data owner instead of moving the data around.
How would you measure coupling in a codebase, and when is deliberately accepting higher coupling the better engineering decision?
basics
~20 sCount incoming dependencies (afferent) and outgoing ones (efferent) per module, plus dependency-cycle checks. Accept higher coupling when the alternative is layers of indirection nobody needs — for stable, rarely-changing dependencies, or in small, short-lived, or performance-critical code.
Connascence is a model that classifies dependencies between software elements more finely than simply calling them 'coupling'. What are its three axes, and how does it make the goal of low coupling actionable?
basics
~20 sConnascence means two pieces of code must change together to stay correct. It grades each dependency by strength (how hard it is to spot and fix), degree (how many places are involved) and locality (how far apart they are). Reduce strength, degree, or distance.
Treating the GRASP controller as the single entry point per use case makes it a natural boundary for cross-cutting policy. Which concerns belong at that boundary (transactions, authorization, idempotency, tracing, validation), and what goes wrong when they are placed above it in the delivery adapter or below it in the domain?
basics
~20 sThe controller is the one place every caller passes through, so transaction start/commit, permission checks, idempotency, and tracing spans fit there. Put them in the HTTP layer and non-HTTP callers skip them; put them in entities and they get duplicated and tangled.
At architectural scale, how does the GRASP "Creator" heuristic extend into lifecycle ownership — who may create objects that cross module or bounded-context boundaries, and how does object reconstitution by persistence frameworks interact with it?
basics
~20 sEach module should own creation of its own types: outsiders send a request or data, and the owning module builds the object and checks the rules. Loading objects from a database is rebuilding an already-valid object, not creating a new one, so it may use a separate hidden path.
Cohesion is usually taught at class level. How does the same principle drive boundaries at module, service and team scale, and what happens when those boundaries are drawn on the wrong criterion?
basics
~20 sThe same rule scales up: group things that change together into the same module or service. Grouping by technical layer instead of by business capability spreads every feature across many deployables, so one change needs many coordinated releases.
How does the Indirection principle scale from a single mediating class to architectural constructs such as an anti-corruption layer, ports-and-adapters, an API gateway, or a message broker — and what changes when the indirection becomes a network hop?
basics
~20 sThe idea is the same at every scale: put something in the middle so two sides don't couple. But once the middle is a separate process, you also inherit latency, partial failure, versioning, deployment and ownership — problems a method call never had.
At architecture scale, when does replacing type conditionals with a polymorphic subtype hierarchy make a system HARDER to evolve, and what alternatives would you reach for?
basics
~20 sIt hurts when the variation isn't really by type, when several variation axes multiply into too many classes, when the variant list is duplicated in databases, APIs and configs, or when adding new operations means changing code owned by other teams. Then prefer data-driven rules, composition, or closed types with exhaustive checks.
How does Protected Variations manifest at architecture scale rather than class scale, and what makes an architectural boundary genuinely protective?
basics
~20 sAt architecture scale, the wrapped variation is whole systems: vendors, external partners, legacy platforms, data formats. Protection means anti-corruption layers, ports and adapters, versioned contracts and plugin points — boundaries that also match who owns and deploys each side.
At architecture scale, what are the costs of applying GRASP's Pure Fabrication liberally, and how would you govern its use across many teams?
basics
~20 sEach invented class adds a name to learn and a hop to follow. Overused, features spread across many thin files, entities go anemic, and reading code gets slow. Govern it with agreed roles, naming conventions, and an explicit reason for each new abstraction.
showing 31–49 of 49