Loading...

SER POPULAR

Original

Maio de 2001

(Este artigo foi escrito como uma espécie de plano de negócios para uma nova linguagem. Então está faltando (porque se dá por certo) o recurso mais importante de uma boa linguagem de programação: abstrações muito poderosas.)

Um amigo meu uma vez contou a um eminente especialista em sistemas operacionais que ele queria projetar uma linguagem de programação realmente boa. O especialista disse a ele que seria um desperdício de tempo, que as linguagens de programação não se tornam populares ou impopulares com base em seus méritos, e portanto, não importa o quão boa fosse sua linguagem, ninguém a usaria. Pelo menos, foi o que havia acontecido com a linguagem que ele havia projetado.

O que torna uma linguagem popular? As linguagens populares merecem sua popularidade? Vale a pena tentar definir uma boa linguagem de programação? Como você faria isso?

Acho que as respostas para essas perguntas podem ser encontradas olhando para os hackers e aprendendo o que eles querem. Linguagens de programação são para hackers, e uma linguagem de programação é boa como linguagem de programação (em vez de, digamos, um exercício em semântica denotacional ou design de compilador) se e somente se os hackers gostarem dela.

1 A Mecânica da Popularidade

É verdade, certamente, que a maioria das pessoas não escolhe linguagens de programação simplesmente com base em seus méritos. A maioria dos programadores é informada sobre qual linguagem usar por outra pessoa. E ainda assim, acho que o efeito de tais fatores externos sobre a popularidade das linguagens de programação não é tão grande quanto às vezes se pensa. Acho que um problema maior é que a ideia de um hacker sobre uma boa linguagem de programação não é a mesma que a da maioria dos projetistas de linguagens.

Entre os dois, a opinião do hacker é a que importa. Linguagens de programação não são teoremas. São ferramentas, projetadas para as pessoas, e elas têm que ser projetadas para se adequar às forças e fraquezas humanas tanto quanto os sapatos têm que ser projetados para os pés humanos. Se um sapato aperta quando você o coloca, é um sapato ruim, por mais elegante que possa ser como peça de escultura.

Pode ser que a maioria dos programadores não consiga distinguir uma boa linguagem de uma ruim. Mas isso não é diferente com qualquer outra ferramenta. Isso não significa que seja perda de tempo tentar projetar uma boa linguagem. Hackers especialistas conseguem identificar uma boa linguagem quando a veem, e eles a usarão. Hackers especialistas são uma minoria minúscula, admitidamente, mas essa minúscula minoria escreve todo o bom software, e sua influência é tal que o restante dos programadores tenderá a usar qualquer linguagem que eles usem. Muitas vezes, de fato, não é meramente influência, mas comando: muitas vezes, os hackers especialistas são os próprios que, como seus chefes ou orientadores acadêmicos, dizem aos outros programadores qual linguagem usar.

A opinião de hackers especialistas não é a única força que determina a relativa popularidade das linguagens de programação - software legado (Cobol) e hype (Ada, Java) também desempenham um papel -, mas acho que é a força mais poderosa a longo prazo. Dada uma massa crítica inicial e tempo suficiente, uma linguagem de programação provavelmente se torna tão popular quanto merece ser. E a popularidade separa ainda mais as boas linguagens das ruins, porque o feedback de usuários reais sempre leva a melhorias. Olhe para o quanto qualquer linguagem popular mudou durante sua vida. Perl e Fortran são casos extremos, mas até mesmo o Lisp mudou muito. O Lisp 1.5 não tinha macros, por exemplo; estes evoluíram mais tarde, depois que os hackers do MIT haviam passado um par de anos usando o Lisp para escrever programas reais. [1]

Portanto, quer uma linguagem tenha que ser boa para ser popular ou não, acho que uma linguagem tem que ser popular para ser boa. E ela tem que permanecer popular para continuar boa. O estado da arte em linguagens de programação não fica parado. E, no entanto, os Lisps que temos hoje ainda são basicamente o que eles tinham no MIT em meados da década de 1980, porque essa é a última vez que o Lisp teve uma base de usuários suficientemente grande e exigente.

Claro, os hackers precisam conhecer um idioma antes de poderem usá-lo. Como eles vão ouvir sobre ele? De outros hackers. Mas tem que haver um grupo inicial de hackers usando o idioma para que outros sequer ouçam sobre ele. Eu me pergunto o quão grande esse grupo precisa ser; quantos usuários formam uma massa crítica? De cabeça, eu diria vinte. Se um idioma tivesse vinte usuários separados, significando vinte usuários que decidiram por conta própria usá-lo, eu o consideraria real.

Chegar lá não pode ser fácil. Eu não ficaria surpreso se fosse mais difícil ir de zero a vinte do que de vinte a mil. A melhor maneira de obter esses vinte usuários iniciais provavelmente é usar um cavalo de Troia: dar às pessoas um aplicativo que elas querem, que por acaso foi escrito na nova linguagem.

2 Fatores Externos

Vamos começar reconhecendo um fator externo que de fato afeta a popularidade de uma linguagem de programação. Para se tornar popular, uma linguagem de programação precisa ser a linguagem de script de um sistema popular. Fortran e Cobol eram as linguagens de script de mainframes IBM iniciais. C era a linguagem de script do Unix e, posteriormente, também o Perl. Tcl é a linguagem de script do Tk. Java e JavaScript são destinados a ser as linguagens de script dos navegadores da web.

Lisp não é uma linguagem extremamente popular porque não é a linguagem de script de um sistema extremamente popular. A popularidade que ela ainda mantém remonta aos anos 1960 e 1970, quando era a linguagem de script do MIT. Muitos dos grandes programadores da época estavam associados ao MIT em algum momento. E no início dos anos 1970, antes do C, o dialeto do Lisp do MIT, chamado de MacLisp, era uma das únicas linguagens de programação que um hacker sério queria usar.

