Lecture
Software architecture is the foundation on which any digital solution is built. It defines not individual lines of code or specific technologies, but the overall way the system is organised: how its parts are connected, how responsibilities are distributed, and how the project's growth, resilience and clarity are ensured.
Without architecture, a software product may work in its early stages, but over time it becomes increasingly difficult to maintain. Changes start to take more time, bugs appear more often, and the system's evolution becomes unpredictable. That is precisely why architecture is needed not only by large projects, but by any software solution that has to evolve, scale and remain manageable.
It is important to distinguish between architectural styles and patterns.
An architectural style is a broader category that sets out the general principles for building systems (for example, client-server, microservices, layered architecture).
An architectural pattern is a specific solution for organising the structure of components within a system and the interaction between them.
The essence of architecture lies in creating a clear structure for the system. It helps define which parts the program consists of, what role each part plays, and how they interact with one another.
Architecture answers not so much the question «how to write the code» as the question «how to organise the system so that it can live and evolve». It is a kind of framework that keeps the project from descending into chaos and helps technical decisions to be made deliberately.
Good architecture makes a system easier for developers to understand, more resilient to change and more convenient to maintain. It reduces the dependency of individual parts on one another and makes it possible to evolve the product without rewriting it entirely.
Architecture is needed so that a software system is not merely functional, but manageable, reliable and ready for change. It helps you think through in advance the key decisions that will affect the entire life cycle of the product.
The main goals of architecture:
| Goal | Value |
|---|---|
| Organising the system | Helps split the project into comprehensible parts |
| Managing complexity | Prevents the code base from growing chaotically |
| Supporting growth | Makes it easier to add new capabilities |
| Improving reliability | Reduces the risk of errors when making changes |
| Easier maintenance | Makes the system clearer for the team |
| Aligning decisions | Helps everyone on the project think along the same lines |
Architecture matters especially when a project runs for a long time, a team works on it, requirements change, and the product has to remain stable and easy to extend.
Software architecture rests on a number of general principles. They help create systems that are easier to understand, change and maintain.
| Principle | What it means |
|---|---|
| Separation of concerns | Each part of the system should perform its own clearly defined job |
| Loose coupling | Components should not depend excessively on one another |
| High cohesion within a module | Everything relating to one task should be located together logically |
| Simplicity | The architecture should solve the problem without unnecessary complication |
| Flexibility | The system should allow changes without destroying the whole structure |
| Scalability of thinking | The architecture should let the project grow without losing manageability |
| Clarity | Decisions should be clear not only to their author, but to other team members as well |
| Resilience to change | Changing one part should not unpredictably break the entire system |
The main idea behind these principles is to make the system not a random collection of code, but a well-considered construction in which every decision has its own place and purpose.
Good architecture should take into account not only current tasks, but also the possible evolution of the product. It does not have to be complex, but it must be thought through well enough to withstand change.
The key requirements include:
| Requirement | Description |
|---|---|
| Clarity | The structure of the system should be easy to explain |
| Maintainability | The code should be convenient to change and support |
| Extensibility | New features should be added without breaking existing logic |
| Reliability | The system should remain stable under changes and load |
| Flexibility | The architecture should adapt to new requirements |
| Controlled complexity | The project must not turn into a set of random dependencies |
| Consistency of solutions | Coherent approaches should be used throughout the system |
| Testability | The system should be convenient to verify for correctness |
It is important to understand that good architecture is not the most complex architecture. On the contrary, strong architecture is often distinguished by clarity, restraint and a good fit with the project's real tasks.
Architecture matters not only for the system itself, but also for the people who work with it. It creates a common language between developers, analysts, managers and other project participants.
When the architecture is clear, the team makes decisions faster, finds the right parts of the system more easily and argues less about the basic organisation of the project. This is especially important as the team grows, when the project is handed over to new developers, or during long-term maintenance of the product.
Architecture helps avoid a situation in which every developer implements solutions their own way. It sets common rules and makes the product's evolution more predictable.
A software system almost always changes: new requirements appear, business processes shift, the number of users grows, new features are added. Architecture allows the system to adapt to these changes.
Without an architectural approach, every change can become more expensive and riskier. With well-considered architecture, growth remains more controllable: the team understands where to add new logic, which parts a change will affect and how not to break mechanisms that already work.
Architecture, then, is not a one-off decision at the start of a project, but an ongoing tool for managing the quality and evolution of a software product.
| Level | What it describes | Examples |
|---|---|---|
| UI level | How the interface and its logic are arranged | MVC, MVP, MVVM |
| Application architecture | How the code inside the application is organised | Layered, Clean, Hexagonal, Onion, Modular Monolith |
| Domain level | How business logic is modelled | DDD, Aggregates, Bounded Contexts |
| System level | How the application is divided into large parts | Monolith, Client-Server, SOA, Microservices |
| Integration level | How the parts of the system communicate | REST, GraphQL, Message Queue, Event-Driven |
| Deployment / Infrastructure level | How the system is deployed and scaled | Serverless, Cloud-Native, Kubernetes-based architecture |

