Software Architecture — Principles, Rules and Styles
All you need to know about software architectures — their purpose, core principles, and rules, their role in an organisation and their impact on dev teams.

Developing software requires much effort and taking into account multiple aspects. However, the critical mission should be customer-centricity. It implies the software is there to serve our end users and fulfil our customers' needs. As a matter of fact, users are more nowadays demanding than 20 years again when consuming an application. Besides, more and more startups emerge. Their successes rely on user-friendly web or mobile applications, beautiful design, great user experience, intuitive (straight to action, tiny time to value), smooth and reliable.
At the same time, many users are IT professionals themselves, such as developers, architects, engineering managers, and product managers. And the codebase and software architecture are maintained (or consumed) by them every day. Easiness, beautiful design, great experience, intuitively, smoothness and reliability counts too. All aim to build a great software product.

In the article, we will discuss a technical matter, i.e., software architecture, concerning software engineers and architects.
First, let’s start with the purpose and core principles before jumping into several architecture styles. At last, I will give my insights in terms of the role and impact software architectures could have on teams and the whole company.
Related articles:
- My path of software craftsmanship — the long way, my return on the experience of 10 years of craftsmanship
- Hexagonal architecture — a way to isolate business logic in code
- Automated quality gate — the first gate to support continuous quality, a first step to improving code quality
Purpose
Customer-centricity, as described earlier, has the following aspects:
- Quality, development efficiency, and time to market, in other words, less friction
- Standards and compliance
- Alignment of product and system strategy with organisation and team topology
- System design upfront to ensure customer centricity
- Help people understand, and make the right decision, to reduce risks and impacts
Quality is the most debatable and nuanced topic among them because it is intrinsic to all aspects of the digital product. But in software development, most projects and teams would omit many aspects of the quality to favour quick wins. Here, I prefer to limit only the quality of how the software is made: the codebase of the software and its components. When the development takes into account quality at every single stage, the development process can be more efficient (less quality issues that slow down teams in their work).
The way to build software must also comply with some standards (coding conventions, patterns, architecture styles), either defined within the engineering teams (guidelines and decisions instances) or referring to public compliances (security, data privacy, legal).
The organisation of code and how we manage several projects have an impact on how teams are organised, and vice-versa (for example monolithic and microservices). The architecture represents and enforces the alignment between the product and the technical system; the development process, and the organisation and team topology.
The way we structure our codebase and components has a direct impact on how we deploy the software. Dependencies between components also emanate and provoke some friction between teams. Not only that, frictions come because of a lack of developer-centricity (referring to customer-centricity earlier). If the codebase is hard to understand and to work with, productivity and time to market are at risk. And last, knowledge of functional and technical details are the sinews of war, as good decisions require a good understanding and mastering of the current state of architecture.
The purpose of software architecture is to provide guidance, standards and governance to help developers while enforcing the quality of the software and the quality of the developer’s experience.
Principles & Rules
For decades, software engineers have learned from school, from books, and from others, tons of coding practices, including best practices, rules, paradigms, design patterns, and architecture. But everything starts from the experiences of ourselves and our predecessors. And the foundation comes from principles and rules.
Five (5) sets of golden principles:
- KISS, YAGNI, DRY, SOLID, ACID: Our duty is to tackle complicated and complex things to make things simple. That means also not overdoing things (over design, over generalisation), which leads to technical debt. When things are simple, the task is easier, the effort is smaller, then the time to market is shorter, and finally, the time to value for users is tiny. In short, lean and no waste.
- Modularity & responsibility isolation: It’s just a matter of time before a system grows more and more complex, and gets messy. The key here is to split into modules by separating concerns. Each module has a concern with a clear responsibility. Similarly, we apply the same principle to lower-level elements, such as classes and functions. A function does only one thing, but good. A class has a singular responsibility. It’s then easy to visualise and navigate through all modules of the system. Explicit naming conventions help in this regard. Single responsibility (with good isolation) eases the understanding and allows decoupling. Later when migration is required, things are just smoother to move around.
- Extendability & evolvability: At the start of a project, things are quite simple. If for example, we require 1 man-month to get a feature delivered, we should require close to the same amount of work to deliver a similar feature. In reality, the longer a system lives, its complexity grows over time. So the effort to deliver a feature is much bigger than when we start a green field project. A system must be extendable at a low cost, enabling us to add new features seamlessly.
- Testability & readability: A software well tested is more guaranteed to function as expected. A good testable system implies also that it is made to be understood. Putting effort into making a system, a module or a component more readable helps to reduce the friction in working with them. Easy to get in and out.
- Maintainability, operability & scalability: Tested systems are less buggy, and less error means also fewer issues in production. But when there is any issue, we would love to find easily traces and troubleshoot. A system must be made so that we can see its running state, observe what’s happening, and be alerted if we must act quickly on the problem. Effective monitoring and observability would help to find the root cause and shorten the time to fix it. Automation is the way to go for reducing the cost of operation. Besides that, modularity combined with automation allows to easily scale up or down the whole application or parts of the application.
💡 Implementing these principles in your team’s software development workflow can be a challenge. But if you use tools like Bit, that becomes easier. With Bit’s component-driven architecture, you can develop, test, version, document, and publish independent components which you (or your team) can then share and reuse across multiple projects, reducing development time considerably and cutting down on boilerplates.
Learn more:
Seven (7) rules:
- Implement the golden principles as cited above.
- Divide and conquer: complexity exists even in small systems and can be broken down into smaller ones.
- Respect standards and conventions: there are public common standards and conventions, and teams may define their own on top of them.
- Compose and isolate units of work: Improves focus and clarity — getting things done easily as a result.
- Allocate time-box for each unit of work: the concept of a unit of work allows a better focus and prioritisation and gets things done one at a time.
- Write code for others to easily read and maintain: code has a life cycle, and may last for decades, so don’t write for yourself only. Sooner or later someone else will take over to change, refactor or maintain the codebase. This should always be considered.
- Boy Scout: always leave the code cleaner than you found it. One day you’ll take over someone else’s code.
Architecture Styles
There are more than ten architecture styles, but here we’ll cover only 5 of them because they are of interest from my point of view.
- Layered Architecture
- Domain-Centric Architecture
- Microservices Architecture
- Event-Driven Architecture
Layered architecture
The layered architecture style is one of the most common architecture styles. Modules or components with similar functionalities are organised into horizontal layers. As a result, each layer performs a specific role within the codebase.

