In software development, we often start architecture discussions with a simple question: Which technology should we use?

Should we go with microservices or a monolith? RabbitMQ or Azure Service Bus? Azure Container Registry or direct deployment to Azure App Service?

These are important questions, but I think we often ask them too early.

Before choosing a technology, we need to understand the problem we are trying to solve. Good architecture is not about using the latest tools or following industry trends. It is about understanding our requirements, comparing different options, and choosing the approach that makes the most sense for our situation.

Every Decision Comes with Trade-Offs

There is no technology that is perfect for every scenario. Every choice has its advantages and disadvantages.

Take microservices, for an instance. They allow teams to deploy and scale services independently, but they also introduce challenges around communication, monitoring, troubleshooting, and deployment.

A monolithic application, on the other hand, is often simpler to develop and maintain, especially when the team is small and the business requirements are still changing.

Does that mean a monolith is always better? Not at all. It depends on the business needs, team structure, and expected growth.

The same thinking applies when choosing databases, messaging systems, cloud services, and deployment strategies.

Example: Azure Container Registry vs. Direct Deployment

Let's consider a simple scenario. We have a .NET Web API that needs to run on Azure App Service.

We have two options.

Option 1: Direct deployment

We build the application and deploy it directly to Azure App Service through a CI/CD pipeline.

This approach is straightforward. There are fewer components to configure and maintain, and the team can focus on building and delivering the application.

Option 2: Container-based deployment

We package the application into a Docker image, push that image to Azure Container Registry (ACR), and configure App Service to run the container.

This approach gives us a consistent deployment artifact that can be promoted across development, testing, and production environments. It can also fit well with an organization that already uses containers across multiple platforms.

However, it introduces additional responsibilities, such as managing the container registry, configuring permissions, scanning images for vulnerabilities, and maintaining Docker configurations.

So, which option should we choose?

If we have a straightforward .NET application that runs entirely on App Service, direct deployment may be enough. Introducing ACR in this case could add extra work without providing much value.

But if the organization has standardized on containers and needs to deploy the same image across different environments or hosting platforms, using ACR may be the better choice.

The point is not that one option is better than the other. The point is to understand whether the additional complexity is worth the benefit.

Start With the Problem, Not the Technology

Before making an architectural decision, I find it useful to ask a few basic questions:

  • What problem are we trying to solve?
  • What are the performances, scalability, and availability requirements?
  • What happens when a dependency fails?
  • Can our team support and maintain the proposed solution?
  • What are the security implications and ongoing costs?
  • Will this decision make future changes easier or introduce unnecessary dependencies?

These questions help us move away from personal preferences and technology trends toward decisions based on actual requirements.

My Personal Approach: Using a Simple Architecture Decision Matrix

Asking the right questions is a good starting point, but how do we compare different options and decide which one makes the most sense?

One approach I find useful is to create a simple architecture decision matrix. It helps compare alternatives based on the factors that matter most to the project, rather than relying only on personal preferences or familiarity with a technology.

Let's take the earlier example of deploying a .NET Web API to Azure App Service. We have two options: direct deployment through a CI/CD pipeline or container-based deployment using Azure Container Registry (ACR).

We can compare these options using the following matrix.

Criteria

Weight

Direct Deployment

ACR + Containers

Simplicity

30%

5

3

Deployment consistency

25%

3

5

Operational effort

20%

5

3

Portability

15%

2

5

Initial setup cost

10%

5

3

Total weight

100%

The weights represent the importance of each criterion to the project. For example, if simplicity is a priority, we might assign it a weight of 30%. If portability is less important, we might assign it 15%.

The scores range from 1 to 5, where 1 means poor and 5 means excellent. Each option is scored against the same criteria.

How does the calculation work?

For each option, multiply the score by the corresponding weight and add the results. Since the weights total 100%, divide the weighted total by 5 to express the result as a percentage.

Direct deployment:

(30 × 5 + 25 × 3 + 20 × 5 + 15 × 2 + 10 × 5) ÷ 5 = 79%

ACR + containers:

(30 × 3 + 25 × 5 + 20 × 3 + 15 × 5 + 10 × 3) ÷ 5 = 76%

Based on these assumptions, direct deployment scores slightly higher because simplicity and lower operational effort are more important in this scenario.

However, if the organization already uses containers across multiple platforms, portability and deployment consistency might carry more weight. In that case, container-based deployment could become the preferred option.

Is this the right decision for every project?

Not necessarily. The weights and scores are subjective and depend on the project's requirements, team capabilities, and business priorities.

This is my personal suggestion for evaluating architectural decisions, not a universal framework. The purpose is not to let a spreadsheet make the decision for us. It is to make our assumptions visible, compare alternatives more consistently, and explain why we chose one approach over another.

For me, the real value of a decision matrix is not the final score. It is the discussion and reasoning behind the decision.

Focus on What Matters

Architecture is about finding the right balance between cost, performance, security, reliability, maintainability, and complexity.

Sometimes, improving one area creates challenges in another.

For example, distributed caching can improve response times, but it also introduces cache invalidation and consistency concerns. An API gateway, message broker, and orchestration layer may be valuable in a complex enterprise system, but they could be unnecessary for a small application.

We should not try to eliminate all complexity. Some complexity is necessary as systems grow.

The goal is to avoid complexity that does not solve a real problem.

Final Thoughts

Technology will continue to change, and new tools will always promise better performance, scalability, or developer productivity. But choosing a technology simply because it is popular does not guarantee a better architecture.

Understand the requirements first. Compare the available options. Be clear about the trade-offs and revisit your decisions when the business needs change.

Sometimes a monolith is the right choice. Sometimes microservices make sense. Sometimes container-based deployment is worth the effort, while a simple CI/CD pipeline is all we need.

Instead of asking, "Which technology is the best?", ask, "What problem are we solving, and which trade-offs make the most sense?"

That is how we move from simply choosing technologies to making better architectural decisions.

Happy Coding!