KISS: Uma Grande Herança do Unix

por Fabio A. Mazzarino

O acrônimo KISS tem várias traduções mas um único significado: “Keep It Simple Stupid”, “Keep It Simple, Soldier”, “Keep It Simple, Sir”, etc. O significado é um só: Mantenha a solução simples, foco na simplicidade. A linguagem C está intimamente ligada com esse conceito, assim como o Unix. Não é a primeira vez que falamos sobre a simplicidade, o assunto já foi abordado no post sobre As Bases da Filosofia Unix, mas dessa vez vamos explorar mais este assunto.

História do KISS

Tem gente que acha que a filosofia KISS nasceu junto com o Unix, e não é verdade. O termo surgiu na Lockheed Martin, dentro da divisão de projetos avançados, como uma forma de nortear o desenvolvimento de aeronaves que precisavam de maior confiabilidade, menor custo, e melhor reparabilidade em campo. Originalmente dizia simplesmente Keep It Simple Stupid, sem vírgula nem vocativo, indicando que os artefatos deveriam ser fáceis de reparar.

Passou então a ser utilizado pela Marinha e pela Aeronáutica norte-americana, popularizando ainda mais o termo.

Mas foi com o desenvolvimento do Unix e a linguagem C, nos anos 70 que o termo passou a fazer parte das práticas do desenvolvimento utilizadas na linguagem C. Ambos foram desenvolvidos tendo em mente essa premissa, o que se mostrou muito eficiente, já que 50 anos depois o Unix é base para grandes sistemas operacionais como MacOS, Linux e Android.

KISS na Linguagem C

Ambos desenvolvidos dentro da mesma empresa, a linguagem C e Unix, acabaram se influenciando mutualmente. Uma evidência dessa influência é a filosofia KISS que permeia tanto a filosofia do desenvolvimento Unix, como as implementações da linguagem C.

Com um pouco de experiência é visível a capacidade de simplificação do código na linguagem C, permitindo construções complexas com poucas linhas, e permitindo a geração de código com baixo consumo de memória e alta performance.

Mas a grande vantagem de se manter a simplicidade está na manutenção. Um código simples, focado em uma única funcionalidade, é muito mais barato de se manter, reduzindo o tempo de resposta a eventos, o tempo de desenvolvimento e principalmente reduzindo o custo.

strcpy()

strcpy é uma ótima forma de ilustrar como a simplicidade do código pode facilitar a manutenção e a performance.

char* strcpy(char *dest, const char *src) {
    if (src != NULL && dest != NULL) {
        for (int ct = 0; ct < strlen(src); ct++) {
            dest[ct] = src[ct];
        }
        dest[strlen(src)] = '\x0'
    }
    return dest;
}

Note como o código é muito próximo da descrição do algoritmo. Vamos fazer um código mais voltado para a simplicidade:

char* strcpy(char *dest, const char *src) {
    if (src || dest)
        while ((*dest++ = *src++));
    return dest;
}

O código simplificado é mais rápido, relativamente fácil de entender, basta conhecer alguns conceitos chaves da linguagem C, como operações lógicas, ponteiros e incrementos pré e pós-fixados. Vale notar que o nível de simplificação também depende da capacidade do time, como um todo, em utilizar sintaxe mais avançada, sob risco de incorrer em outros problemas de manutenção.

Projetos Maiores

Quando falamos de projetos maiores a simplicidade da solução como um todo serve para facilitar a manutenção, reduzindo o custo de correção de bugs, e facilitando a adição de novas funcionalidades. A seguir vou tentar listar algumas experiências próprias em que a falta de simplicidade acabava por trazer problemas na manutenção do código.

Dados Duplicados

Em determinado sistema era necessário gerir um conjunto de nós remotamente, através da rede, e dentro do sistema havia dois módulos que gerenciavam aspectos diferentes dos nós. Contrariando as recomendações cada módulo dentro do arquivo de configuração sua própria lista de nós. Os dados duplicados adicionavam uma complexidade desnecessária ao código, já que eram necessários diversos tipos de sincronizações entre as listas.

Consequência da complexidade. O desalinhamento entre as listas era fonte de várias falhas de regressão, e dificultava muito a curva de aprendizagem para novos desenvolvedores. Consequência: cada bug gerava uma cascata de gastos.

Arquivos Gigantes

Em um outro sistema havia poucos arquivos de código fonte com com tamanhos descomunais. Não havia uma política para modularizar a solução, nem para organizar os trechos de código, nem para evitar duplicidade de código. Por consequência havia muito código duplicado, além de existir funções enormes, dificultando também o entendimento dos algoritmos e regras de negócio.

Neste caso a complexidade faziam com que qualquer mudança que poderia ser pequena implicasse em uma alteração de código ampla e arriscada. O volume de testes unitários necessários eram volumosos, e por isso mesmo nem sempre efetuados, e as chances de uma falha de regressão era muito grande. A consequência era uma grande dificuldade de manter a estabilidade do código, e o volume de suporte era relativamente grande.

Adicionalmente código se torna cada vez mais extenso, fazendo com que a curva de aprendizagem para os novos programadores fosse muito longa. Somado com a dificuldade de entendimento dos algoritmos e regras de negócio trazia uma outra consequência: o conhecimento profundo do código acabava por se concentrar em poucas pessoas, criando um gargalo arriscado.

Conclusões

Manter a simplicidade do código não é simplesmente um preciosismo, é redução de custos, economia de dor de cabeça, redução de suporte e principalmente é maior satisfação do usuário. Investir em simplificar o desenvolvimento é sempre um ótimo investimento.

Leia Mais

Você pode ler mais sobre a simplicidade no livro de Eric S. Raymond: The Art of Unix Programming.