Hoje, o Lisp é a linguagem de script de dois sistemas moderadamente populares, o Emacs e o AutoCAD, e por esse motivo, suspeito que a maior parte da programação em Lisp feita hoje é feita em Emacs Lisp ou AutoLisp.

As linguagens de programação não existem isoladamente. Hackear é um verbo transitivo - os hackers geralmente estão hackeando algo - e, na prática, as linguagens são julgadas em relação ao que elas são usadas para hackear. Então, se você quiser projetar uma linguagem popular, você precisa fornecer mais do que uma linguagem ou projetar sua linguagem para substituir a linguagem de script de algum sistema existente.

O Common Lisp é impopular em parte porque é um órfão. Originalmente, ele veio com um sistema para hackear: a Lisp Machine. Mas as Lisp Machines (junto com os computadores paralelos) foram atropeladas pelo aumento do poder dos processadores de uso geral na década de 1980. O Common Lisp poderia ter permanecido popular se tivesse sido uma boa linguagem de script para o Unix. Infelizmente, é uma linguagem terrivelmente ruim para isso.

Uma maneira de descrever essa situação é dizer que uma linguagem não é julgada por seus próprios méritos. Outra visão é que uma linguagem de programação realmente não é uma linguagem de programação a menos que também seja a linguagem de script de algo. Isso só parece injusto se for uma surpresa. Acho que não é mais injusto do que esperar que uma linguagem de programação tenha, digamos, uma implementação. É apenas parte do que uma linguagem de programação é.

Uma linguagem de programação precisa de uma boa implementação, é claro, e essa implementação deve ser gratuita. As empresas pagarão por software, mas os hackers individuais não, e são os hackers que você precisa atrair.

Uma linguagem também precisa ter um livro sobre ela. O livro deve ser curto, bem escrito e cheio de bons exemplos. K&R é o ideal aqui. No momento, eu diria quase que uma linguagem precisa ter um livro publicado pela O'Reilly. Isso está se tornando o teste de importância para os hackers.

Deve haver também documentação on-line. De fato, o livro pode começar como documentação on-line. Mas acho que os livros físicos ainda não estão obsoletos. Seu formato é conveniente, e a censura de fato imposta pelas editoras é um filtro útil, embora imperfeito. As livrarias são um dos lugares mais importantes para aprender sobre novas linguagens.

3 Brevidade

Dado que você pode fornecer as três coisas de que qualquer linguagem precisa - uma implementação gratuita, um livro e algo para hackear -, como você cria uma linguagem que os hackers vão gostar?

Uma coisa que os hackers gostam é a brevidade. Hackers são preguiçosos, da mesma forma que matemáticos e arquitetos modernistas são preguiçosos: eles odeiam qualquer coisa extrânea. Não seria longe da verdade dizer que um hacker prestes a escrever um programa decide que linguagem usar, pelo menos subconscientemente, com base no número total de caracteres que ele terá que digitar. Se isso não é precisamente como os hackers pensam, um designer de linguagem faria bem em agir como se fosse.

É um erro tentar agradar o usuário com expressões prolixas que pretendem se assemelhar ao inglês. O Cobol é notório por esse defeito. Um hacker consideraria ser solicitado a escrever

adicionar x a y dando z

em vez de

z = x+y

algo entre um insulto à sua inteligência e um pecado contra Deus.

Às vezes, tem-se dito que o Lisp deveria usar first e rest em vez de car e cdr, porque tornaria os programas mais fáceis de ler. Talvez pelas primeiras duas horas. Mas um hacker pode aprender rapidamente o suficiente que car significa o primeiro elemento de uma lista e cdr significa o resto. Usar first e rest significa 50% mais digitação. E eles também têm comprimentos diferentes, o que significa que os argumentos não se alinharão quando forem chamados, como car e cdr muitas vezes são, em linhas sucessivas. Descobri que importa muito como o código se alinha na página. Mal consigo ler código Lisp quando ele é definido em uma fonte de largura variável, e amigos dizem que isso é verdade para outras linguagens também.

A brevidade é um lugar onde as linguagens fortemente tipadas perdem. Todas as outras coisas sendo iguais, ninguém quer começar um programa com uma série de declarações. Qualquer coisa que possa ser implícita, deve ser.

Os tokens individuais também devem ser curtos. O Perl e o Common Lisp ocupam polos opostos nesta questão. Os programas Perl podem ser quase criptograficamente densos, enquanto os nomes dos operadores internos do Common Lisp são comicamente longos. Os designers do Common Lisp provavelmente esperavam que os usuários tivessem editores de texto que digitariam esses nomes longos por eles. Mas o custo de um nome longo não é apenas o custo de digitá-lo. Há também o custo de lê-lo e o custo do espaço que ele ocupa na sua tela.

4 Hackabilidade

Há uma coisa mais importante do que a brevidade para um hacker: poder fazer o que você quer. Na história das linguagens de programação, uma surpreendente quantidade de esforço foi dedicada a impedir que os programadores façam coisas consideradas impróprias. Este é um plano perigosamente presunçoso. Como o designer da linguagem pode saber o que o programador precisará fazer? Acho que os designers de linguagem fariam melhor em considerar seu usuário-alvo como um gênio que precisará fazer coisas que eles nunca anteciparam, em vez de um atrapalhado que precisa ser protegido de si mesmo. O atrapalhado vai se atirar no pé de qualquer maneira. Você pode salvá-lo de se referir a variáveis em outro pacote, mas não pode salvá-lo de escrever um programa mal projetado para resolver o problema errado e levar uma eternidade para fazê-lo.

Bons programadores muitas vezes querem fazer coisas perigosas e pouco atraentes. Por pouco atraente, quero dizer coisas que vão por trás de qualquer fachada semântica que a linguagem está tentando apresentar: obter a representação interna de alguma abstração de alto nível, por exemplo. Os hackers gostam de hackear e hackear significa entrar nas coisas e adivinhar o designer original.

