"Big companies use microservices, so we should move too" is one of the most expensive misunderstandings in software projects. Microservices architecture is an approach that splits an application into small services, each doing one job, owning its own data and able to be released on its own. In the right place it speeds teams up; in the wrong place it multiplies maintenance work and cost.
In this guide we explain what microservices are, how they differ from a monolith and a modular monolith, how to draw service boundaries, what they cost you (network latency, availability, distributed transactions, observability), a six-question decision test, a three-year cost comparison and a gradual path away from a monolith. The example figures are illustrative; they are not the result of any particular product or an industry average.
What Is Microservices Architecture?
In a microservices architecture, the application is made up of small services separated along business areas. Each service is responsible for a single business capability (for example orders, stock, payments or notifications), owns its own data store and talks to the others over the network, usually through an interface (API) or messaging. Services are developed, tested and released independently of each other.
The critical point is not being "small" but being independent: if changing one service does not force the others to be released again, the boundary has been drawn correctly. If you need a refresher on how services talk to each other, we covered the basics in our API integration guide.
It also helps to be clear about what the word does not mean. It does not mean a specific programming language, a specific cloud platform or a specific tool. It is a way of organizing a system and the teams around it. Two companies can both say "we use microservices" and have very different systems, because the real question is whether the pieces can change and ship without waiting for each other.
We recommend reading: Our custom software service
What Is the Difference Between a Monolith, a Modular Monolith and Microservices?
The options are not a yes-or-no choice, they are a spectrum. A monolith is an application released as one piece. A modular monolith is also released as one piece, but inside it there are modules with clear boundaries. Microservices turn those modules into separately released services.
| Topic | Monolith | Modular monolith | Microservices |
|---|---|---|---|
| Release | One piece | One piece | Separate per service |
| Code boundaries | May be unclear | Clear module boundaries | Process boundary |
| Data | Shared database | Schema or rules per module | Each service owns its data |
| Scaling | Whole application together | Whole application together | Service by service |
| Operational load | Low | Low | High |
| Suitable when | Small, single team | Most business applications | Many teams, different scaling needs |
The monolith is often described as the "old" way, but that is misleading. A monolith with disciplined modules is simple to run, simple to test and simple to debug, because a function call is still a function call. The problems people blame on monoliths usually come from missing boundaries inside the code, not from the fact that it is released as one piece.
We covered the layers of a solution written from scratch in our what is custom software guide; the architecture choice is only one of those layers.
How Do You Draw Service Boundaries?
The success of microservices depends on the boundary passing through the right place. A wrong boundary means releasing several services at the same time for every change.
- Split by business capability: Business areas such as "take an order", "reduce stock" and "collect payment" are boundary candidates; technical layers such as "database layer" or "interface layer" are not.
- Make data ownership clear: Every piece of data should have exactly one owning service; other services should reach that data through the owner's interface, not straight from its database.
- Keep what changes together, together: Two parts that always change at the same time are really one service.
- Match the team boundary: A service should have a clear owning team; the boundary follows the team structure.
A useful habit is to test each proposed boundary with a few real change requests from the last year. If most of them would touch only one service, the boundary is probably good. If many would touch three or four services at once, the pieces you separated actually belong together.
The precondition for setting boundaries is having the business areas written down. You can do this with the method in our requirements analysis guide.
What Does Microservices Cost You?
Separating services does not simplify the application; it moves complexity from inside the code onto the network. Five costs stand out in practice.
| Cost | What happens | Mitigation |
|---|---|---|
| Network latency | A function call becomes a network call | Keep call chains short, use caching where needed |
| Availability | Every service in the chain becomes a point of failure | Timeouts, retries, fallback behavior |
| Distributed transactions | There is no single database transaction | Compensating steps, designs that prevent double processing |
| Observability | One failure spreads across several services | Shared logging, tracing, request correlation ID |
| Deployment and testing | Many release pipelines and version compatibility | Automation, contract tests |
The effect on availability becomes clear with a calculation: if five services that are each 99.9% available are called in series, the combined availability is 0.9995 ≈ 0.995, that is 99.5%. A 30-day month has 43,200 minutes; 99.9% corresponds to about 43.2 minutes of downtime, while 99.5% corresponds to about 216 minutes. There is a simple measure for latency too: four service hops × 15 ms = 60 ms of extra time. Both figures are illustrative; measure your own services. We explained how availability targets are written into a contract in our SLA guide.
The distributed transaction problem deserves a plain example. In a monolith, "create the order and reduce the stock" can be one database transaction: either both happen or neither does. When orders and stock are separate services, each with its own database, that guarantee disappears. If the order is saved but the stock call fails, someone has to undo or repair the order. That is why microservice designs need compensating steps and operations that are safe to repeat, and why these designs take real effort.
Microservices or Monolith? A Six-Question Test
Answer the questions below for your own system. Each "yes" is one point in favor of microservices.
- Are there several independent teams working in the same codebase and waiting for each other?
- Do the parts of the system have very different scaling needs (for example only order intake is under heavy load)?
- Do the parts have to be released at different speeds?
- Are the business-area boundaries clear and stable over time?
- Does the team have the experience and time for automated deployment, monitoring and incident response?
- Is it a business requirement that one part crashing does not affect the others?
| Number of "yes" answers | Meaning | Recommended step |
|---|---|---|
| 0–2 | A monolith or modular monolith is enough | Keep module boundaries clear |
| 3–4 | A specific part is a candidate to become a service | Split off only that part, keep the rest |
| 5–6 | Microservices are a strong candidate | Build observability and automation first |
Most business software (orders, stock, customers, reporting) stays in the first two rows. You can find where the architecture decision sits in the software life cycle in our software development life cycle guide.
Notice that question five is about people, not technology. Many failed migrations had good reasons on the first four questions and no capacity on the fifth. Without automated releases, monitoring and a habit of handling incidents, each new service is another thing to look after by hand, and the cost grows with every service you add.
How Does the Three-Year Cost of Microservices Compare with a Monolith?
Microservices grow development, infrastructure and maintenance together. The assumptions below are illustrative: the same scope, 50 person-days × 1.2 buffer = 60 person-days, ₺9,000 per day.
- Monolith: 60 person-days × ₺9,000 = ₺540,000; maintenance 15% per year, so ₺243,000 over 3 years; infrastructure ₺20,000 per year, so ₺60,000 over 3 years.
- Microservices (5 services): 35% extra effort for contracts between services, the deployment pipeline and observability: 60 × 1.35 = 81 person-days × ₺9,000 = ₺729,000; maintenance 15% per year, ₺328,050 over 3 years; infrastructure ₺72,000 per year, ₺216,000 over 3 years.
| Item | Monolith | Microservices |
|---|---|---|
| Development | ₺540,000 | ₺729,000 |
| Maintenance (3 years, 15% per year) | ₺243,000 | ₺328,050 |
| Infrastructure (3 years) | ₺60,000 | ₺216,000 |
| Three-year total | ₺843,000 | ₺1,273,050 |
The difference is ₺430,050, about 51% more than the monolith (430,050 ÷ 843,000). That difference should be compared with the value that independent releases and scaling would bring you: if you do not truly have separate teams or separate scaling needs, the extra cost buys nothing. You can find the details of each cost item in our software project cost guide.
The numbers also show where the money goes. Development rises because of the extra work on contracts, pipelines and monitoring; maintenance rises because it is a percentage of that larger development cost; infrastructure rises most steeply, because five services need more running environments than one. Change the assumptions to match your own project and the result will move, but the direction rarely changes.
How Do You Move Gradually from a Monolith to Microservices?
Rewriting everything in one go is the riskiest path. The safer path is to separate the parts one by one.
- Modularize: First draw clear module boundaries inside the monolith; most of the benefit comes here.
- Choose a candidate: Pick a single part that needs its own scaling or its own release rhythm.
- Define the interface: Write down and version the contract the part exposes to the outside.
- Separate the data: Move the part's data to its own store and cut direct access to shared tables.
- Run in parallel: Run the old and new paths side by side for a while and compare the results.
- Remove the old code: When verification is done, delete its counterpart in the monolith.
Leave a way back at every step. The habit of testing a restore from our data backup guide is useful when moving data; for authentication between services, see our API security guide.
How Do You Set Up Observability and Deployment for Microservices?
As the number of services grows, "where did it fail?" gets harder to answer. That is why observability and deployment automation are the foundation to build before the first service is split out.
- Correlation ID: An identifier created when the request enters is carried to every service and every log line, so one request can be traced end to end.
- Shared logging and metrics: Every service logs in the same format; latency, error rate and queue length appear on a single dashboard.
- Health checks and timeouts: Every call has a short timeout and limited retries, so an unresponsive service does not lock the chain.
- Automated deployment pipeline: Each service has its own test and release pipeline; if releases are manual, the microservices advantage disappears.
- Rollback: Each release has a written, tested path back to the previous version.
| Target | Allowed downtime in a 30-day month | Meaning |
|---|---|---|
| 99.9% | 43,200 × 0.001 = 43.2 min | Strict target; every service must be very solid |
| 99.5% | 43,200 × 0.005 = 216 min | Compound value of a five-service serial chain |
| 99% | 43,200 × 0.01 = 432 min | Loose target; for non-critical parts |
Set the target service by service: a critical part such as payment can work to a strict target and a supporting part such as notifications to a looser one. If failures of services outside the critical path are designed not to stop the main transaction (for example by queuing), the compound availability does not drop. For testing service interface contracts automatically, see our software testing guide.
When Do You Really Need Microservices?
- A large product with many teams: When dozens of developers change the same code and wait for each other.
- Scale differences between parts: When only one area faces heavy traffic and duplicating the whole application is wasteful.
- A need for independent releases: When one area must be released several times a week and another once a month.
- Failure isolation: When a critical part such as payments must not be affected by a minor part such as notifications.
- Different technology needs: When one area truly needs a separate runtime environment.
If you offer a product through subscriptions and run it for many customers at once, the architecture choice matters even more; see our SaaS guide for details.
What Are Common Mistakes in Microservices Projects?
- Choosing it because it is fashionable: Starting without a defined need means paying the cost and not getting the benefit.
- Services that are too small: In an over-split system, every workflow turns into dozens of network calls.
- A shared database: If services share the same table, there is no independence; you end up with a "distributed monolith".
- Leaving observability for last: Without logging and tracing, finding a fault takes days.
- Skipping tests and version compatibility: When a service interface changes, its consumers break without warning.
- Not changing the team structure: If a service exists but its owner is unclear, independence stays on paper.
The common thread is that each mistake treats microservices as a technical upgrade instead of an organizational and operational change. The architecture works only when the teams, the release process and the monitoring change with it.
Recommended reading: How to Choose a Database?
Recommended reading: What Is Technical Debt?
Software Architecture Decisions with İnovabil
At İnovabil our focus is software written from scratch for your company: custom software, ERP, CRM, e-commerce, web, mobile and integration. We suggest evaluating the architecture decision in writing during requirements analysis, together with the company's team structure, user count and growth expectations; for most business applications, starting with a structure that has clear module boundaries and then separating the part where a real need appears is firmer ground.
We developed CRM, purchasing and mobile for Avcılar İnşaat; a purchasing system for İZBAN; logistics and shipment planning with wholesale order management for Karyak; and warehouse management with a complaint and support management system for Sleepy. Write a short description of your system today and your growth goal; let us run the six-question test together and produce a written assessment.
We recommend reading: Our software development process: step by step from analysis to release
Frequently Asked Questions
What are microservices, and how do they work in short?
It means splitting an application into small services, each running a single business capability, owning its own data and able to be released independently. Services talk to each other through an interface or messaging.
What is the difference between microservices and a monolith?
A monolith is released as one piece and usually uses a shared database. Microservices are released per service, own separate data and scale service by service; in return, operational complexity and cost are higher.
Are microservices better for every project?
No. For most small and medium business applications, a monolith with clear module boundaries is cheaper and easier to manage. Microservices make sense when you have many teams, different scaling needs or a need for independent releases.
How much do microservices increase the cost?
In the example, the three-year cost of the same scope is ₺843,000 for a monolith and ₺1,273,050 for five microservices, a difference of about 51%. The figures are illustrative; recalculate the development effort, infrastructure and maintenance share for your own project.
How do I convert an existing monolith to microservices?
First make the module boundaries clear, then pick a single part that needs its own scaling or release rhythm and separate its interface and data, run it in parallel with the old path, and remove the old code once verified. Avoid rewriting everything in one go.