How deeply should you determine the architecture of a project at the start? What criteria should you use? What should you focus on from the beginning?
In this article, we will touch on where to start designing the architecture and how to make sure that you don’t have to redo it during the process.
But first, let's answer the question - why?
For a business customer, it might seem that deeply considering the architecture in the early stages isn’t very important. You can often hear something like, "Let's quickly build something functional, and then we can make it pretty with diagrams."
But this is actually a misconception. Of course, even without a formal architecture, developers will come up with something. For example, they might take a ready-made architecture from a textbook or rely on the one they have experience with. And, in the end, something will get "built". But, based on our experience, most often you’ll get something like this:
It seems like you’ve built a structure. And it has all the features - windows, doors, balconies, a roof. And yes , you can live in it. But how long will it stand? It’s hard to say. It’s difficult to assess its quality and whether it meets the needs of those who will live in it. Additionally, due to architectural inaccuracies, the construction may be stopped at any moment because continuing would be too dangerous or costly. You might need to demolish it and start over.
That’s why planning software architecture from the start is critical. Today, we will discuss a set of rules that may not seem advanced but will help you lay a solid foundation for your projects. Inspired by Ray Dalio’s book “Principles”, I’ve developed basic principles for software architecture that I actively use in my work when starting a new project.
Principle 1: Architecture is subordinate to product and business goals
Not the other way around.
What happens if this principle is violated? When we start prioritizing the internal architecture over the needs of the people who will use the product, we forget why we’re creating it. We become "architectural astronauts", creating overly complex solutions for non-existent problems, wasting the team's time and the business’ money.
It’s less of a problem in large companies where they can afford costly experiments. But for small companies, this kind of resource misallocation can be disastrous. For example, instead of building a simple blog, a developer might get carried away and implement microservices, Kubernetes, and all the patterns they know - building a "mini-spaceship" that never takes off.
According to management textbooks, an ideal workflow starts with a company strategy, followed by a direction strategy, and then a product strategy. And the architecture should be derived from the product strategy, and based on the architecture, the code is written. I agree with this because lower-level decisions should stem from higher-level strategies. But in reality, many projects start with only a vague vision and no clear product strategy. It may exist in theory, but no one has documented it.
Software architecture is primarily about understanding the goals - who needs it and why. The architect must understand the product’s economics: how much revenue it should generate, how much the owners are willing to invest, and the time frame for launching it. Understanding the project's future is equally important.
There are tools available that help you see and understand how your product fits into the business and operates on different levels. We use some of these tools during the analytical stages. All of them provide a vision of the product and help clarify why we are writing code:
Principle 2: Architecture defines systems, their boundaries, and connections
Seems obvious, right? But let's dig a bit deeper.
Imagine looking at a plant section under a microscope. You’d see large and small cells.
The largest concentration of tissue is often at the boundaries between the cells. The same applies to systems in software architecture—what happens at the boundaries and connections is often the most critical part. What’s inside is shaped by these external connections.
A high-quality definition of subsystem boundaries and understanding types is the basis of architecture.
If this principle is ignored and boundaries and connections are not properly defined, disappointment follows. A client comes with an approximate vision, and the team jumps into iterative work without carefully defining the key system boundaries. For example, you might find out halfway through development that a crucial product element requires integration with third-party systems in an unsupported way, leading to costly redesigns.
Example: while developing a personal account for an online store, it turns out that the ability to communicate with personal managers is critical to the business, but the CRM doesn’t support real-time messaging. Imagine discovering this after spending 50% of the budget.
That’s why boundaries are essential. To address this, we often use a variation of the diagrammatic system context from the C4 model during the early stages of work. Here’s an example:
Let's say we have a system - let’s call it a "delivery service". There are people (clients, administrators) who use it and other systems with which it interacts (delivery services). We must register and consider all these connections, capturing the context of the entire enterprise.
Principle 3: Architecture works with two constraints: hardware and people
Architecture is always about constraints. Two fundamental constraints prevent us from waving a magic wand and suddenly getting a working result.
In our case, the constraints are hardware and people. Architecture must provide solutions for both.
Hardware constraints are about understanding the available equipment. We’ve all encountered applications that don’t run smoothly on powerful devices due to inadequate optimization (hello, Notion!).
As architects, we need to consider where our software will run, what devices and operating systems it will use, how much data storage is required, and network performance. And since we live in the physical world, everything breaks eventually.
When starting a new project, we try to work with the most basic numbers.
Examples of fundamental constraints:
https://gist.github.com/hellerbarde/2843375
See also: https://vercel.com/blog/latency-numbers-every-web-developer-should-know
Understanding product requirements and matching them to these constraints often begins with a simple estimate of key parameters based on the product strategy.
For example, for one sports project, we estimated the number of coaches, teams, and players, and how often they would use the platform. From this, we determined the necessary hosting setup and its cost. It’s also important to consider data volume (e.g., video, images), which can lead to cost and storage limitations or hit pricing tiers with hosting providers.
Sidenote: I am not suggesting premature optimization - trying to squeeze out maximum resource efficiency early on. Instead, I’m advising that you understand the actual business requirements and ensure your system performs adequately for them.
The second constraint is people. They have limited attention spans, limited knowledge, and different ideas about how things should work. As architects, we must always keep in mind who the architecture is for.
A developer can’t keep the entire project in mind at once. Most of their time is spent reading code, not writing it. In this sense, the architecture serves as a map, helping them navigate through the product and understand what changes need to be made and how those changes impact the system.
Architecture should work for the people who will interact with it. Understanding their skills and needs is crucial. If they aren’t available now, you’ll need a plan to onboard them—whether through hiring, contractors, or another approach.
Consider who will be working with your architecture:
- Development team: sometimes we know who will develop the project’s architecture, but other times, especially in large companies with tenders, it’s less clear.
- Internal customers and controllers: these may include CTO or an architectural committee ensuring adherence to the company's broader IT strategy.
- External regulatory bodies: in industries like finance or healthcare, these bodies will review products before launch.
- Support and development teams: often, different teams handle product development and ongoing support.
Depending on their knowledge and skills, you’ll need to tailor your architectural approach - simplifying where necessary or investing more time in training for complex solutions.
When thinking about “architecture for people” it is important to consider:
- Domain separation: Splitting a large system into domain areas (sales, order processing, product catalog, etc.) can improve team efficiency. This avoids overlap and conflict. In domain-driven design, this is known as "bounded context."
- Key architectural approaches: Decide whether to use a modular monolith or microservices. If it’s the latter, describe the interaction patterns.
If you neglect either of these architectural aspects—hardware or people—you’ll likely end up with a slow, fragile, unreliable system, or an over-complicated product where people struggle to understand and work with the code.
There are many approaches and engineering practices in software architecture textbooks, but if we look closely, we will notice that each one aligns more closely with one of these aspects:
Your task is to select those approaches that best fit your team and product, and then clearly communicate them to your team.
Principle 4: Architecture must allow the project to grow and evolve
Software architecture doesn’t just support the current product; it should enable growth and change in the future. The question isn’t "How do we design it so we never have to redo it?" but rather, "How do we design it so we don’t have to redo it in the next few months?"
Think of software architecture like a landscape design. Code will grow and expand, and some parts will fade or become obsolete. Like gardeners, we must organize and maintain it. We can, for example, transplant a "tree" (a block of code) or rearrange "flowerbeds" (modules) in our project. Unlike construction architecture, we have more flexibility in software design.
The project architecture should mainly focus on future changes to the project.
We must plan for growth—load increases, new features, additional users, new interfaces, or integrations. After reviewing the product roadmap, it’s useful to highlight the areas likely to change and focus on those.
As software architects, we must prepare the "beds" for future growth and always keep in mind what might grow within the product.
Principle 5: Code and architecture should be self-describing
In short: sometimes it is easier to write code than to draw a diagram.
Diagrams become outdated as the code evolves, and unless they’re updated regularly, they become useless.
Situations when code is better:
A code example of implementing a typical feature can better demonstrate to the team how different modules interact than a diagram. Walk the team through the code and use it for onboarding new developers.
Code examples of common patterns—such as microservice calls, logging, or authentication—can provide clarity. If there’s no time for a full feature, collecting typical patterns into one guide is helpful.
Auto-generation of code documentation: API documentation (requests, parameters, data formats) can be generated automatically. We often write server code with request and response objects, and generate an OpenAPI/Swagger specification (e.g., via Swashbuckle in .NET). There are rarer but effective examples like generating architecture diagrams based on code for infrastructure (e.g., K8S).
Additionally, tools can help developers navigate the system in absence of detailed architecture docs:
- Tools like NDepend can show how modules are related. The advantage is that the diagram is not just a static picture but an interactive map that lets you zoom into individual modules.
- Generated ER diagrams for databases can also be visual, especially with some manual grouping afterward.
For large projects, these tools will only help with parts of the application. But even with "spaghetti architecture," at least the map will be accurate.
Conclusion
If you follow these principles, your architecture won’t be arbitrary, overcomplicated, or underdeveloped. You’ll be able to create a solid architecture that’s appropriate for your project and its current stage assuming, of course, you have the time and skills!
Good luck with your architecture!
Author - Andrey Stepanov, CTO ByteMinds
Top comments (1)
Great write up. Structurizr is great. Made a video about it recently - youtube.com/watch?v=ySW7Jo9SyW0