Deixe-se ser adivinhado. Quando você cria qualquer ferramenta, as pessoas a usam de maneiras que você não pretendia, e isso é especialmente verdadeiro de uma ferramenta altamente articulada como uma linguagem de programação. Muitos hackers vão querer modificar seu modelo semântico de uma maneira que você nunca imaginou. Eu digo, deixe-os; dê ao programador acesso ao máximo de conteúdo interno que você puder sem colocar em risco os sistemas de tempo de execução, como o coletor de lixo.

No Common Lisp, muitas vezes quis iterar pelos campos de uma struct - para remover referências a um objeto excluído, por exemplo, ou encontrar campos que não foram inicializados. Eu sei que as structs são apenas vetores por baixo. E ainda assim, não posso escrever uma função de uso geral que eu possa chamar em qualquer struct. Só posso acessar os campos pelo nome, porque é isso que uma struct é supostamente significar.

Um hacker pode querer subverter o modelo pretendido das coisas apenas uma ou duas vezes em um programa grande. Mas que diferença faz poder fazê-lo. E pode ser mais do que uma questão de apenas resolver um problema. Há também um tipo de prazer nisso. Hackers compartilham o prazer secreto do cirurgião em mexer em entranhas nojentas, o prazer secreto do adolescente em estourar espinhas. [2] Para os meninos, pelo menos, certos tipos de horrores são fascinantes. A revista Maxim publica um volume anual de fotografias, contendo uma mistura de pin-ups e acidentes horríveis. Eles conhecem seu público.

Historicamente, o Lisp tem sido bom em deixar os hackers fazerem o que quiserem. A correção política do Common Lisp é uma aberração. Os primeiros Lisps permitiam que você colocasse as mãos em tudo. Felizmente, muito desse espírito é preservado em macros. Que coisa maravilhosa poder fazer transformações arbitrárias no código-fonte.

As macros clássicas são uma ferramenta real de hacker - simples, poderosa e perigosa. É tão fácil entender o que elas fazem: você chama uma função nos argumentos da macro e o que quer que ela retorne é inserido no lugar da chamada da macro. As macros higiênicas incorporam o princípio oposto. Elas tentam me proteger de entender o que elas estão fazendo. Nunca ouvi macros higiênicas explicadas em uma frase. E elas são um exemplo clássico dos perigos de decidir o que os programadores têm permissão para querer. As macros higiênicas se destinam a me proteger da captura de variáveis, entre outras coisas, mas a captura de variáveis é exatamente o que eu quero em algumas macros.

Uma linguagem realmente boa deve ser limpa e suja: com design limpo, com um pequeno núcleo de operadores bem compreendidos e altamente ortogonais, mas suja no sentido de que permite que os hackers façam o que quiserem com ela. C é assim. Também eram os primeiros Lisps. Uma linguagem real de hacker sempre terá um caráter um pouco boêmio.

Uma boa linguagem de programação deve ter recursos que façam o tipo de pessoas que usam a frase "engenharia de software" sacudir a cabeça com desaprovação. No outro extremo do continuum estão linguagens como Ada e Pascal, modelos de propriedade que são boas para ensinar e pouco mais.

5 Programas Descartáveis

Para ser atraente para os hackers, uma linguagem deve ser boa para escrever os tipos de programas que eles querem escrever. E isso significa, talvez surpreendentemente, que ela tem que ser boa para escrever programas descartáveis.

Um programa descartável é um programa que você escreve rapidamente para alguma tarefa limitada: um programa para automatizar alguma tarefa de administração do sistema, ou gerar dados de teste para uma simulação, ou converter dados de um formato para outro. O surpreendente sobre os programas descartáveis é que, como os edifícios "temporários" construídos em tantas universidades americanas durante a Segunda Guerra Mundial, eles muitas vezes não são descartados. Muitos evoluem para programas reais, com recursos reais e usuários reais.

Eu tenho a impressão de que os melhores programas grandes começam a vida dessa maneira, em vez de serem projetados grandes desde o início, como a Barragem de Hoover. É aterrorizante construir algo grande do zero. Quando as pessoas assumem um projeto que é grande demais, ficam sobrecarregadas. O projeto ou fica atolado, ou o resultado é estéril e rígido: um shopping center em vez de um centro da cidade de verdade, Brasília em vez de Roma, Ada em vez de C.

Outra maneira de obter um programa grande é começar com um programa descartável e continuar melhorando-o. Essa abordagem é menos intimidante, e o design do programa se beneficia da evolução. Eu acho que, se olharmos, descobriríamos que essa é a maneira como a maioria dos grandes programas foram desenvolvidos. E aqueles que evoluíram dessa forma provavelmente ainda estão escritos na linguagem em que foram escritos pela primeira vez, porque é raro um programa ser portado, exceto por razões políticas. E, portanto, paradoxalmente, se você quiser criar uma linguagem que seja usada para sistemas grandes, você tem que torná-la boa para escrever programas descartáveis, porque é daí que vêm os sistemas grandes.

O Perl é um exemplo marcante dessa ideia. Ele não apenas foi projetado para escrever programas descartáveis, mas era praticamente um programa descartável em si. O Perl começou a vida como uma coleção de utilitários para gerar relatórios e só evoluiu para uma linguagem de programação à medida que os programas descartáveis que as pessoas escreviam nele ficavam maiores. Só foi a partir do Perl 5 (se tanto) que a linguagem era adequada para escrever programas sérios, e no entanto já era massivamente popular.

