BT

Facilitating the Spread of Knowledge and Innovation in Professional Software Development

Write for InfoQ

Topics

Choose your language

InfoQ Homepage News Is SOLID Still Relevant in Modern Software Architecture?

Is SOLID Still Relevant in Modern Software Architecture?

This item in japanese

Lire ce contenu en français

Bookmarks

Daniel Orner published a recent article arguing that SOLID principles are still the foundation for modern software architecture. According to Orner, while the practice of software development has changed in the past 20 years, SOLID principles are still the basis of good design. The author explains how they also apply to functional programming and microservices architecture, with examples.

SOLID is a mnemonic and acronym for five software design principles enumerated in 2000 by Robert C. Martin. According to the article’s author, these "SOLID principles are a time-tested rubric for creating good software" and can be adapted to modern software engineering practices.

The author points out some relevant developments in the software industry since the creation of the SOLID principles. Dynamically-typed languages and paradigms such as functional programming or metaprogramming have gained traction and are a common sight in software today. He adds that microservices and software-as-a-service made the monolithic deployment pattern less common and states that many principles governed by SOLID are no longer commonly used by as many programmers as before.

Other aspects of software design have not changed, the author says. People continue to write and modify code, it still is organised into modules, and there is still a need to define its visibility according to its intended user base.

The author proposes to reword the original SOLID principle definitions so that they become applicable to object-oriented (OOP), functional (FP), or multi-paradigm programming and, sometimes, to microservices-based systems.

The author restates the single responsibility principle as "each module should do one thing and do it well". Besides OOP, the new definition is also applicable to functional programming and microservice design.

The open-closed principle becomes "you should be able to use and add to a module without rewriting it". It is accomplished in FP by using "hook points" and is a natural characteristic of OOP.

The author defines the Liskov substitution principle as "you should be able to substitute one thing for another if those things are declared to behave the same way". It now applies too to dynamic programming languages with the help of duck typing or filter functions.

As redefined by the author, the interface segregation principle becomes "don’t show your clients more than they need to see". In other words, only document what your client needs to know. This definition is also applicable to microservices through separate deployments or separate documentation sets.

The definition of the dependency inversion principle remains the same: "depend upon abstractions, not concretions". The author believes that abstraction is still an essential concept, applying to OOP, FP, and even microservices (using message passing instead of direct communication).

Other authors have different perspectives regarding microservices. Paulo Merson argues that SOLID principles are good for OOP but do not fully apply to microservices. Therefore, Merson proposes a different set of principles for microservice design: IDEALS. These are: interface segregation, deployability, event-driven, availability over consistency, loose-coupling, and single responsibility.

Rate this Article

Adoption
Style

Hello stranger!

You need to Register an InfoQ account or or login to post comments. But there's so much more behind being registered.

