Implementing Clean Architecture and Adding a Caching Layer
Published: 2024-05-05 17:02:42

In this article, we'll discuss implementing Clean Architecture and taking it a step further by adding a caching mechanism in front of our repository. This allows us to navigate between the database (Db) and Redis while performing a one-way data flow: read-only from Redis and write-only directly to the Db.

**Building a Web Application with Clean Architecture and Caching**

So far, for our final year project, we've been able to draft the database schema, which I shared in a previous LinkedIn post: https://www.linkedin.com/posts/joel-ndoh_dbdiagramio-database-relationship-diagrams-activity-7176510355722956800-m30p?utm_source=share&utm_medium=member_desktop.

I'd like to give a big shoutout to [Rufai Quadri](https://www.linkedin.com/article/edit/7187866455948873728/#?lipi=urn%3Ali%3Apage%3Ad_flagship3_publishing_post_edit%3B4tJH%2Bk2VQCKQX074%2F4hGKw%3D%3D) for designing the entire user interface.

We've begun development, with me handling the backend while [Promise Sheggsmann](https://www.linkedin.com/article/edit/7187866455948873728/#?lipi=urn%3Ali%3Apage%3Ad_flagship3_publishing_post_edit%3B4tJH%2Bk2VQCKQX074%2F4hGKw%3D%3D) and [Jay Stance](https://www.linkedin.com/article/edit/7187866455948873728/#?lipi=urn%3Ali%3Apage%3Ad_flagship3_publishing_post_edit%3B4tJH%2Bk2VQCKQX074%2F4hGKw%3D%3D) work on the dashboards and mobile app, respectively.

Since our system's requirements are dynamic, we aimed to create a plug-and-play system that can be easily adapted for any feature at any time.

**Using Clean Architecture for a Modular and Maintainable System**

Uncle Bob's Clean Architecture has been my go-to approach for every project I've worked on in the past eight months. There was no question about using it for this project either.

Over the past few months, I've observed various implementations of Clean Architecture, all adhering to the core concepts. Here's how I've structured mine:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fn7vo0jmx0uf2rajg8ze.png)


1. Resource/Entity: These are the fundamental objects of the entire project, defining the basic data structure and properties.

2. Database: Here, I've modeled the schema for each resource and exposed a few database queries for each schema in a dedicated "schema-repository.js" file. This ensures that all database queries throughout the application are performed from a single location, preventing them from being scattered across the project. This makes it much easier to identify and fix any issues with database queries that might be affecting the database or application performance. This approach stems from my personal experience of having the database layer within the same layer as the service, which I found to be cumbersome and something I wouldn't want to repeat myself or recommend to others.

3. Cache Layer: This layer consists of a single file containing a list of frequently used Redis queries. Similar to the database queries, this promotes code organization by keeping all Redis queries in one place.

4. Database Service Layer: This layer is crucial for creating a well-cached application. By "cache," I mean the application caches static data whenever possible to prevent serving stale data to users. Here, we have a database service file for all our schemas. This implementation effectively bridges the gap between achieving a well-cached system and avoiding the issue of stale data.

5. Service Layer: This layer houses all our business logic. Each resource has its own dedicated service file named "resource_name-service.js". Previously, I used to combine the middleware, database, and service layers into a single "controller" layer. However, over time, while working on larger projects, this approach proved to be difficult to manage and maintain.

6. Routing/Middleware and Helper   

- Routing/Middleware: In this layer, we've ensured that no business logic runs here. It's solely for routing and validating user input. We then use middleware for tasks like rate limiting and authentication.

- Helper: This layer contains functions that are not tightly coupled with our project's core business logic. Here, you might find functions for:

1. Handling external API calls

2. Sending messages to message queues

3. Receiving messages from message queues

4. Executing routine tasks that ultimately call methods within the service layer.

This concludes my breakdown of how I implemented Clean Architecture in my final year project.