O que torna uma linguagem boa para programas descartáveis? Para começar, ela deve estar prontamente disponível. Um programa descartável é algo que você espera escrever em uma hora. Então a linguagem provavelmente deve já estar instalada no computador que você está usando. Não pode ser algo que você tenha que instalar antes de usá-lo. Ela tem que estar lá. O C estava lá porque veio com o sistema operacional. O Perl estava lá porque originalmente era uma ferramenta para administradores de sistemas, e o seu já o havia instalado.

Estar disponível significa mais do que estar instalado, no entanto. Uma linguagem interativa, com uma interface de linha de comando, está mais disponível do que uma que você tem que compilar e executar separadamente. Uma linguagem de programação popular deve ser interativa e iniciar rapidamente.

Outra coisa que você quer em um programa descartável é a brevidade. A brevidade sempre é atraente para os hackers, e nunca mais do que em um programa que eles esperam produzir em uma hora.

6 Bibliotecas

Claro, o máximo em brevidade é ter o programa já escrito para você e apenas chamá-lo. E isso nos leva ao que eu acho que será uma característica cada vez mais importante das linguagens de programação: as funções de biblioteca. O Perl vence porque tem grandes bibliotecas para manipular strings. Essa classe de funções de biblioteca é especialmente importante para programas descartáveis, que muitas vezes são originalmente escritos para converter ou extrair dados. Muitos programas em Perl provavelmente começam apenas como um par de chamadas de biblioteca juntas.

Acho que muitos dos avanços que acontecerão nas linguagens de programação nos próximos cinquenta anos terão a ver com as funções de biblioteca. Acho que as linguagens de programação futuras terão bibliotecas tão cuidadosamente projetadas quanto a linguagem principal. O design de linguagens de programação não será sobre se você deve tornar sua linguagem fortemente ou fracamente tipada, orientada a objetos, funcional ou o que for, mas sobre como projetar ótimas bibliotecas. O tipo de projetistas de linguagens que gosta de pensar em como projetar sistemas de tipos pode estremecer com isso. É quase como escrever aplicativos! Que pena. As linguagens são para os programadores, e as bibliotecas são o que os programadores precisam.

É difícil projetar boas bibliotecas. Não se trata simplesmente de escrever muito código. Assim que as bibliotecas ficarem muito grandes, às vezes pode demorar mais para encontrar a função de que você precisa do que para escrever o código você mesmo. As bibliotecas precisam ser projetadas usando um pequeno conjunto de operadores ortogonais, assim como a linguagem principal. Deve ser possível para o programador adivinhar qual chamada de biblioteca fará o que ele precisa.

As bibliotecas são um ponto fraco do Common Lisp. Existem apenas bibliotecas rudimentares para manipular strings e quase nenhuma para se comunicar com o sistema operacional. Por razões históricas, o Common Lisp tenta fingir que o sistema operacional não existe. E porque você não pode se comunicar com o sistema operacional, é improvável que você possa escrever um programa sério usando apenas os operadores internos do Common Lisp. Você precisa usar alguns truques específicos da implementação também, e na prática esses tendem a não lhe dar tudo o que você quer. Os hackers pensariam muito mais bem do Lisp se o Common Lisp tivesse poderosas bibliotecas de strings e bom suporte ao sistema operacional.

7 Sintaxe

Será que uma linguagem com a sintaxe do Lisp, ou mais precisamente, a falta de sintaxe, algum dia se tornaria popular? Eu não sei a resposta para essa pergunta. Acho que a sintaxe não é a principal razão pela qual o Lisp não é atualmente popular. O Common Lisp tem problemas piores do que a sintaxe pouco familiar. Conheço vários programadores que se sentem à vontade com a sintaxe prefixada e, no entanto, usam o Perl por padrão, porque ele tem poderosas bibliotecas de strings e pode se comunicar com o sistema operacional.

Existem dois possíveis problemas com a notação prefixada: que ela é pouco familiar para os programadores e que não é suficientemente densa. A sabedoria convencional no mundo do Lisp é que o primeiro problema é o real. Não tenho tanta certeza. Sim, a notação prefixada faz os programadores comuns entrarem em pânico. Mas acho que a opinião dos programadores comuns não importa. As linguagens se tornam populares ou impopulares com base no que os hackers especialistas pensam delas, e acho que os hackers especialistas podem lidar com a notação prefixada. A sintaxe do Perl pode ser bastante incompreensível, mas isso não impediu a popularidade do Perl. Se algo, pode ter ajudado a criar um culto do Perl.

Um problema mais sério é a difusão da notação prefixada. Para os hackers especialistas, esse realmente é um problema. Ninguém quer escrever (aref a x y) quando poderia escrever a[x,y].

[1]

Neste caso particular, há uma maneira de nos esquivarmos do problema. Se tratarmos as estruturas de dados como se fossem funções em índices, poderíamos escrever (a x y) em vez disso, o que é ainda mais curto do que a forma Perl. Truques semelhantes podem encurtar outros tipos de expressões.

Podemos nos livrar de (ou tornar opcional) muitos parênteses tornando a indentação significativa. É assim que os programadores leem o código de qualquer maneira: quando a indentação diz uma coisa e os delimitadores dizem outra, seguimos a indentação. Tratar a indentação como significativa também eliminaria essa fonte comum de bugs, além de tornar os programas mais curtos.

Às vezes, a sintaxe infixada é mais fácil de ler. Isso é especialmente verdadeiro para expressões matemáticas. Usei o Lisp durante toda a minha vida de programação e ainda não acho as expressões matemáticas de prefixo naturais. E no entanto é conveniente, especialmente quando você está gerando código, ter operadores que aceitem qualquer número de argumentos. Então, se tivermos sintaxe infixada, provavelmente deve ser implementada como uma espécie de macro de leitura.

Não acho que devamos ser religiosamente opostos a introduzir sintaxe no Lisp, desde que ela se traduza de uma maneira bem compreendida em s-expressions subjacentes. Já existe uma boa dose de sintaxe no Lisp. Não é necessariamente ruim introduzir mais, desde que ninguém seja forçado a usá-la. No Common Lisp, alguns delimitadores são reservados para a linguagem, sugerindo que pelo menos alguns dos designers pretendiam ter mais sintaxe no futuro.

