Como escrever código que será reutilizado



A ideia de que o código projetado para reutilização pode ser uma panacéia para todos os problemas de programação é um mito perigoso. Agora vou explicar o porquê.

Vamos imaginar que você esteja escrevendo uma biblioteca e de repente tenha uma idéia brilhante, da qual uma solução generalizada pode ser obtida, aplicável em uma ampla gama de casos. Você prescreve febrilmente APIs que dominam qualquer funcionalidade e se adaptam a qualquer cenário. Você adiciona todos os scripts que vêm à sua mente. O código aumenta e aumenta, mas, em última análise, realmente se generaliza no sentido mais amplo da palavra. Ele é como bolos quentes, e você é feliz.

Mas um dia, uma nova API está surgindo no horizonte. É mais conciso e adequado para um número maior de cenários, e também ganha em velocidade e simplicidade. Sua API cai no esquecimento - todo mundo muda imediatamente para uma novidade tentadora. No entanto, após algum tempo, a mesma história se repete: a API se torna cada vez mais pesada devido a constantes adições ao código, projetadas para novas condições, até que, no final, algo mais o substitua. E assim por diante ad infinitum.

Por que isso é assim?

A raiz de todos os problemas nesse caso é o desejo de escrever soluções generalizadas. Se o código reproduzível usa um caso padrão como padrão, torna-se inchado, inconveniente de usar e gradualmente se transforma em pura dor de cabeça.

Algum grau de generalização é um pré-requisito para o uso repetido de qualquer código. Mas se você for longe demais, o utilitarismo começa a sofrer. Portanto, se eu expressar meu pensamento em poucas palavras, escrever um código reutilizável não se resume a torná-lo o mais abrangente possível. Tudo é muito mais complicado.
Para criar um código reproduzível prático, você precisa garantir que ele não seja usado regularmente, mas espontaneamente, quando necessário. Digamos, ao trabalhar em um produto, você de repente encontra um código que pode ser usado para suas necessidades. Você pega esse trecho, modifica-o um pouco e o implementa no aplicativo. Assim, você paga apenas pelo que realmente se beneficia e exatamente quando é necessário.

Mais tarde, você descobre que esta versão revisada pode ser útil em outro aplicativo. Você novamente pega esse fragmento, modifica-o levemente e o usa no terceiro círculo. Portanto, aumentando gradualmente a reprodutibilidade, você não apenas obtém o máximo benefício desse fragmento, mas também protege seu produto do código que não faz nada por ele e geralmente não é necessário nele.

O principal aqui é de nenhuma maneira tentar prever o futuro. A reprodutibilidade deve ser limitada aos limites de visibilidade atuais; no futuro, você corrigirá o código adequadamente sempre que surgir uma nova oportunidade para sua aplicação. Isso não apenas poupará tempo e esforço, mas também escreverá códigos mais econômicos, legais e modernos, aprimorados para reutilização.

Aqui estão algumas sugestões práticas sobre como tornar o código reutilizável.

Evitar duplicação


Como Lemony Sinquet disse corretamente: “Não repita. Primeiro, você se repete, depois diz a mesma coisa e, terceiro, todo mundo já ouviu isso. ”

Lembre-se, falamos sobre a reutilização que ocorre espontaneamente? É exatamente isso que (e somente isso) deve ser limitado ao objetivo do código ergonômico. Portanto, escreva o código que você precisa neste momento específico e continue no mesmo espírito até perceber que precisa resolver o mesmo problema repetidamente. Em seguida, faça a refatoração, coloque o código em algum local acessível e consulte-o conforme necessário. Agindo dessa maneira, você não obterá um código generalizado desnecessário, mas um código no qual não há duplicação.

De fato, o mesmo princípio é postulado pelo princípio DRY (não se repita), que afirma que a mesma lógica não deve ser escrita repetidamente no código - isso gera um dever técnico. Repetições sem sentido entopem o sistema, reduzem a qualidade da base de códigos e, além disso, transformam-na em um pesadelo para quem tem a responsabilidade de manter o código do produto. É importante lembrar: o princípio DRY é um tipo de filosofia que exige abandonar as ambições pessoais de programação e fazer o que é melhor para o projeto. Se alguém já fez algo, use-o. Não há necessidade de reinventar a roda.

Verifique se a classe / método / função é responsável por uma coisa.


Nesta ocasião, podemos lembrar a bela afirmação de Louis Sullivan: "A forma vem do destino". Na tradução, isso significa o seguinte: se uma função, classe ou método faz a única coisa, você as altera por apenas um motivo. Sim, com essa abordagem, você frequentemente precisará criar métodos que usarão outros métodos, mas eles permanecerão simples e não muito coerentes.

