Improved Fault Tolerance
初級If a microservice fails, it ideally doesn't bring down the entire system, making the system more resilient.
Architecture
Scalability, microservices, caching, queues and trade-offs.
38 問
If a microservice fails, it ideally doesn't bring down the entire system, making the system more resilient.
Let's look at the main advantages of using microservices:
Key Benefits
Thanks to reduced codebase ownership and the interoperability of services, smaller, focused teams can thrive and communicate more efficiently.
Decoupling services means one service's issues or updates generally won't affect others, promoting agility.
Different services can be built using varied languages or frameworks. While this adds some complexity, it allows for best-tool-for-the-job selection.
No more unwieldy, monolithic codebases to navigate. With microservices, teams can focus on smaller, specific codebases, thereby enabling more targeted maintenance.
Security policies and mechanisms can be tailored to individual services, potentially reducing the overall attack surface.
Each microservice can be scaled independently, which is particularly valuable in dynamic, going-viral, or resource-intensive scenarios.
Microservices mesh well with Agile, enabling teams to iterate independently, ship updates faster, and adapt to changing requirements more swiftly.
While the Singleton pattern offers benefits such as a single point of access and delayed instantiation, its drawbacks and potential misapplications are worth considering.
Key Considerations
Scope of Singleton Behavior
The Singleton pattern isn't always the most suitable for enabling unique global access. Classes managed by dependency injection (DI) frameworks, for instance, often provide more adaptable and testable mechanisms for context-driven singletons.
Drawbacks of the Singleton Pattern
Best Practices for Singleton Usage
Considering the potential drawbacks, it's good to adhere to these best practices:
Explore all 85 answers here 👉 Devinterview.io - Software Architecture
Instead, they define the character of the message using classes and descriptions, and subscribers subscribed interested subjects receive those messages.
Core Components
Mechanism
Application Scenarios
Coupling is the level of dependence that modules have on one another. Low coupling is a design goal, indicating that modules are fairly independent.
In contrast, cohesion reflects the degree to which the elements within a module belong together. High cohesion suggests that all elements in a module are closely related.
Practical Example: Data Validation Form
Consider a form where email and phone number are mandatory.
This approach can lead to redundant and error-prone code, especially as the form grows more complex. Instead, one could use a ValidateEmail and ValidatePhoneNumber module, enforcing responsibility and independence.
The API Gateway acts as a single entry point for a client to access various capabilities of microservices.
Gateway Responsibilities
Key Benefits
Contextual Use
The gateway pattern is particularly useful:
Code Example: Setting Up an API Gateway
Here is the Python code:
from flask import Flask, request
import requests
app = Flask(__name__)
@app.route('/')
def api_gateway():
# Example: Aggregating and forwarding requests
response1 = requests.get('http://service1.com')
response2 = requests.get('http://service2.com')
# Further processing of responses
return 'Aggregated response'Model-View-Controller (MVC) is an architectural pattern known for its clear separation of concerns. It divides software into three main components, promoting maintainability and scalability.
Visual Representation
.png'alt=media&token=245cccca-91d6-412e-91ed-4b0838d00046)
Key Components
Core Concepts
Interaction Flow
Benefits and Limitations
Advantages
Limitations
Domain-Driven Design (DDD) provides a model for designing and structuring microservices around specific business domains. It helps teams reduce complexity and align better with domain experts.
Context Boundaries
In DDD, a Bounded Context establishes clear boundaries for a domain model, focusing on a specific domain of knowledge. These boundaries help microservice teams to operate autonomously, evolving their services within a set context.
Ubiquitous Language
Ubiquitous Language is a shared vocabulary that unites developers and domain experts. Microservices within a Bounded Context are built around this common language, facilitating clear communication and a deeper domain understanding.
Strong Consistency and Relational Databases
Within a Bounded Context, microservices share a consistent data model, often dealing with strong consistency and using relational databases. This cohesion simplifies integrity checks and data relationships.
Code Example
PaymentService Microservice: ``java @Entity public class Payment { @Id private String paymentId; private String orderId; // ... other fields and methods } ``
OrderService Microservice:```java @Entity public class Order { @Id private String orderId; // ... other fields and methods }
public void updateOrderWithPayment(String orderId, String paymentId) { // Update the order } ```
OrderDetailsService Microservice: ``java @Entity public class OrderDetail { @EmbeddedId private OrderDetailId orderDetailId; private String orderId; private String itemId; private int quantity; // ... other fields and methods } ``
The principle of least knowledge (LoD), also known as the law of Demeter, emphasizes reducing the dependencies between modules and classes to make systems more modular, easier to maintain, and less prone to errors.
Core Tenets
The Law of Demeter distills the following key principles:
Verbal Expressions
The Law of Demeter has been formulated using several verbal expressions, offering different perspectives on its core tenets:
"Don't talk to strangers"
This phrase is an analogue for the principle that objects or methods should have limited access to other entities.
"Only talk to your immediate friends"
This expression emphasizes that a module should interact with its closely related modules and avoid extensive collaboration, mitigating the risk of creating tightly coupled systems.
Code Example: Demeter Principle Violation
Here is the code:
public class Owner {
private Car car;
public Owner() {
this.car = new Car();
}
public void startCar() {
car.start();
}
}
public class Car {
private Engine engine;
public Car() {
this.engine = new Engine();
}
public void start() {
engine.start();
}
}
public class Engine {
public void start() {
System.out.println("Starting engine");
}
}In this system, the Owner class knows too much about the Engine class.
Code Example: Applying the Law of Demeter
Here is the code:
public class Owner {
private Car car;
public Owner() {
this.car = new Car();
}
public void startCar() {
car.startEngine();
}
}
public class Car {
private Engine engine;
public Car() {
this.engine = new Engine();
}
public void startEngine() {
engine.start();
}
}
public class Engine {
public void start() {
System.out.println("Starting engine");
}
}In this improved structure, the Owner class directly communicates with the Car class, maintaining a more logical and appropriate communication pattern.
Modularity in software architecture refers to the degree to which a software system can be broken down into separate functional or logical modules or components. These modules are often designed to be distinct, yet interrelated, promoting ease of development, flexibility, maintainability, and reusability.
Core Attributes of Modularity
Benefits of Modularity
Real-World Application
The Layered Architecture Pattern is characterized by the hierarchical organization of the software components into distinct layers, each serving a specific role and potentially necessitating communication with adjacent layers. It's also known as the N-Tier Architecture or the Multi-Tier Architecture.
Key Components
Advantages
Common Use Cases
Drawbacks
Code Example: Basic Three-Layer Architecture
Layers
Presentation Layer:
This layer is responsible for displaying information to users and handling user interactions. In a web application, it might correspond to the View. In a Windows Forms app, it is the form itself.
public class UserController
{
private readonly UserService _userService;
public UserController(UserService userService)
{
_userService = userService;
}
public void DisplayUserInfo(string userId)
{
var userInfo = _userService.GetUserInfo(userId);
// Pass userInfo to the view for display
}
}Business Logic Layer:
This layer implements the business rules and processes. It acts as an intermediary between the presentation and data layers.
public class UserService
{
private readonly UserRepository _userRepository;
public UserService(UserRepository userRepository)
{
_userRepository = userRepository;
}
public UserInfo GetUserInfo(string userId)
{
// Apply any business rules or logic here before retrieving the user data
var userInfo = _userRepository.GetUserById(userId);
return userInfo;
}
}Data Layer:
This layer is responsible for data storage and access, such as a database, file system, or web service.
public class UserRepository
{
public UserInfo GetUserById(string userId)
{
// Code to interact with the data storage medium to retrieve user information
}
}Wiring the Layers
In a real-world application, you might perform dependency injection to wire up the layers. Here is the C# code:
// In your Main method or application entry point
var userRepository = new UserRepository(); // A concrete implementation
var userService = new UserService(userRepository);
var userController = new UserController(userService);In many modern systems, this wiring could be handled by an IoC container.
SOLID is an acronym that represents the five basic principles of object-oriented programming. These guidelines help to enhance code readability, reusability, and maintainability.
The SOLID Principles
A class should have only one reason to change. In other words, it should have only one responsibility.
A module (i.e., a function or a class) should be open for extension, but closed for modification.
Derived classes should be substitutable for their base classes, meaning that they should share the same interface and be used interchangeably with objects of the base class.
Many client-specific interfaces are better than one general-purpose interface.
High-level modules should not depend on low-level modules. Both should depend on abstractions. Additionally, abstractions should not depend on details; details should depend on abstractions.
What the SOLID Principles Mean
A Service Mesh is a dedicated infrastructure layer that simplifies network requirements for microservices, making communication more reliable, secure, and efficient. It is designed to reduce the operational burden of communication between microservices.
Why Service Mesh?
Elements of Service Mesh
The Service Mesh architecture comprises two primary components:
Key Capabilities
Code Example: Service Mesh Components in Kubernetes
Here is the YAML configuration:
For the Control Plane:
apiVersion: v1
kind: Pod
metadata:
name: control-plane-pod
labels:
component: control-plane
spec:
containers:
- name: controller
image: control-plane-image
ports:
- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: control-plane-service
spec:
selector:
component: control-plane
ports:
- protocol: TCP
port: 80
targetPort: 8080For the Data Plane:
apiVersion: v1
kind: Pod
metadata:
name: service-1-pod
labels:
app: service-1
spec:
containers:
- name: service-1-container
image: service-1-image
ports:
- containerPort: 8080
- name: proxy
image: envoyproxy/envoy-alpine
containers:
- name: service-2-container
image: service-2-image
ports:
- containerPort: 8080
- name: proxy
image: envoyproxy/envoy-alpineIn this example, Envoy serves as the sidecar proxy (Data Plane) injected alongside service-1 and service-2, and the control-plane-pod and control-plane-service represent the control plane.