Uma das peças de sintaxe mais flagrantemente não-lispianas no Common Lisp ocorre em strings de formato; o formato é uma linguagem por si só, e essa linguagem não é o Lisp. Se houvesse um plano para introduzir mais sintaxe no Lisp, os especificadores de formato poderiam ser incluídos nele. Seria uma boa coisa se os macros pudessem gerar especificadores de formato da mesma maneira que geram qualquer outro tipo de código.

Um eminente hacker do Lisp me disse que sua cópia do CLTL se abre na seção de formato. A minha também. Isso provavelmente indica espaço para melhorias. Também pode significar que os programas fazem muita E/S.

8 Eficiência

Todo mundo sabe que uma boa linguagem deve gerar código rápido. Mas na prática, não acho que o código rápido venha principalmente de coisas que você faz no design da linguagem. Como Knuth apontou há muito tempo, a velocidade só importa em alguns gargalos críticos. E como muitos programadores observaram desde então, muitas vezes nos enganamos sobre onde estão esses gargalos.

Portanto, na prática, a maneira de obter código rápido é ter um profiler muito bom, em vez de, digamos, tornar a linguagem fortemente tipada. Você não precisa conhecer o tipo de cada argumento em cada chamada no programa. Você precisa ser capaz de declarar os tipos de argumentos nos gargalos. E ainda mais, você precisa ser capaz de descobrir onde estão os gargalos.

Uma reclamação que as pessoas tiveram com o Lisp é que é difícil saber o que é caro. Isso pode ser verdade. Também pode ser inevitável, se você quiser ter uma linguagem muito abstrata. E de qualquer maneira, acho que um bom profiler resolveria muito o problema: você logo aprenderia o que era caro.

Parte do problema aqui é social. Os designers de linguagem gostam de escrever compiladores rápidos. É assim que eles medem sua habilidade. Eles veem o profiler como um complemento, na melhor das hipóteses. Mas na prática, um bom profiler pode fazer mais para melhorar a velocidade dos programas reais escritos na linguagem do que um compilador que gera código rápido. Aqui, novamente, os designers de linguagem estão um pouco desconectados de seus usuários. Eles fazem um ótimo trabalho resolvendo ligeiramente o problema errado.

Pode ser uma boa ideia ter um profiler ativo - empurrar os dados de desempenho para o programador em vez de esperar que ele venha perguntar por eles. Por exemplo, o editor poderia exibir os gargalos em vermelho quando o programador editar o código-fonte. Outra abordagem seria de alguma forma representar o que está acontecendo nos programas em execução. Isso seria um grande ganho especialmente em aplicativos baseados em servidor, onde você tem muitos programas em execução para observar. Um profiler ativo poderia mostrar graficamente o que está acontecendo na memória à medida que um programa está sendo executado, ou até mesmo fazer sons que indiquem o que está acontecendo.

O som é um bom sinal de problemas. Em um lugar em que trabalhei, tínhamos um grande painel de mostradores que exibiam o que estava acontecendo com nossos servidores web. Os ponteiros eram movidos por pequenos servomotores que faziam um leve ruído quando giravam. Eu não conseguia ver o painel da minha mesa, mas descobri que podia dizer imediatamente, pelo som, quando havia um problema com um servidor.

Talvez seja possível até mesmo escrever um analisador de desempenho que detectaria automaticamente algoritmos ineficientes. Não me surpreenderia se certos padrões de acesso à memória se revelassem sinais inequívocos de algoritmos ruins. Se houvesse um pequeno homem correndo dentro do computeiro executando nossos programas, ele provavelmente teria uma história tão longa e lamentável para contar sobre seu trabalho quanto um funcionário do governo federal. Muitas vezes tenho a sensação de que estou enviando o processador em muitas caçadas infrutíferas, mas nunca tive uma boa maneira de ver o que ele está fazendo.

Vários Lisps agora compilam em código de bytes, que é então executado por um interpretador. Isso geralmente é feito para facilitar a portabilidade da implementação, mas poderia ser um recurso útil da linguagem. Pode ser uma boa ideia tornar o código de bytes uma parte oficial da linguagem e permitir que os programadores usem código de bytes embutido em gargalos. Então, tais otimizações também seriam portáveis.

A natureza da velocidade, conforme percebida pelo usuário final, pode estar mudando. Com o aumento de aplicativos baseados em servidor, cada vez mais programas podem se revelar limitados por E/S. Vale a pena tornar a E/S rápida. A linguagem pode ajudar com medidas simples e diretas, como funções de saída formatada simples e rápidas, e também com mudanças estruturais profundas, como cache e objetos persistentes.

Os usuários se interessam pelo tempo de resposta. Mas outro tipo de eficiência será cada vez mais importante: o número de usuários simultâneos que você pode suportar por processador. Muitos dos aplicativos interessantes escritos no futuro próximo serão baseados em servidor, e o número de usuários por servidor é a questão crítica para qualquer um que hospede tais aplicativos. No custo de capital de um negócio que oferece um aplicativo baseado em servidor, esse é o divisor.

Por anos, a eficiência não importou muito na maioria dos aplicativos de usuário final. Os desenvolvedores puderam assumir que cada usuário teria um processador cada vez mais poderoso em sua mesa. E pela Lei de Parkinson, o software se expandiu para usar os recursos disponíveis. Isso vai mudar com os aplicativos baseados em servidor. Nesse mundo, o hardware e o software serão fornecidos juntos. Para as empresas que oferecem aplicativos baseados em servidor, fará uma grande diferença no resultado final quantos usuários elas podem suportar por servidor.