Below is an overview of popular types of software architecture. The years are approximate, because many approaches emerged gradually: first as a practice, then as a term.
| Architecture | Approximate years of appearance / popularisation | Level |
Main characteristic advantages and disadvantages |
|---|---|---|---|
| Monolithic architecture | 1960s–1970s | Application architecture |
The entire application is built and deployed as a single whole +Simple development at the start; easy to run; easier to debug; less infrastructure -Hard to scale in parts; over time the code can become tangled; any change requires deploying the whole application |
| Modular monolith | 1990s / 2000s | Application architecture |
A single deployable artifact, but with a clear internal split into modules +A good balance of simplicity and structure; easier to maintain; simpler than microservices -Requires discipline; module boundaries are easy to violate; scaling is still confined to a single application |
| Client-server architecture | 1980s | System architecture |
The client requests data or functions from the server +Separation of the UI and server-side logic; centralised data; convenient for networked applications -The server can become a bottleneck; dependence on the network; synchronisation complexity |
| Three-tier architecture | 1990s | Application / system architecture |
A split into presentation, business logic and data layer +A clear structure; layers can be developed separately; well suited to enterprise systems -Can become too formal; business logic is sometimes smeared across the layers |
| N-tier architecture | 1990s | System architecture |
Several logical or physical tiers: UI, API, business logic, database and so on +Flexibility; the load can be distributed; convenient for enterprise systems -More complexity; more network calls; higher latency |
| Layered Architecture | 1970s / 1980s | Application architecture |
The code is divided into layers: controller, service, repository, database +Simple and clear; well suited to most CRUD applications; easy to teach a team -Can lead to an anaemic model; a lot of «glue» classes often appear; does not always express the business domain well |
| MVC | 1979 / 1980s | UI / application architecture |
A split into Model, View, Controller +Convenient for separating the interface from the logic; widely known; many frameworks -In large projects the controller can grow out of hand; different frameworks interpret MVC differently |
| MVP | 1990s | UI architecture |
The View is as passive as possible, while the Presenter drives the display logic +Convenient for testing UI logic; a good separation of responsibilities -A lot of boilerplate code; the Presenter can become too large |
| SOA, Service-Oriented Architecture | 1990s / 2000s | Enterprise / system architecture |
The system consists of services, often with centralised integration +Reuse of services; integration of large enterprise systems; standardisation -Can be heavyweight; complex infrastructure; a centralised bus often becomes a bottleneck |
| Enterprise service bus (ESB) | 2000s | integration architecture |
regarded as an implementation of Service-Oriented Architecture (SOA). The core principle of a service bus is to concentrate message exchange between different systems at a single point where, when required, transactional control, data transformation and message persistence are provided. All settings for processing and transmitting messages are likewise assumed to be concentrated at that single point and are expressed in terms of services, so that when any information system connected to the bus is replaced, there is no need to reconfigure the remaining systems. The name was chosen by analogy with a computer's system bus, which allows several devices to be connected and data to be transferred between them over a single set of conductors. Key benefits
Key disadvantages
|
| Microservice architecture | 2010s | System / deployment architecture |
The system consists of small, independently deployable services +Independent deployment; scaling of individual parts; autonomous teams; different technologies for different services -High infrastructure complexity; distributed transactions; monitoring, networking, DevOps and observability become mandatory |
| Event-Driven Architecture | 2000s / 2010s | System architecture |
Components communicate through events +Loose coupling; good scalability; convenient for asynchronous processes -Harder to debug; eventual consistency; harder to trace the flow of execution |
| Event Sourcing* | 2000s / 2010s | Architectural pattern for storing state |
State is stored as a sequence of events +A complete history of changes; state can be restored to any point in time; convenient for auditing -Complexity of event migrations; harder queries; requires a good event model |
| DDD Architecture* | 2003 | Domain model architecture / design approach |
The architecture is built around the business domain, bounded contexts and aggregates +Well suited to complex business logic; helps define the boundaries of modules and services; a shared language with the business -Hard to master; unnecessary for simple CRUD; requires the involvement of domain experts |
| MVVM | around 2005 | UI architecture |
The View is linked to the ViewModel through binding +Well suited to reactive UIs; less manual code for updating the interface; convenient to test the ViewModel -Complexity of binding mechanisms; sometimes hard to debug; the ViewModel can grow out of hand |
| Hexagonal Architecture / Ports and Adapters | 2005 | Application architecture |
The domain is isolated from the outside world through ports and adapters +Good testability; independence from the database, UI and frameworks; clean business logic -More abstractions; can be excessive for simple CRUD systems |
| ECS (Entity-Component-System |
around 2007 1998 — Thief: The Dark Project: the first ideas of composing game objects out of components. 2002 — Dungeon Siege (Scott Bilas): formalisation of the «Data-Driven Game Object System» approach. 2007 — Operation Flashpoint: Dragon Rising: the development team experimented with ECS. |
architectural pattern |
makes it possible to separate data from logic, providing flexibility, scalability and high performance. The main elements of ECS Component — data describing the properties of an entity (position, health, speed). Components contain no logic. System — a set of functions that process component data (for example, the movement system updates position based on speed). |
| Clean Architecture | around 2012 | Application architecture |
Dependencies point inwards: towards the domain/use cases +Independence from frameworks; high testability; protects business logic well -Many layers and interfaces; requires experience; can be excessive for small projects |
| Onion Architecture | around 2008 | Application architecture |
The domain at the centre, infrastructure on the outside +Similar to Clean/Hexagonal; separates business logic well from storage and delivery details -Can be difficult to apply correctly; requires discipline with dependencies |
| CQRS | 2010s | Architectural pattern |
Separation of commands that change data from queries that read it +Reads and writes can be optimised separately; convenient for complex domains; combines well with event sourcing -Complicates the system; duplication of models; eventual consistency |
| Serverless Architecture | 2014–2015 | Cloud / deployment architecture |
Code runs as functions or managed services without server management +No need to manage servers; auto-scaling; pay per use -Vendor lock-in; cold start; harder local debugging; platform limitations |
| Microkernel / Plugin Architecture | 1980s / 1990s | Application architecture |
There is a system core and pluggable plugins +Flexible extension; convenient for IDEs, CMSs, browsers and platforms -Complexity of the plugin API; risk of incompatibility; the core must be very well designed |
| Pipe and Filter | 1970s | Data processing architecture |
Data passes through a chain of independent filters +Easy to compose; good for ETL, compilers and stream processing -Not always suitable for interactive systems; state can be hard to manage |
| Peer-to-Peer, P2P | 1990s / 2000s | Distributed architecture |
Nodes interact directly without a central server +No single point of failure; good distribution; scales with the number of participants -Security complexity; harder to control data; instability of nodes |
| REST Architecture | 2000 | API architecture |
Resources are accessed through HTTP methods and URIs +Simplicity; well suited to web APIs; caching; broad support -Not always convenient for complex operations; can lead to overfetching/underfetching |
| GraphQL Architecture | 2015 | API architecture |
The client itself specifies which data it needs +Less redundant data; convenient for complex frontend applications; a single endpoint -Caching complexity; risk of heavy queries; protection against overload is required |
| Broker / Message Queue Architecture | 1990s / 2000s | Integration architecture |
Components communicate through a message broker +Asynchrony; resilience to temporary failures; loose coupling -Monitoring complexity; latency; duplicate messages are possible |
| Cloud-Native Architecture | 2010s | Cloud / system architecture |
Applications are designed for containers, automatic scaling and fault tolerance +High scalability; convenient deployment; resilience; well suited to Kubernetes -A high barrier to entry; complex infrastructure; requires mature DevOps |
Not all of these architectures are alternatives to one another. They are often combined.
For example, a real system might look like this:
Microservices ├── Order Service: Clean Architecture + DDD + REST ├── Payment Service: Hexagonal Architecture + Events ├── Notification Service: Event-Driven └── Frontend: MVVM or MVC
In other words, microservices are responsible for dividing the system up, DDD for the business model, Clean/Hexagonal for the structure of the code inside a service, and REST/Event-driven for the interaction between the parts.
Monolithic software architecture is an approach in which all the main components of an application are combined into a single software unit.
In a monolith, the user interface, business logic, database access and other modules are usually developed, deployed and scaled together. Such an application is easier to create and launch in the early stages, but as the system grows it becomes harder to change, test, scale and maintain.

A modular monolith is an architectural approach in which the application remains a single deployable software unit but is internally divided into independent logical modules.
Each module is responsible for its own area of functionality — users, orders, payments or reports, for example. Unlike an ordinary monolith, a clear internal structure matters here: modules have their own boundaries, depend on one another as little as possible and interact through defined interfaces.
This approach preserves the simplicity of developing and deploying a monolith, but makes the system clearer, more maintainable and easier to split into microservices later if needed.

Client-server architecture is an approach in which the system is divided into two main parts: the client and the server.
The client is responsible for interacting with the user: it displays the interface, accepts the user's actions and sends requests. The server processes those requests, executes business logic, works with the database and returns the result to the client.
This approach makes it possible to store data and logic centrally on the server, while the client applications can vary: a website, a mobile app, a desktop application or another device.

Three-tier architecture is an approach to building an application in which the system is divided into three logical tiers:
1. The presentation tier is responsible for the user interface: web pages, a mobile app or a desktop client.
2. The business logic tier handles user requests and executes the application's rules, validations, calculations and core logic.
3. The data tier is responsible for storing and retrieving data, usually through a database or file storage.
The main idea of this architecture is to separate the interface, the logic and the data so that the system is easier to develop, maintain, test and scale.

N-tier architecture is an architectural approach in which the application is divided into several independent logical levels — tiers.
Such a system usually includes a presentation tier, a business logic tier, a data access tier, a data storage tier and additional tiers such as an API gateway, cache, integrations or security services.
The main idea of N-tier architecture is to divide responsibility between the layers. Each tier performs its own task and interacts with adjacent tiers through defined interfaces. This makes the system more flexible, scalable and maintainable than a simple monolith or a classic three-tier architecture.

Layered Architecture is an architectural approach in which the application is divided into several layers, with each layer responsible for its own part of the system.
Typically a presentation layer, an application layer, a business logic layer, a data access layer and a data storage layer are identified. Upper layers use lower ones, but must not interfere directly with their internal implementation.
The main idea of layered architecture is the separation of responsibilities. This helps organise the code and simplifies maintenance, testing and evolution of the system, since changes in one layer affect the other parts of the application less.

MVC architecture is an architectural approach in which the application is divided into three main parts: Model, View and Controller.
The Model is responsible for the data, the business logic and the rules for working with it. The View is responsible for displaying information to the user. The Controller accepts the user's actions, processes requests and connects the model with the view.
The main idea of MVC is to separate the application logic, the data and the user interface. This simplifies development, testing and maintenance of the system, because changes to the interface affect the business logic less, and vice versa.

MVP architecture is an architectural approach in which the application is divided into three parts: Model, View and Presenter.
The Model is responsible for the data, the business logic and working with data sources. The View is responsible only for displaying the interface and passing on the user's actions. The Presenter receives events from the View, calls the Model, processes the result and updates the View.
The main idea of MVP is to separate the user interface from the control logic. This simplifies testing, maintenance and changes to the interface, because the core interaction logic lives in the Presenter while the View remains as «passive» as possible.

MVVM architecture is an architectural approach in which the application is divided into three main parts: Model, View and ViewModel.
The Model is responsible for the data, the business logic and working with data sources. The View is responsible for the user interface and the display of data. The ViewModel connects the View and the Model: it prepares data for display, handles user commands and manages the state of the interface.
The main idea of MVVM is to separate the interface from the display logic and state. This is convenient for applications with an active user interface, since the View can update automatically when the data changes through data binding (data binding).

SOA / Service-Oriented Architecture is an approach in which an application is built as a set of separate services that interact with one another through standardised interfaces.
Each service is responsible for a particular business function, such as managing users, orders, payments or notifications. Services can be built with different technologies and reused across different systems.
The main idea of SOA is to divide a large system into autonomous services with clear interaction contracts. This increases flexibility and component reuse and simplifies integration between different applications and enterprise systems.

Microservice architecture is an approach in which an application is built as a set of small independent services.
Each microservice is responsible for a separate business function, such as users, orders, payments, notifications or the product catalogue. Such services usually have their own logic, their own API and often a separate database.
The main idea of microservice architecture is to divide a large system into autonomous parts that can be developed, deployed, scaled and updated independently of one another. This increases the system's flexibility, but it also complicates the management of interaction, monitoring, security and infrastructure.

Event-Driven Architecture is an approach in which the components of a system interact through events.
An event means that something has happened in the system: a user has registered, an order has been created, a payment has gone through, an item has been added to the warehouse. One component publishes an event, and other components subscribe to it and react independently.
The main idea of Event-Driven Architecture is to reduce tight coupling between the parts of a system. Components do not have to call one another directly: they exchange events through a message broker or an event bus. This increases flexibility, scalability and the convenience of asynchronous processing, but it requires good control over delivery, event ordering and error handling.

Event Sourcing: an architectural pattern for storing state
Event Sourcing is an architectural pattern in which the state of the system is stored not as a current record, but as the sequence of events that brought the system to that state.
For example, instead of storing only the order status «paid», the system saves a chain of events: order created → item added → payment completed → order confirmed. The current state can be restored by applying all the events in sequence.
The main idea of Event Sourcing is to record the history of changes as the primary source of truth. This gives a full audit trail of actions, the ability to restore the state at any point in time and easier analysis of business processes, but it requires careful handling of event versions, processing order and the storage of large volumes of history

DDD Architecture / Domain-Driven Design is an approach to software design in which the structure of the system is built around the problem domain and the business logic rather than around the database or the framework.
The main idea of DDD is to make the code as close as possible to real business concepts: order, customer, payment, product, warehouse, reservation and so on. Business rules are placed in the domain layer, while technical details — the database, API, UI, message queues — are moved outwards.
DDD helps build a system around the business model, where the main rules live in the domain layer and the technical details are plugged in separately and do not drive the application's architecture.
An object with a unique identifier.
Example:
User
Order
Product
Payment
For instance, two orders may have the same total, but they are different entities because they have different OrderId values.
public class Order
{
public OrderId Id { get; private set; }
public OrderStatus Status { get; private set; }
public List<OrderItem> Items { get; private set; }
public void Confirm()
{
if (!Items.Any())
throw new Exception("Cannot confirm an empty order");
Status = OrderStatus.Confirmed;
}
}
An object without an identifier of its own. Its significance is determined by the values of its fields.
Example:
Money
Email
Address
FullName
DateRange
public class Money
{
public decimal Amount { get; }
public string Currency { get; }
public Money(decimal amount, string currency)
{
Amount = amount;
Currency = currency;
}
}
A group of related objects that change as a single whole.
Example:
Order
├── OrderItem
├── DeliveryAddress
└── PaymentInfo
An aggregate usually has a main object — the Aggregate Root.
Order = Aggregate Root
OrderItem = an internal part of the aggregate
External code should work only through Order, rather than modifying OrderItem directly.
A class or interface for saving and retrieving aggregates.
public interface IOrderRepository
{
Task<Order?> GetByIdAsync(OrderId id);
Task SaveAsync(Order order);
}
The repository hides database details from the domain logic.
A class for business logic that does not belong to any one specific entity.
Example:
PricingService
PaymentPolicy
DeliveryCostCalculator
public class DeliveryCostCalculator
{
public Money Calculate(Address address, List<OrderItem> items)
{
// business rules for calculating delivery
}
}
Coordinates the execution of use cases: create an order, pay for an order, cancel an order.
public class CreateOrderUseCase
{
private readonly IOrderRepository _orders;
public async Task Execute(CreateOrderCommand command)
{
var order = Order.Create(command.UserId, command.Items);
await _orders.SaveAsync(order);
}
}
It should not contain complex business logic. It calls domain objects and repositories.
A fact that has already occurred in the problem domain.
OrderCreated
OrderPaid
UserRegistered
ProductReserved
public class OrderPaidEvent
{
public OrderId OrderId { get; }
public DateTime PaidAt { get; }
}
An example for an online store project:
src/
└── Shop/
├── Domain/
│ ├── Orders/
│ │ ├── Order.cs
│ │ ├── OrderId.cs
│ │ ├── OrderItem.cs
│ │ ├── OrderStatus.cs
│ │ ├── IOrderRepository.cs
│ │ ├── OrderCreatedEvent.cs
│ │ └── Services/
│ │ └── OrderPricingService.cs
│ │
│ ├── Users/
│ │ ├── User.cs
│ │ ├── UserId.cs
│ │ └── Email.cs
│ │
│ ├── Products/
│ │ ├── Product.cs
│ │ ├── ProductId.cs
│ │ └── Money.cs
│ │
│ └── Shared/
│ ├── Entity.cs
│ ├── ValueObject.cs
│ └── DomainEvent.cs
│
├── Application/
│ ├── Orders/
│ │ ├── CreateOrder/
│ │ │ ├── CreateOrderCommand.cs
│ │ │ └── CreateOrderHandler.cs
│ │ ├── PayOrder/
│ │ │ ├── PayOrderCommand.cs
│ │ │ └── PayOrderHandler.cs
│ │ └── CancelOrder/
│ │ ├── CancelOrderCommand.cs
│ │ └── CancelOrderHandler.cs
│ │
│ └── Users/
│ └── RegisterUser/
│ ├── RegisterUserCommand.cs
│ └── RegisterUserHandler.cs
│
├── Infrastructure/
│ ├── Persistence/
│ │ ├── AppDbContext.cs
│ │ ├── OrderRepository.cs
│ │ └── UserRepository.cs
│ │
│ ├── Messaging/
│ │ └── EventPublisher.cs
│ │
│ └── ExternalServices/
│ ├── PaymentGateway.cs
│ └── EmailSender.cs
│
└── Presentation/
├── Controllers/
│ ├── OrdersController.cs
│ └── UsersController.cs
│
└── DTOs/
├── CreateOrderRequest.cs
└── RegisterUserRequest.cs
Presentation
Accepts HTTP requests, renders the UI, calls Application.
Application
Describes the use cases: create an order, pay for an order, register a user.
Domain
Contains the main business logic: entities, aggregates, rules, events, value objects.
Infrastructure
Works with the database, external APIs, message queues, file systems and other technical details.

Hexagonal Architecture / Ports and Adapters is an architectural approach in which the application's business logic sits at the centre of the system and does not depend on external technologies.
At the centre is the application core: the domain model, the business rules and the use cases. External elements — the database, the web interface, APIs, message queues, file systems or third-party services — are connected to the core through ports and adapters.
Ports describe the interaction interfaces, while adapters implement the connection to specific technologies. The main idea of this architecture is to isolate the business logic from the infrastructure so that the system is easier to test, change and port to other technologies.

ECS / Entity-Component-System is an architectural approach often used in game engines and simulations, where the objects of the system are split into entities, components and systems.
Entity is an object or identifier, such as a player, an enemy, an item or a vehicle. Component stores an entity's data, such as position, health, speed or appearance. System contains the logic that processes components, such as movement, physics, rendering or collisions.
The main idea of ECS is to separate data from behaviour. Entities consist of a set of components, and systems process every entity that has the required components. This makes the architecture flexible, performant and convenient for bulk processing of large numbers of objects.
Why ECS is convenient in games
Performance: data is stored compactly and makes efficient use of the processor cache. This is especially important for games with large numbers of objects.
Flexibility: new components and systems are easy to add without rewriting code.
Scalability: suitable for complex game worlds with thousands of entities.
Reuse: systems can be applied to different entities, which reduces code duplication.
ECS compared with OOP
| Approach | Data storage | Logic | Performance | Applicability |
|---|---|---|---|---|
| OOP | Inside objects | Methods inside classes | Degrades with large numbers of objects | Suitable for smaller projects |
| ECS | In separate structures (components) | In systems | High, thanks to Data-Oriented Design | Ideal for large-scale games |
In Unity the situation is as follows:
The base level (GameObject + Component) — out of the box Unity uses a component model: any object in a scene is a GameObject to which various MonoBehaviour components can be attached. This is not pure ECS, but an approach close to it in spirit. In other words, base Unity is already «component-based», but not «system-based» in the strict ECS sense.
Pure ECS (Unity DOTS) — a full implementation of ECS arrived as a separate package: DOTS (Data-Oriented Technology Stack). It includes:
Entities — the ECS core, where entities are IDs and data is stored in struct components.
Jobs System — multithreaded processing of systems.
Burst Compiler — a compiler for maximum code optimisation.
Conclusion:
Built-in Unity (GameObject + MonoBehaviour) is a component architecture, but not a full-fledged ECS.
For genuine ECS you need the separate DOTS package (Entities + Jobs + Burst).
| Approach | Built-in Unity | Unity DOTS (ECS) |
|---|---|---|
| Model | GameObject + MonoBehaviour | Entity + Component + System |
| Performance | Average, depends on the number of objects | High, optimised for cache use and multithreading |
| Flexibility | Convenient for smaller projects | Ideal for large worlds and thousands of objects |
| Package required? | No, built in | Yes, Entities/Jobs/Burst are needed |

Clean Architecture is an architectural approach in which the application's business logic sits at the centre of the system and does not depend on external details.
Inside are the entities, the business rules and the use cases. The outer layers are responsible for the interface, controllers, databases, APIs, frameworks and other technical details.
The main idea of Clean Architecture is that dependencies must point inwards, towards the business logic. This makes it possible to change the database, the UI, the framework or external services without significantly affecting the core of the application, and it also simplifies testing and maintenance of the system.

Onion Architecture is an architectural approach in which the application is built as a series of concentric layers around the domain model.
At the centre is the Domain: entities, value objects, business rules and domain services. The outer layers contain the Application / Use Cases, interfaces, infrastructure, the database, APIs, the UI and external services.
The main idea of Onion Architecture is that dependencies point inwards only, towards the domain logic. The domain must not depend on the database, on frameworks or on the interface. This makes the business logic easier to test, maintain and port to other technologies.

CQRS / Command Query Responsibility Segregation is an architectural approach in which operations that change data and operations that read data are separated.
CQRS usually distinguishes two sides:
The Command Side is responsible for actions that change the state of the system: create an order, pay for an order, cancel a reservation, edit a user profile.
The Query Side is responsible only for reading data: retrieve a list of orders, show a user card, produce a report or statistics.
The main idea of CQRS is not to mix write and read logic. This makes it possible to optimise writes and reads separately, use different data models, improve performance and simplify complex business logic. CQRS is often used together with Event Sourcing and Event-Driven Architecture.

Serverless Architecture is an architectural approach in which the developer does not manage servers directly but hosts code and services on a cloud platform.
The application usually consists of individual functions, API gateways, managed databases, message queues, file storage and other cloud services. Code is triggered by an event: an HTTP request, a file upload, a message in a queue, a data change or a schedule.
The main idea of Serverless is to focus on business logic and hand infrastructure, scaling, fault tolerance and server startup over to the cloud provider. This is convenient for event-driven and variable workloads, but it requires taking into account platform limitations, cold starts, the cost of invocations and dependence on the cloud vendor.

Microkernel / Plugin Architecture is an architectural approach in which the application consists of a small base core and a set of pluggable modules — plugins.
The system core contains the minimal essential functionality: starting the application, common rules, life-cycle management, and the registration and invocation of plugins. Plugins add specific capabilities: data import, reports, integrations, additional formats, business extensions or user-defined functions.
The main idea of Microkernel Architecture is to make the system extensible without modifying the core. New features can be added, removed or updated as separate plugins, which is convenient for platforms, IDEs, CMSs, browsers, enterprise systems and products with a large number of extensions.

Pipe and Filter Architecture is an architectural approach in which data processing is broken down into a sequence of independent stages.
Filter is an individual handler that receives input data, performs one specific operation on it and passes the result on.
Pipe is the mechanism for passing data between filters.
The main idea of Pipe and Filter is to build the system as a processing chain: input data → filter 1 → filter 2 → filter 3 → result. This approach is convenient for stream processing, ETL processes, compilation, logging, image, audio and video processing, and message queues. It makes it easier to add, replace and reuse individual processing stages.
The way Middleware works in Laravel, for example, can be regarded as an instance of Pipe and Filter Architecture, but not as the whole of Laravel's architecture.
In Laravel an HTTP request passes through a chain of middleware:
HTTP Request
↓
Middleware 1: authorisation check
↓
Middleware 2: CSRF check
↓
Middleware 3: logging
↓
Middleware 4: localisation
↓
Controller
↓
HTTP Response
Each middleware resembles a Filter:
Filter = Middleware
It receives the request, performs a single task and passes the request on.
And passing the request between middleware resembles a Pipe:
Pipe = the chain that passes Request → next()
But an important point: Laravel as a whole is not solely a Pipe and Filter architecture. Laravel more often combines several approaches:
MVC — Controllers, Models, Views
Layered Architecture — Route → Controller → Service → Repository → DB
REST - support for resource routes and controllers
Pipe and Filter — Middleware pipeline
Event-Driven — Events / Listeners / Queues

Peer-to-Peer Architecture / P2P is an architectural approach in which the participants in a system interact directly with one another, without a mandatory central server.
Every node in the network, or peer, can be both a client and a server at the same time: it can request data from other nodes and itself provide data or resources to other participants.
The main idea of P2P is to distribute the storage, processing and exchange of data across a multitude of equal nodes. This increases the fault tolerance and scalability of the system, but it complicates node discovery, data synchronisation, security, access control and network management.

REST Architecture / Representational State Transfer is an architectural style for building networked APIs, most often web services over HTTP.
In REST the system works with resources: users, orders, products, payments. Each resource has its own URL, and operations on it are performed with standard HTTP methods: GET to read, POST to create, PUT/PATCH to modify, DELETE to remove.
The main idea of REST is to make the interaction between client and server simple, uniform and independent of the internal implementation. The client sends a request to a resource, the server processes it and returns a representation of the data, usually in JSON format. REST is well suited to web applications, mobile applications and integrations between systems.

GraphQL Architecture is an architectural approach to building APIs in which the client itself specifies which data it needs and the server returns exactly the requested structure.
Instead of numerous REST endpoints such as /users, /orders, /products, a single GraphQL endpoint is normally used, for example /graphql. The client sends a request describing the fields it needs, and the server processes it through the schema, queries, mutations and resolvers.
The main idea of GraphQL is to give the client a flexible way of retrieving related data with no superfluous or missing fields. This is convenient for web and mobile applications where different screens require different sets of data, but it requires control over query complexity, authorisation, caching and resolver performance.

Broker / Message Queue Architecture is an architectural approach in which the components of a system exchange data not directly but through an intermediary service — a message broker.
One service sends a message to a queue or topic, and another service receives and processes it. For example, the order service publishes an OrderCreated message, and the notification service, the warehouse and analytics receive it via the broker.
The main idea of this architecture is to reduce direct dependency between services and make data exchange asynchronous. This increases the scalability and resilience of the system: if the recipient is temporarily unavailable, the message can stay in the queue and be processed later. At the same time it is important to control redelivery, message ordering, processing errors and idempotency.

Cloud-Native Architecture is an approach to building applications designed from the outset to run in a cloud environment.
Such systems are usually built from microservices, containers, managed cloud services, APIs, message queues, automatic scaling, monitoring and CI/CD processes.
The main idea of Cloud-Native is to make the application flexible, scalable and resilient to failures. Components can be developed, deployed and scaled independently, while the infrastructure is managed automatically using cloud platforms, container orchestration and DevOps practices.

Architecture description languages (ADLs) are used to describe software architecture. Various organisations have developed a number of different ADLs, including AADL (an SAE standard), Wright and Acme (developed at Carnegie Mellon University), xADL (developed at UCI), Darwin (developed at Imperial College London), DAOP-ADL (developed at the University of Málaga) and ByADL (University of L’Aquila, Italy). The concepts of component, connector and configuration are common to all these languages. Besides these specialised languages, the Unified Modeling Language (UML) is also often used to describe architecture.
Software architecture is the foundation that determines a system's resilience, clarity and capacity to evolve. It helps manage complexity, distribute responsibility between the parts of the system, reduce the risks of change and create the conditions for long-term maintenance of the product.
Its main value lies not in formally following rules, but in creating a clear and dependable structure. Good architecture makes a software product more flexible, the team more effective and the evolution of the system more predictable.
This is precisely why architecture is one of the key components of quality software development. It helps you not merely to create a working system, but to build a solution that can grow, change and retain its value over time.
Comments