These 5 layers are commonly known as presentation, application, domain, persistence, and data. However, this style does not have a restriction on the number of layers but embraces the concept of separation of concerns, which helps to understand the roles and responsibilities of each layer and the relationship between them.
Domain-Centric Architecture
Inspired by DDD, this takes form in an attempt to isolate the business logic from technical concerns, at the code level. Just like its name suggests, the domain is at the centre, isolated from the infrastructure. There are 3 similar styles that are mentioned by several communities, conferences and books.

To name them: onion architecture, hexagonal architecture and clean architecture. I won’t go into details as I have already written an article on hexagonal architecture and mentioned a bit about the 2 other styles.
Microservices Architecture
This architecture has been hyped for about a decade now. The intent was to divide a complex system (back then monolith) into sub-systems that take up single responsibility as a service. They have their own characteristics and come with benefits and drawbacks. I won’t go into too much detail but focus on what is relevant.
The key point of microservices is team autonomy in how to build and deploy. A microservice has its own autonomous and independent lifecycle: build, maintenance, and scalability. The team owning it may have its own practices and standards and can use a technical stack of choice. It is relatively small — but it’s a subject of debate on how small it should be.
On the other hand, there are a few challenges in terms of cross-service interaction, deployment, monitoring and observability.
By analogy, a monolith system is like a Titanic, whereas a microservices system is like a small town. Let’s imagine we have several buildings, houses and apartments within a city, each one has its role and responsibility. On the Titanic, there are over many facilities and 1720 rooms for passengers. To host the same number of people, we would need more space (around 50 square kilometres) and define that as a small town holding about 500 buildings (houses, apartments and facilities).
If there is any issue, what would happen on either the Titanic or in the small town? With a monolith, everything is in the same boat, centralised. With microservices, it would be challenging to troubleshoot as everything is distributed. Then there are some tools and patterns to centralise things so we can have better visibility and control, such as APM (application performance monitoring), ESB (event service bus) and API gateway (routing, filtering, authentication, security, quotas).
💡 Note: Microservices can be complex — but making the right decisions on identifying and isolating each microservice is half the battle. Treating the microservices architecture like composable building blocks is key, and it’s made easier with Bit.
Learn more:
Event-driven architecture
As described earlier, microservices are to communicate with each other, either using a request/response over REST and/or via events using a message broker. The pattern of propagating events through the system is called event-driven architecture (EDA). It allows services to be more responsive (async calls), to easily scale (each service may independently scale up/down), be fault tolerant (a service may fail, but not the system), and robust (retries with persistent messages).
The five (5) elements are:
- an event: message/notification that is generated and published by a producer and consumed by consumers. They carry information about an action or state change within the system.
- a producer that publishes an event to trigger something, for one/many consumers to react to it.
- a consumer who can subscribe to a specific channel in order to receive events and react to them.
- an event channel: a medium through which events are delivered. These can be pub/sub channels, point-to-point channels, and hybrid channels.
- a message broker that carries all messages in a robust and reliable manner.
The role of the software architect
Architects are required to have a broad and deep knowledge of software development, technology and technical practices in order to be good at design and taking decisions.

