avatarAli Zeynalli

Summary

This web page discusses 23 basic principles in software architecture, including Dependency Inversion, Separation of Concerns, Inversion of Control, Dependency Injection, Single Responsibility, Don't Repeat Yourself (DRY), Open-Closed, Persistence Ignorance, YAGNI, Boy Scout Rule, Liskov-Substitution, Encapsulation, Loose Coupling, Cohesion, Interface Segregation, Bounded Context, Stable Dependencies, Polymorphism, Modularization, Abstraction, Keep It Simple, Stupid (KISS), Incremental/Iterative Approach, and Least Knowledge.

Abstract

The web page provides an overview of 23 fundamental principles that software architects deal with on a daily basis. These principles include Dependency Inversion, which states that the direction of dependency should be towards abstraction, not implementation; Separation of Concerns, which separates software systems based on the kind of work they do; Inversion of Control, which inverts the flow of control managed by third-party frameworks; Dependency Injection, which injects dependencies through constructors in runtime; Single Responsibility, which limits each building block of a software system to one responsibility; Don't Repeat Yourself (DRY), which eliminates redundancy in code; Open-Closed, which states that a software artifact should be open for extension but closed for modification; Persistence Ignorance, which bases on the idea that code should be unaffected by the choice of database or persistence technology; YAGNI, which avoids premature optimization of a software system; Boy Scout Rule, which encourages refactoring code as anti-patterns are encountered; Liskov-Substitution, which states that subtypes should be mutually substitutable and not alter the behavior of parent classes; Encapsulation, which restricts access to components from outside the system; Loose Coupling, which states that software systems should be loosely dependent on each other; Cohesion, which refers to the degree to which the elements inside a module belong together; Interface Segregation, which states that no client should be forced to depend on methods it does not use; Bounded Context, which provides a way of tackling complexity in large applications by breaking them up into separate conceptual modules; Stable Dependencies, which states that different building blocks of a software system should only depend on reliable, stable artifacts; Polymorphism, which belongs to the 4 Pillars of Object Oriented Programming and motivates the usage of interfaces; Modularization, which divides a software system into multiple independent modules; Abstraction, which states that the process of removing physical, spatial, or temporal details or attributes in the study of objects or systems to focus attention on details of greater importance; Keep It Simple, Stupid (KISS), which motivates software engineers to keep the code simple and understandable; Incremental/Iterative Approach, which bases on the idea that software systems should be developed on an incremental and iterative manner; and Least Knowledge, which states that different parts of a software system should only have knowledge that they need.

Opinions

  • The author believes that experienced software architects are aware of these principles and able to spot the right places in their software products to implement specific principles.
  • The author emphasizes the importance of eliminating redundancy in code and avoiding premature optimization of a software system.
  • The author encourages refactoring code as anti-patterns are encountered to improve code quality over time.
  • The author believes that different building blocks of a software system should only depend on reliable, stable artifacts.
  • The author emphasizes the importance of keeping the code simple and understandable to avoid potential future misunderstandings from other peer engineers.
  • The author believes that software systems should be developed on an incremental and iterative manner, which is a basic principle of Agile Software Development Manifesto.
  • The author believes that different parts of a software system should only have knowledge that they need, which is another term for encapsulation or information hiding principles.

23 Basic Principles in Software Architecture

Photo by Cris DiNoto on Unsplash

Software Architecture bases on set of basic principles that is actual for every kind of software system. Experienced Software Architects are aware of them and able to spot the right places in their software products to implement specific principle. Let us have a quick overview over some basic principles that Software Architects deals with on daily basis:

1.Dependency Inversion… This principle states that direction of dependency should be towards abstraction not implementation. If compile-time dependency flows in direction of run-time execution this makes directed dependency. With Dependency Inversion we invert the direction of dependency control. Take a look at my following article for deeper understanding: How to apply SOLID Software Design Principles to Spring Boot Application (Part 5)

2.Separation of Concerns… This principle states that a software system should be separated by the kind of work it does. For Example: It is noteworthy to separate the software system into different pieces by business logic, infrastructure or user interface. By splitting the system into different parts based on different activity areas makes it easier to develop/test/deploy. SoC is a driving force behind Software Architecture Patterns like Domain Driven Design, Hexagonal Architecture, Clean Architecture.

3.Inversion of Control…

This principle is similar to Dependency Inversion Principle but in broader context. IoC inverts the flow of control which is managed by different third party frameworks such as Spring Framework. Unlike traditional Java EE programs where Beans are initialized procedurally by the engineer that developed it, Spring takes control of Configuration Beans, which means inverting the control.

4.Dependency Injection…

This Principle states that for example in java terms: dependency should be injected through constructor in run-time. Action Interface is injected in Human class through its HumanAction Implementation, that decides in run-time which specific action to implement. This technique gives some flexibility of dependencies:

5.Single Responsibility…

This principle’s main idea is to limit each building block of a software system by one and only responsibility. No matter what is the scope of a building block, be it plugin, package, class, function even a variable. Each of these building blocks should have only one responsibility. Take a look at my other article for deeper understanding: How to apply SOLID Software Design Principles to Spring Boot Application (Part 1)

6.Don’t Repeat Yourself (DRY)…

This principle aims to eliminate redundancy in code by avoiding duplicate code. If there is existing functionality for some behaviour this should be repeatedly used, instead of having same code snippet in multiple instances.

Every piece of knowledge must have a single, unambiguous, authoritative representation within a system.

7.Open-Closed…

A Software artifact should be open for extension but closed for modification.

