Let's assume I have an API endpoint which needs some Product data to process the requests properly. Imagine that there's some application layer service which has to handle the contract (let it be a query for example). The application layer service communicates with some external provider in order to get the Product information. Pseudocode could like this:
class ApplicationService
{
IProductCache _productCache;
IProductProvider _productProvider;
public void Handle(Contract contract)
{
var products = _productCache.GetProducts();
if (products == null)
{
products = _productProvider.GetProducts();
}
...
}
}
In such a solution application layer is aware that there's some caching mechanism and the application service firstly communicates with cache then with the provider. We could also encapsulate the caching mechanism in the infrastructure layer (in which IProductProvider implementation belongs to). We would have something like this:
class ApplicationService
{
IProductProvider _productProvider;
public void Handle(Contract contract)
{
var products = _productProvider.GetProducts();
...
}
}
class ProductsProvider : IProductProvider
{
IProductCache _productCache;
public Product[] GetProducts()
{
var cachedProducts = _productCache.GetProducts();
if (cachedProducts not empty)
{
return cachedProducts;
}
// else communicate with external provider
...
}
}
Which solution is better and more proper? What are the advantages and disadvantages of both of them? Could you share your thoughts on this? Thanks in advance for any help.
Hexagonal architecture states that applications are formed in concentric layers with references going inward. The outmost layer of an hexagonal application is the adapters layers. The layer next inward to the adapters is the port layer. The most inward layer is business logic.
Ports act as a boundary between your business logic (inwards) and infrastructure (outwards).
Adding a cache to the communication with the products persistence store is an implementation detail of the communication with the products store. It should go in the adapter layer implementing the IProductCache.GetProducts()
port. You should put the reference to IProductCache
in ProductProvider
.
ApplicationService
is not a good place to inject a cache, because that adapter is responsible for the communication with the client. Caching the products has nothing to do with the communication with the client but with the communication with the product data store.
However, this will add cache to every parts of your application that need the products list. Sometimes you may need to force the communication and ignore the cache. In that situation, you should implement two adapters for the port, one with cache and another without. Then configure your dependency injection to inject the right adapter for each use case.