Skip to content

Instantly share code, notes, and snippets.

@makomweb
Last active October 14, 2025 06:09
Show Gist options
  • Select an option

  • Save makomweb/8ce3964e34d47c92827a9555103503e4 to your computer and use it in GitHub Desktop.

Select an option

Save makomweb/8ce3964e34d47c92827a9555103503e4 to your computer and use it in GitHub Desktop.
SOLID principles

SOLID

Single responsible principle

  • a module should be responsible to one, and only one, actor
  • a class should have only one reason to change
  • solves the problem of God objects, tight coupling and change chains (and more)
Solution: Don't rely on technology but rely on functionality (feature)!
E.g. don't depend on email technology but depend on messenging functionality.
Sending the message via email becomes a hidden and technical implementation detail.

Open closed principle

  • software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification
  • once a software module is completed, it should not be modified when adding new functionality
  • instead its behavior should be extended by adding new code, rather than changing existing code
Solution: Make a class final and use the decorator pattern!

Liskov substitution principle

  • we should be able to replace a class with a subclass without any unexpected behavior
  • solves:
    • subclasses can be used interchangably with their base classes without altering the functionality or correctness of the program
    • prevents the use of inheritance for quick'n'dirty hacks
Solution: "Replacing" and introducing unexpected behavior must be prevented!
This can be accomplished by relying on properly typed ValueObjects instead of badly applied inheritance principles.

Interface segregation principle

  • no client should be forced to depend on methods it does not use
  • split large interfaces into smaller more specific ones so that clients only need to know about the functionlity/features they are interested in
  • solves:
    • prevents a class carrying unwanted dependencies and methods which it does not use
    • keeps code robust and easy to maintain
    • reduces the risk of bugs due to changes in unrelated methods affecting classes that should not logically be affected
    • more likely to adhere to single responsibility principle
Solution: Refactor the large interface step by step by introducing more streamlined interfaces.
The result is in contrast to have a single large interface. 
After that, let services implement only the interface which is required by the client.

Dependency inversion principle

  • high-level modules (business logic/what is done) should not depend on low-level modules (technical details/how it is done)
  • both should depend on abstractions (e.g. by using interfaces or implementing interfaces)
  • abstractions should depend upon details
  • details (concrete implementations) should depend upon abstractions
  • solves:
    • addresses the problem of tightly coupled code which often occurs when high-level modules directly depend on low-level modules
    • tight coupling leads to:
      • difficulty in modifying:
        • changing the low level module affects the high level module
      • challenging tests:
        • high-level modules are harder to test in isolation because they directly depend on the technical details (the low-level module)
Solution: Shift the concrete dependency to an abstraction and use dependency injection whenever applicable.

Sources

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment