[Off-Topic] O Programador Humilde, por Edsger W. Dijkstra

2010 April 12, 08:49 h - tags: career principles off-topic

Depois de escrever meu artigo na Info, Fábrica de Software é uma Besteira, recebi um retweet com um link muito legal de um texto que eu não conhecia. The Humble Programmer.

Claro, o autor é super conhecido, o grande Edsger W. Dijkstra. Ele é mais conhecido pelo paper seminal A Case against the GO TO Statement. De qualquer forma o The Humble Programmer foi um discurso que ele deu ao receber o prêmio Alan Turing de 1972.

O texto é fantástico e deve ser lido na íntegra, mas resolvi retirar alguns trechos para comentar. O mais interessante é ler com o contexto do fim dos anos 60 em mente e como muito do que ele espera para o futuro é uma coisa que nós, 50 anos depois, ainda continuamos esperando. Não publiquei este texto na Info mesmo por dois motivos: primeiro porque é mais voltado a programadores, segundo porque este é um dos meus textos “tamanho Akita” :-)

Duas opiniões sobre programação vem desses dias. Eu os menciono agora, devo retornar a eles depois. Uma opinião era que um programador competente deveria ter mente voltada a quebra-cabeças e gostar muito de truques espertos; a outra opinião é que programação era nada mais do que otimizar a eficiência do processo computacional, em uma direção ou outra.

Infelizmente, a imagem do programador mudou, mas para dois extremos: temos os super-programadores, autores renomados, mas a profissão me si se tornou uma commodity, um bem de consumo farto e barato, justamente pelo que comentei no artigo sobre fábricas de software. O barateamento artificial de profissão está levando a um sucateamento e uma demora maior para pesquisas e evoluções na área, especialmente se contarmos que a competição para baixar o preço não vem a partir de aumentar a qualidade técnicas dos processos e tecnologias, mas principalmente de usar a globalização para levar a tarefa para áreas onde os recursos humanos são mais baratos, como Índia e China. Não quer dizer que todos da profissão sejam operários, os que cresceram sozinhos e evoluíram tem posições e tarefas respeitáveis, mas isso se deve mais ao esforço individual.

Essa última opinião era o resultado da circunstância frequente que, de fato, o equipamento disponível era dolorosamente lento, e nessa época se encontrava a expectativa ingênua que, assim que máquinas mais poderosas estivessem disponíveis, programação não seria mais um problema, e então o esforço de ir até os limites da máquina não seriam mais necessários e programação era basicamente isso, não era? Mas nas décadas seguintes uma coisa completamente diferente aconteceu: máquinas mais poderosas ficaram disponíveis. Mas em vez de nos encontrarmos num estado de perfeita harmonia com todos os problemas de programação resolvidos, nos encontramos até o pescoço na crise do software! Como pode?

Pelo menos hoje ninguém assume que só porque as máquinas serão melhores a programação será mais simples. Mas notem uma coisa que sempre repito: as pessoas acham que os problemas de software são coisas recentes, mas o termo “crise do software” foi cunhado ainda na década de 70 … e até hoje não foi resolvida.

A visão é que, muito antes dos anos 70 terminarem, devemos ser capazes de desenhar e implementar os tipos de sistemas que agora estão forçando nossa habilidades de programação, ao custo de somente uma pequena porcentagem de homens-anos que nos custam agora, e que além disso, esses sistemas serão virtualmente livre de bugs. Essas duas melhorias andam de mãos dadas. Nessa última questão software parece ser diferente de muitos outros produtos, onde como regra uma alta qualidade implica em alto preço. Aqueles que quiserem software confiável descobrirão que devem encontrar meios de evitar a maioria dos bugs para começo de conversa, e como resultado o processo de programação se tornará mais barato. Se quiser programadores mais efetivos, descobrirão que eles não devem desperdiçar tempo debugando, eles não devem introduzir bugs para começo de conversa. Em outras palavras: ambas os objetivos apontam para a mesma mudança.

“Programadores mais efetivos … não devem desperdiçar tempo debugando”, isso é uma conclusão que existe há pelo menos 5 décadas e ainda assim até hoje os programadores da atualidade – treinados em faculdades para atender “fábrica”, e portanto serem operários de ferramentas – tem ataques de histeria quando sua ferramenta não tem capacidades específicas para debugar!

“Aqueles que quiserem software confiável descobrirão que devem encontrar meios de evitar a maioria dos bugs.” Ou seja, a eficiência não vem de querer achar bugs o mais rápido possível mas evitar que eles sejam introduzidos em primeiro lugar. Sei que vai parecer bem pedante, mas nós temos técnicas para isso e a grande maioria dos programadores não as usa, sequer são ensinadas na faculdade. Procure por Extreme Programming. Para evitar que bugs sejam inseridos por descuido (não significa acabar com 100% dos bugs mas evitar a maioria) existem técnicas como Testar Primeiro, Programação em Par, Integração Contínua, Testes para evitar Bugs de Regressão, Testes de Aceitação. Enfim, existem diversas técnicas simples e eficientes que a grande maioria do mercado sequer tem consciência de sua existência.

Agora para as necessidades econômicas. Atualmente se encontra a opinião que nos anos 60 programação era uma profissão muito cara, e que nos anos seguintes salários de programadores devem cair. Normalmente essa opinião é expressada conectada com a recessão, mas poderia ser um sintoma de algo diferente e até saudável, de que talvez os programadores de décadas passadas não fizeram um bom trabalho como deveriam. A sociedade não está satisfeita com a performance dos programadores e seus produtos. Mas há outro fator de maior peso. Na situação presente é normal que para um sistema específico, o preço a ser pago pelo desenvolvimento de software seja da mesma ordem de magnitude do preço do hardware necessário, e a sociedade mais ou menos aceita isso. Mas fabricantes de hardware nos dizem que na próxima década os preços de hardware devem cair por um fator de 10. Se o desenvolvimento de software continuar com os mesmos processos desajeitados e caros como agora, as coisas devem ficar completamente fora de balanço. Você não pode esperar que a sociedade aceite isso, e portanto devemos aprender a programar com eficiência uma ordem de magnitude maior. Para colocar de outra forma: enquanto as máquinas eram os ítens mais caros no orçamento, a profissão de programação conseguia livrar sua cara com suas técnicas desajeitadas, mas esse guarda-chuva vai se fechar rapidamente.

E esse tem sido nosso desafio nas últimas décadas: como “baratear” a tarefa de programação. Porém isso pode ser levado para o lado errado. Um dos lados errados é baratear a mão de obra, basta pegar países mais pobres e que cobram menos. Outro lado é baratear a tecnologia. Isso funciona até um ponto de inflecção onde precisaríamos de um novo degrau de sofisticação mas não a teremos porque o barateamento cortou as pesquisas e inovações da área. O argumento todo é baseado em “como não tornar mais caro o que hoje já é caro” e para isso uma das formas é avançar a tecnologia para, por exemplo, demandar menos tarefas manuais que possam ser automatizadas. Até hoje ainda há “programadores” que perdem seu tempo abrindo as mesmas janelas e clicando nos mesmos botões “next, next, next” toda vez que precisa empacotar uma nova versão do software. Isso é automatizável, mas como o programador foi treinado para apenas seguir procedimentos, a maioria não se acha capaz de ser criativo e transformar um procedimento manual num script automatizado, por exemplo. É um caso onde o “barateamento” da mão de obra e de sua formação está impedindo o barateamento dos processos e o avanço da tecnologia. Isso era um problema nos anos 70, continua sendo no século XXI.

O argumento 3 é baseado na aproximação construtiva ao problema de programar corretamente. Hoje uma técnica comum é fazer um programa e depois testá-lo. Mas: teste de programa pode ser uma maneira muito efetiva de mostrar a presença de bugs, mas é totalmente inadequado para mostrar sua ausência. A única forma efetiva de aumentar o nível de confiança de um programa significativamente é dar uma prova convincente de sua correção. Mas então não se deve fazer o programa primeiro e depois provar sua correção, porque senão o requerimento de fornecer a prova somente aumentará a carga do pobre programador. Do contrário: o programador deve fazer a prova de correção e o programa crescerem de mãos dadas. O argumento 3 é essencialmente baseada na seguinte observação. Se o primeiro perguntar qual é a estrutura que uma prova convincente deve ter, tendo encontrado isso, então construir um programa que satisfaz os requerimentos da prova, então essa preocupação de correção se torna um guia heurístico muito efetivo.

Preciso admitir que o Dijkstra se refere a provas formais matemáticas, neste caso. Mas eu gostaria de expandir o conceito. O que ele diz é que o correto seria primeiro criar uma “prova” e depois implementar o código que supre os requerimentos dessa “prova”. Eu gostaria de dizer que Dijkstra praticamente foi pioneiro no conceito de “Test First” de Extreme Programming, também conhecido como TDD ou “Test Driven Development” onde o conceito é: 1) primeiro escreva um teste que descreve o requerimento; 2) agora implementamos o código que faz o teste falhar; 3) em seguida implementamos o restante que faz o teste passar; 4) vamos para o próximo requerimento. Dijkstra sabia há 50 anos que esta ordem de desenvolvimento é que minimiza o volume de bugs a posteriori – além de dezenas de outros benefícios que já descobrimos hoje.

O argumento 4 tem a vez com a maneira com que a quantidade de esforço intelectual necessário para desenhar um programa depende do tamanho do programa. Foi sugerido que existe algum tipo de lei da natureza nos dizendo que a quantidade de esforço intelectual necessário cresce com o quadrado do tamanho do programa. Mas, graças aos céus, ninguém conseguiu provar essa lei. E isso porque ela não precisa ser verdade. Todos sabemos que a única ferramenta mental que exige uma peça finita de raciocínio e pode cobrir diversos casos é chamada de “abstração”; como resultado a exploração efetiva de seus poderes de abstração devem ser consideras como uma das atividades mais vitais de um programador competente. Nesse sentido deve valer a pena apontar que o propósito de abstração não é ser vago, mas criar um novo nível semântico onde se pode ser absolutamente preciso. (…) Um resultado foi a identificação de vários padrões de abstração que tem um papel vital em todo o processo de composição dos programas. O suficiente já é conhecido sobre esses padrões de abstração para devotar uma aula sobre cada um deles.

Isso é mais complexo mas tem a ver com a capacidade de abstração do programador. Em si esse conceito é “abstrato” e difícil de definir. A primeira parte tem a ver com talento: uma pessoa que não tem talento para programação não será um programador e ponto final. Partindo dessa premissa, que existe a centelha do talento, agora são necessárias milhares de horas de prática, e eu me refiro a prática de código mesmo e não apenas repetindo procedimentos, mas experimentando as situações mais diferentes possíveis.

Só assim a intuição vai emergir da experiência possibilitando identificar padrões no código, oportunidades de refatoramentos e otimizações, criação de construções de mais alto nível para simplificar o programa e assim por diante. Esse caminho começa com o programador seguindo procedimentos, mas deve evoluir rapidamente para e experimentação. Isso é fundamental.

Como curiosidade, parte do que ele descreve é o que hoje conhecemos também como “Design Patterns”.

Agora para o quinto argumento. Tem a ver com a influência da ferramenta que estamos tentando usar contra nossos hábitos de pensamento. Eu observo uma tradição cultural, que em todas as probabilidades tem suas raízes na Renascença, de ignorar essa influência, de tomar a mente humana como um mestre supremo e autônomo de seus artefatos. Mas se eu começar a analisar os hábitos de pensamentos meus e de meus colegas humanos, eu chego, quer eu queira ou não, a uma conclusão completamente diferente, que as ferramentas que estamos tentando usar e a linguagem ou notação que usamos para expressar ou registrar nossos pensamentos, são os maiores fatores que determinam o que podemos pensar ou expressar! A análise dessa influência que linguagens de programação tem nos hábitos de pensamento de seus usuários, e o reconhecimento que, agora, poder cerebral é de longe o recurso mais escasso, juntos nos dão uma nova coleção de parâmetros para comparar méritos relativos de várias linguagens de programação. O programador competente é totalmente consciente do tamanho estritamente limitado de seu crânio; então ele aproxima da tarefa de programação com total humildade, e entre outras coisas ele evita truques espertos como se fosse a praga. (…) Outra lição que devemos aprender do passado recente é que o desenvolvimento de linguagens de programação “mais ricas” ou “mais poderosas” foi um erro no sentido de que essas mostruosidades barrocas, essas conglomerações de idiossincrasias, são realmente ingerenciáveis, ambas mecanicamente e mentalmente. Eu vejo um grande futuro para linguagens de programação muito sistemáticas e muito modestas.

