Clean Architecture – Caching As A Proxy

In the last post on Clean Architecture, we explored how caching could be implemented in a pluggable manner within the Interface Adapters layer. 

Here is the diagram of the data retrieval part of the system:

 

I have highlighted the interface connecting from CachedCustomerRepository to the database. However, there is a problem. 

Again here is the listing for CachedCustomerRepository:

  public class CachedCustomerRepository : ICustomerRepository
  {
     private ICache<Customer> Cache { get; set; }
     private ICustomerDatabase Database { get; set; }

     public CachedCustomerRepository(ICache<Customer> cache, ICustomerDatabase database)
     {
        Cache = cache;
        Database = database;
     }

     public Customer GetCustomer(string emailAddress)
     {
        var customer = Cache.Get(emailAddress);
        if (customer != null)
           return customer;
        customer = Database.GetCustomer(emailAddress);
        if (customer == null)
           return null;
        // Put the customer into the cache for future calls.
        Cache.Set(customer.EmailAddress, customer);
        return customer;
     }
  }

Notice how the interface to the database is named ICustomerDatabase

As I see it, we can do improve this design. 

As it stands, if we wanted to revert to a simpler system, one without the caching infrastructure and rip out CachedCustomerRepository, so that we can connect up the SqlCustomerRepository to the use case, then we would be in trouble. The use case uses ICustomerRepository, yet SqlCustomerRepository implements ICustomerDatabase!

 

To make this work, could we have our business logic make its data calls against ICustomerDatabase

We don’t want the business logic to be aware it’s calling a database—the use case should utilise a neutral interface like ICustomerRepository.

How about SqlCustomerRepository implementing ICustomerRepository instead of ICustomerDatabase

Let’s try that out. Here is what the system diagram will look like without caching:

 

Yes, the system is pluggable—we can unplug SqlCustomerRepository and plug in a different database implementation.

OK, what about if we reinstate caching? Here is the system diagram:

 

Isn’t that nice?! The entire caching infrastructure, especially the logic module switching between cache and database data retrieval, CachedCustomerRepository, plugged upstream into the use case and downstream into the SqlCustomerRepository modules. It just connects up! 

Technically, the new implementation of CachedCustomerRepository is a proxy, a segment that sits between two interfaces of the same type. Proxy is a valuable design pattern—it allows us to slip behaviour between an interface consumer and interface implementer. 

Our new versatile system, whereby database implementation, caching implementation and the data retrieval workflow are pluggable modules, resembles how Lego blocks connect to one another. Elegant Software Architecture is highly pluggable—in the right way.

0 replies

Leave a Reply

Want to join the discussion?
Feel free to contribute!

Leave a Reply