Em alguns aplicativos, o processador será o fator limitante, e a velocidade de execução será a coisa mais importante a otimizar. Mas muitas vezes a memória será o limite; o número de usuários simultâneos será determinado pela quantidade de memória necessária para os dados de cada usuário. A linguagem também pode ajudar aqui. Um bom suporte para threads permitirá que todos os usuários compartilhem um único heap. Também pode ajudar ter objetos persistentes e/ou suporte de nível de linguagem para carregamento lento.

9 Tempo

O último ingrediente de que uma linguagem popular precisa é o tempo. Ninguém quer escrever programas em uma linguagem que possa desaparecer, como tantas outras linguagens de programação. Portanto, a maioria dos hackers tenderá a esperar até que uma linguagem tenha existido por alguns anos antes mesmo de considerar usá-la.

Os inventores de coisas maravilhosas novas muitas vezes ficam surpresos ao descobrir isso, mas você precisa de tempo para transmitir qualquer mensagem às pessoas. Um amigo meu raramente faz algo na primeira vez que alguém pede. Ele sabe que as pessoas às vezes pedem coisas que, no final, não querem. Para evitar perder seu tempo, ele espera até a terceira ou quarta vez que lhe pedem algo; nessa altura, quem quer que esteja pedindo a ele provavelmente já estará bastante irritado, mas pelo menos eles provavelmente realmente querem o que quer que estejam pedindo.

A maioria das pessoas aprendeu a fazer um tipo de filtragem semelhante sobre coisas novas que ouvem. Eles nem começam a prestar atenção até ouvirem sobre algo dez vezes. Eles estão perfeitamente justificados: a maioria dos novos "whatevers" quentes acaba se revelando um desperdício de tempo e eventualmente desaparece. Ao adiar o aprendizado do VRML, evitei ter que aprendê-lo.

Então, qualquer pessoa que inventa algo novo tem que esperar repetir sua mensagem por anos antes que as pessoas comecem a entendê-la. Escrevemos o que, até onde eu sei, foi o primeiro aplicativo baseado em servidor web, e levou anos para convencer as pessoas de que não precisava ser baixado. Não era que eles fossem estúpidos. Eles simplesmente nos ignoraram.

A boa notícia é que a simples repetição resolve o problema. Tudo o que você precisa fazer é continuar contando sua história, e eventualmente as pessoas começarão a ouvir. Não é quando as pessoas notam que você está lá que elas prestam atenção; é quando elas notam que você ainda está lá.

É bom que geralmente leve um tempo para ganhar momentum. A maioria das tecnologias evolui bastante mesmo depois de serem lançadas pela primeira vez - especialmente as linguagens de programação. Nada poderia ser melhor, para uma nova tecnologia, do que alguns anos sendo usada apenas por um pequeno número de adotantes iniciais. Os adotantes iniciais são sofisticados e exigentes, e rapidamente eliminam quaisquer defeitos que ainda existam em sua tecnologia. Quando você tem apenas alguns usuários, você pode estar em contato próximo com todos eles. E os adotantes iniciais são compreensivos quando você melhora seu sistema, mesmo que isso cause alguma quebra.

Existem duas maneiras pelas quais a nova tecnologia é introduzida: o método de crescimento orgânico e o método de grande impacto. O método de crescimento orgânico é exemplificado pela clássica startup de garagem subfinanciada. Um par de caras, trabalhando no anonimato, desenvolvem uma nova tecnologia. Eles a lançam sem marketing e inicialmente têm apenas alguns usuários (fanáticos). Eles continuam a melhorar a tecnologia e, enquanto isso, sua base de usuários cresce por meio do boca a boca. Antes que eles percebam, eles se tornaram grandes.

A outra abordagem, o método de grande impacto, é exemplificada pela startup apoiada por VC, com forte marketing. Eles se apressam em desenvolver um produto, lançá-lo com grande publicidade e, imediatamente (esperam), ter uma grande base de usuários.

Geralmente, os caras da garagem invejam os caras do grande impacto. Os caras do grande impacto são suaves e confiantes e respeitados pelos VCs. Eles podem pagar o melhor de tudo, e a campanha de relações públicas em torno do lançamento tem o efeito colateral de transformá-los em celebridades. Os caras de crescimento orgânico, sentados em sua garagem, sentem-se pobres e desamados. E, no entanto, acho que eles muitas vezes se enganam ao se sentirem com pena de si mesmos. O crescimento orgânico parece render melhores tecnologias e fundadores mais ricos do que o método de grande impacto. Se você olhar para as tecnologias dominantes hoje, você descobrirá que a maioria delas cresceu organicamente.

Esse padrão não se aplica apenas a empresas. Você o vê também na pesquisa patrocinada. Multics e Common Lisp foram projetos de grande impacto, e Unix e MacLisp foram projetos de crescimento orgânico.

10 Redesign

"A melhor escrita é a reescrita", escreveu E. B. White. Todo bom escritor sabe disso, e isso é verdade também para o software. A parte mais importante do design é o redesign. As linguagens de programação, especialmente, não são redesenhadas o suficiente.

Para escrever um bom software, você deve manter simultaneamente duas ideias opostas em sua cabeça. Você precisa da fé ingênua do jovem hacker em suas habilidades e, ao mesmo tempo, do ceticismo do veterano. Você tem que ser capaz de pensar o quão difícil pode ser? com metade de seu cérebro, enquanto pensa isso nunca vai funcionar com a outra.

O truque é perceber que não há realmente contradição aqui. Você quer ser otimista e cético sobre duas coisas diferentes. Você tem que ser otimista sobre a possibilidade de resolver o problema, mas cético sobre o valor de qualquer solução que você tenha até agora.

As pessoas que fazem um bom trabalho muitas vezes pensam que o que elas estão trabalhando não presta. Outros veem o que eles fizeram e ficam cheios de admiração, mas o criador está cheio de preocupação. Esse padrão não é coincidência: é a preocupação que tornou o trabalho bom.