Cada sistema é construído por meio de uma linguagem orientada ao assunto, criada por programadores com o objetivo de descrever adequadamente esses sistemas. As funções cumprem o papel dos verbos nessas línguas e as classes desempenham o papel dos substantivos. Juntos, eles geralmente formam o nível básico de organização de qualquer idioma; consequentemente, se você os prescrever de uma maneira de qualidade, seu código será de alta qualidade.

Existem duas regras de ouro para criar funções e classes que podem ser aplicadas várias vezes, apenas duas:

  • Eles devem ser pequenos
  • Eles deveriam fazer uma coisa, e bem

Isso pressupõe que a função não deve crescer o suficiente para conter estruturas aninhadas. O nível de aninhamento, portanto, não deve exceder um ou dois. Graças a essa técnica, o código se torna mais fácil de ler, analisar e assimilar.

Além disso, é necessário garantir que todos os operadores em uma única função permaneçam no mesmo nível de abstração. A mistura de níveis é sempre confusa e, mais cedo ou mais tarde, levará a um trabalho árduo com o código. Programadores profissionais vêem o código reproduzível como um tipo de narrativa, não apenas um pedaço de texto. Eles usam os recursos da linguagem de programação escolhida para criar blocos mais expressivos, significativos e organizados que constroem perfeitamente a narrativa.

Não abuse da herança


Às vezes, nós, os desenvolvedores, tentamos olhar para o futuro distante do projeto e começamos a desempenhar funções adicionais com os pensamentos “e se você precisar” e “algum dia será útil”. Não faça isso. Até agora, isso não foi útil para você, agora você não precisa e, na maioria dos casos ... não será necessário (para parafrasear o conhecido princípio de YAGNI - Você não vai precisar dele). Este princípio se aplica à herança. Não o insira se não tiver plena confiança de que a implementação será repetida várias vezes.

Com tudo isso, a hereditariedade é uma ótima maneira de adicionar funcionalidade a uma classe. Mas os programadores tendem a ultrapassar os limites, construindo hierarquias de classe em seis ou mais níveis. A “Gangue dos Quatro” em seu livro “Design Patterns” descreve sucintamente os riscos de herança excessiva:

"Como a subclasse tem acesso aos detalhes de implementação da classe pai, costuma-se dizer que a herança viola o encapsulamento".

A hereditariedade leva a uma forte coesão dos componentes, porque a superclasse abre seu interior para as subclasses, e essas, por sua vez, são completamente dependentes da superclasse em tudo relacionado à operação correta. Nessa situação, a superclasse perde sua flexibilidade - torna-se difícil alterar qualquer coisa em sua funcionalidade. Por esse motivo, a hereditariedade é uma maneira ruim de obter a reutilização de código.

Uma abordagem mais razoável é pensar no paradigma da estrutura dos objetos, e não na hereditariedade. Isso permitirá que as pessoas que usam seu código obtenham mais facilmente exatamente a funcionalidade de que precisam e criem seus próprios objetos com base nas restrições que são relevantes para elas. Você deve até considerar criar interfaces procedurais que cada uma das classes possa implementar de sua própria maneira. As interfaces geralmente são mais fáceis de entender e implementar do que as classes com herança em várias camadas.

Para resumir, só se deve recorrer à hereditariedade se uma classe for uma continuação lógica de outra e a maior parte do código da classe herdada usar o código da superclasse. Em qualquer outro caso, basta assinar a sentença de morte e as chances do seu código de reutilização.

Em conclusão


Em geral, escrever código para reutilização não significa criar enormes blocos monolíticos generalizados. A chave para escrever código reproduzível está nos elementos que visam uma tarefa específica, que são facilmente montados, soldados bem e não muito firmemente interconectados.

E, finalmente, não use um uso repetido por si só - não vale a pena. É melhor definir uma meta para evitar duplicação, não para escrever fragmentos vazios e desnecessários, para garantir que o código seja fácil de ler e manter. Quando você desenvolve uma visão correta das coisas, a reprodutibilidade virá por si só.

Lembre-se sempre: a reutilização começa com o fato de você ter encontrado uma solução bem-sucedida para uma tarefa específica. Todo o resto deve fluir dessa premissa, e você tem o direito de escolher o método mais apropriado para trazer um determinado pedaço de código para um novo nível. Como Ralph Johnson observou, com razão: "Antes de pensar em reutilizar o código, você precisa garantir que pode usá-lo."

Source: https://habr.com/ru/post/pt481296/


All Articles