Um bom programador reconhece suas limitações e busca ferramentas que melhor se adequem aos problemas. A maioria das guerras de linguagens começa com argumentos assim, mas o problema é que a insistência em se ter “apenas uma linguagem” e acumular em cima dela tudo que todos querem, a torna um monstro “barroco”, como Dijkstra coloca. Programadores – pessoas – tem cérebros limitados, e nós precisamos conseguir nos expressar em forma de código. Quanto mais complicada a ferramenta, mais da mente é gasta para manter as peças na cabeça e menos em criar código elegante.

Veja o próprio Dijkstra, até os anos 70, ele literalmente viu a criação dos computadores, programou em praticamente tudo, desde linguagem de máquina, até Fortran, Lisp, Algol. Se naquela época ele poderia conhecer a fundo múltiplas linguagens, eu não vejo desculpa para hoje, com todos os recursos extras que temos, não sabermos uma ordem de magnitude mais linguagens e tecnologias e técnicas.

Ele menciona linguagens mais “modestas” e eu diria que isso são nossas atuais linguagens dinâmicas de alto nível como Ruby ou Python. Abstrações que permitem sistemas ainda maiores com menos complexidade.

Para complementar quero colocar um aviso a aqueles que identificam a dificuldade da tarefa de programação com a briga contra as inadequações de nossas ferramentas atuais, porque eles podem concluir que, uma vez que nossas ferramentas se tornem mais adequadas, programação não será um problema. Programação continuará sendo muito difícil, porque uma vez que nos livrarmos dos desajeitos circunstanciais, nos encontraremos livres para lidar com problemas que agora estão muito além da nossa capacidade de programação.

E desde a década de 70 sabemos que não existe bala de prata, não é uma nova ferramenta que vai simplesmente tornar a tarefa de programar magicamente ordens de magnitude mais eficientes. Não existe almoço de graça.

Isso já nos ensinou algumas lições, e a que eu escolhi estressar nesta palestra é o seguinte. Nós devemos fazer um trabalho de programação melhor, dado que nos aproximemos da tarefa com total apreciação por sua tremenda dificuldade, dado que nos seguremos a linguagens de programação modestas e elegantes, dado que nós respeitemos as limitações intrínsecas da mente humana e aproximemos da tarefa como Programadores Muito Humildes.

Programadores precisam ser Humildes no sentido correto da palavra: em assumir suas próprias limitações e criar novas técnicas, tecnologias e maneiras de executar o mesmo trabalho com mais qualidade, mais eficiência, quebrando as regras e tradições e criando novos padrões. Programadores que seguem apenas o que foi ensinado, apenas os procedimentos, são arrogantes porque acham que tudo que já poderia ter sido descoberto já foi.

Eu sempre repito que um bom programador é burro e preguiçoso. Burro porque se ele se achar inteligente vai achar também que já sabe tudo, e se já sabe tudo para que pesquisar mais? E preguiçoso porque um programador esforçado demais vai seguir o mesmo procedimento todos os dias, com muito afinco, já um preguiçoso vai se cansar de fazer isso e vai criar uma forma automatizada para fazer o mesmo trabalho e sobrar mais tempo para ele descansar.

Acho que o Dijkstra concordaria com essa colocação ;-)

Comments

comentários deste blog disponibilizados por Disqus