Skip to content

Latest commit

 

History

History
66 lines (39 loc) · 6.52 KB

DESIGN.md

File metadata and controls

66 lines (39 loc) · 6.52 KB

Design Overview

Microservice Architecture

The project is designed using a microservice architecture to ensure scalability, flexibility, and ease of maintenance. By breaking down the application into smaller, self-contained services, we can independently develop, deploy, and scale different parts of the system. This approach allows us to better manage complex systems and respond more effectively to changing requirements.

Microservices

1. Library Service

The Library Service is responsible for managing books and authors. Given that the data in this service may evolve and expand over time, I chose MongoDB as the database. MongoDB's flexible schema allows us to easily accommodate changes and additions to the data model without requiring extensive migrations or disruptions.

2. Identity Service

The Identity Service handles user management and authentication. This service uses two different data stores:

  • Redis: Chosen for storing tokens due to its high performance and speed. Redis allows for quick access to tokens, which is critical for efficient authentication and session management.
  • PostgreSQL: Used for storing user data, as it provides a robust, relational data structure. PostgreSQL ensures that user data is stored with a clear and consistent schema, which is essential for maintaining data integrity and supporting complex queries.

3. Favorites Service

The Favorites Service is designed to manage user favorites across different types of entities. It is built with flexibility in mind, allowing for the addition of new domains, such as favorite authors or reviews, in the future. This service is designed to work seamlessly with any entity type, making it highly adaptable to evolving business needs.

API Gateway

The API Gateway serves as the entry point to the system, consolidating access to the various microservices. It performs input validation, checks whether users are authenticated, and routes requests to the appropriate service. This centralized approach simplifies the client-side interaction with the system by providing a single, unified API.

Inter-service Communication

For communication between microservices, RabbitMQ was chosen as the message broker. RabbitMQ enables reliable and asynchronous messaging, which is essential for decoupling services and ensuring that they can operate independently. This approach also enhances the system's resilience by allowing services to continue functioning even if some parts are temporarily unavailable.

Why RabbitMQ?

  • Asynchronous Communication: RabbitMQ supports asynchronous messaging, which is vital for handling long-running processes and reducing system latency.
  • Scalability: RabbitMQ can easily handle high-throughput environments, making it suitable for a growing application with increasing demand.
  • Flexibility: It provides support for various messaging patterns, allowing us to implement complex workflows across microservices.

Command Query Responsibility Segregation (CQRS)

I chose to implement the CQRS pattern in this architecture to further enhance scalability and maintainability. By separating the read and write operations into distinct models and services, CQRS allows us to optimize each operation according to its specific requirements. This separation provides several advantages:

  • Scalability: High-load commands or queries can be isolated and scaled independently by deploying them as separate microservices. This ensures that performance bottlenecks in one area do not affect the entire system.
  • Optimization: Read and write operations can be optimized differently based on their specific needs. For example, queries can be tuned for quick retrieval of data, while commands can be focused on ensuring data integrity and consistency.
  • Flexibility: With CQRS, we can easily introduce new functionality, such as complex event sourcing, without impacting other parts of the system. This approach also makes it easier to evolve the architecture over time.

Frontend Design

For the frontend, I chose the @mui/joy library. This library was selected for the following reasons:

  • @mui/joy: @mui/joy provides a modern, aesthetic, and accessible set of components that can be easily customized to fit the design needs of the application. The library is designed with flexibility and simplicity in mind, allowing developers to quickly build consistent user interfaces with minimal effort.

Performance Consideration: @mui/joy and Styled Components

While @mui/joy relies on styled-components for styling, which may introduce some performance overhead, this impact is not critical for the following reasons:

  • Optimized for Modern Browsers: @mui/joy is optimized for modern browsers, and the performance overhead is minimal in most real-world scenarios. The benefits of using a well-maintained and flexible component library outweigh the potential downsides.
  • Caching and Server-Side Rendering: Techniques like caching and server-side rendering (SSR) can further mitigate any performance concerns. @mui/joy supports these techniques, which helps maintain a smooth user experience.

API Design

For the API, I chose GraphQL in combination with class-validator. This choice offers several advantages:

  • GraphQL: Allows clients to request exactly the data they need, reducing over-fetching and improving efficiency. It also supports strong typing, which helps in generating API clients and improves developer productivity.
  • class-validator: Facilitates input validation, ensuring that incoming data meets the expected format and structure. This helps in catching errors early and improving the robustness of the API.
  • Developer Familiarity: Given that the team is already familiar with these technologies, this choice reduces the learning curve and accelerates development.

Conclusion

This architectural design leverages the strengths of microservices, enabling us to build a scalable, maintainable, and flexible application. The combination of MongoDB, PostgreSQL, Redis, RabbitMQ, and GraphQL ensures that each service is optimized for its specific role, while the API Gateway and messaging infrastructure provide a seamless and reliable communication layer. The adoption of the CQRS pattern further enhances the scalability of the system, allowing us to handle high-load scenarios by scaling individual operations as needed. The choice of @mui/joy for the frontend provides a solid foundation for a consistent and user-friendly interface, with performance concerns being effectively managed through modern optimization techniques.