Research on Software Architecture Patterns - SubarnaSaha08/JUMCMS-Jahangirnagar-University-Medical-Center-Management-System GitHub Wiki
What does Software Architecture Pattern mean?
A software architecture pattern is a high-level, reusable solution to common structural problems in software system design. It defines how components of a system interact and are organized, guiding the overall structure and ensuring scalability, maintainability, and performance. Common architecture patterns include layered architecture, microservices, and event-driven architecture, each suited to different types of applications. By following these patterns, developers can create systems that are more efficient, modular, and easier to manage as they grow.
Model View Controller (MVC)
Author
Subarna Saha
, Shabrina Akter Shahana
Introduction
A popular software architecture pattern that divides an application into three interrelated components - Model, View, and Controller - is called the Model-View-Controller (MVC) design pattern. Because the concerns are separated, it is simpler to design, test, and maintain the program because each component can develop alone without being tightly coupled to other features. Nowadays, MVC is widely used in desktop software, mobile apps, and web applications. It was first developed for desktop applications.
Overview of MVC Components
Model
The application's business logic or essential data are represented by the model. It oversees the system's logic, rules, and data directly. Since the Model is not dependent on the user interface (UI), modifications made to the UI will not have an impact on how the Model handles data.
Responsibilities:
Manage the application's data. Handle business logic and database interaction. Notify the View of any changes to the data.
Example:
In an e-commerce app, the Model would manage data related to products, orders, and users. It may handle CRUD operations (Create, Read, Update, Delete) and business logic like calculating prices.
View
The View represents the presentation layer of the application. It is responsible for rendering the data from the Model in a format suitable for interaction by the user. The View listens to updates from the Model and reflects those updates by refreshing the user interface accordingly.
Responsibilities:
Display data to the user. Update UI when notified by the Model. Do not handle business logic.
Example:
In a blogging platform, the View could be a webpage that displays the content of blog posts, comments, and user profiles, updating dynamically as the data changes.
Controller
The Controller acts as an intermediary between the Model and the View. It processes user input, manipulates the Model, and updates the View accordingly. The Controller retrieves the data from the Model and sends it to the View for presentation.
Responsibilities:
Handle user input (e.g., clicking a button, submitting a form). Update the Model based on input. Decide which View to display in response to user actions.
Example:
In a social media app, when a user posts a comment, the Controller handles the input, updates the Model (adding the comment to the database), and refreshes the View to display the new comment.
MVC Workflow
User Input: The user interacts with the View by performing an action, such as clicking a button or entering data in a form.
Controller Processing: The Controller receives the input from the View, processes the input, and decides what action to take. It may involve querying or updating the Model.
Model Interaction: If the Controller needs to modify data, it will interact with the Model, which performs the necessary operations (e.g., querying a database, performing calculations).
View Update: The Model notifies the View of any changes, and the View is updated to reflect the current state of the Model.
Repeat: The cycle repeats as the user continues interacting with the application.
Advantages of MVC
- Separation of Concerns: By separating the application into three components, MVC promotes modularity. Each component (Model, View, and Controller) is independent, making it easier to manage, maintain, and test the application.
- Reusability: Since the View and Model are independent, the same Model can be reused for different Views. This makes it easy to implement multiple user interfaces (e.g., desktop, web, mobile) using the same business logic.
- Maintainability: Code changes in one component, such as UI updates, do not affect the other parts of the application. This makes maintaining and updating the application more manageable.
- Parallel Development: Multiple developers can work on different components of the application at the same time (e.g., one on the UI and another on the business logic).
Disadvantages of MVC
-
Complexity: The separation of concerns, while beneficial, can lead to complexity in small applications where the MVC structure may seem like over-engineering.
-
Overhead: MVC introduces additional layers of abstraction, which may result in extra boilerplate code. Managing the communication between the Model, View, and Controller can add overhead.
-
Learning Curve: For beginners, understanding the interactions between the three components may be challenging, especially for new developers unfamiliar with design patterns.
Compatibility of MVC with Django
The MVC design pattern is considered perfect for Django because Django inherently follows a very similar architectural pattern called MTV (Model-Template-View), which closely aligns with the principles of MVC. Here’s why MVC suits Django:
-
Separation of Concerns
Django strictly adheres to the separation of concerns, a key principle of MVC. In Django, the components are designed to manage different parts of the application independently, just like in MV: Model: Handles the data and business logic. Django’s ORM (Object-Relational Mapping) allows you to define the data models and interact with databases without writing SQL. Template (equivalent to the View in MVC): Manages how data is presented to the user. Templates in Django define the HTML structure and are responsible for displaying the data passed by the View. View (equivalent to the Controller in MVC): Acts as a controller by handling user requests, interacting with the Model, and returning the appropriate template response to the user.
-
Modular Structure
Django, following an MVC-like structure, makes the application modular. Developers can easily: Change or update the user interface (Template) without altering the data or business logic (Model). Modify the data layer (Model) without affecting the user interface (Template). Improve or extend business logic (View) independently of the rest of the system. This makes Django ideal for building scalable, maintainable applications.
-
URL Routing in Views
In Django, Views handle the logic associated with user requests. URL routing maps URLs to specific view functions (which act as controllers in MVC), making it easy to manage how data flows in response to different user actions.
-
Built-in Admin Interface
Django's admin interface is directly tied to the Model component, making it easy to interact with the database without manually writing data management views. This tight coupling between the Model and the interface is a perfect example of how Django uses the principles of MVC for efficient management of data.
References
Command Query Responsibility Segregation (CQRS)
Introduction
Command Query Responsibility Segregation (CQRS) is a software architectural pattern that separates read (query) and write (command) operations into two different models. This separation allows each model to evolve and scale independently, optimizing each side of the system based on its unique requirements. CQRS is often used in combination with event sourcing and is particularly useful in systems that handle high levels of complexity, scalability, and performance requirements.
What is CQRS?
CQRS is derived from the principle of Command Query Separation (CQS), which states that a function should either perform an action (command) or return data (query) but not both. CQRS extends this principle by completely separating the command and query logic into different models.
-
Commands are responsible for changing the state of the system. Examples include actions like "create an order," "update customer information," or "cancel a booking."
-
Queries are responsible for retrieving data without modifying the state of the system. Examples include fetching a list of products, getting the details of an order, or querying customer details.
In CQRS, the two responsibilities (commands and queries) are handled by different objects or even services, allowing each to be independently optimized and maintained.
How CQRS Works
In a CQRS-based system, the application is divided into two main components:
-
Command Model (Write Model):
- Handles all the operations that modify the application state.
- Validates business logic, performs actions, and may generate events (if combined with event sourcing).
- Optimized for write performance, concurrency control, and consistency.
-
Query Model (Read Model):
- Handles all the operations that read or retrieve data from the system.
- Optimized for fast and efficient data access.
- Can have different data representations than the command model for optimal query performance.
Benefits of CQRS
- Performance Optimization: CQRS allows you to optimize read and write operations independently. For example, you can use one database optimized for writes (e.g., NoSQL or a relational database with ACID guarantees) and another optimized for reads (e.g., a cache or a denormalized database).
-
Scalability: As both the command and query models are independent, they can be scaled individually based on their load. This is particularly useful in high-load systems where reads and writes have different scalability needs.
-
Maintainability and Flexibility: By separating concerns, CQRS allows for more maintainable code. Each model can evolve without affecting the other, and you can introduce new features or make changes in one model without worrying about the impact on the other.
-
Better Data Representation: In traditional systems, you may be forced to structure data to accommodate both read and write needs, which can lead to complexity. With CQRS, the read model can have its own schema optimized for queries, making it easier to retrieve data. Drawbacks and Challenges of CQRS
-
Complexity: Implementing CQRS introduces a higher level of architectural complexity. This includes managing two separate models and ensuring that eventual consistency is handled correctly when using asynchronous updates between the command and query models.
-
Eventual Consistency: In many CQRS implementations, especially those that use event sourcing or messaging systems, the system may not guarantee strong consistency between the write and read models. This can lead to temporary discrepancies between the two models, which must be managed appropriately.
-
Tooling and Infrastructure: CQRS may require additional tooling and infrastructure, such as messaging queues, databases, or caching mechanisms. This may increase operational overhead.
When to Use CQRS
CQRS is most useful in scenarios where:
- The system needs to scale both read and write operations independently. The application has complex business logic that is difficult to manage with a single model.
- Read and write operations have significantly different performance, consistency, or data representation requirements.
- The system is designed for high availability and can tolerate eventual consistency.
CQRS and Event Sourcing
CQRS is often paired with Event Sourcing, a pattern where state changes (commands) are captured as a sequence of events. This allows for a complete history of changes, making it easier to rebuild the state of the system or perform auditing. In event sourcing, each command results in one or more events being recorded, and the query model can subscribe to these events to update its representation of the data.
Example Use Case: E-Commerce Application
In an e-commerce system, CQRS can be applied as follows:
-
Command Model: Handles operations like placing an order, updating inventory, or processing payments. This model ensures that business rules are enforced, and it generates events when actions are performed.
-
Query Model: Handles operations like fetching the order history, retrieving product catalogs, or checking the status of a shipment. This model is optimized for fast reads and may use a different database schema (e.g., a denormalized schema for better performance).
-
Eventual Consistency: When an order is placed, the command model updates the system state, and an event is emitted. The query model listens for these events and updates the data representation accordingly. If the query is made immediately after the command, the system may show the previous state until the event is processed.
Tools for Implementing CQRS
There are several tools and frameworks that can help in implementing CQRS:
Axon Framework (Java): A comprehensive framework for implementing CQRS and event sourcing in Java.
- MediateR (C#): A lightweight library for handling CQRS in .NET applications.
- NServiceBus (C#): A service bus that supports CQRS and event-driven architectures.
- Eventuate.io: A platform that provides CQRS and event sourcing infrastructure for microservices.
How CQRS Can Benefit the Django Framework
CQRS can offer valuable benefits when integrated into the Django framework, especially for applications that require high scalability and complex business logic. By separating the read and write operations, Django applications can be optimized for performance in scenarios where read-heavy or write-heavy workloads exist. Django's ORM (Object-Relational Mapping) makes it easy to manage models, but as the application grows, keeping queries efficient can become challenging. CQRS allows developers to design read models tailored specifically for querying data, bypassing the constraints of the write models, leading to more efficient data retrieval.
Additionally, in Django, where large-scale systems often need to handle diverse interactions (e.g., API consumers, front-end applications, etc.), CQRS helps by ensuring that each interaction is handled by a properly optimized model. By adopting CQRS in a Django project, developers can also leverage Django's ecosystem to independently scale read and write services, providing better performance and maintainability in large-scale applications.
Entity Boundary Control (EBC)
The Entity-Boundary-Control (EBC) pattern is an architectural pattern primarily used in object-oriented design to improve the separation of concerns in software systems. It is widely used in business applications to structure components for maintainability, scalability, and testing. This pattern divides the system into three main components: Entities, Boundaries, and Controllers.
Here’s a breakdown of the EBC pattern:
Entities:
- Entities represent the core business logic or data structures of the system. They encapsulate data and behavior related to the business domain.
- They typically don't depend on other system components like user interfaces or databases.
- Examples: Customer, Order, Product, etc.
Boundaries:
- Boundaries are responsible for handling interactions between the system and external actors (such as users or other systems).
- They define how data enters and leaves the system. This can be through APIs, user interfaces, or any external input/output mechanisms.
- Boundaries are often designed to shield the core entities from external complexities.
- Examples: UI forms, REST controllers, API gateways, etc.
Controllers:
- Controllers manage the flow of the application by coordinating interactions between entities and boundaries.
- They contain logic for invoking operations on entities and handling responses to boundaries.
- Controllers should not contain business logic themselves but delegate to entities or services.
- Examples: Business logic controllers, service controllers, or workflow engines.
Pros
-
Less Coupling: Components don’t depend on each other directly, making it easier to change or fix parts of the system without affecting everything else.
-
Easier to Expand: You can add new features or components without disrupting the existing ones.
-
Flexible: You can easily add or change how events are handled without messing with the main logic of the application.
-
Works in the Background: Events can be processed without making the user wait, which can make the app feel faster.
-
Clear Flow: The way data and actions move through the system can be easier to follow, especially in complex setups.
Cons
-
More Complex: Setting up an event system can make the overall system more complicated, especially for smaller projects.
-
Harder to Debug: It can be tough to track down issues since events might not follow a straightforward path.
-
Extra Work: Sometimes, handling events can slow things down a bit, depending on how it's set up.
-
Too Many Events: If not designed well, you might end up with too many events, which can make the system confusing.
-
Dependency on Events: Even though components are loosely connected, they might still rely too much on specific events, which can limit flexibility.
Decision about selection of Architecture pattern
We chose the MVC Architecture pattern for our project which will be implemented using Django framework because it naturally aligns with Django's architecture, making it easier to manage the separation of concerns between the model, view, and controller layers. This structure simplifies the development and maintenance of web applications. Additionally, we plan to experiment with the CQRS pattern to optimize performance by separating read and write operations, enabling better scalability and handling of complex queries as the project grows. This combination offers both simplicity and flexibility for future expansion.