Simples x Complexo

Airton Gessner
mercos-engineering
Published in
8 min readOct 25, 2019

Simples, complexo, fácil e difícil, são palavras frequentes no ambiente de desenvolvimento de software. Se você é desenvolvedor e ainda não ouviu a famosa frase: "Isso é fácil, é só um botão", sinta-se privilegiado, já que essa afirmação é extremamente comum. Mas você já parou pra pensar o porquê ela é dita com tanta frequência? O que realmente significam os termos fácil e difícil? Qual a relação deles com simples e complexo? Como essas definições impactam no trabalho de um desenvolvedor? Essas são algumas perguntas que pretendo responder nesse post.

Essa reflexão começou há algum tempo aqui na Mercos, quando tivemos um dev-talks do Rafael Amadigi Dal Santo sobre Simplicidade. Apenas um parênteses, dev-talks é um evento semanal onde alguém do time de engenharia compartilha alguma metodologia, tecnologia ou outra coisa que ache interessante com todo o time. Voltando, foi em um dev-talks que começamos a discutir a filosofia “simples” e a partir dela chegamos a algumas conclusões e exemplos que respondem as perguntas iniciais.

A filosofia

Pra começar, precisamos definir o que significa cada palavra. Pra isso, vamos voltar a frase do botão, comparando ela com outra frase:

  • “Isso é fácil, é só um botão.”
  • “Isso é simples, é só um botão.”

Analisando as duas sentenças, poderíamos concluir que elas significam a mesma coisa, certo?

Utilizar simples e fácil como sinônimos é algo muito comum, mas por definição elas não são e nada melhor do que o dicionário para confirmar. Então, vamos lá. Começando por fácil:

  • Algo que se executa sem dificuldade.

Já que fácil é o contrário de difícil, então, difícil é:

  • Algo que exige esforço pra ser feito, trabalhoso.

Agora podemos concluir que fácil é algo que não exige esforço pra ser feito. Aqui entra tanto o esforço físico, quanto o esforço mental. É importante lembrar também que o esforço é relativo. Dirigir um carro de Fórmula 1, é algo que, presumo, ser quase impossível pra mim. Já para um piloto, é o seu dia-a-dia. Agora, programar uma função que soma dois números, seria fácil pra mim, já pra um piloto que não conhece programação, seria muito mais difícil.

Continuando com as definições, temos o simples:

  • Algo que é feito de um elemento básico, que não se compõe de partes ou substâncias diferentes.

Feito de um elemento básico vs que não exige esforço pra ser feito. Olhando assim, parece que estamos comparando maçãs com laranjas, certo? Pois é, estamos! A palavra simples está ligada a um elemento, enquanto fácil, está relacionado a um trabalho ou esforço, que pode ser para criar, utilizar ou alterar esse elemento.

E concluindo essa etapa, temos o complexo:

  • Algo composto de numerosos elementos interligados ou que funcionam como um todo.

A partir das definições, vamos partir para um exemplo prático. Considere a seguinte imagem:

Diagram BPMN (https://theartfulmodeller.com/2015/11/09/fixing-a-look-at-me-diagram/)

Podemos considerar esse diagrama como complexo, certo? Pois é uma construção composta por diversos elementos interligados que funcionam como um todo. Agora, pensando no trabalho para entender ou ainda, alterar esse diagrama, acredito que pra maioria das pessoas (desse planeta) seria difícil e é nesse momento que os conceitos de fácil, difícil, simples e complexo começam a se relacionar.

Elementos complexos tendem a ser difíceis de entender, utilizar, etc. Já elementos simples são o oposto, eles tendem a ser fáceis. Porém, muitas vezes é difícil (ou quase impossível) fugir da complexidade, ela é natural. Então, ao invés de evitar a complexidade, podemos criar camadas que a ocultem. Assim, ao invés de expor o diagrama, podemos, por exemplo, criar um botão que executa todo o fluxo e esconde a complexidade, deixando-a restrita a quem criou o botão.

Elemento simples que oculta complexidade

Com isso respondemos a pergunta do porquê muitas pessoas dizem que criar um botão é fácil. Muito provavelmente, elas não conhecem a complexidade que está atrás desse elemento e assumem que algo simples é fácil de criar.

Voltando para as duas frases iniciais, podemos concluir que:

  • “Isso é fácil, é só um botão.” — É relativo, fácil pra que? Pra criar, pra utilizar? Fácil pra quem?
  • “Isso é simples, é só um botão.” — Nesse caso a afirmação é correta. Um botão é simples porque é composto de um elemento básico e isso não muda.

Steve Jobs, deu a seguinte declaração em uma entrevista:

O simples pode ser mais difícil do que o complexo: é preciso trabalhar duro para limpar seus pensamentos de forma a torná-los simples. Mas no final vale a pena, porque, quando chegamos lá, podemos mover montanhas.

Cá entre nós, podemos concordar que ele e a Apple seguiram essa ideia, já que uma das grandes características dos seus produtos é essa: a facilidade de utilizar.

Mas nós, como seres humanos, somos obcecados por facilidade, está no nosso DNA. Por isso é importante que, ao invés de buscarmos a facilidade durante o processo de criação de um elemento ou produto, devemos buscar a simplicidade do produto final.

Assim como Jobs falou, é muito mais fácil criar complexidade do que simplicidade, mas quando conseguimos o nosso trabalho está feito. Quando criamos algo complexo, ele sempre será mais difícil de entender e utilizar do que algo simples. Por isso, por mais difícil que possa ser, precisamos nos esforçar para criar simplicidade.

Na vida real

Esses conceitos são universais e podem ser aplicados em diferentes áreas do conhecimento. Uma dessas áreas é o desenvolvimento de software e para entender como eles se manifestam, precisamos definir qual o produto do nosso trabalho. Quando falamos em produto do trabalho de um desenvolvedor de software, é comum pensarmos apenas no software utilizado pelo nosso cliente, ou, mais precisamente, na interface da aplicação, esquecendo da outra parte que é tão importante quanto: o código.

O produto "código" também é de extremo valor para uma empresa que produz produtos de software, já que ele é utilizado diariamente pela equipe de engenharia, seja para correção de bugs ou liberação de novas features. Assim, é importante deixar o código simples como um botão e não complexo como um grande diagrama.

E como atingimos isso? Já adianto que não existe bala de prata, uma única solução que resolva tudo, mas existem algumas regras que podemos seguir. Vou apresentar algumas delas aqui de forma resumida.

A primeira é relacionada a nomes. Considere a seguinte função:

Analisando essa função, fica difícil de saber ao que ela se propõe, certo? O nome da função, obter_retorno, não significa nada em termos de negócio, apenas que não é uma função void. Já dentro da função, criamos uma lista retorno e filtramos cada elemento da variável lista recebida por parâmetro, verificando se o elemento na posição 0 é igual a 4. Sem saber o contexto de onde essa função é utilizada, fica muito difícil de entendê-la.

Agora, temos outra versão da mesma função, utilizando nomes mais significativos:

Ao invés de obter_retrono, temos obter_celulas_selecionadas e ao invés de lista, temos tabuleiro. Então, lendo apenas a assinatura da função, já sabemos que ela obtém as células selecionadas de um tabuleiro. Além disso, os enums também adicionam maior clareza, já que são representados por palavras ao invés de apenas valores. Nesse caso, o código não fica mais simples, já que o número de elementos aumenta, mas ainda assim fica mais fácil de entender.

O próximo exemplo é relacionado ao tamanho dos métodos.

O conceito de função grande é relativo e, se você já trabalhou com desenvolvimento, é bem provável que já viu funções muito maiores que essa. Algumas literaturas que sugerem um número máximo de linhas em torno de 20 ou ainda que você não precise usar o scroll para visualizá-la por completo. Minha opinião: quanto menos elementos, mais simples a função e é essa a regra que tento seguir. Para reduzir o escopo da função, podemos dividir o código em funções menores. Assim, o exemplo anterior pode ser representado por:

Além da função salvar_pedido ficar mais "agradável aos olhos", as novas funções seguem o Single Responsability Principle, ou seja, fazem apenas uma coisa. Outro ganho, é o que chamamos de código em prosa. Código em prosa é aquele código que conta uma história. Nessa função, essa história começa ao validar_pedido, passa por calcular_total e por fim persitir_pedido, dando foco ao "o que" é feito e não "como" é feito. Aqui o código fica mais simples, já que o número de elementos da função principal é reduzido.

Outra causa de complexidade que estava presente no exemplo anterior é a duplicidade de código. As duas validações de data, no início da função, são basicamente a mesma, então ao invés de repetir a implementação, podemos ter uma função validar_data.

Alguns outros exemplos que podemos citar:

  • Estado mutável: quando você tem uma variável e não tem controle sobre quem pode alterar seu valor ou quando ele pode ser alterado, fica mais difícil entender o fluxo de execução do software, já que você precisa mapear todos os lugares que interagem com ela. Sugestão: Evite a mutabilidade sempre que possível.
  • Falta de testes automatizados: Além de garantir que o software faz o que foi proposto, os testes são uma ótima fonte de documentação pois descrevem os cenários que a função atende. Mesmo com o custo de tornar o code base mais complexo, já que o número de elementos aumenta, os ganhos gerados pelos testes compensam.
  • Idioma do código: esse ponto pode ser polêmico mas, na minha experiência pessoal, um código escrito no idioma que é falado dentro da empresa, torna o desenvolvimento do software muito mais fácil. Quando o código é escrito em outro idioma, os termos de negócio tendem a não estar totalmente traduzidos, ou ainda, essas traduções nem existem.
  • Volume de código: mais código, mais elementos, mais complexidade. Evite código duplicado e também código morto. Deixar o código ali por "medo" de apagar é sintoma de algum outro problema no software, como falta de testes automatizados ou o não uso de um versionador de código.

Além desses exemplos, existem inúmeros outros que poderiam ser listados aqui, mas essa não é a ideia. Já existe uma literatura muito rica em termos de qualidade de software que trata desses pontos.

A ideia principal desse artigo é mostrar que simples, complexo, fácil e difícil são palavras frequentes, mas que muitas vezes não damos a devida atenção aos seus significados. Programar um software que funcione e que a máquina entenda é relativamente fácil, enquanto programar um software que funcione e que outras pessoas entendam, nem tanto.

Criando um código simples, ele tende a ser fácil para a maioria das pessoas entenderem e isso pode reduzir o tempo e custo do desenvolvimento de forma drástica a longo prazo. Infelizmente, eu desconheço uma fórmula matemática que calcule essa economia e acredito que esse é o motivo de ser tão difícil convencer muitos gestores sobre os benefícios da qualidade de código. O que temos, são inúmeros exemplos na internet de códigos que quebraram em produção, gerando verdadeiras catástrofes. Um código que busca a simplicidade e a facilidade, pode ser uma arma contra esse tipo de catástrofe. Então, se você ainda não parou pra pensar nisso, comece agora, antes que o seu software morra no espaço.

--

--