Microservice patterns are recurring solutions to common problems that arise when designing, implementing and maintaining microservices-based architectures. These patterns help to address specific challenges and make informed decisions to build scalable, maintainable and flexible systems.

In a previous post, we told you what a microservice architecture is and we went from some more traditional ones such as MVC to Clean Architecture, with all the importance it has in microservice architectures today, to finish with the Database per Microservice pattern.

We continue this series of microservices architecture patterns with the second part, where we look at architecture patterns that focus on the organisation and structure of microservices.

We continue with DDD, Clean Architecture and hexagonal architecture, these 3 patterns can go hand in hand, so we will see what they can bring together. Finally, we will look at serverless architecture in microservices.

Organisation and structure of microservices

DDD

DDD (Domain-Driven Design) is an approach to software development that focuses on modelling the problem domain comprehensively and enriching communication and collaboration between development teams and domain experts, such as users and stakeholders.

DDD provides a set of principles and patterns that help create software that accurately reflects business rules and processes, leading to more effective and maintainable solutions.

At its core, DDD is based on the following key ideas:

When partitioning domains, you can follow different strategies (e.g. Logical Entities vs Business Processes) and have different considerations (e.g. The subdomains of the global business, their associated characteristics, development team, technology family, dependency constraints...)

DDD offers a structured way to address complex domain issues and provides clarity in communication between development teams and business experts. The focus on domain modelling and cooperation between different stakeholders contributes to the creation of high quality software that is better aligned with business needs.

Here, a diagram of the simplified and limited example, methods and events could be adapted and extended according to the needs of the e-commerce application and the specific domain model.

It is possible to observe the different domains that would emerge a priori with their entities.

DDD

Hexagonal architecture

The hexagonal architecture proposes that our domain is the kernel of the layers and that it is not coupled to anything external. Instead of making explicit use of the dependency inversion principle, we bind to contracts (interfaces or ports) rather than concrete implementations.

Also known as port and adapter architecture, the design is based on separation of concerns and independence of layers. It seeks to isolate the kernel of the application, where the business logic resides, from interactions with external components such as user interfaces and databases.

Roughly, and without going into too much detail, it suggests that we think of our kernel as an API with well-specified contracts. Defining ports or entry points and interfaces (adapters) so that other modules (UI, DB, Test) can implement them and communicate with the business layer without the business layer having to know the origin of the connection.

In e-commerce, this architecture is essential to ensure the flexibility, maintainability and evolution of the system.

These are called ports and adapters, which could be defined as follows:

Key components:

An example of code would be:

  1. Port

Product management service port:

public interface ProductService {
    Product createProduct(ProductDTO productDTO);
    List<Product> getAllProducts();
}
  1. Kernel domain

Product entity:

public class Product {
    private String id;
    private String name;
    private double price;

    // Builders, getters and setters
}

DTO for product creation:

public class ProductDTO {
    private String name;
    private double price;

    // Builders, getters and setters
}
  1. Adapter

Product controller:

@RestController
@RequestMapping("/products")
public class ProductController {
    private final ProductService productService;

    public ProductController(ProductService productService) {
        this.productService = productService;
    }

    @PostMapping
    public ResponseEntity<Product> createProduct(@RequestBody ProductDTO productDTO) {
        Product createdProduct = productService.createProduct(productDTO);
        return ResponseEntity.status(HttpStatus.CREATED).body(createdProduct);
    }

    @GetMapping
    public ResponseEntity<List<Product>> getAllProducts() {
        List<Product> products = productService.getAllProducts();
        return ResponseEntity.ok(products);
    }
}
  1. Service implementation
@Service
public class ProductServiceImpl implements ProductService {
    private final ProductRepository productRepository;

    public ProductServiceImpl(ProductRepository productRepository) {
        this.productRepository = productRepository;
    }

