Clean Code (Código limpo) – Limites

Raramente controlamos todo o software em nossos sistemas, é comum utilizarmos softwares de terceiros em nossas aplicações. Neste artigo, examinamos as práticas e técnicas para manter os limites do nosso software limpos.

Usando código de terceiros

Existe uma tensão natural entre o provedor de uma interface e o usuário de uma interface. Os pacotes e bibliotecas de terceiros buscam ampla aplicabilidade para que possam trabalhar em muitos ambientes e atrair um público maior. Os usuários, por outro lado, desejam uma interface que se concentre em suas necessidades específicas. Essa tensão pode causar problemas nos limites de nossos sistemas.

Por exemplo, é comum ao usar uma biblioteca de terceiro, termos que realizar um cast para um objeto conhecido. Neste caso desenvolvedor tem a responsabilidade de obter um objeto da biblioteca e fazer o cast para o tipo desejado. Isso funciona, mas não é um código limpo. Além disso, esse código não conta sua história tão bem quanto poderia. A legibilidade deste código pode ser bastante melhorada usando objetos genéricos que já é muito utilizada em bibliotecas do C#.

Uma maneira mais limpa pode ser parecida com a exibida abaixo. Como podemos ver, nenhum usuário da classe Geometry se importaria nem um pouco se os genéricos fossem usados dentro dela ou não. Essa escolha se tornou (e sempre deve ser) um detalhe de implementação.

    public class Geometry
    {
        private LLClass geometry = new LLClass();

        public Geometry getById(String id)
        {
            return (Geometry) geometry.get(id);
        }
    }

A interface ILLClass (classe genérica criada para este exemplo) está oculta. Geometry é capaz de evoluir com muito pouco impacto no resto da aplicação. O uso de genéricos não é mais um grande problema, porque a conversão e o gerenciamento de tipo são feitos dentro da classe Geometry e não em cada chamada do geometry.get(id).

Essa interface também deve ser adaptada e restrita para atender às necessidades da sua aplicação. Isso resulta em um código mais fácil de entender e mais difícil de usar indevidamente. A classe Geometry pode impor regras de design e negócios necessárias e limitantes.

Não estamos sugerindo que todo uso de qualquer classe seja encapsulado em qualquer forma. Em vez disso, estamos aconselhando você a não passar a classe/interface ILLClass (ou qualquer outra interface em um limite) em torno de seu sistema. Se você usar uma interface de fronteira como a do exemplo, mantenha-a dentro da classe, ou em uma família próxima de classes, onde ela é usada. Evite devolvê-la ou aceitá-la como um argumento para APIs públicas.

Explorando e aprendendo os limites

Aprender o código de terceiros é difícil. Integrar o código de terceiros também é difícil. Fazer as duas coisas ao mesmo tempo é duplamente difícil. E se adotássemos uma abordagem diferente? Em vez de experimentar as coisas novas em nosso código de produção, poderíamos escrever alguns testes para explorar nossa compreensão do código de terceiros. Jim Newkirk chama esses testes de “testes de aprendizagem”.

Nos “testes de aprendizagem”, chamamos a API de terceiros, pois esperamos usá-la em nosso aplicativo. Basicamente, estamos fazendo experimentos controlados que verificam nossa compreensão dessa API. Os testes se concentram no que queremos usar e aprender.

Aprender biblioteca de terceiros

Digamos que queremos usar alguma biblioteca de terceiros. Nós baixamos e abrimos a página de documentação introdutória. Sem muita leitura, escrevemos nosso primeiro caso de teste, esperando que ele escreva algo no console.

Provavelmente você falhou neste teste, mas tudo bem, você volta até a documentação, faz algumas leituras e descobre o problema. Você corrige o teste e executa novamente. Usando a classe de testes como eu laboratório de aprendizado.

Você vai repetir este processo até ter uma boa compreensão deste laboratório, e também ter um código bom e limpo que pode ser usado como referência para o seu projeto.

Os “testes de aprendizagem” são melhores do que gratuitos

Os testes de aprendizado acabam não custando nada. Tivemos que aprender a utilizar a API de qualquer maneira, e escrever esses testes foi uma maneira fácil e isolada de obter esse conhecimento. Os “testes de aprendizagem” foram experimentos precisos que ajudaram a aumentar nossa compreensão.

Estes não são apenas gratuitos, mas também apresentam um retorno do investimento positivo. Quando há atualizações do pacote de terceiros, executamos os “testes de aprendizado” para ver se há diferenças de comportamento esperado. Se o pacote de terceiros mudar de alguma forma incompatível com nossos testes, vamos descobrir imediatamente.

Quer você precise do aprendizado fornecido pelos testes ou não, um limite limpo deve ser suportado por um conjunto de testes que impõem nessa interface, valores de entradas, da mesma forma que o código de produção. Sem esses testes de limite para facilitar a migração, podemos ficar tentados a ficar com a versão antiga por mais tempo do que deveríamos.

Usando código que ainda não existe

Existe outro tipo de fronteira, aquela que separa o conhecido do desconhecido. Frequentemente, há lugares no código em que nosso conhecimento parece cair do limite. Às vezes, o que está do outro lado da fronteira é incognoscível (pelo menos agora). Às vezes, optamos por não olhar além da fronteira.

Limites Limpos

Coisas interessantes acontecem nos limites. Mudança é uma daquelas coisas. Bons designs de software acomodam mudanças sem grandes investimentos e retrabalho. Quando usamos código que está fora de nosso controle, cuidados especiais devem ser tomados para proteger nosso investimento e garantir que alterações futuras não sejam muito caras.

O código na fronteirasprecisa de separação clara e testes que definam as expectativas. Devemos evitar deixar muito do nosso código saber sobre os detalhes de terceiros. É melhor depender de algo que você controla do que de algo que você não controla, para que não acabe controlando você.

Conclusão

Gerenciamos os limites de terceiros tendo muito poucos lugares no código que se referem a eles. Podemos envolvê-los como fizemos com o Geometry, ou podemos usar um adaptador para converter nossa interface perfeita para a interface fornecida. De qualquer forma, nosso código fala melhor conosco, promove o uso internamente consistente através da fronteira e tem menos pontos de manutenção quando o código de uma forte externa muda.

Qualquer dúvida ou dicas, entre em contato: leandrolt@gmail.com

Referência
– Clean Code: A Handbook of Agile Software Craftsmanship (English Edition) – Robert C. Martin – Capítulo 8

Leave a Reply

Your email address will not be published. Required fields are marked *