Se você conseguir manter o equilíbrio entre esperança e preocupação, eles impulsionarão um projeto da mesma forma que suas duas pernas impulsionam uma bicicleta para a frente. Na primeira fase do motor de inovação de dois ciclos, você trabalha furiosamente em algum problema, inspirado pela confiança de que será capaz de resolvê-lo. Na segunda fase, você olha para o que fez à luz fria da manhã e vê todos os seus defeitos muito claramente. Mas desde que seu espírito crítico não supere sua esperança, você será capaz de olhar para seu sistema admitidamente incompleto e pensar: "Quão difícil pode ser chegar ao resto do caminho?", dando continuidade ao ciclo.

É delicado manter os dois elementos equilibrados. Em hackers jovens, o otimismo predomina. Eles produzem algo, estão convencidos de que é ótimo e nunca o melhoram. Em hackers mais velhos, o ceticismo predomina e eles nem mesmo ousam se envolver em projetos ambiciosos.

Qualquer coisa que você possa fazer para manter o ciclo de redesign em andamento é boa. A prosa pode ser reescrita repetidamente até que você fique satisfeito com ela. Mas o software, como regra, não é redesenhado o suficiente. A prosa tem leitores, mas o software tem usuários. Se um escritor reescrever um ensaio, as pessoas que leram a versão antiga dificilmente reclamarão que seus pensamentos foram quebrados por alguma incompatibilidade recém-introduzida.

Os usuários são uma faca de dois gumes. Eles podem ajudá-lo a melhorar sua linguagem, mas também podem desencorajá-lo de melhorá-la. Então, escolha seus usuários com cuidado e seja lento para aumentar seu número. Ter usuários é como otimização: o curso sábio é adiá-la. Além disso, como regra geral, você pode a qualquer momento mudar mais do que pensa. Introduzir mudanças é como tirar um curativo: a dor é uma memória quase tão logo você a sinta.

Todos sabem que não é uma boa ideia ter uma linguagem projetada por um comitê. Os comitês produzem design ruim. Mas acho que o pior perigo dos comitês é que eles interferem no redesign. É tanto trabalho introduzir mudanças que ninguém quer se incomodar. O que um comitê decide tende a permanecer dessa forma, mesmo que a maioria dos membros não goste.

Até mesmo um comitê de dois pessoas atrapalha o redesign. Isso acontece particularmente nas interfaces entre pedaços de software escritos por duas pessoas diferentes. Para mudar a interface, ambos têm que concordar em mudá-la ao mesmo tempo. E assim as interfaces tendem a não mudar, o que é um problema porque elas tendem a ser uma das partes mais ad hoc de qualquer sistema.

Uma solução aqui pode ser projetar sistemas de forma que as interfaces sejam horizontais em vez de verticais - de modo que os módulos sejam sempre estratos verticais de abstração. Então a interface tenderá a ser de propriedade de um deles. O nível inferior de dois níveis será ou uma linguagem na qual o superior é escrito, caso em que o nível inferior possuirá a interface, ou será um escravo, caso em que a interface poderá ser ditada pelo nível superior.

11 Lisp

Tudo isso implica que há esperança para um novo Lisp. Há esperança para qualquer linguagem que dê aos hackers o que eles querem, incluindo o Lisp. Acho que cometemos um erro ao pensar que os hackers são repelidos pela estranheza do Lisp. Essa ilusão reconfortante pode ter nos impedido de ver o problema real com o Lisp, ou pelo menos com o Common Lisp, que é que ele é ruim para fazer o que os hackers querem fazer. A linguagem de um hacker precisa de bibliotecas poderosas e algo para hackear. O Common Lisp não tem nenhum dos dois. A linguagem de um hacker é concisa e hackável. O Common Lisp não é.

A boa notícia é que não é o Lisp que é ruim, mas o Common Lisp. Se pudermos desenvolver um novo Lisp que seja uma linguagem de verdade para hackers, acho que os hackers o usarão. Eles usarão qualquer linguagem que faça o trabalho. Tudo o que temos que fazer é garantir que esse novo Lisp faça algum trabalho importante melhor do que outras linguagens.

A história oferece algum encorajamento. Com o tempo, as novas linguagens de programação sucessivas têm adotado cada vez mais recursos do Lisp. Não há mais muito a copiar antes que a linguagem que você criou seja o Lisp. A última linguagem na moda, o Python, é um Lisp aguado com sintaxe infixa e sem macros. Um novo Lisp seria um passo natural nessa progressão.

Às vezes, penso que seria uma boa jogada de marketing chamar isso de uma versão melhorada do Python. Isso soa mais moderno do que Lisp. Para muitas pessoas, Lisp é uma linguagem de IA lenta com muitos parênteses. A biografia oficial de Fritz Kunze evita cuidadosamente mencionar a palavra L. Mas meu palpite é que não devemos ter medo de chamar o novo Lisp de Lisp. Lisp ainda tem muito respeito latente entre os melhores hackers - aqueles que fizeram o 6.001 e entenderam, por exemplo. E esses são os usuários que você precisa conquistar.

Em "Como se Tornar um Hacker", Eric Raymond descreve o Lisp como algo semelhante ao latim ou grego - uma linguagem que você deve aprender como um exercício intelectual, mesmo que você não a use muito.

O Lisp vale a pena ser aprendido pela profunda experiência de iluminação que você terá quando finalmente o entender; essa experiência o tornará um programador melhor pelo resto de seus dias, mesmo que você nunca use muito o próprio Lisp.

Se eu não conhecesse o Lisp, ler isso me faria fazer perguntas. Uma linguagem que me tornaria um programador melhor, se isso significa algo, significa uma linguagem que seria melhor para programação. E essa é, de fato, a implicação do que Eric está dizendo.

Desde que essa ideia ainda esteja flutuando, acho que os hackers serão receptivos o suficiente a um novo Lisp, mesmo que seja chamado de Lisp. Mas esse Lisp deve ser uma linguagem de hacker, como os Lisps clássicos dos anos 1970. Deve ser conciso, simples e hackável. E deve ter bibliotecas poderosas para fazer o que os hackers querem fazer agora.

Na questão das bibliotecas, acho que há espaço para superar linguagens como Perl e Python em seu próprio jogo. Muitos dos novos aplicativos que precisarão ser escritos nos próximos anos serão aplicativos baseados em servidor. Não há razão para que um novo Lisp não tenha bibliotecas de strings tão boas quanto o Perl, e se esse novo Lisp também tiver bibliotecas poderosas para aplicativos baseados em servidor, ele poderia ser muito popular. Hackers de verdade não virarão o nariz para uma nova ferramenta que lhes permitirá resolver problemas difíceis com algumas chamadas de biblioteca. Lembre-se, os hackers são preguiçosos.

Poderia ser uma vitória ainda maior ter suporte central da linguagem para aplicativos baseados em servidor. Por exemplo, suporte explícito para programas com vários usuários ou propriedade de dados no nível de tags de tipo.

Os aplicativos baseados em servidor também nos dão a resposta para a pergunta de o que esse novo Lisp será usado para hackear. Não prejudicaria tornar o Lisp melhor como uma linguagem de script para Unix. (Seria difícil deixá-lo pior.) Mas acho que existem áreas em que as linguagens existentes seriam mais fáceis de superar. Acho que pode ser melhor seguir o modelo do Tcl e fornecer o Lisp junto com um sistema completo para dar suporte a aplicativos baseados em servidor. O Lisp é um ajuste natural para aplicativos baseados em servidor. Fechamentos léxicos fornecem uma maneira de obter o efeito de subrotinas quando a interface do usuário é apenas uma série de páginas da web. As s-expressions se encaixam bem no HTML, e as macros são boas para gerá-lo. Precisam existir melhores ferramentas para escrever aplicativos baseados em servidor, e precisa haver um novo Lisp, e os dois funcionariam muito bem juntos.

12 A Linguagem dos Sonhos

A título de resumo, vamos tentar descrever a linguagem dos sonhos do hacker. A linguagem dos sonhos é bonita, limpa e concisa. Ela tem um toplevel interativo que inicia rapidamente. Você pode escrever programas para resolver problemas comuns com muito pouco código. Quase todo o código em qualquer programa que você escreve é código específico para seu aplicativo. O resto já foi feito por você.

A sintaxe da linguagem é breve até a falha. Você nunca precisa digitar um caractere desnecessário, ou mesmo usar muito a tecla shift.

Usando grandes abstrações, você pode escrever a primeira versão de um programa muito rapidamente. Mais tarde, quando você quiser otimizar, há um profiler realmente bom que lhe diz onde focar sua atenção. Você pode tornar os loops internos cegantemente rápidos, até mesmo escrevendo byte code inline, se precisar.

Existem muitos bons exemplos para aprender, e a linguagem é intuitiva o suficiente para que você possa aprender a usá-la a partir de exemplos em alguns minutos. Você não precisa consultar o manual com muita frequência. O manual é curto e tem poucos avisos e qualificações.

A linguagem tem um núcleo pequeno e bibliotecas poderosas e altamente ortogonais que são tão cuidadosamente projetadas quanto a linguagem central. As bibliotecas funcionam bem juntas; tudo na linguagem se encaixa como as peças de uma câmera fina. Nada é preterido ou retido por compatibilidade. O código-fonte de todas as bibliotecas está prontamente disponível. É fácil conversar com o sistema operacional e com aplicativos escritos em outras linguagens.

A linguagem é construída em camadas. As abstrações de alto nível são construídas de uma maneira muito transparente a partir de abstrações de nível mais baixo, que você pode obter se quiser.

Nada é escondido de você que não seja absolutamente necessário. A linguagem oferece abstrações apenas como uma maneira de economizar seu trabalho, em vez de como uma maneira de dizer o que você deve fazer. Na verdade, a linguagem o incentiva a ser um participante igual em seu design. Você pode mudar tudo sobre ela, incluindo até mesmo sua sintaxe, e qualquer coisa que você escreva tem, tanto quanto possível, o mesmo status que o que vem predefinido.

Notas

[1] Macros muito próximos da ideia moderna foram propostos por Timothy Hart em 1964, dois anos após o lançamento do Lisp 1.5. O que faltava, inicialmente, eram maneiras de evitar a captura de variáveis e a avaliação múltipla; os exemplos de Hart estão sujeitos a ambos.

[2] Em When the Air Hits Your Brain, o neurocirurgião Frank Vertosick relata uma conversa na qual seu residente-chefe, Gary, fala sobre a diferença entre cirurgiões e internistas ("pulgas"):

Gary e eu pedimos uma pizza grande e encontramos um balcão aberto. O chefe acendeu um cigarro. "Olhe para aquelas malditas pulgas, tagarelando sobre alguma doença que eles verão uma vez em suas vidas. Esse é o problema com as pulgas, elas só gostam da coisa bizarra. Elas odeiam seus casos de pão e manteiga. Essa é a diferença entre nós e as malditas pulgas. Veja, nós amamos grandes hérnias de disco lombares, mas elas odeiam a hipertensão..."

É difícil pensar em uma hérnia de disco lombar como suculenta (exceto literalmente). E, no entanto, acho que sei o que eles querem dizer. Muitas vezes tive um inseto suculento para rastrear. Alguém que não é programador acharia difícil imaginar que pode haver prazer em um bug. Certamente é melhor se tudo simplesmente funcionar. De certa forma, é. E, no entanto, há uma satisfação sombria inegável em caçar certos tipos de bugs.