    @Override
    public Product createProduct(ProductDTO productDTO) {
        Product product = new Product();
        product.setName(productDTO.getName());
        product.setPrice(productDTO.getPrice());

        // Logic additional, validations, etc.

        return productRepository.save(product);
    }

    @Override
    public List<Product> getAllProducts() {
        return productRepository.findAll();
    }
}
  1. Organisation is important

A good example of how it would need to be organised in packages would be:

Organisation

Hexagonal + DDD + Clean Architecture

Using hexagonal architecture, Domain-Driven Design (DDD) and Clean Architecture together can lead to highly efficient and business-oriented software design.

We will explore how these three approaches combine to create a robust and modular structure.

Relationship between hexagonal architecture, DDD and Clean Architecture

Hexagonal architecture and Clean Architecture share similar design principles. Both emphasise the separation of responsibilities and the creation of flexible and maintainable code.

Hexagonal architecture and DDD complement each other well, as DDD provides a solid guide to modelling the domain kernel, while hexagonal architecture helps to implement that domain logic in a flexible, decoupled design.

In short, these three methodologies and approaches work together to produce software systems that are understandable, maintainable and adaptable, while faithfully reflecting the complexity and business rules of the domain they address.

Joint implementation

Combining these approaches gives you:

In summary, the application of hexagonal architecture, Domain-Driven Design and Clean Architecture together provide a solid foundation for software design. This combination promotes flexibility, business focus and adaptability, resulting in robust and maintainable applications over the long term.

Serverless

Serverless computing technology has transformed the way applications are deployed and scaled in the cloud.

While the term serverless can be somewhat misleading (as there are still servers running), it refers to an abstraction of the underlying infrastructure that allows developers to focus on the code and logic of their application rather than managing servers and resources.

What is serverless computing?

Serverless computing is a cloud development and deployment model where the cloud provider is responsible for managing the underlying infrastructure.

Developers simply upload their code to the cloud and the platform takes care of executing it in response to events such as HTTP requests, database changes or queue loads.

This allows applications to scale automatically on demand without the need to worry about server provisioning.

The benefits of serverless computing:

Focus on business. Teams can focus on solving real business problems rather than worrying about infrastructure.

Use cases:

  1. Web applications.

Serverless is ideal for web applications with variable load, as they can automatically scale according to traffic.

  1. Data processing.

Batch or real-time data processing is efficient with serverless because you can run task-specific functions.

  1. Microservices.

Each microservice can be implemented as a serverless function, making it easier to maintain and scale independently.

Challenges:

Example of serverless computing:

Let’s say you have an online store and you want to perform an action every time an order is placed, such as sending a confirmation e-mail to the customer and updating the inventory. You can take advantage of serverless computing to handle these actions efficiently.

//  Lambda function to process orders
exports.handler = async (event) => {

    // Parse on event (which could be an order in JSON format)
    const order = JSON.parse(event.body);

    // Simulate the sending of a confirmation email  
    await sendConfirmationEmail(order.customerEmail, order.orderId);

    // Update the inventory
    await updateInventory(order.products);

    // Response successful
    return {
        statusCode: 200,
        body: JSON.stringify({ message: order processed successfully' })
    };

};

//  Function to send a confirmation  email 
async function sendConfirmationEmail(email, orderId) {

    // Logic to send the email 
    console.log(`Confirmation email sent   to ${email} for the order ${orderId}`);

}

// Function to update the inventory
async function updateInventory(products) {

    // Logic to update the inventory of the products
    console.log('Inventory updated for the products:', products);

}

How does it work?

This example shows how you can use serverless computing to handle specific tasks in your e-commerce application without having to keep servers running all the time. This saves resources and allows you to focus on delivering a great customer experience.

What did you think? Got any questions? Feel free to leave a comment - we hope you find it useful!

Tell us what you think.

Comments are moderated and will only be visible if they add to the discussion in a constructive way. If you disagree with a point, please, be polite.

Subscribe