Skip to main content

Command Palette

Search for a command to run...

[Repost] Código limpo precisa também ser simples

Published
6 min read
[Repost] Código limpo precisa também ser simples

Este é um repost do meu extinto Medium, como pretendo abordar o tema novamente, vale a pena trazer este registro como contexto para o Zé de alguns anos atrás.

Muitas vezes definimos que “A qualidade é atingida quando os requisitos são cumpridos”, e essa é uma boa definição, porém, não parece ser o suficiente para descrever um bom projeto, dado que os requisitos podem ser falhos ou levar a mais interpretações do que apenas o que parece óbvio. Buscando mais profundamente a definição do que significa um bom projeto de engenharia, é possível encontrar um denominador comum entre os melhores, a simplicidade.

A simplicidade está presente em coisas icônicas que vemos hoje, como o volkswagen w30, o projeto inicial do que conhecemos hoje como fusca, como a caneta esferográfica da bic e a sub metralhadora ak-47, entre outros tantos projetos, muitos deles não tendo atingido todos os requisitos, no entanto obtendo sucesso, não necessariamente pela simplicidade, mais também por ela.

Já que a simplicidade parece estar tão intrinsecamente ligada a qualidade de um projeto, devemos buscar a definição da simplicidade, e no dicionário encontramos:

substantivo feminino

. ausência de complicação.

.qualidade do que é simples, do que não é composto.

Isso não nos ajudou muito. Buscando na teoria dos sistemas, de acordo com Verônica Macário de Oliveira e José de Arimatéia Dias Valadão em Entre a simplificação e a complexidade, a heterogeneidade: Teoria Ator-Rede e uma nova epistemologia para os estudos organizacionais, “ … a complexidade de um sistema não está ligada apenas a quantidade de elementos que o mesmo possui, mas também a forma como eles se relacionam…”, fazendo um paralelo com desenvolvimento de software podemos notar que quanto mais tecnologias, bibliotecas, serviços e demais coisas usamos em nossos projetos mais complexos eles ficam, e de acordo com o citado não devemos apenas nos preocupar com a quantidade de coisas em nossos projetos, mas também com a forma como esses itens se relacionam no nosso sistema. Posto isso chegamos a uma boa ideia do que é simplicidade, mas ainda precisamos saber como podemos usa-la a nosso favor, para melhorarmos nossos projetos e o nosso código de forma geral, vamos descobrir isso.

Um excelente principio que tem como base a simplicidade é o KISS (Keep it simple stupid). Esse acrônimo foi desenvolvido por Kelly Johnson, engenheiro da Lockheed Martin, a empresa responsável por projetos como sr-71 e o U-2(não a banda), o principio se baseia em tornar as coisas simples levando em conta a manutenção e as ferramentas necessárias para executa-la, quanto menos melhor.

Trazendo esse principio para a qualidade de software devemos citar outros princípios como DRY (don’t repeat yourself) cujo o objetivo é evitar repetições no próprio código, criando classes e métodos apropriados, e como o principio Rule of least power que podemos traduzir como regra do menor poder, consiste em escolher a linguagem menos poderosa apropriada para a finalidade do que desenvolveremos, originalmente proposto como um axioma para um bom design esse principio é uma extensão do KISS, escolhendo linguagens mais “simples” temos uma manutenção mais simples, e a simplicidade aqui não está ligada a quantidade de trabalho ou código, mas a quantidade de itens em nosso sistema, e a quantidade de interações que cada item precisa fazer dentro do projeto. Obviamente nos dias de hoje não é possível não utilizar frameworks e bibliotecas, porém, é necessário ser mais criterioso sobre a necessidade de se utilizar aquilo que estamos queremos utilizar, e ter conhecimento sobre a complexidade que estamos adicionando em nosso sistema.

Uma outra forma de tornar o seu código mais simples, além da implementação dos princípios citados, é aumentar a concisão com que escrevemos nosso código. Concisão consiste em remover redundâncias (DRY) mas também em expressar uma ideia com um numero reduzido de sentenças, focando no que é essencial para que ela seja compreendida. Um exemplo simples em código é:

talk(text: string){
  const human = new Human()
  human.talk(text);
  // do another stuffs
}

Isso poderia ser reescrito desta forma

talk(text: string){
  (new Human()).talk(text);
  // do another stuffs
}

Se a variável human não seria mais utilizada no código, ela não precisa existir, porém, vale lembrar que, isso é apenas um exemplo não uma regra, pois isso implicaria em outros problemas de design, e também que ser conciso não significa diminuir a legibilidade do código.

Um outro exemplo de como simplicidade faz a diferença, dado os seguintes requisitos:
Uma função que receba um array numérico, separe os pares e retorne-os em um outro array.

Parece bastante simples, no entanto, se entregarmos esse código para qualquer desenvolvedor utilizando quase qualquer linguagem de programação, podemos esperar alguns dos seguintes códigos como retorno:

const separeteEven = (numbers) => {
    const evens = []
    for(const number of numbers){
        if (number % 2 === 0) {
            evens.push(number)
        }
    }
    return evens
}

Esse é um código que poderia ser esperado pela maior parte dos usuários de outras linguagens além de javascript, se não fosse a atribuição de uma arrow function a uma constante.

Este outro também podemos considerar uma implementação comum dentro da maior parte das linguagens

function separeteEven(numbers) {
    const evens = []
    let count = 0
    while (numbers.length > count) {
        if (numbers[count] % 2 === 0) {
            evens.push(numbers[count])
        }
        count++;
    }
    return evens
}

Esta é uma outra implementação possível

const separeteEven = (numbers) => numbers.filter((number) => {if(number % 2 === 0) return number});

E ainda com uma variação

const separeteEven = (numbers) => numbers.filter((number) => number % 2 === 0? number : false);

Se olharmos para essas quatro implementações, todas tem um código relativamente limpo, as nomenclaturas estão explicativas, a função tem apenas uma responsabilidade, porém, dado um escopo bem definido é relativamente simples construir um código limpo. O ponto aqui não é qual destas implementações é mais correta, mais performática, ou menor. A real discussão proposta vai também, além da pura simplicidade, dado que em uma implementação tão simples em requisitos a simplicidade torna-se muito relativa. A argumentação verdadeiramente focada na simplicidade é, porque temos tantas formas de se implementar um requisito simples, isso não é produtivo, é claro que a função map por exemplo, tem a finalidade de que o programador não precise implementar um for que é mais custoso para digitar, no entanto segundo o livro Aprendendo a programar utilizando python 3 “Programação é raciocínio, passamos a maior parte do tempo pensando, e a outra parte que na verdade é a menor delas, digitando …”, essa afirmação coloca em cheque a existência de recursos como esse na linguagem e, por consequência, o uso deles em seus projetos.

Isso não é uma exclusividade do javascript, podemos ter tantas implementações quanto as apresentadas, em python por exemplo. É claro que estas são características da linguagem e não temos, ao menos de imediato, como deixar as linguagens que usamos menores, e mais simples, então, o que podemos fazer para tornar nosso código mais simples? Ai entra o code style, ele pode fazer muito para manter a simplicidade, seja escolhendo açucares sintáticos como map ou sempre utilizando for, não importa, o importante é definir e utilizar apenas um para a finalidade definida, a final “se existe mais de uma maneira de fazer algo, tem algo errado”.

Vale sempre lembrar, os códigos aqui são apenas exemplos e não regras, e vale também lembrar que a simplicidade deve atender os requisitos do projeto, do contrário só vai trazer complexidades.