IoC é a melhor estratégia para desacoplar um sistema. Facilita a criação de testes, separa as dependências e isola o domínio. No entanto existe uma técnica, bem pouco usada, que permite interceptar um componente e adicionar novos comportamentos, e ainda assim executar o componente original.

Slab Of Green And Gold

Performance

Se houvesse uma forma de definir performance em uma única palavra, Cache seria a resposta.

Há muitas formas de obter performance. Otimizando o código. Melhorando a consulta no banco. Criando um índice. Melhorando o algoritmo. Usando programação paralela. Adicionando mais hardware. Ainda assim, quando o seu sistema se tornar grande o suficiente, atendendo milhares de milhões de requisições por minuto, você será obrigado a rever a estratégia de cache da sua aplicação.

O problema

Considere o seguinte código:

Veja que a Controller espera um ICarStore. Que por sua vez acessa o banco de dados. Efetua uma pesquisa e devolve a resposta da requisição.

Uma pergunta:

Mia wants treats!

Como adicionar Cache sem alterar a Controller e nem o CarStore?

Imagine que a implementação do ICarStore esteja num componente fora do seu alcance. Uma biblioteca do Nuget, por exemplo. E esse componente está demorando muito para responder.

A técnica

A técnica consiste em utilizar o IoC. A estratégia é composta por duas etapas.

A primeira é criar uma classe de cache que receba o ICarStore e também faça a implementação da interface.

A segunda é registrar a Classe concreta que implementa o ICarStore e substituir o registro dele no DI.

Primeira etapa

Veja a implementação abaixo

Esse componente vai receber uma classe Concreta que implementa ICarStore e ao mesmo tempo, ela implementa essa interface.

Segunda etapa

Em algum lugar do código há um registro da Interface com a implementação dela.

É necessário interferir no DI do ASP.NET Core.

Primeiro o ASP.NET Core associa o ICarStore à sua implementação original, CarStore.

Em seguida o código registra a classe Concreta CarStore e refaz o registro de ICarStore, só que dessa vez, associando ao componente criado anteriormente.

Lembre-se que esse é um demo. Geralmente existe uma lógica para habilitar ou não essa substituição.

Abaixo o código do CarCachingStore completo

Ouça e veja a implementação comentada

Casos de Uso

Um bom uso dessa técnica é com Cache. A aplicação só conhece uma interface. Ela não precisa entender quando o dado virá do Cache. Assim evita implementações como:

  • ICarCacheStore
  • ICarStore

E é possivel controlar quando ativar o Cache de acordo com o ambiente. Utilizar Cache somente no ambiente de produção e em desenvolvimento manter os dados sempre frescos.

Você pode adicionar Log em componentes.

Quem utiliza?

Esse técnica aprendi enquanto analisava o código do IdentityServer4. Eles utilizam através do Builder do IdentityServer4 quando é acionado o método para habilitar cache.

Download

O código do projeto está disponível no meu GitHub