This simple description of the principle was firstly introduced by Bertrand Meyer. Software system that needs modification each time for any additional functionality is just a big mess. On the other hand, this kind of chaotic program is welcoming occasional bugs every time modification is made. Preferably, every new functionality should be maximum of new code and minimum of change in old code, in ideal world: zero changes in old code.

8.Persistence Ignorance…

PI bases on the idea that code should be unaffected by whichever database or persistence technology is chosen. Business Logic should be free of any technology chosen to be applied. If tomorrow, there is better alternative persistence technology which is more effective and for better price, changing this part of software system should not affect upper abstraction layers.

9.YAGNI…

You ain’t gonna need it. This principle tries to avoid premature optimization of a software system. Often developers overengineer some things in a software system with the vision that some time in future it will be helpful. But this time often never comes.

10.Boy Scout Rule…

Always leave the campground cleaner than you found it.

The main idea here is to always keep refactoring code as you encounter anti-patterns while developing further. This leads to better code quality over time.

11.Liskov-Subsititution…

If for each object o1 of type S there is an object o2 of type T such that for all programs P defined in terms of T, the behaviour of P is unchanged when o1 is substituted for o2 then S is a subtype of T.

This definition from Barbara Liskov might sound pretty confusing but in essence, it is a simple and easy to understand principle. If we restate the above given definition, the principle’s motto is: when using inheritance, hierarchy of inheritance should be from functional and business logic aspect consistent. The subtypes should be mutually substitutable and not alter behavior of parent class. As a simple example we can take “infamous square/rectangle” problem. Where square should not be subtype of rectangle, because definition of height and length of these two geometric forms are different (square’s height and weight are equal whereas for rectangle they will vary).

12.Encapsulation…

Different building blocks of a Software System should make use of Encapsulation by restricting access to its components from outside world. This achieved by setting components private in a class scope or setting access restrictions in plugin scope (in terms of java) so hiding information.

13.Loose Coupling…

One of the most important principles in Software Architecture is Loose Coupling which means simply put loose dependencies. This principle states that software systems should be loosely dependent on each other. If one part of software systems changes, this should influence other parts minimally. Loose Coupling is possible through Dependency Inversion, Asynchronous Messaging Middleware, Event Sourcing etc. Take a look at my following article, if you want to get deeper view in different forms of coupling in software engineering: 9 Forms of Coupling in Software Architecture

14. Cohesion…

Cohesion refers to the degree to which the elements inside a module belong together. In one sense, it is a measure of the strength of relationship between the methods and data of a class and some unifying purpose or concept served by that class.

It is a best practice to have highly cohesive classes, which motivates single responsibility principle, loose coupling etc.

15. Interface Segregation…

Interface-Segregation Principle states that no client should be forced to depend on methods it does not use.

We should make it clear that, this principle is applicable mostly to statically-typed programming languages like Java, C etc. In dynamically typed languages like Python or Ruby this principle does not make a big sense.

We can imagine a situation that our Income and Expense Use Cases are dependent on a functionality that holds business logic for both cases. So Income Use Case has an abundant dependency on a functionality that is used for Expense Use Case and Expense Use Case has the same issue in respect to Income Use Case. Following is the Violation of ISP based on above discussion:

16. Bounded Context…

Bounded contexts are a central pattern in Domain-Driven Design. They provide a way of tackling complexity in large applications or organizations by breaking it up into separate conceptual modules. Each conceptual module then represents a context that is separated from other contexts (hence, bounded), and can evolve independently. Each bounded context should ideally be free to choose its own names for concepts within it, and should have exclusive access to its own persistence store. [1]

17.Stable Dependencies…

This principle states that different building blocks of a software system should only depend on artifacts that reliable, stable. This principle makes more sense in docker image terms, where you import different dependencies from docker hub without even knowing how reliable/stable are they.

18. Polymorphism…

This actually belongs to 4 Pillars of Object Oriented Programming and motivates usage of interfaces (in java terms!) which can be provisioned in multiple forms. Polymorphism means: entity with multiple forms.

19. Modularization…

Modularization is the process of dividing a software system into multiple independent modules where each module works independently. This principle is another form of single responsibility separation of concerns principles applied to the static structure of a software system.

20. Abstraction… This also belongs to 4 Pillars of Object Oriented Programming and states:

The process of removing physical, spatial, or temporal details or attributes in the study of objects or systems to focus attention on details of greater importance; it is similar in nature to the process of generalization;

21. Keep It Simple, Stupid (KISS)…

As it is understandable from the above statement this principle motivates software engineers to keep the code simple and stupid(understandable) to avoid potential future misunderstandings from other peer engineers.

22. Incremental/Iterative Approach…

This principle is basics of Agile Software Development Manifesto, that bases on the idea that software system should be developed on incremental and iterative manner. That means with every iteration software system is incremented and gone live.

23. Least Knowledge…

Or information envying is another term to encapsulation or information hiding principles which states that different parts of software system should only have knowledge that they need.

If you are interested in more Software Architecture topics take a look at my other articles.

Relevant Articles:

  1. Managing Architecture Debt with Dependency Structure Matrix
  2. Hexagonal Architecture Pattern with Spring Boot example
  3. 5 Software Design Patterns implemented in Spring
  4. Cloud-Native Architecture Patterns (Part 1)
  5. Cloud-Native Architecture Patterns (Part 2)

P.S. You can connect with me on twitter or linkedin.

Software Architecture
Software Design
Software Engineering
Clean Code
Clean Architecture
Recommended from ReadMedium