Get the most out of the InfoQ experience.

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Community comments

  • With a grain of salt...

    by Paul Grebenc,

    Your message is awaiting moderation. Thank you for participating in the discussion.

    I think it's less a question of whether SOLID is still relevant, than a question of how blind one's adherence to or extreme the interpretation of these principles should be. Benefits can become liabilities, depending on how they are put into practice.

    An example would be the 'single responsibility principle'. Focusing modules in terms of a 'single' responsibility can greatly simplify your projects, reducing complexity and entanglement. However, I've seen this interpreted as a mandate to split what could logically be seen as the 'single overall' responsibility of a module into the finest-grained division of responsibilities possible. This is done to a point where the actual responsibility of each component has nothing to do with the business and only has meaning in the context of interdependencies with the rest of the implementation.

    Another would be the suggestion of the open-closed principle, that "you should be able to use and add to a module without rewriting it", but again this can come at a greater cost than not adhering to it. Unchecked, an attempt to adhere to this principle can easily lead to over-engineering solutions that can accommodate or adapt to any possible requirement change from the start. Often, it is easier, cheaper and even safer to simply rewrite something that is simple as something else that is still simple, than it is to forever bend and twist an existing component to suit new purposes.

  • Was it ever really relevant?

    by Jonathan Allen,

    Your message is awaiting moderation. Thank you for participating in the discussion.

    SOLID started out as just a random blog post with no real evidence to support the theories. In fact, it's not even the whole blog post, as six of the eleven 'principles' were dropped because they didn't fit the acronym.

    Martin himself, in the second blog post on the topic, said SOLID was no more meaningful than "Apple a day keeps the doctor away" and was about feelings and he had no proof they actually worked.

  • Re: With a grain of salt...

    by Jonathan Allen,

    Your message is awaiting moderation. Thank you for participating in the discussion.

    The reason SOLID 'works' is because nobody believes in SOLID, but instead use it as an excuse to do whatever they want.

    Consider the principles in use versus their origin.

    SRP: People say "you have to know when to apply it". Which basically means it has been reduced to "A class should only have one reason to change unless you think it should have more than one reason to change". That's not useful advice.

    OCP: If you read the original literature on OCP, it was a specific way to prevent breaking changes by making all classes inheritable, and never adding methods to an already published class. Nobody believes this any more. But rather than abandon OCP, people instead pretend it means "Do whatever you want so long as you can call it extensible". Again, not real advice.

    LSP: This is the only real principle in SOLID, and it's a very good one that should be followed 100% of the time. But since the overall rule of SOLID is, "You need to know when to apply it", LSP ceases to mean anything. "A subclass must always obey the contract of its parent class unless it doesn't" isn't advice.

    ISP: This is a fun one. Originally it was a trick to reduce recompiles in C++. The "interface" was header files. By breaking up one massive header into four smaller ones, you reduce the chance that the header you care about is the one that's changed. Useful yes, if you are already in the position of having a "god object" that you can't break up. But certainly not a situation that a Java or C# programmer will ever be in because they don't have header files. So instead it has transformed into something vague about interfaces existing.

    DI: There's two terms with this abbreviation. And two definitions for it. Dependency inversion, which is when you change the dependency chain from A -> B to B -> A. And dependency injection, where you basically acknowledge that constructors exist and you can pass an interface to that constructor. But no real guidance on when you should use either DI. So again, the developer is left to do whatever they want.

    In conclusion, SOLID only continues to exist because people ignore the meaning of SOLID and use it as a generic justification for any design. If they were forced to use a strict interpretation, they would quickly abandon it.

  • Re: With a grain of salt...

    by Dan Ormisher,

    Your message is awaiting moderation. Thank you for participating in the discussion.

    I feel like you misunderstand the point of the SOLID principles. First of all, they are principles/heuristics/rules of thumb. This means by their very nature they don't always apply. They are just a starting point for good coding practices, and a good way to think about your code in a different way.

    You also seem to be putting forward a strawman argument for most of these principles by stating what they "originally" meant rather than what the common understanding is.

    For example ISP. This has nothing to do with performance or compilation speed. It is about not loading interfaces with too many method declarations. The reasons for this are quite simple: a) It means any classes implementing the interface can remain small, which makes them more likely to adhere to SRP and also keeps them readable and easy to maintain. b) It keeps interfaces focused and more likely to describe the actions they encapsulate. Sticking to this rule has quite a dramatic impact on the readability and composability of your code.

    With regards to DI, in SOLID this refers to Dependency Inversion not dependency injection. Injection is just one of the methods to achieve Inversion. Inversion refers to removing dependencies on implementation details. For example if we have a class that instantiates a class that accesses your SQL database, you can invert the dependency there so that the class is passed an interface that contains some methods to load the data you need. Doing this decouples the class and the SQL implementation details, making them easier to change in isolation.

    You shouldn't expect SOLID to give you implementation details, as like I stated earlier they are just rules of thumb for good practice. Implementation details vary from language to language and like with everything in programming 'the developer is left to do whatever they want'. In the end they all come down to patterns to try and make your code easier to change, and there are no hard and fast rules for that.

  • Re: With a grain of salt...

    by Jonathan Allen,

    Your message is awaiting moderation. Thank you for participating in the discussion.

    If ISP meant what you think it means, then it's redundant with SRP. A class should never have enough responsibilities to implement multiple interfaces or even a single complicated interface.

    Yes, the common understanding no longer has anything to do with the original, but that's not a strawman. It's part of the explanation for how the parts of SOLID devolved from specific recommendations to generic slogans.

  • Re: With a grain of salt...

    by Jonathan Allen,

    Your message is awaiting moderation. Thank you for participating in the discussion.

    I feel like you misunderstand the point of the SOLID principles. First of all, they are principles/heuristics/rules of thumb. This means by their very nature they don't always apply.



    That is a fundamental flaw in the whole concept.

    SRP doesn't mean anything if you don't apply it consistently. Again, "A class shouldn't have more than one reason to change unless it has more than one reason to change" isn't useful advice.

    The goal is LSP is that subclasses ALLWAYS fulfill the base class contract. If you only occasionally apply the rule, then you lose all of the advantages.

    Contrast this with the Framework Design Guidelines, which specifically distinguishes between "must" and "should" rules and explains in which circumstances the rules can be disregarded.

  • Architecture?

    by Saheem Siddiqi,

    Your message is awaiting moderation. Thank you for participating in the discussion.

    As principles of OO design, yes, they are still relevant. However, I'm not aware of these principles being elevated to motivating specific architectures. What's the architectural equivalent of inheritance that would make Liskov's relevant, for example?

    In any case, with respect to the original article, the major hurdle to applying SOLID is OO design itself. People don't do it. The industry is rife with very procedural, script-oriented design with the Class serving as a mechanism to capture common routines based on data flow. The cohesion between class attributes in these situations is low. This is neither right nor wrong. The point is the spirit of SOLID is violated without attempting OO design. Are you attempting object modeling with all that it entails: identification and representation of domain concepts, encapsulation, design-to-interfaces, etc. It's challenging and time-consuming to get right. Many people decide to ignore it, and so SOLID becomes lipstick on a pig.

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

BT