PROGRAMAÇÃO DE BAIXO PARA CIMA
OriginalJaneiro de 1993
(Esse ensaio é da introdução aOn Lisp.)
É um princípio de longa data do estilo de programação que os elementos funcionais de um programa não devem ser muito grandes. Se algum componente de um programa cresce além do estágio em que é prontamente compreensível, ele se torna uma massa de complexidade que oculta erros tão facilmente quanto uma grande cidade oculta fugitivos. Tal software será difícil de ler, difícil de testar e difícil de depurar.
De acordo com esse princípio, um programa grande deve ser dividido em partes, e quanto maior o programa, mais ele deve ser dividido. Como você divide um programa? A abordagem tradicional é chamada de design de cima para baixo: você diz "o propósito do programa é fazer essas sete coisas, então eu o divido em sete sub-rotinas principais. A primeira sub-rotina tem que fazer essas quatro coisas, então ela, por sua vez, terá quatro de suas próprias sub-rotinas," e assim por diante. Esse processo continua até que o programa inteiro tenha o nível certo de granularidade-- cada parte grande o suficiente para fazer algo substancial, mas pequena o suficiente para ser entendida como uma única unidade.
Programadores experientes de Lisp dividem seus programas de maneira diferente. Além do design de cima para baixo, eles seguem um princípio que poderia ser chamado de design de baixo para cima-- mudando a linguagem para se adequar ao problema. Em Lisp, você não apenas escreve seu programa em direção à linguagem, você também constrói a linguagem em direção ao seu programa. Enquanto você está escrevendo um programa, pode pensar "Eu gostaria que Lisp tivesse tal e qual operador." Então você vai e o escreve. Depois você percebe que usar o novo operador simplificaria o design de outra parte do programa, e assim por diante. A linguagem e o programa evoluem juntos. Como a fronteira entre dois estados em guerra, o limite entre a linguagem e o programa é desenhado e redesenhado, até que eventualmente ele se estabilize ao longo das montanhas e rios, as fronteiras naturais do seu problema. No final, seu programa parecerá como se a linguagem tivesse sido projetada para ele. E quando a linguagem e o programa se encaixam bem, você acaba com um código que é claro, pequeno e eficiente.
Vale a pena enfatizar que o design de baixo para cima não significa apenas escrever o mesmo programa em uma ordem diferente. Quando você trabalha de baixo para cima, geralmente acaba com um programa diferente. Em vez de um único programa monolítico, você obterá uma linguagem maior com operadores mais abstratos, e um programa menor escrito nela. Em vez de um lintel, você obterá um arco.
No código típico, uma vez que você abstrai as partes que são meramente de contabilidade, o que resta é muito mais curto; quanto mais você constrói a linguagem, menos distância você terá que percorrer de cima para baixo. Isso traz várias vantagens:
Ao fazer a linguagem fazer mais do trabalho, o design de baixo para cima produz programas que são menores e mais ágeis. Um programa mais curto não precisa ser dividido em tantos componentes, e menos componentes significam programas que são mais fáceis de ler ou modificar. Menos componentes também significam menos conexões entre componentes, e assim menos chance de erros ali. Assim como os designers industriais se esforçam para reduzir o número de partes móveis em uma máquina, programadores experientes de Lisp usam o design de baixo para cima para reduzir o tamanho e a complexidade de seus programas.
O design de baixo para cima promove a reutilização de código. Quando você escreve dois ou mais programas, muitas das utilidades que você escreveu para o primeiro programa também serão úteis nos seguintes. Uma vez que você adquiriu um grande substrato de utilidades, escrever um novo programa pode levar apenas uma fração do esforço que exigiria se você tivesse que começar com Lisp puro.
O design de baixo para cima torna os programas mais fáceis de ler.
Uma instância desse tipo de abstração pede ao leitor que entenda um operador de uso geral; uma instância de abstração funcional pede ao leitor que entenda uma sub-rotina de propósito específico. [1]
Porque isso faz com que você esteja sempre atento a padrões em seu código, trabalhar de baixo para cima ajuda a esclarecer suas ideias sobre o design do seu programa. Se dois componentes distantes de um programa forem semelhantes em forma, você será levado a notar a semelhança e talvez a redesenhar o programa de uma maneira mais simples.
O design de baixo para cima é possível até certo ponto em linguagens além de Lisp. Sempre que você vê funções de biblioteca, o design de baixo para cima está acontecendo. No entanto, Lisp lhe dá poderes muito mais amplos nesse departamento, e aumentar a linguagem desempenha um papel proporcionalmente maior no estilo Lisp-- tanto que Lisp não é apenas uma linguagem diferente, mas uma maneira completamente diferente de programar.
É verdade que esse estilo de desenvolvimento é mais adequado para programas que podem ser escritos por pequenos grupos. No entanto, ao mesmo tempo, ele estende os limites do que pode ser feito por um pequeno grupo. Em The Mythical Man-Month, Frederick Brooks propôs que a produtividade de um grupo de programadores não cresce linearmente com seu tamanho. À medida que o tamanho do grupo aumenta, a produtividade dos programadores individuais diminui. A experiência da programação em Lisp sugere uma maneira mais otimista de formular essa lei: à medida que o tamanho do grupo diminui, a produtividade dos programadores individuais aumenta. Um pequeno grupo vence, relativamente falando, simplesmente porque é menor. Quando um pequeno grupo também aproveita as técnicas que Lisp torna possíveis, ele pode vencer de forma decisiva.
Novo: Baixe On Lisp Grátis.
[1] "Mas ninguém pode ler o programa sem entender todas as suas novas utilidades." Para ver por que tais afirmações geralmente estão erradas, veja a Seção 4.8.