Home Blog Design SOLID, CUPID & GRASP – three (more) principles that every developer should know about

SOLID, CUPID & GRASP – three (more) principles that every developer should know about

Continuing our ‘fancy acronym’ series (everything has to have one!) it’s time to take a look at three more sets of design principles: SOLID (single responsibility, open-closed, Liskov substitution, interface segregation, dependency inversion), CUPID (composable, Unix, predictable, idiomatic, domain-based) and GRASP (general responsibility assignment software patterns). These three acronyms all have an appeal to us at Boldare.

SOLID, CUPID & GRASP – three (more) principles that every developer should know about

Table of contents

You might be also interested in the article:

KISS, YAGNI, DRY – three principles that every developer should know about

KISS, YAGNI, DRY – three principles that every developer should know about

What is SOLID, and why is it more than just an acronym?

The mnemonic acronym SOLID incorporates a set of software principles of object-oriented design. Originally introduced by Robert C. Martin in his 2000 paper “Design Principles and Design Patterns”, and later turned into an acronym by Michael Feathers, the ingredients are:

Single responsibility principle – “A class should have one and only one reason to change, meaning that a class should have only one job”

The idea is that each individual class only has responsibility for one part of the software or digital product’s function; i.e. each class does just one thing, keeping the design as simple as possible, and therefore future changes and updates are easier and less disruptive.

Open-closed principle – “Objects or entities should be open for extension but closed for modification”

Again, with future changes in mind, each class should be capable of being extended (open) but its source code should not be changeable (closed).

Liskov substitution principle – “Let q(x) be a property provable about objects of x of type T. Then q(y) should be provable for objects y of type S where S is a subtype of T”

Or, in other words, each derived class is substitutable for its parent class – similar to the open-closed principle, it ensures that extending derived classes cannot fundamentally change the behavior of the product.

Interface segregation – “A client should never be forced to implement an interface that it doesn’t use, or clients shouldn’t be forced to depend on methods they do not use”

This encourages multiple, client-specific interfaces rather than attempting to extend the use of an existing interface.

Dependency inversion principle – “Entities must depend on abstractions, not on concretions. It states that the high-level module must not depend on the low-level module, but they should depend on abstractions”

The idea here is to decouple the software’s modules, avoiding unnecessary dependencies, resulting in code that is more flexible and reusable.

SOLID has in mind that software evolves. However awesome your digital product is on release, times change, user needs change, business priorities change, and the software will likely be updated, expanded, refactored, etc. By applying the SOLID principles, designers and developers can ensure that future updates are as pain-free as possible. SOLID products are more maintainable, scalable, testable, and reusable.

You might be also interested in the article:

Is TypeScript a good investment for your next digital product?

Is TypeScript a good investment for your next digital product?

What is CUPID, and why is it… joyful?

CUPID is the creation of Dan North, originating as a criticism of the SOLID principles above. Of course, just being critical isn’t very constructive or helpful, hence the suggestion of CUPID as a replacement. What does CUPID stand for?

Composable – “plays well with others”

Composable code has classes and functions that are easily combined, assembled in different combinations, to address specific requirements. It is also intention-revealing, requires minimal dependencies and small surface area.

Unix – “does one thing well”

Unix is a longstanding operating system (or family of systems) that led to today’s Linux. The Unix philosophy encourages coding components that work well together, each doing one thing and doing it well. Again, a call for simplicity.

Predictable – “does what you expect”

The goal here is code that is robust, reliable, and resilient. It should also behave as expected. If it looks like X then X is what it should be and do. No unpleasant surprises are the idea here.

Idiomatic – “feels natural”

Quirky code is out! With CUPID, the code should be understandable by someone else, not just you, the original coder. (To be clear, that “someone else” is an experienced developer who understands the language in use, including its libraries and so on).

Domain-based – “the solution domain models the problem domain in language and structure”

The code should be compatible with its domain, using the problem domain’s language to avoid the need for future developers to ‘translations’ or cognitive leaps in order to understand it.

The advantages of CUPID (that have nothing to do with bow and arrows)

CUPID principles have the same basic philosophy as SOLID: when coding, think about the people who will come after you. The idea is that when some future developer has to dive into your code, they find it easy to understand, navigate, and update – Dan North refers to this as “joyful software”!

You might be also interested in the article:

What is Webflow and how did we build an animal-saving website with it?

What is Webflow and how did we build an animal-saving website with it?

SOLID vs. CUPID - Is the new always better?

Given that CUPID is a response to SOLID (and in some ways, its antithesis) it makes sense to take a moment to compare the two…

First up, there’s no denying that CUPID is more straightforward at first glance – check out the above descriptions again! That said, software development is not a simplistic field so maybe we should be wary of ‘simple’? It’s worth noting that Dan North goes into more detail than we do here in his original article, and has promised to explore each aspect of CUPID in more depth in the future. So, CUPID appears simpler now, but maybe we should wait for more nuance to arrive…

One clear difference from the get-go is that while SOLID is a set of principles to use during development, CUPID describes the properties that the finished code should have. One focuses on process, the other on results. In that sense, SOLID is arguably a little more restrictive, telling you how to code. Whereas CUPID is more free, however you get there is up to you, as long as the finished product has its five properties.

However, both have the same goal: software and code that can be more easily updated because it’s less likely to present obstacles to people who work on it in the future. The target is the same – it’s up to you which you feel most comfortable with.

You might be also interested in the article:

What is code refactoring and why should you agree to it?

What is code refactoring and why should you agree to it?

What is GRASP, and why is it challenging?

GRASP stands for general responsibility assignment software patterns and is a collection of, “nine fundamental principles in object design and responsibility assignment”, as described by Craig Larman in his book Applying UML and Patterns (1997).

The nine GRASP principles (or challenges) are:

  • Creator – Who creates an object or a new instance of a class?
  • Information Expert – What responsibilities can be assigned to an object?
  • Low Coupling – How are objects connected to each other? How do you support low dependency, low change impact, and increased reuse?
  • Controller – How are requests delegated from UI layer objects to domain layer objects, including coordinating the system operation?
  • High Cohesion – How are the operations of elements functionally related? How do you keep objects focused, understandable, and manageable, (including supporting Low Coupling)?
  • Polymorphism – How do you handle alternative elements based on type? How do you create pluggable software components?
  • Indirection – Focused on avoiding a direct coupling between two or more elements through the use of intermediate units to handle inter-element communication, so as to avoid a direct connection.
  • Pure Fabrication – Called a ‘service’ in domain-driven design, this class does not represent anything from the problem domain but is created to ensure High Cohesion and Low Coupling are achieved.
  • Protected Variations – Designing objects, subsystems, and systems so that variations in these elements does not impact on other elements?

Advantages of GRASP that you won’t find anywhere else

Rather than being a set of criteria for creating better software (like SOLID and CUPID), GRASP addresses specific development challenges and collects proven programming principles of object-oriented design. Rather than a ‘set of rules’ for better software or a description of well-crafted code, GRASP is more a collection of best practice answers to frequently encountered coding challenges.

As such, unlike SOLID and CUPID, GRASP is not incompatible with either – life isn’t always an either-or choice (and neither is programming).

How can SOLID, CUPID, and GRASP lead to better products?

You could argue that none of these three object-oriented design principles affect the user experience of your product too much. Maybe not, but they can bring substantial benefits to the business that owns the digital product because when that product is inevitably adjusted, updated, evolved or refactored, the process will be much easier thanks to your optimized code. That’s where time, money, and effort are saved. They also – when applied correctly – save a lot of developer stress! And that is worth more than any budget.