SER POPULAR
OriginalMaio de 2001
(Este artigo foi escrito como uma espécie de plano de negócios para uma nova linguagem . Portanto, falta (porque ele toma como certa) a característica mais importante de uma boa linguagem de programação: abstrações muito poderosas.)
Um amigo meu disse uma vez a um eminente especialista em sistemas operacionais que ele queria projetar uma linguagem de programação realmente boa. O especialista lhe disse que seria perda de tempo, que linguagens de programação não se tornam populares ou impopulares com base em seus méritos e, portanto, não importa quão boa fosse sua linguagem, ninguém a usaria. Pelo menos, foi o que aconteceu com a linguagem que ele projetou.
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 observando hackers e aprendendo o que eles querem. Linguagens de programação são para hackers, e uma linguagem de programação é boa como uma linguagem de programação (em vez de, digamos, um exercício em semântica denotacional ou design de compilador) se e somente se 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 ouve que linguagem usar de outra pessoa. E ainda assim eu acho que o efeito de tais fatores externos na popularidade das linguagens de programação não é tão grande quanto às vezes se pensa. Eu acho que um problema maior é que a ideia de um hacker sobre uma boa linguagem de programação não é a mesma da maioria dos designers de linguagem.
Entre os dois, a opinião do hacker é a que importa. Linguagens de programação não são teoremas. Elas são ferramentas, projetadas para pessoas, e elas têm que ser projetadas para se adequarem às forças e fraquezas humanas tanto quanto sapatos têm que ser projetados para pés humanos. Se um sapato aperta quando você o calça, é um sapato ruim, por mais elegante que seja como uma peça de escultura.
Pode ser que a maioria dos programadores não consiga diferenciar uma linguagem boa de uma ruim. Mas isso não é diferente com nenhuma outra ferramenta. Não significa que seja perda de tempo tentar projetar uma boa linguagem. Hackers especialistas conseguem diferenciar uma boa linguagem quando veem uma, e eles a usarão. Hackers especialistas são uma pequena minoria, é verdade, mas essa pequena minoria escreve todos os bons softwares, e sua influência é tanta que o resto dos programadores tenderá a usar qualquer linguagem que eles usem. Frequentemente, de fato, não é meramente influência, mas comando: frequentemente os hackers especialistas são as mesmas pessoas que, como seus chefes ou orientadores docentes, dizem aos outros programadores qual linguagem usar.
A opinião de hackers especialistas não é a única força que determina a popularidade relativa 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. Veja o quanto qualquer linguagem popular mudou durante sua vida. Perl e Fortran são casos extremos, mas até mesmo Lisp mudou muito. O Lisp 1.5 não tinha macros, por exemplo; elas evoluíram mais tarde, depois que hackers do MIT passaram alguns anos usando Lisp para escrever programas reais. [1]
Então, quer uma linguagem tenha que ser boa para ser popular, eu acho que uma linguagem tem que ser popular para ser boa. E ela tem que permanecer popular para permanecer boa. O estado da arte em linguagens de programação não para. E ainda assim os Lisps que temos hoje ainda são muito parecidos com o que eles tinham no MIT em meados dos anos 1980, porque essa foi a última vez que o Lisp teve uma base de usuários suficientemente grande e exigente.
Claro, hackers precisam saber sobre uma linguagem antes de poderem usá-la. Como eles vão ouvir? De outros hackers. Mas tem que haver um grupo inicial de hackers usando a linguagem para que outros ao menos ouçam sobre ela. Eu me pergunto quão grande esse grupo tem que ser; quantos usuários formam uma massa crítica? De cabeça, eu diria vinte. Se uma linguagem tivesse vinte usuários separados, ou seja, vinte usuários que decidiram por conta própria usá-la, eu consideraria isso real.
Chegar lá não deve 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 conseguir esses vinte usuários iniciais é provavelmente usar um cavalo de Troia: dar às pessoas um aplicativo que elas querem, que por acaso é escrito na nova linguagem.
2 Fatores externos
Vamos começar reconhecendo um fator externo que afeta a popularidade de uma linguagem de programação. Para se tornar popular, uma linguagem de programação tem que ser a linguagem de script de um sistema popular. Fortran e Cobol eram as linguagens de script dos primeiros mainframes da IBM. C era a linguagem de script do Unix, e assim, mais tarde, foi Perl. Tcl é a linguagem de script do Tk. Java e Javascript são pretendidos a serem as linguagens de script dos navegadores da web.
Lisp não é uma linguagem massivamente popular porque não é a linguagem de script de um sistema massivamente popular. A popularidade que ela mantém remonta às décadas de 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 de Lisp do MIT, chamado MacLisp, era uma das únicas linguagens de programação que um hacker sério gostaria de usar.
Hoje, o Lisp é a linguagem de script de dois sistemas moderadamente populares, Emacs e Autocad, e por essa razão suspeito que a maior parte da programação em Lisp feita hoje seja feita em Emacs Lisp ou AutoLisp.
Linguagens de programação não existem isoladas. Hackear é um verbo transitivo — hackers geralmente estão hackeando algo — e, na prática, as linguagens são julgadas em relação a qualquer coisa que elas são usadas para hackear. Então, se você quer projetar uma linguagem popular, você tem que fornecer mais do que uma linguagem, ou você tem que projetar sua linguagem para substituir a linguagem de script de algum sistema existente.
Common Lisp é impopular em parte porque é órfão. Originalmente, ele veio com um sistema para hackear: a Lisp Machine. Mas as Lisp Machines (junto com computadores paralelos) foram esmagadas pelo poder crescente dos processadores de propósito geral na década de 1980. Common Lisp poderia ter permanecido popular se tivesse sido uma boa linguagem de script para Unix. Infelizmente, é uma linguagem terrivelmente ruim.
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 isso deve ser gratuito. Empresas pagarão por software, mas 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 fino, bem escrito e cheio de bons exemplos. K&R é o ideal aqui. No momento, eu quase diria que uma linguagem precisa ter um livro publicado pela O'Reilly. Isso está se tornando o teste de importância para hackers.
Deveria haver documentação online também. Na verdade, o livro pode começar como documentação online. Mas não acho que os livros físicos estejam ultrapassados ainda. O formato deles é 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 novos idiomas.
3 Brevidade
Considerando que você pode fornecer as três coisas que qualquer linguagem precisa — uma implementação gratuita, um livro e algo para hackear — como criar uma linguagem que os hackers gostem?
Uma coisa que os hackers gostam é de brevidade. Hackers são preguiçosos, da mesma forma que matemáticos e arquitetos modernistas são preguiçosos: eles odeiam qualquer coisa estranha. Não estaria longe da verdade dizer que um hacker prestes a escrever um programa decide qual linguagem usar, pelo menos subconscientemente, com base no número total de caracteres que ele terá que digitar. Se não é exatamente assim que os hackers pensam, um designer de linguagem faria bem em agir como se fosse.
É um erro tentar mimar o usuário com expressões longas e prolixas que pretendem se assemelhar ao inglês. O Cobol é famoso por essa falha. Um hacker consideraria ser solicitado a escrever
adicione x a y resultando em z
em vez de
z = x+y
como algo entre um insulto à sua inteligência e um pecado contra Deus.
Às vezes, foi dito que Lisp deveria usar first e rest em vez de car e cdr, porque isso tornaria os programas mais fáceis de ler. Talvez nas primeiras horas. Mas um hacker pode aprender rápido 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 geralmente são, em linhas sucessivas. Descobri que importa muito como o código se alinha na página. Mal consigo ler o código Lisp quando ele é definido em uma fonte de largura variável, e amigos dizem que isso também é verdade para outras linguagens.
Brevidade é um lugar onde linguagens fortemente tipadas perdem. Todas as outras coisas sendo iguais, ninguém quer começar um programa com um monte de declarações. Qualquer coisa que possa ser implícita, deve ser.
Os tokens individuais também devem ser curtos. Perl e Common Lisp ocupam polos opostos nessa questão. Programas Perl podem ser quase enigmaticamente densos, enquanto os nomes dos operadores Common Lisp integrados são comicamente longos. Os designers do Common Lisp provavelmente esperavam que os usuários tivessem editores de texto que digitariam esses nomes longos para 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 tela.
4 Hackabilidade
Há uma coisa mais importante do que brevidade para um hacker: ser capaz de fazer o que você quer. Na história das linguagens de programação, uma quantidade surpreendente de esforço foi feita para impedir que programadores fizessem coisas consideradas impróprias. Este é um plano perigosamente presunçoso. Como o designer da linguagem pode saber o que o programador vai precisar fazer? Eu acho que os designers de linguagem fariam melhor em considerar seu usuário-alvo como um gênio que precisará fazer coisas que nunca previram, em vez de um trapalhão que precisa ser protegido de si mesmo. O trapalhão vai atirar no próprio pé de qualquer maneira. Você pode poupá-lo de se referir a variáveis em outro pacote, mas não pode poupá-lo de escrever um programa mal projetado para resolver o problema errado e levar uma eternidade para fazê-lo.
Bons programadores geralmente querem fazer coisas perigosas e desagradáveis. Por desagradáveis, quero dizer coisas que vão além de qualquer fachada semântica que a linguagem esteja tentando apresentar: obter a representação interna de alguma abstração de alto nível, por exemplo. Hackers gostam de hackear, e hackear significa entrar nas coisas e questionar o designer original.
Deixe-se ser questionado. Quando você faz qualquer ferramenta, as pessoas a usam de maneiras que você não pretendia, e isso é especialmente verdadeiro para uma ferramenta altamente articulada como uma linguagem de programação. Muitos hackers vão querer ajustar seu modelo semântico de uma maneira que você nunca imaginou. Eu digo, deixe-os; dê ao programador acesso a tantas coisas internas quanto você puder sem colocar em risco sistemas de tempo de execução como o coletor de lixo.
No Common Lisp, muitas vezes eu quis iterar pelos campos de uma struct — para pentear referências a um objeto deletado, por exemplo, ou encontrar campos que não foram inicializados. Eu sei que as structs são apenas vetores por baixo. E ainda assim eu não consigo escrever uma função de propósito geral que eu possa chamar em qualquer struct. Eu só consigo acessar os campos pelo nome, porque é isso que uma struct deve significar.
Um hacker pode querer subverter o modelo pretendido das coisas apenas uma ou duas vezes em um grande programa. Mas que diferença faz ser capaz de fazer isso. E pode ser mais do que uma questão de apenas resolver um problema. Há um tipo de prazer aqui também. Os hackers compartilham o prazer secreto do cirurgião em cutucar 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 macabros. Eles conhecem seu público.
Historicamente, o Lisp tem sido bom em deixar os hackers fazerem o que querem. A correção política do Common Lisp é uma aberração. Os primeiros Lisps deixavam você colocar as mãos em tudo. Uma boa parte desse espírito é, felizmente, preservada em macros. Que coisa maravilhosa, poder fazer transformações arbitrárias no código-fonte.
Macros clássicas são uma ferramenta de hacker de verdade — 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 ela retorna é inserido no lugar da chamada da macro. Macros higiênicas incorporam o princípio oposto. Elas tentam proteger você 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 podem querer. Macros higiênicas têm a intenção de me proteger da captura de variáveis, entre outras coisas, mas captura de variáveis é exatamente o que eu quero em algumas macros.
Uma linguagem realmente boa deve ser limpa e suja: projetada de forma limpa, com um pequeno núcleo de operadores bem compreendidos e altamente ortogonais, mas suja no sentido de que deixa os hackers fazerem o que quiserem com ela. C é assim. Assim eram os primeiros Lisps. A linguagem de um verdadeiro hacker sempre terá um caráter ligeiramente vulgar.
Uma boa linguagem de programação deve ter recursos que façam o tipo de pessoa que usa a frase "engenharia de software" balançar a cabeça em desaprovação. Na outra ponta do continuum estão linguagens como Ada e Pascal, modelos de propriedade que são bons para ensinar e não muito mais que isso.
5 Programas Descartáveis
Para ser atraente para 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 de sistema, ou gerar dados de teste para uma simulação, ou converter dados de um formato para outro. O surpreendente sobre programas descartáveis é que, como os prédios "temporários" construídos em tantas universidades americanas durante a Segunda Guerra Mundial, eles geralmente não são jogados fora. Muitos evoluem para programas reais, com recursos reais e usuários reais.
Tenho um palpite de que os melhores grandes programas começam a vida dessa forma, em vez de serem projetados grandes desde o início, como a Represa Hoover. É assustador construir algo grande do zero. Quando as pessoas assumem um projeto que é muito grande, elas ficam sobrecarregadas. O projeto ou fica atolado, ou o resultado é estéril e de madeira: um shopping em vez de um centro 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 assustadora, e o design do programa se beneficia da evolução. Acho que, se alguém olhasse, essa seria a maneira como a maioria dos programas grandes foi desenvolvida. E aqueles que evoluíram dessa maneira provavelmente ainda são escritos em qualquer linguagem em que foram escritos inicialmente, porque é raro um programa ser portado, exceto por razões políticas. E então, paradoxalmente, se você quer fazer uma linguagem que seja usada para grandes sistemas, você tem que torná-la boa para escrever programas descartáveis, porque é daí que vêm os grandes sistemas.
Perl é um exemplo marcante dessa ideia. Ele não foi projetado apenas para escrever programas descartáveis, mas era praticamente um programa descartável em si. 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 conforme os programas descartáveis que as pessoas escreviam nele se tornaram maiores. Foi somente com Perl 5 (se é que foi) que a linguagem se tornou adequada para escrever programas sérios, e ainda assim 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 já deve estar instalada no computador que você está usando. Não pode ser algo que você tenha que instalar antes de usá-la. Ela tem que estar lá. C estava lá porque veio com o sistema operacional. Perl estava lá porque era originalmente uma ferramenta para administradores de sistema, e o seu já a tinha instalado.
Estar disponível significa mais do que estar instalado, no entanto. Uma linguagem interativa, com uma interface de linha de comando, é 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 rápido.
Outra coisa que você quer em um programa descartável é brevidade. Brevidade é sempre atraente para hackers, e nunca mais do que em um programa que eles esperam entregar em uma hora.
6 Bibliotecas
Claro que o máximo em brevidade é ter o programa já escrito para você, e meramente chamá-lo. E isso nos leva ao que eu acho que será um recurso cada vez mais importante das linguagens de programação: funções de biblioteca. Perl vence porque tem grandes bibliotecas para manipular strings. Essa classe de funções de biblioteca é especialmente importante para programas descartáveis, que geralmente são escritos originalmente para converter ou extrair dados. Muitos programas Perl provavelmente começam como apenas algumas chamadas de biblioteca grudadas.
Acho que muitos dos avanços que acontecerão em linguagens de programação nos próximos cinquenta anos terão a ver com funções de biblioteca. Acho que as futuras linguagens de programação terão bibliotecas que são tão cuidadosamente projetadas quanto a linguagem principal. O design de linguagem de programação não será sobre se você deve tornar sua linguagem fortemente ou fracamente tipada, ou orientada a objetos, ou funcional, ou o que for, mas sobre como projetar ótimas bibliotecas. O tipo de designer de linguagem que gosta de pensar sobre como projetar sistemas de tipos pode estremecer com isso. É quase como escrever aplicativos! Uma pena. Linguagens são para programadores, e bibliotecas são o que os programadores precisam.
É difícil projetar boas bibliotecas. Não é simplesmente uma questão de escrever muito código. Quando as bibliotecas ficam muito grandes, às vezes pode levar mais tempo para encontrar a função que você precisa do que escrever o código você mesmo. 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.
Bibliotecas são um lugar onde o Common Lisp falha. Existem apenas bibliotecas rudimentares para manipular strings, e quase nenhuma para falar com o sistema operacional. Por razões históricas, o Common Lisp tenta fingir que o SO não existe. E como você não pode falar com o SO, é improvável que você consiga escrever um programa sério usando apenas os operadores internos do Common Lisp. Você tem que usar alguns hacks específicos de implementação também, e na prática eles tendem a não lhe dar tudo o que você quer. Os hackers pensariam muito melhor do Lisp se o Common Lisp tivesse bibliotecas de strings poderosas e bom suporte ao SO.
7 Sintaxe
Uma linguagem com a sintaxe do Lisp, ou mais precisamente, a ausência de sintaxe, poderia se tornar popular? Não sei a resposta para essa pergunta. Acho que a sintaxe não é a principal razão pela qual o Lisp não é popular atualmente. O Common Lisp tem problemas piores do que a sintaxe desconhecida. Conheço vários programadores que se sentem confortáveis com a sintaxe de prefixo e ainda usam Perl por padrão, porque ele tem bibliotecas de strings poderosas e pode se comunicar com o sistema operacional.
Há dois problemas possíveis com a notação de prefixo: que ela não é familiar para programadores e que ela não é densa o suficiente. A sabedoria convencional no mundo Lisp é que o primeiro problema é o real. Não tenho tanta certeza. Sim, a notação de prefixo faz programadores comuns entrarem em pânico. Mas não acho que as opiniões de programadores comuns importem. As linguagens se tornam populares ou impopulares com base no que hackers especialistas pensam delas, e acho que hackers especialistas podem ser capazes de lidar com a notação de prefixo. A sintaxe Perl pode ser bem incompreensível, mas isso não atrapalhou a popularidade do Perl. Se alguma coisa, pode ter ajudado a fomentar um culto ao Perl.
Um problema mais sério é a difusão da notação de prefixo. Para hackers especialistas, isso realmente é um problema. Ninguém quer escrever (aref axy) quando poderia escrever a[x,y].
Neste caso em particular, há uma maneira de sair do problema. Se tratarmos estruturas de dados como se fossem funções em índices, poderíamos escrever (axy) em vez disso, 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 o recuo significativo. É assim que os programadores leem o código de qualquer maneira: quando o recuo diz uma coisa e os delimitadores dizem outra, seguimos o recuo. Tratar o recuo como significativo eliminaria essa fonte comum de bugs, além de tornar os programas mais curtos.
Às vezes, a sintaxe infixa é mais fácil de ler. Isso é especialmente verdadeiro para expressões matemáticas. Usei Lisp durante toda a minha vida de programação e ainda não acho expressões matemáticas prefixadas naturais. E ainda assim é conveniente, especialmente quando você está gerando código, ter operadores que aceitam qualquer número de argumentos. Então, se tivermos sintaxe infixa, ela provavelmente deve ser implementada como algum tipo de macro de leitura.
Não acho que devamos nos opor religiosamente à introdução de sintaxe no Lisp, desde que ela seja traduzida de uma forma bem compreendida em s-expressões subjacentes. Já existe uma boa quantidade 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 partes mais notoriamente não lispy da sintaxe em Common Lisp ocorre em strings de formato; formato é uma linguagem por si só, e essa linguagem não é Lisp. Se houvesse um plano para introduzir mais sintaxe em Lisp, especificadores de formato poderiam ser incluídos nele. Seria uma coisa boa se as macros pudessem gerar especificadores de formato da mesma forma que geram qualquer outro tipo de código.
Um eminente hacker Lisp me disse que sua cópia do CLTL cai aberta para o formato de seção. 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
Uma boa linguagem, como todos sabem, deve gerar código rápido. Mas, na prática, não acho que 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 certos gargalos críticos. E, como muitos programadores observaram desde então, muitas vezes nos enganamos sobre onde estão esses gargalos.
Então, 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 saber 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 têm com o Lisp é que é difícil dizer o que é caro. Isso pode ser verdade. Também pode ser inevitável, se você quiser ter uma linguagem muito abstrata. E, em qualquer caso, acho que uma boa criação de perfil ajudaria muito a consertar o problema: você logo aprenderia o que é caro.
Parte do problema aqui é social. Designers de linguagem gostam de escrever compiladores rápidos. É assim que eles medem suas habilidades. Eles pensam no profiler como um complemento, na melhor das hipóteses. Mas, na prática, um bom profiler pode fazer mais para melhorar a velocidade de programas reais escritos na linguagem do que um compilador que gera código rápido. Aqui, novamente, designers de linguagem estão um pouco fora de contato com seus usuários. Eles fazem um trabalho muito bom em resolver um pouco o problema errado.
Pode ser uma boa ideia ter um profiler ativo — para enviar dados de desempenho ao programador em vez de esperar que ele venha solicitá-los. Por exemplo, o editor pode exibir gargalos em vermelho quando o programador edita o código-fonte. Outra abordagem seria representar de alguma forma o que está acontecendo em programas em execução. Isso seria uma vitória especialmente grande em aplicativos baseados em servidor, onde você tem muitos programas em execução para analisar. Um profiler ativo pode mostrar graficamente o que está acontecendo na memória enquanto um programa está em execução, ou até mesmo fazer sons que dizem o que está acontecendo.
O som é uma boa pista para problemas. Em um lugar onde trabalhei, tínhamos um grande quadro de mostradores mostrando 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 quadro da minha mesa, mas descobri que conseguia dizer imediatamente, pelo som, quando havia um problema com um servidor.
Pode até ser possível escrever um profiler que detecte automaticamente algoritmos ineficientes. Eu não ficaria surpreso se certos padrões de acesso à memória se revelassem sinais seguros de algoritmos ruins. Se houvesse um sujeito pequeno correndo dentro do computador executando nossos programas, ele provavelmente teria uma história longa e melancólica para contar sobre seu trabalho como funcionário do governo federal. Muitas vezes tenho a sensação de que estou enviando o processador em muitas perseguições 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 tornar a implementação mais fácil de portar, mas pode 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 inline em gargalos. Então, essas otimizações também seriam portáteis.
A natureza da velocidade, conforme percebida pelo usuário final, pode estar mudando. Com o surgimento de aplicativos baseados em servidor, mais e mais programas podem acabar sendo limitados por i/o. Valerá a pena tornar o i/o rápido. A linguagem pode ajudar com medidas diretas, como funções de saída simples, rápidas e formatadas, e também com mudanças estruturais profundas, como cache e objetos persistentes.
Os usuários estão interessados no 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 uma empresa que oferece um aplicativo baseado em servidor, este é o divisor.
Durante anos, a eficiência não importou muito na maioria dos aplicativos de usuário final. Os desenvolvedores puderam presumir 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 mudará com os aplicativos baseados em servidor. Nesse mundo, o hardware e o software serão fornecidos juntos. Para empresas que oferecem aplicativos baseados em servidor, fará uma grande diferença no resultado final quantos usuários eles podem suportar por servidor.
Em algumas aplicações, o processador será o fator limitante, e a velocidade de execução será a coisa mais importante a ser otimizada. Mas frequentemente a memória será o limite; o número de usuários simultâneos será determinado pela quantidade de memória que você precisa para os dados de cada usuário. A linguagem pode ajudar aqui também. 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 em nível de linguagem para carregamento lento.
9 Tempo
O último ingrediente que uma linguagem popular precisa é tempo. Ninguém quer escrever programas em uma linguagem que pode desaparecer, como muitas linguagens de programação fazem. Então, a maioria dos hackers tende a esperar até que uma linguagem esteja por aí por alguns anos antes mesmo de considerar usá-la.
Inventores de coisas novas maravilhosas geralmente se surpreendem ao descobrir isso, mas você precisa de tempo para passar qualquer mensagem às pessoas. Um amigo meu raramente faz alguma coisa na primeira vez que alguém lhe pede. Ele sabe que as pessoas às vezes pedem coisas que elas não querem. Para evitar desperdiçar seu tempo, ele espera até a terceira ou quarta vez que lhe pedem para fazer algo; a essa altura, quem quer que esteja pedindo pode estar bem irritado, mas pelo menos provavelmente realmente quer o que quer que esteja pedindo.
A maioria das pessoas aprendeu a fazer um tipo similar de filtragem em coisas novas que ouvem falar. Elas nem começam a prestar atenção até ouvirem sobre algo dez vezes. Elas estão perfeitamente justificadas: a maioria das novidades quentes acabam sendo uma perda de tempo e eventualmente desaparecem. Ao atrasar o aprendizado de VRML, evitei ter que aprendê-lo.
Então, qualquer um que invente algo novo tem que esperar continuar repetindo sua mensagem por anos antes que as pessoas comecem a entendê-la. Nós escrevemos o que foi, até onde eu sei, o primeiro aplicativo baseado em servidor web, e levou anos para que entendêssemos que não precisava ser baixado. Não era que eles fossem estúpidos. Eles apenas nos deixaram desligados.
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á.
Ainda bem que geralmente demora um pouco para ganhar impulso. 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 falhas restantes em sua tecnologia. Quando você tem apenas alguns usuários, pode estar em contato próximo com todos eles. E os adotantes iniciais são indulgentes quando você melhora seu sistema, mesmo que isso cause alguma quebra.
Há duas maneiras de introduzir novas tecnologias: o método de crescimento orgânico e o método do big bang. O método de crescimento orgânico é exemplificado pela clássica startup improvisada de garagem subfinanciada. Alguns caras, trabalhando na obscuridade, desenvolvem uma nova tecnologia. Eles a lançam sem marketing e inicialmente têm apenas alguns usuários (fanaticamente devotados). Eles continuam a melhorar a tecnologia e, enquanto isso, sua base de usuários cresce pelo boca a boca. Antes que percebam, eles são grandes.
A outra abordagem, o método big bang, é exemplificada pela startup apoiada por VC e fortemente comercializada. Eles correm para desenvolver um produto, lançam-no com grande publicidade e imediatamente (esperam) têm uma grande base de usuários.
Geralmente, os caras da garagem invejam os caras do big bang. Os caras do big bang são suaves, confiantes e respeitados pelos VCs. Eles podem pagar o melhor de tudo, e a campanha de RP em torno do lançamento tem o efeito colateral de torná-los celebridades. Os caras do crescimento orgânico, sentados em suas garagens, se sentem pobres e não amados. E ainda assim eu acho que eles frequentemente se enganam ao sentir pena de si mesmos. O crescimento orgânico parece render melhor tecnologia e fundadores mais ricos do que o método do big bang. Se você olhar para as tecnologias dominantes hoje, você verá que a maioria delas cresceu organicamente.
Esse padrão não se aplica somente a empresas. Você o vê também em pesquisas patrocinadas. Multics e Common Lisp foram projetos big-bang, e Unix e MacLisp foram projetos de crescimento orgânico.
10 Redesenho
"A melhor escrita é reescrita", escreveu EB White. Todo bom escritor sabe disso, e isso também é verdade para software. A parte mais importante do design é o redesign. Linguagens de programação, especialmente, não são redesenhadas o suficiente.
Para escrever um bom software, você deve simultaneamente manter duas ideias opostas na 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 uma metade do seu cérebro enquanto pensa que nunca vai funcionar com a outra.
O truque é perceber que não há nenhuma contradição real 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.
Pessoas que fazem um bom trabalho frequentemente pensam que o que quer que estejam fazendo não é bom. 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ê puder manter a esperança e a preocupação equilibradas, elas levarão um projeto adiante da mesma forma que suas duas pernas levam uma bicicleta adiante. Na primeira fase do motor de inovação de dois ciclos, você trabalha furiosamente em algum problema, inspirado por sua confiança de que será capaz de resolvê-lo. Na segunda fase, você olha para o que fez na luz fria da manhã e vê todas as suas falhas muito claramente. Mas, desde que seu espírito crítico não supere sua esperança, você será capaz de olhar para seu sistema reconhecidamente incompleto e pensar: quão difícil pode ser fazer o resto do caminho?, continuando assim o ciclo.
É complicado manter as duas forças equilibradas. Em hackers jovens, o otimismo predomina. Eles produzem algo, estão convencidos de que é ótimo e nunca melhoram. Em hackers velhos, o ceticismo predomina, e eles nem ousam assumir projetos ambiciosos.
Qualquer coisa que você possa fazer para manter o ciclo de redesign em andamento é bom. A prosa pode ser reescrita várias vezes até que você esteja 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 reescreve um ensaio, as pessoas que leem a versão antiga dificilmente reclamarão que seus pensamentos foram quebrados por alguma incompatibilidade recém-introduzida.
Usuários são uma faca de dois gumes. Eles podem ajudar você a melhorar sua linguagem, mas também podem impedi-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 caminho sensato é adiá-la. Além disso, como regra geral, você pode a qualquer momento se safar mudando mais do que pensa. Introduzir mudanças é como arrancar um curativo: a dor é uma memória quase assim que você a sente.
Todo mundo sabe que não é uma boa ideia ter uma linguagem projetada por um comitê. Comitês produzem design ruim. Mas acho que o pior perigo dos comitês é que eles interferem no redesign. Dá tanto trabalho introduzir mudanças que ninguém quer se incomodar. O que quer que um comitê decida tende a permanecer assim, mesmo que a maioria dos membros não goste.
Até mesmo um comitê de dois 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 nada, 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 para que as interfaces sejam horizontais em vez de verticais — para que os módulos sejam sempre estratos de abstração empilhados verticalmente. Então a interface tenderá a ser propriedade de um deles. O mais baixo dos dois níveis será uma linguagem na qual o superior é escrito, em cujo caso o nível mais baixo possuirá a interface, ou será um escravo, em cujo caso a interface pode ser ditada pelo nível superior.
11 Ceceio
O que 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 Lisp. Acho que podemos ter cometido um erro ao pensar que os hackers são desestimulados 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 é péssimo 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 nenhuma das duas coisas. A linguagem de um hacker é concisa e hackeavel. 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 hacker de verdade, acho que os hackers vão usá-lo. 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, sucessivas novas linguagens de programação tiraram mais e mais recursos do Lisp. Não há mais muito o que copiar antes que a linguagem que você fez seja Lisp. A mais recente linguagem popular, Python, é um Lisp diluído com sintaxe infixa e sem macros. Um novo Lisp seria um passo natural nessa progressão.
Às vezes, penso que seria um bom truque de marketing chamá-lo de uma versão melhorada do Python. Isso soa mais descolado 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 com 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 pegaram 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 como latim ou grego — uma língua que você deve aprender como um exercício intelectual, mesmo que não vá realmente usá-la:
Vale a pena aprender Lisp pela profunda experiência de esclarecimento que você terá quando finalmente aprender; essa experiência fará de você um programador melhor pelo resto de seus dias, mesmo que você nunca use muito o Lisp.
Se eu não conhecesse Lisp, ler isso me faria fazer perguntas. Uma linguagem que me tornaria um programador melhor, se é que isso significa alguma coisa, significa uma linguagem que seria melhor para programação. E essa é de fato a implicação do que Eric está dizendo.
Enquanto essa ideia ainda estiver circulando, acho que os hackers serão receptivos o suficiente para um novo Lisp, mesmo que ele se chame Lisp. Mas esse Lisp deve ser uma linguagem de hacker, como os Lisps clássicos dos anos 1970. Deve ser conciso, simples e hackeavel. E deve ter bibliotecas poderosas para fazer o que os hackers querem fazer agora.
Em matéria de bibliotecas, acho que há espaço para vencer 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 Perl, e se esse novo Lisp também tivesse bibliotecas poderosas para aplicativos baseados em servidor, ele poderia ser muito popular. Hackers de verdade não torcerão o nariz para uma nova ferramenta que os deixará resolver problemas difíceis com algumas chamadas de biblioteca. Lembre-se, hackers são preguiçosos.
Poderia ser uma vitória ainda maior ter suporte de linguagem principal para aplicativos baseados em servidor. Por exemplo, suporte explícito para programas com múltiplos 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 questão de para que esse novo Lisp será usado para hackear. Não faria mal nenhum tornar o Lisp melhor como uma linguagem de script para Unix. (Seria difícil piorá-lo.) Mas acho que há áreas em que as linguagens existentes seriam mais fáceis de superar. Acho que seria 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. Os fechamentos léxicos fornecem uma maneira de obter o efeito de sub-rotinas quando a interface do usuário é apenas uma série de páginas da web. As expressões S mapeiam bem em HTML, e as macros são boas para gerá-lo. É preciso haver ferramentas melhores para escrever aplicativos baseados em servidor, e é preciso haver um novo Lisp, e os dois funcionariam muito bem juntos.
12 A Linguagem dos Sonhos
Para resumir, vamos tentar descrever a linguagem dos sonhos do hacker. A linguagem dos sonhos é bonita , limpa e concisa. Ela tem um nível superior interativo que inicia rápido. Você pode escrever programas para resolver problemas comuns com muito pouco código. Quase todo o código em qualquer programa que você escreve é um código específico para sua aplicação. Todo o resto foi feito para você.
A sintaxe da linguagem é breve demais. 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 quiser otimizar, há um profiler muito bom que lhe diz onde concentrar sua atenção. Você pode fazer loops internos incrivelmente rápidos, até mesmo escrevendo código de bytes em linha, se precisar.
Há 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 olhar muito no manual. O manual é fino 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 principal. Todas as bibliotecas funcionam bem juntas; tudo na linguagem se encaixa como as partes de uma câmera fina. Nada é depreciado ou mantido para compatibilidade. O código-fonte de todas as bibliotecas está prontamente disponível. É fácil falar com o sistema operacional e com aplicativos escritos em outras linguagens.
A linguagem é construída em camadas. As abstrações de nível mais alto são construídas de uma forma muito transparente a partir de abstrações de nível mais baixo, que você pode obter se quiser.
Nada está escondido de você que não tenha que estar. A linguagem oferece abstrações apenas como uma forma de poupar seu trabalho, em vez de uma forma de lhe dizer o que fazer. Na verdade, a linguagem o encoraja a ser um participante igual em seu design. Você pode mudar tudo sobre ela, incluindo até mesmo sua sintaxe, e qualquer coisa que você escrever tem, tanto quanto possível, o mesmo status do que vem predefinido.
Notas
[1] Macros muito próximas da ideia moderna foram propostas por Timothy Hart em 1964, dois anos após o lançamento do Lisp 1.5. O que faltava, inicialmente, eram maneiras de evitar captura de variáveis e 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 em que seu residente-chefe, Gary, fala sobre a diferença entre cirurgiões e internistas ("pulgas"):
Gary e eu pedimos uma pizza grande e encontramos uma cabine aberta. O chefe acendeu um cigarro. "Olhe para essas malditas pulgas, tagarelando sobre alguma doença que verão uma vez na vida. Esse é o problema com as pulgas, elas só gostam de coisas bizarras. Elas odeiam seus casos de pão com manteiga. Essa é a diferença entre nós e as malditas pulgas. Veja, nós amamos grandes e suculentas hérnias de disco lombar, mas elas odeiam hipertensão..."
É difícil pensar em uma hérnia de disco lombar como algo suculento (exceto literalmente). E ainda assim acho que sei o que elas significam. Muitas vezes tive um bug suculento para rastrear. Alguém que não é um programador acharia difícil imaginar que poderia haver prazer em um bug. Certamente é melhor se tudo simplesmente funcionar. De certa forma, é. E ainda assim há inegavelmente uma satisfação sombria em caçar certos tipos de bugs.