The software architect works very closely with teams to support the teams, product managers and engineering managers. They usually collaborate with the enterprise architect and solution architect as they are doing deep dives into details and are more operational in supporting the delivery team. In some companies, there may not have a solution and/or enterprise architect.
Their role is to:
- Make high-level design choices and technical decisions.
- Communicate with teams and clients/PM/PO to align the implementation with the functional requirements.
- Ensure software meets all technical and functional requirements (quality, security, modularity & responsibility isolation, extendability & evolvability, testability & readability, maintainability, operability & scalability).
- Define technical standards to frame the software.
Architects play an important role within an organisation, as they are empowered to make technical decisions.
The impacts
Then any decision will have a direct or indirect impact on the teams’ work and planning. There are some cases where a technical issue can block a feature from being prioritised. For example, if a decision is about to forbid the use of a tool that is required to develop a feature, then that feature can’t be implemented.
Nevertheless, any bad decision would result in technical debt which will be hard to re-align later on and could also create some frustration within the teams. For example, a pattern that has been introduced and used by many teams will stay certainly for a long time before anyone can remove it.
Wrap up
We have discussed the purpose of software architecture. We learned that user-centricity is key, but technical requirements are also super important in the long run. And everything is related to quality, including functional and technical aspects. We have also discussed the principles and rules that serve as a foundation to enforce the quality and continued existence of the software, as it is meant to keep evolving in time. Then we went through a few architectures such as layered architecture, domain-centric architecture, event-driven architecture and microservices. Each of them has their own characteristics and benefits. And lastly, we discussed the importance of the architect’s role.
I hope you found this insightful!
Glossary
- DRY: Do not repeat yourself
- DISS: Keep it simple and stupid
- YAGNI: You are gonna need it
- SOLID: Single responsibility, open-close, Liskov substitution, interface segregation, dependency inversion
- ACID: Atomicity, coherence, isolation, durability
- EDA: Event-driven architecture
- REST: Representational State Transfer
- ESB: Event service bus
- API: Application programming interface
- APM: Application performance monitoring
- DDD: Domain-driven design
- PO: Product owner
- PM: Product manager
Build composable apps with reusable components, just like Lego

Bit is an open-source toolchain for the development of composable software.
With Bit, you can develop any piece of software — a modern web app, a UI component, a backend service or a CLI script — as an independent, reusable and composable unit of software. Share any component across your applications to make it easier to collaborate and faster to build.
Join the 100,000+ developers building composable software together.
Get started with these tutorials:





