Mostrando postagens com marcador Computação. Mostrar todas as postagens
Mostrando postagens com marcador Computação. Mostrar todas as postagens

sexta-feira, 24 de agosto de 2012

Ano Turing

Neste ano, comemoramos o centenário do nascimento do grande cientista da computação Ala Turing. A vida e a obra de Turing são fascinantes. A frase de Harvey Dent no filme  Batman O Cavaleiro das Trevas Ressurge poderia ser aplicada a vida de Turing :  “ou você morre como um herói, ou vive o suficiente para se tornar um vilão”


Durante a segunda guerra, Alan Mathison Turing trabalhou em Bletchley Park, o centro de operações de criptanálise durante a guerra. O trabalho do jovem Turing sobre uma máquina Universal capaz de resolver um problema lógico foi seu passaporte para esta grande aventura de criptanálise. Turing era a pessoa certa no momento certo. Os alemães possuíam uma máquina eletro-mecânica de criptografia chamada Enigma utilizada para criptografar suas instruções militares. A máquina Enigma era supostamente indecifrável. Para quebrar o código Enigma, Turing e sua equipe construíram uma máquina que analisava o código enigma buscando regularidades, traços recorrentes que pudessem ajudar na quebra do código. Essa máquina tinha a capacidade para escanear 25000 caracteres por segundo. Depois da guerra, a homossexualidade de Turing foi vista como uma ameaça pelo governo britânico. Ele submeteu-se (ou foi submetido) a tratamento  hormonal controverso como uma alternativa à prisão. Turing morreu em 1954, duas semanas antes do seu aniversário de 42 anos, por envenamento. Em 2009, o primeiro ministro britânico fez um pedido oficial de desculpas pública, em nome do governo britânico,  devido à maneira pela qual Turing foi tratado após a guerra.

O nome de Turing está relacionado intimamente com diversas contribuições na área da Computação. Vamos conhecer algumas delas:

Máquina de Turing

Formalmente, uma máquina de Turing (com uma fita) é usualmente definida como uma Tupla M=(Q,\Sigma, \Gamma, s, b, F, \delta), onde
  • Q é um conjunto finito de estados
  • \Sigma é um alfabeto finito de símbolos
  • \Gamma é o alfabeto da fita (conjunto finito de símbolos)
  • s \in Q é o estado inicial
  • b \in \Gamma é o símbolo branco (o único símbolo que se permite ocorrer na fita infinitamente em qualquer passo durante a computação)
  • F \subseteq Q é o conjunto dos estados finais
  • \delta: Q \times \Gamma ⇒ Q \times \Gamma \times \{\leftarrow,\rightarrow\} é uma função parcial chamada função de transição, onde \leftarrow é o movimento para a esquerda e \rightarrow é o movimento para a direita.


A máquina de Turing é um dispositivo teórico construído para capturar formalmente a noção de computabilidade ou procedimento efetivo ou mecânico (tudo que pode ser feito seguindo-se diretamente um algoritmo ou um conjunto de regras). Observe que Turing conseguiu propor uma formalização para um conceito totalmente abstrato de computabilidade.

Tese de Church-Turing

O mais interessante é que diversas extensões da Máquina de Turing não conseguiam ser mais poderosas que a Máquina de Turing simples. Turing estava andando no mesmo terreno que Cantor quando começou a descobrir os primeiros paradoxos da cardinalidade dos números infinitos.

Exemplos:
Máquina de Turing com múltiplas fitas.
Máquina de Turing com múltiplos cabeçotes.
Máquina de Turing com fita infinita para os dois lados.
Máquina de Turing não-determinísticas
Máquina de Turing Multidimensional


Church definiu um modelo de computabilidade diferente chamado lambda cálculo. Esse modelo de computabilidade também não conseguia ser mais poderoso que a computabilidade definida pela Máquina de Turing. A tese de Church-Turing estabelece que os limites da máquina de Turing também descreve os limites de todos os computadores.

Máquina de Turing Universal


A máquina de Turing Universal é uma máquina de Turing que pode simular uma Máquina de Turing arbitrária e uma  entrada arbitrária. A máquina de Turing Universal é a origem da dualidade programa/dado que é parte essencial da arquitetura dos computadores modernos. Observe que essa dualidade permite a ideia de um programa vírus. Um vírus é um dado/programa que explora um programa/dado para ser executado.


Turing-complete


Um sistema é dito Turing-Complete se ele pode simular uma máquina de Turing Universal ou um outro sistema Turing-Complete conhecido. Suponha que eu queira provar que a linguagem C é Turing-complete, basta eu fazer um programa que simule uma máquina de Turing Universal ou fazer um interpretador em C da linguagem brainfuck (linguagem Turing-complete conhecida).










terça-feira, 10 de julho de 2012

Uma breve História da Engenharia de Software


Este texto foi compartilhado pelo professor João Carlos de A. R. de Oliveira. Neste texto, Niklaus Wirth faz um passeio pela história da engenharia de software. Durante esse passeio, ele faz uma crítica a passividade das universidades ao assimilar os maus hábitos da indústria. Interessante notar que durante a história da computação, nem sempre as linguagens de programação que se tornaram populares eram as melhores disponíveis.

Boa Leitura!

          Uma breve História da Engenharia de Software

                                                    Niklaus Wirth
Resumo

Nós apresentamos uma perspectiva pessoal da arte da programação. Começamos com o seu estado por volta de 1960 e acompanhamos o seu desenvolvimento até os dias atuais. O termo engenharia de software tornou-se conhecido após uma conferência em 1968, quando as dificuldades e armadilhas de projetar sistemas complexos foram discutidas francamente. A busca de soluções começou. Ela se concentrou em melhores metodologias e ferramentas. As mais importantes foram as linguagens de programação que refletem os estilos procedimental, modular e, em seguida, orientado a objeto. A engenharia de software está intimamente ligada ao aparecimento e aperfeiçoamento desses estilos. Também importantes foram os esforços de sistematização, automatização da documentação do programa e testes. Por último, a verificação analítica e
provas de correção deveriam substituir os testes.

Mais recentemente, o rápido crescimento do poder computacional tornou possível aplicar computação em tarefas cada vez mais complicadas. Esta tendência aumentou drasticamente as demandas por engenheiros de software. Programas e sistemas se tornaram complexos e quase impossíveis de ser completamente compreendidos. A queda dos custos e a abundância de recursos computacionais inevitavelmente reduziram os cuidados para um bom projeto. A qualidade parecia extravagante, uma perda na corrida pelo lucro. Mas devemos estar preocupados com a resultante deterioração da qualidade. Nossas limitações não são dadas por hardwares lentos, mas pela nossa própria capacidade intelectual. Por experiência, sabemos que a maioria dos programas pode ser significativamente melhorados, ficando mais confiáveis, econômicos e confortáveis de se utilizar.

A década de 1960 e a origem de Engenharia de Software

É lamentável que pessoas que lidam com os computadores costumam ter pouco interesse em sua história. Como resultado, muitos conceitos e idéias são propagados e anunciados como novos, sendo que existem há décadas, talvez sob uma terminologia diferente. Creio que vale a pena gastar ocasionalmente algum tempo para analisar o passado e investigar como os termos e conceitos surgiram.

Eu considero o final dos anos 1950 como um período essencial da era da computação. Computadores de grande porte foram disponibilizados para instituições de pesquisa e universidades. A presença deles foi notada principalmente na engenharia e nas ciências naturais, mas também nos negócios, onde logo tornaram-se indispensáveis. O tempo em que eles eram acessíveis apenas a uns poucos em laboratórios, quando quebravam toda vez que alguém queria usá-los, pertence ao passado. O seu aparecimento, dos laboratórios fechados de engenheiros eletricistas para o domínio público, fez com que a sua utilização, em especial a sua programação, se tornasse uma atividade para muitos. Uma nova profissão nasceu, mas os computadores de grande porte se tornaram ocultos, dentro de porões muito bem guardados. Programadores traziam os seus programas para o balcão, onde havia um atendente que os pegava e enfileirava, e onde os resultados poderiam ser buscados horas ou dias depois. Não havia nenhuma interatividade entre homem e computador.

A programação foi conhecida por ser uma tarefa sofisticada que exige dedicação e pesquisas minuciosas, e uma paixão por códigos obscuros e truques. Para facilitar essa codificação, notações formais foram criadas. Nós agora as chamamos de linguagens de programação. A idéia principal era substituir seqüências de código de instrução especial por fórmulas matemáticas. A primeira linguagem amplamente conhecida, Fortran, foi lançada pela IBM (Backus, 1957), logo seguida pelo Algol (1958) e sua sucessora oficial em 1960. Como os computadores eram usados para a computação em vez de armazenamento de dados e comunicação, essas linguagens serviam principalmente para a cálculos matemáticos. Em 1962, a linguagem Cobol foi lançada pelo Departamento de Defesa dos EUA para aplicações de negócios.

Mas, como a capacidade de computação cresceu, assim também ocorreu com as exigências sobre os programas e programadores: tarefas tornaram-se mais e mais complicadas. Foi lentamente reconhecido que a programação era uma tarefa difícil, e que dominar os problemas complexos não era trivial, mesmo quando - ou porque - os computadores eram tão poderosos. A salvação foi procurada em "melhores" linguagens de programação, mais "ferramentas", sobretudo na automação. Uma melhor linguagem deve ser útil em uma ampla área de aplicação, ser mais parecida com uma linguagem "natural", oferecer mais facilidades. PL / 1 foi concebida para unificar os mundos científico e comercial. Foi anunciada sob o slogan "Todo mundo pode programar graças ao PL / 1". As linguagens de programação e seus compiladores tornaram-se um marco principal da ciência da computação. Mas eles não se ajustavam à matemática nem à eletrônica, os dois setores tradicionais em que os computadores eram usados. Uma nova disciplina surgiu, chamada de Ciência da Computação na América e de Informática na Europa.

Em 1963, o primeiro sistema de tempo compartilhado apareceu (MIT, Stanford, McCarthy, DEC PDP-1). Isso trouxe de volta a  interatividade. Os fabricantes de computadores aderiram à idéia e desenvolveram sistemas de tempo compartilhado para os seus grandes mainframes (IBM 360/67, a GE
645). Descobriu-se que a transição de sistemas de processamento em lote para sistemas de tempo compartilhado, ou a sua fusão, era muito mais difícil do que o previsto. Os sistemas eram anunciados e não podiam ser entregues a tempo. Os problemas eram muito complexos.
As pesquisas deveriam ser conduzidas no dia-a-dia. As novidades do momento eram o multiprocessamento e programação concorrente. As dificuldades levaram as grandes empresas à beira do colapso. Em 1968, uma conferência patrocinada pela NATO, foi dedicada ao tema (1968 em Garmisch-Partenkirchen, Alemanha) [1]. Apesar de críticas terem ocasionalmente sido expressas anteriormente [2, 3] só após a conferência as dificuldades foram discutidas abertamente e confessadas com franqueza  incomum, e os termos  “engenharia de software” e “crise de software” foram criados..

A programação como uma Disciplina

No mundo acadêmico, foram sobretudo E.W. Dijkstra e C.A.R. Hoare que reconheceram os problemas e ofereceram novas idéias. Em 1965, Dijkstra escreveu o seu famoso “Notes on Structured Programming” [4] e declarou a programação como uma disciplina, em contraste com o artesanato. Também em 1965, Hoare publicou um importante artigo sobre estruturação de dados [5]. Essas idéias tiveram uma profunda influência sobre as novas linguagens de programação, em particular Pascal [6]. As línguagens são os veículos nos quais essas idéias deveriam ser expressas. A programação estruturada tornou-se sustentada por uma linguagem de programação estruturada.

Além disso, em 1966, Dijkstra escreveu um artigo seminal sobre processos que cooperam harmoniosamente [7], postulando uma disciplina baseada em semáforos como primitivas para sincronização de processos concorrentes. Hoare seguiu em 1966 com seu “Communicating Sequential Processes (CSP)” [8], percebendo que, no futuro, os programadores teriam que lidar com as dificuldades dos processos concorrentes. Obviamente, isso resultaria em uma metodologia estruturada e disciplinada ainda mais atraente.

Claro, tudo isso não mudou a situação, nem dissipou todas as dificuldades da noite pro dia. A indústria não poderia mudar nem as políticas nem as ferramentas rapidamente. No entanto, cursos de formação intensiva sobre a programação estruturada foram organizados, notavelmente através de H.D. Mills na IBM. Nada menos do que o Departamento de Defesa dos EUA percebeu que os problemas eram urgentes e crescentes. Ele começou um projeto que culminou com a linguagem de programação Ada, uma linguagem altamente estruturada, apropriada para uma ampla variedade de aplicações. O desenvolvimento de software no Departamento de Defesa dos EUA seria então baseado exclusivamente em Ada [9].

Unix e C

No entanto, uma outra tendência começou a permear toda a área de programação, principalmente na academia,, apontando na direção oposta. Foi provocada pela disseminação do sistema operacional UNIX, contrastando com o MULTICS do MIT e utilizado nos minicomputadores que estavam surgindo rapidamente. UNIX foi um alívio muito bem-vindo em relação aos grandes sistemas operacionais estabelecidos em computadores de grande porte. Em seu reboque, UNIX trouxe a linguagem C [8], que tinha sido expressamente concebida para apoiar o desenvolvimento do UNIX. Evidentemente por causa disso, era atrativo, senão mesmo obrigatório, o uso de C para o desenvolvimento de aplicações rodando em UNIX, que atuou como um cavalo de Tróia para C.

Do ponto de vista da engenharia de software, a rápida disseminação da C representou um grande salto para trás. Ele revelou que a comunidade em geral não havia compreendido o verdadeiro significado do termo "linguagem de alto nível", que se tornou um chavão mal-entendido. O que, então, deveria ser "alto nível"? Como esta questão está no centro de engenharia de software, precisamos entrar em detalhes.

Abstração

Os sistemas computacionais são máquinas de grande complexidade. Esta complexidade pode ser dominada intelectualmente por uma única ferramenta: Abstração. Uma linguagem representa um computador abstrato cujos objetos e construções se encontram mais perto (em mais alto nível) para o problema a ser representado do que em uma máquina concreta. Por exemplo, em uma linguagem de alto nível lidamos com os números, matrizes indexadas, tipos de dados, instruções condicionais e repetitivas, e não com bits e bytes, palavras endereçadas, desvios e códigos de condição. No entanto, essas abstrações são benéficas somente se forem consistentemente e completamente definidas em termos de suas próprias propriedades. Se isto não é assim, se as abstrações podem ser entendidas só em termos de facilidades de um computador subjacente, então os benefícios são marginais, quase insignifcantes. Se a depuração de um programa - sem dúvida a atividade mais comum da engenharia de software - requer uma "descarga da memória em hexadecimal", a linguagem vale pouco a pena.

A expansão generalizada do C mina a tentativa de elevar o nível da engenharia de software, porque C oferece abstrações que não se sustentam de fato: Matrizes permanecem sem a verificação de índice, os tipos de dados não são conferidos quanto a consistência, os ponteiros são meramente endereços onde adição e subtração são aplicáveis . Poderíamos ter classificado C como sendo algo entre enganoso e até mesmo perigoso. Mas, ao contrário, as pessoas em geral, particularmente na academia, acharam-no intrigante e  "melhor que o código Assembly”, porque ele apresentava alguma sintaxe.

O problema era que suas regras poderiam ser facilmente quebradas, exatamente o que muitos programadores estimavam. Era possível acessar  todas as idiossincrasias de um computador, itens que uma linguagem de alto nível deveria esconder. C proporcionou liberdade, onde as linguagens de alto nível eram consideradas engessadas impondo uma disciplina indesejada. Era um convite para usar truques que tinham sido necessários para atingir a eficiência nos primeiros tempos dos computadores, mas agora eram armadilhas que tornavam grandes sistemas propensos a erros e dispendiosos para depurar e manter.

Linguagens que apareceram por volta de 1985 (como Ada e C + +), tentaram remediar estes defeitos e cobrir uma variedade muito maior de aplicações previsíveis. Como conseqüência, elas se tornaram grandes e suas descrições volumosas. Compiladores e ferramentas de apoio tornaram-se volumosos e complexos. Descobriu-se que, em vez de resolver problemas, eles acrescentaram problemas. Como Dijkstra disse: Eles pertenciam ao conjunto de problemas ao invés do conjunto de soluções.

Avanços na engenharia de software pareciam estagnar. As dificuldades cresceram mais rapidamente do que novos instrumentos que poderiam contê-las. No entanto, ao menos, pseudo-ferramentas como métricas de software revelaram-se como sendo de nenhuma ajuda, e os engenheiros de software já não eram julgados pelo número de linhas de código produzidas por hora.

O advento do micro-computador

A propagação da engenharia de software e Pascal notadamente não ocorreu na indústria, mas em outras frentes: nas escolas e nas casas. Em 1975, micro-computadores apareceram no mercado (Commodore, Tandy, da Apple, muito mais tarde IBM). Eles foram baseados em processadores singlechip (Intel 8080, Motorola 6800, a Rockwell 6502) com barramentos de 8 bits de dados, 32KB de memória ou menos, e freqüências de relógio inferior a 1 MHz. Eles fizeram os computadores acessíveis às pessoas em contraste com as grandes organizações como empresas e universidades. Mas eram brinquedos e não máquinas computacionais úteis. O salto veio quando foi demonstrado que as linguagens poderiam ser usadas também com microcomputadores. O grupo de Ken Bowles da Universidade da Califórnia em San Diego construiu um editor de texto, um sistema de arquivos e um depurador de todo o compilador Pascal portátil (código P), desenvolvido na ETH, e os distribuiram por  US$ 50. O mesmo fez a empresa Borland com a sua versão do compilador. Isso aconteceu numa época em que outros compiladores eram softwares caros, e foi nada menos do que uma virada na comercialização de software. De repente, havia um mercado de massa. A computação veio a público.

Enquanto isso, as exigências em sistemas de software cresciam ainda mais, assim como a complexidade dos programas. O ofício da programação se tornou tarefa para invasores (“hackers”). Foram procurados métodos para sistematizar, se não a construção, pelo menos programas de testes e documentação. Embora isso fosse útil, os problemas reais de programação “agitada” sob pressão do tempo permaneceram. Dijkstra trouxe a dificuldade ao ponto de dizer: “Testes podem mostrar a presença de erros, mas nunca poderão provar a sua ausência”. Ele também desdenhou: “Engenharia de Software é a programação para quem não pode”.

A programação como uma disciplina matemática

Já em 1968 R. W. Floyd sugeriu a ideia de asserções de estados, das verdades sempre válidas em certos pontos do programa [10]. Isso levou ao artigo seminal de Hoare intitulado "Uma base axiomática da Programação de Computadores", postulando a chamada lógica de Hoare [11]. Alguns anos mais tarde Dijkstra deduziu a partir dela, o cálculo de transformadores dos predicados [12]. A programação foi obtendo uma base matemática. Programas já não eram apenas o código para controle de computadores, mas textos estáticos, que podem ser submetidos a um raciocínio matemático.

Embora estes desenvolvimentos fossem reconhecidos em algumas universidades, eles passaram praticamente despercebidos na indústria. Na verdade, a lógica de Hoare e os transformadores de predicados de Dijkstra eram explicados de maneira satisfatória, mas para algoritmos simples, como a multiplicação de números inteiros, busca binária, e máximo divisor comum. Entretanto, a indústria foi atingida por sistemas verdadeiramente grandes. Isto não era óbvio para todos, se as teorias matemáticas iriam resolver problemas reais, quando a análise de algoritmos simples, por si só, já era bastante exigente.

A solução foi basear-se em uma  forma disciplinada de programação, ao invés de em uma rigorosa teoria científica. Uma contribuição importante para a programação estruturada foi feita por Parnas, em 1972, com a idéia de Ocultação de Informação [13], e ao mesmo tempo por Liskov com o conceito de Tipos de Dados Abstratos[14]. Ambos incorporam a idéia de quebrar sistemas de grande porte em partes, chamados  módulos, e definir claramente as suas interfaces. Se um módulo A usa (importa) um módulo B, então A é chamado de um cliente de B. O projetista de de A, então não precisa saber os detalhes, o funcionamento do B, mas apenas as propriedades declaradas em sua interface. Este princípio constitui, provavelmente, a mais importante contribuição à engenharia de software, ou seja, a construção de sistemas por grandes grupos de pessoas. O conceito de modularização é bastante reforçado pela técnica de compilação separada com verificação automática de compatibilidade nas  interfaces.

Assim como a programação estruturada foi o espírito orientador do Pascal, a modularização foi a principal ideia por detrás da linguagem Modula-2, o sucessor do Pascal, publicado em 1979 [15]. De fato, sua motivação veio da linguagem Mesa, um desenvolvimento interno do Laboratório de Pesquisa da Xerox em Palo Alto, sendo ela mesma uma descendente do Pascal. O conceito de modularização e compilação em separado também foi adotado pela linguagem Ada (1984), que também foi amplamente baseada em Pascal. Nela os módulos foram chamados de pacotes.

A Era da estação de trabalho pessoal

No entanto, um outro desenvolvimento influenciou o campo de computação mais profundamente do que todas as linguagens de programação. Foi a estação de trabalho, cuja primeira encarnação, o “Alto”, foi construído, mais uma vez, no Laboratório de Pesquisa da Xerox em Palo Alto (1975) [16]. Em contraste com os referidos micro-computadores, a estação era poderosa o suficiente para permitir o desenvolvimento de software sério, computações complexas, bem como a utilização de um compilador para uma
linguagem de programação avançada. O mais importante, foi pioneira nas telas de  alta resolução – mapeamento de bits e no dispositivo apontador chamado mouse, que, juntos, trouxeram uma mudança revolucionária no uso do computador. Junto com o “Alto”, o conceito de rede de área local (LAN) foi introduzido, bem como servidores centrais para impressão (a laser), armazenamento de arquivos em larga escala, e serviço de correio eletrônico. Não há exagero na afirmação que a era da computação moderna começou em 1975 com o “Alto”. O “Alto” causou nada mais nada menos do que uma revolução, e como resultado as pessoas de hoje não tem idéia de como a computação era feita antes de 1975 sem estações de trabalho pessoais altamente interativas. A influência desses acontecimentos sobre engenharia de software não pode ser sobrestimada.

Como a demanda de softwares cada vez mais complexos cresceu persistentemente, como as dificuldades tornaram-se mais ameaçadoras e como alguns fracassos espetaculares demonstraram que os problemas eram graves, a procura de panaceias (remédio para todos os males) começou. Muitas curas foram oferecidas, vendidas, e logo esquecidas. Uma delas, no entanto, mostrou-se fecunda e sobreviveu: Programação orientada a objeto (POO).

Até 1980, o modelo de computação comumente aceito era transformar os dados de seu estado dado em resultado, transformando gradualmente a entrada em  saída. Em sua forma abstrata mais simples, esta é a máquina de estado finito. Este ponto de vista da computação, surgiu a partir da tarefa original dos computadores: computação de resultados numéricos. No entanto, outro modelo ganhou terreno na década de 1960: era proveniente da simulação de sistemas complexos (supermercados, fábricas, ferrovias, logística). Sua abstração consiste de atores (processos) que vêm e vão, que passam fases em sua vida, e que trazem um conjunto de dados privados representando o seu estado atual. Provou-se natural pensar sobre tais atores com seus estados como uma unidade, como um objeto. Algumas linguagens de programação foram projetadas com base nesse modelo, sendo seu ancestral Simula, de Dahl e Nygaard em 1965. Mas elas permaneceram confinadas no campo de simulação de sistemas de eventos discretos. Somente após o surgimento de poderosos computadores pessoais que o modelo POO ganhou aceitação mais ampla. Agora, sistemas de computação possuem janelas, ícones, menus, botões, barras, etc, tudo facilmente identificável como objetos visíveis e com estado e comportamentos individuais. Linguagens apareceram apoiando esse modelo, entre elas Smalltalk (Goldberg e Kay, 1980), Object Pascal (Tesler, 1985), C++ (Stroustrup, 1985), Oberon (Wirth, 1988), Java (Sun, 1995) e C # (Microsoft, 2000). A orientação a objeto tornou-se uma tendência e um chavão. De fato, escolher o modelo certo para uma aplicação é importante. Mesmo assim, não se deve desprezar o fato de que existem aplicações para as quais a POO não é o modelo adequado.

Abundância de Poder Computacional

O período desde 1985 até há alguns anos tem se caracterizado principalmente por enormes avanços na tecnologia de hardware. Hoje, mesmo minúsculos computadores, tais como os telefones celulares, têm potência e capacidade  cem vezes maiores do que tinham 20 anos atrás. É justo dizer que as tecnologias de semicondutores e de discos têm determinado todos os avanços recentemente. Quem, por exemplo, teria sonhado em 1990 com pastilhas de memória com vários gigabytes de dados, discos minúsculos com dezenas de gigabytes de capacidade e processadores com taxas de relógio de vários gigahertz?

Este rápido desenvolvimento ampliou significativamente a área de aplicações do computador. Isto aconteceu sobretudo em relação a tecnologia de comunicação. Agora, é difícil acreditar que antes de 1975 tecnologias de comunicação e computação foram consideradas campos distintos. A eletrônica as uniu e a Internet cresceu. Sua característica é uma largura de banda que parece ser ilimitada. Fico impressionado quando comparo isso com o primeiro minicomputador com que eu trabalhei em 1965, um DEC PDP-1: taxa de relógio <1 MHz, memória de 8K palavras de 18 bits e um tambor de armazenamento de cerca de 200 KB. Ele era compartilhado por até 16 usuários. É um milagre que algumas pessoas insistiam em acreditar que um dia os computadores se tornariam poderosos o suficiente para serem úteis.

Na década de 1990, um fenômeno começou a se espalhar sob o nome de Código Aberto. A desconfiança contra os grandes sistemas projetados em segredo industrial se manifestou. A vasta comunidade de programadores decidiu construir softwares e  distribuir seus produtos gratuitamente através da Internet. Embora seja difícil reconhecer isso como um princípio de negócio - tornando a idéia de patentes obsoleta - o movimento acabou por ser bastante bem sucedido. As noções de qualidade e responsabilidade em caso de falha pareciam irrelevantes. O Código Aberto apareceu como a alternativa bem-vinda à hegemonia industrial e ao lucro abrasivo, e também contra a dependência desamparada.

É geralmente difícil em engenharia de software distinguir as estratégias de negócios das idéias científicas. Nessas últimas, o Código Aberto parece ser uma última tentativa de encobrir o fracasso. A escrita de código complicado e a desagradável descriptografia por outros é aparentemente considerada mais fácil ou mais econômica do que o projeto cuidadoso e a descrição de interfaces claras dos módulos. A fácil adaptação dos módulos, quando disponíveis em código fonte é também um argumento fraco. Qual seria o interesse em um crescimento selvagem das variedades das variantes? Não o da engenharia de alta qualidade e do profissionalismo.

Desperdício de Software

Enquanto o incrível aumento no poder de hardware foi muito benéfico para uma ampla gama de aplicações (pensamos em administração, bancos, ferrovias, companhias aéreas, sistemas de orientação, engenharia, ciência), o mesmo não pode ser dito em relação à engenharia de software. Certamente, a engenharia de software tem se beneficiado também das muitas ferramentas sofisticadas de desenvolvimento. Mas a qualidade de seus produtos dificilmente reflete sinais de grande progresso. Não é à toa: afinal, o aumento do próprio poder foi a razão para o crescimento assustador da complexidade. Qualquer que seja o  progresso feito na metodologia de software, este será rapidamente compensado pela maior complexidade das tarefas. Isto é refletido pela Lei de  Reiser: "O software se torna lento mais rapidamente do que o hardware se torna rápido". Na verdade, novos problemas têm sido resolvidos, mas são tão difíceis que os engenheiros têm muitas vezes de ser admirados mais por seu otimismo e coragem do que por seu sucesso.

O que aconteceu em engenharia de software era previsível e inerente a um campo da engenharia, onde a demanda cresce, o trabalho é feito sob pressão (de tempo), e o custo dos recursos está quase desaparecendo. A conseqüência é o desperdício de recursos baratos - ciclos de processador e bits de armazenamento - resultando em um código ineficiente e dados volumosos. Este desperdício se torna cada vez mais presente e representa uma grave falta de senso de qualidade. A ineficiência dos programas é facilmente coberta pela obtenção de processadores mais rápidos, e o projeto precário da estrutura de dados é compensado pela utilização de dispositivos de armazenamento maiores. Mas seus efeitos colaterais são a diminuição da qualidade - de robustez, confiabilidade e facilidade de uso. Bom, um projeto cuidadoso é demorado e dispendioso. Mas ainda é mais barato do que o do não confiável e complicado, quando o custo de "manutenção" não está contabilizado  A tendência é inquietante, e assim é a complacência de clientes.

Reflexões Pessoais e Conclusões

O que podemos fazer para liberar essa sobrecarga? Há pouca vantagem em ler a história, a menos que estejamos dispostos a aprender com ela. Por isso, atrevo-me a refletir sobre o passado e tentar tirar algumas conclusões. Um esforço principal deve ser a educação com um sentido de qualidade.
Os programadores devem estar engajados na cruzada contra a complexidade de fabricação caseira. O crescimento canceroso da complexidade não é uma coisa para ser admirada, ele deve ser combatido sempre que possível [17]. Programadores devem dispor de tempo e respeito para produzir um trabalho de alta qualidade. Isso é fundamental e, ultimamente, é mais eficaz do que as melhores ferramentas e regras. Vamos iniciar um esforço global para impedir que o software se torne conhecido como softwaste!

Recentemente eu tenho me familiarizado com alguns projetos onde grandes sistemas operacionais comerciais foram descartados em favor do Sistema Oberon, cujo principal objetivo foi a clareza e a concentração no essencial [18]. Os líderes do projeto, sendo obrigados a entregar um software confiável e econômico, reconheceram que eram incapazes de fazê-lo, - mesmo com todo o cuidado – tendo que construir o seu trabalho em cima do software de base complexo - uma plataforma - que nem era totalmente descrita, nem segura. Nós sabemos que qualquer corrente é tão forte quanto seu elo mais fraco. Isso vale também para as hierarquias de módulos. Os sistemas podem ser projetados com cuidado e profissionalismo, mas continuarão sujeitos a erros se construídos sobre uma plataforma complexa e pouco confiável.

A louca corrida por uma maior complexidade - eufemisticamente chamada de sofisticação - há muito tempo também se apropriava do instrumento mais importante do engenheiro de software. Linguagens modernas como Java e C # podem ser melhores do que as antigas como Fortran, PL / I e C, mas estão longe de serem perfeitas, e elas poderiam ser muito melhores. Seus manuais de várias centenas de páginas são um sintoma inequívoco da sua inadequação. Engenheiros na indústria, no entanto, raramente são livres de restrições. Supostamente, eles devem ser compatíveis com o resto do mundo, e se desviar dos padrões estabelecidos pode ser fatal.

Mas isso não pode ser dito sobre as universidades. É, portanto, um fato triste que elas têm permancido inativas e complacentes. Não só tem a pesquisa em linguagem e metodologia de projeto perdido o seu glamour e atratividade, mas pior, as ferramentas comuns na indústria tem sido discretamente adotadas sem debate e crítica. As linguagens atuais podem ser inevitáveis na indústria, mas para ensinar, para uma introdução fundamentada, ordenada, estrutrada e sistemática, elas são totalmente erradas e obsoletas.

Isto está notavelmente de acordo com as tendências do século 21: Nós ensinamos, aprendemos e realizamos apenas o que é imediatamente rentável, o que é solicitado pelos alunos. Em poucas palavras: Nós focamos no que vende. Universidades eram tradicionalmente isentas desta corrida comercial. Eram lugares onde as pessoas deviam refletir sobre o que interessa a longo prazo. Elas eram líderes espirituais e intelectuais, mostrando o caminho para o futuro. Em nossa área de computação, estou com medo, elas simplesmente tornam-se seguidores dóceis. Elas parecem ter sucumbido ao anseio da moda para a inovação contínua, e ter perdido de vista a necessidade do trabalho cuidadoso.

Se podemos aprender alguma coisa com o passado, é que a ciência da computação é na essência uma questão metodológica. É suposto desenvolver  técnicas (ensináveis) e conhecimento que são geralmente benéficos em uma ampla variedade de aplicações. Isso não significa que a ciência da computação deva derivar para todas estas aplicações diversas e acabe perdendo a sua identidade. A engenharia de software seria a principal beneficiária de uma educação profissional em programação disciplinada. Entre suas feramentas, as linguagens figuram na vanguarda. Uma linguagem com construções adequadas e estrutura, suportada por abstrações limpas, contribui para a construção de artefatos e é essencial na educação. A complexidade caseira e  artificial não tem lugar entre essas linguagens. E finalmente: Deve ser um prazer trabalhar com elas, porque elas nos permitem criar artefatos que podemos mostrar e nos orgulhar.

Referências

1. P. Naur and B. Randell, Eds. Software Engineering. Report on a Conference held in   Garmisch, Oct. 1968, sponsored by NATO
2. E.W. Dijkstra. Some critical comments on advanced programming. Proc. IFIP
Congress, Munich, Aug. 1962.
3. R.S. Barton. A critical review of the state of the programming art. Proc. Spring Joint
Computer Conference, 1963, pp 169 – 177.
4.. E. W. Dijkstra. Notes on structured programming. In Structured Programming.
O.-J. Dahl, E. W. Dijkstra and C.A.R. Hoare, Acad. Press, 1972.
5. C.A.R. Hoare. Notes on data structuring. In Structured Programming. O.-J. Dahl, E.
W. Dijkstra and C.A.R. Hoare, Acad. Press, 1972.
6. N. Wirth. The Programming Language Pascal. Acta Informatica 1, (1971) 35 - 63
7. E. W. Dijkstra, Cooperating sequential processes. Sept. 1965. Reprinted in
Programming Languages, F. Genuys, Ed., Acad. Press, New York, 1968, 43-112.
8. C.A.R. Hoare. Communicating sequential processes Comm. ACM, 21, 8 (August
1978) pp. 666 - 677.
9. J.G.P. Barnes. An Overview of Ada. Software - Practice and Experience, 10 (1980) 851 – 887.
10. R.W. Floyd. Assigning meanings to programs, Proc. of Symp. in Applied
Mathematics., 19 (1967), pp. 19-32
11. C.A.R. Hoare. An axiomatic basis for computer. Comm. ACM, 12, 10 (October
1969), pp. 576 - 580
12. E. W. Dijkstra. Guarded commands, nondeterminacy and formal derivation of
programs. Comm. ACM, 18, 8, pp. 453–457, August 1975.
13. D. L. Parnas. Abstract types defined as classes of variables. ACM Sigplan
Notices II 2, 149 - 154 (1976)
14. B. Liskov and S. Zilles. Programming with abstract data types. Proc. ACM SIGPLAN symposium, Santa Monica, 1974, pp. 50-59.
15. N. Wirth. Programming in Modula-2. Springer, 1974. ISBN 0-387-50150-9.
16. C.P. Thacker et al. Alto: A personal computer. Xerox PARC, Tech. Rep CSL-79-11
17. N. Wirth. A plea for lean software. IEEE Computer, Feb. 1995, pp. 64-68.
18. M. Franz. Oberon: The overlooked Jewel. In L. Boszormenyi, J. Gutknecht, G.
Pomberger. The School of Niklaus Wirth. ISBN 1-55860-723-4 and 3-932588-85-1.


domingo, 1 de julho de 2012

Sobre a crueldade de ensinar realmente a ciência da computação


                               Sobre a crueldade de ensinar realmente a ciência da computação
                                                         Edsger Wybe Dijkstra

                         Tradução: Professor João Carlos de A. R. de Oliveira – DCC/UFJF

      A segunda parte dessa palestra persegue algumas das consequências científicas e educacionais da suposição de que os computadores representam  uma  novidade  radical.   Para dar a essa suposição um  conteúdo claro, nós devemos ser muito mais precisos em  relação  ao  que queremos  dizer,  nesse  contexto,  com  o  adjetivo "radical".  Faremos  isso  na  primeira  parte  dessa  palestra,  onde   também  forneceremos a evidência para suportar a nossa suposição.       
      O modo usual no qual hoje planejamos o amanhã é no vocabulário de ontem.  Assim fazemos porque tentamos usar os conceitos que nos são familiares   e   que  adquiriram  seus  significados  em  nossa  experiência passada.  Obviamente, as palavras e os conceitos não se ajustam perfeitamente porque nosso futuro difere do nosso passado,  mas então nós esticamos um pouco.  Os lingüistas estão bastante familiarizados com o fenômeno de que o significado das palavras evolui no tempo, mas também sabem que isso é um processo lento e gradual.
       É o modo mais comum de tentar enfrentar a novidade: por meio de metáforas e analogias, tentamos ligar o novo ao velho, a novidade ao familiar.  Sob mudanças suficientemente lentas e graduais, isso funciona razoavelmente bem; no caso de uma descontinuidade repentina, contudo,  o  método se quebra: embora possamos glorificá-la com o nome "senso comum", nossa  experiência  passada  não  é  mais  relevante,  as analogias se tornam pobres e as metáforas enganam mais que iluminam.  Esta é a situação característica da novidade "radical".   
       Enfrentar a novidade radical requer um método ortogonal.  É preciso considerar o passado, as experiências coletadas e os hábitos formados como um infeliz acidente da história, e abordar a novidade radical com a mente em branco, conscientemente se recusando a tentar ligá-la ao que já é familiar, uma vez que o familiar é irremediavelmente inadequado. É preciso inicialmente, com uma espécie de personalidade dividida, se inteirar da novidade radical como um tópico dissociado.    Inteirar-se  de  uma novidade radical é como criar e  aprender uma língua estrangeira que  não pode  ser traduzida para a língua natal. (Quem já aprendeu mecânica quântica sabe o que estou dizendo.)  É  desnecessário  afirmar  que  o  ajuste  às  novidades  radicais não é atividade popular, porque ele requer trabalho árduo. Pela mesma razão, as próprias novidades radicais não são bem-vindas.
      Nesse momento você deve estar se perguntando porque eu dediquei tanta atenção e gastei tanta eloqüência à simples e óbvia noção da novidade  radical.    Minha  justificativa  é  muito simples: as  novidades radicais são tão perturbadoras, que  elas  tendem  a  ser  suprimidas  ou  ignoradas,  a ponto de mesmo a possibilidade de sua  existência em geral ser mais freqüentemente negada que admitida.
      Quanto à evidência histórica, devo ser breve.  Carl Friedrich Gauss, o Príncipe da Matemática, mas também um tanto covarde, certamente conhecia  o  destino de Galileu - e provavelmente poderia ter  previsto a calúnia contra Einstein - quando decidiu suprimir a descoberta da geometria não-Euclidiana, deixando assim para Bolyai e Lobatchewsky receberem o bombardeio.  Provavelmente é iluminador  voltar um pouco mais até a Idade Média.  Uma de suas características era que o "raciocínio por analogias" era peremptório; outra característica era a quase total estagnação intelectual, e agora vemos porque as duas andam juntas.  Uma razão para mencionar isso é assinalar que ao se desenvolver uma audição apurada para as analogias   descabidas é possível detectar muito pensamento medieval atualmente.
      O outro ponto que não me canso de frisar é que a fração da população para a qual a mudança gradual parece ser o único  paradigma  da história é muito grande, provavelmente muito maior do que você possa esperar.  De fato, quando comecei a observar isso, seu número se mostrou muito maior do que eu imaginava.
      Por exemplo, a vasta maioria da comunidade matemática nunca questionou a sua suposição tácita de que praticar matemática continuará sendo o mesmo tipo de atividade mental que sempre foi: novos tópicos aparecem, florescem e se vão como no passado, mas, sendo o cérebro humano o que é, nossos modos de ensinar, aprender e entender matemática, de resolver problemas e de descobrir novas áreas da matemática continuarão praticamente os mesmos.  Herbert Robbins declara francamente porque ele descarta a possibilidade de um salto quântico na habilidade matemática:
        "Ninguém consegue correr 100 metros em cinco segundos, não importando o quanto foi investido em treinamento e maquinário.  O mesmo pode ser dito sobre o uso do cérebro.  O cérebro humano hoje não é diferente do que foi a cinco mil anos  atrás.   E quando ele se dedica à matemática, você  deve compreender que aí a mente humana está no limite máximo de sua capacidade." Meu comentário na margem foi: "então, reduza o  uso  do  cérebro  e  calcule !".  Usando  a analogia de Robbins, pode-se constatar que,  para ir de A até B rapidamente, hoje existem alternativas que são ordens de magnitude mais efetivas.  Robbins com certeza se nega a reconhecer qualquer alternativa ao uso tradicional do cérebro com a expressão "praticar matemática", assim exorciza o perigo da novidade radical com o simples dispositivo de ajustar suas definições às suas necessidades: simplesmente, por definição, a matemática continuará sendo o que sempre foi.  Demais para os matemáticos.    
      Deixe-me dar apenas mais um exemplo do descrédito generalizado a respeito da existência das novidades radicais e, por isso, a necessidade de aprender como enfrentá-las.  É a prática educacional  predominante, onde a mudança gradual, quase imperceptível, parece ser o único paradigma.  Quantos textos educativos não são recomendados por seus apelos à intuição dos estudantes !  Tenta-se constantemente apresentar tudo que poderia ser novidade excitante como algo  tão familiar quanto possível.  Conscientemente, tenta-se ligar o material novo ao suposto mundo familiar do estudante. Isso já começa   no ensino da aritmética.  Ao invés de se ensinar que 2 + 3 = 5, o  repugnante operador aritmético "mais" é cuidadosamente disfarçado,   sendo chamado "e", são dados aos garotos primeiramente um monte de exemplos familiares, com objetos claramente visíveis, tais como  pêras e maçãs que são dentro em contraste aos objetos igualmente enumeráveis tais como porcentagens e elétrons, que são fora.  A mesma tradição deplorável se reflete no nível universitário em diferentes cursos introdutórios de cálculo, para o futuro físico, arquiteto ou administrador, cada qual adornado com exemplos de seus respectivos campos. O dogma educacional parece ser que tudo vai bem desde  que o estudante não perceba que está aprendendo alguma coisa realmente nova; com freqüência, a impressão do estudante é de fato correta. Considero a falha de uma prática educacional na preparação da futura geração para o fenômeno das novidades radicais um sério defeito. (Quando o Rei Fernando visitou a universidade conservadora de Cervera,  o  reitor  assegurou  orgulhosamente ao monarca: "Longe de nós, Senhor, a perigosa novidade  do  pensar".    Os  problemas  da Espanha, no século seguinte, justificam a minha caracterização do defeito como "sério".) Demais para a adoção na educação do paradigma da mudança gradual. 
      O  conceito  das  novidades  radicais  é relevante atualmente  porque, embora estejamos mal preparados para enfrentá-las, a ciência e a tecnologia têm se mostrado especialistas em nos infligi-las. Exemplos mais antigos são a teoria da  relatividade  e  a  mecânica  quântica; exemplos tecnológicos mais recentes são a bomba atômica e a pílula.  Durante décadas os dois primeiros deram origem a uma torrente de panfletos religiosos, filosóficos ou quase-científicos.  Podemos observar diariamente a maneira profundamente inadequada de  se abordar as últimas duas, seja por líderes governamentais ou religiosos, seja pelo público em geral.  Demais para os danos causados  à paz de nossas mentes pelas novidades radicais.
       Eu levantei tudo isso porque acredito que os computadores automáticos representam uma novidade radical e que somente identificando-os como tal, podemos constatar a tolice, a falsa noção e a  mitologia que os cerca.  Uma inspeção cuidadosa revelará que a situação é até pior, os computadores automáticos incorporam não apenas uma novidade radical, mas duas delas.
       A primeira novidade radical é uma conseqüência direta da potência dos equipamentos computacionais atuais.  Nós todos sabemos como enfrentar algo grande e complexo: dividir e reinar, isto é: nós vemos  o  todo como uma composição de partes e lidamos com cada  parte separadamente.  E se a parte é muito grande, nós repetimos  o  procedimento.    A    cidade  é  composta  de  quarteirões, que são  estruturados em ruas, que contém prédios, que são feitos de paredes e pisos,  estes  de  tijolos, etc., chegando eventualmente até as partículas elementares.  E nós temos nossos especialistas ao longo do percurso, desde o planejador urbano, passando pelo arquiteto até o físico de estado sólido e além.  Uma vez que, em certo sentido o "todo" é maior que as suas partes, a profundidade da decomposição hierárquica é algo como o logaritmo da razão dos "tamanhos" do todo e da menor parte. De um bit para algumas centenas de megabytes, de um microssegundo para meia hora de computação, tudo isso nos mostra a fantástica razão de dez elevado a nove !  O programador fica em destaque, pois é a única disciplina e profissão na qual essas razões gigantescas que confundem totalmente a nossa  imaginação, têm de ser vencidas com uma única tecnologia.  Ele deve estar habilitado  a  pensar  em  termos  de hierarquias conceituais  muito mais profundas, que mente alguma jamais precisou encarar.  Comparando o número de níveis semânticos, uma teoria matemática é praticamente  plana.    Por  necessitar   hierarquias   conceituais  profundas,  o  computador  nos  apresenta  um  desafio  intelectual  radicalmente novo, sem precedente na história.
     Outra vez tenho de reforçar essa novidade radical porque o verdadeiro crente nas mudanças graduais e nos aperfeiçoamentos incrementais não consegue vê-la. Para ele, o computador é algo como a familiar caixa registradora, apenas um pouco  maior,  mais  rápido  e  mais flexível.  Mas a analogia é ridiculamente pobre: é ordens de magnitude pior que comparar a velocidade de  um  jato  supersônico  com a de um bebê engatinhando, já que a razão de velocidades é apenas mil.
       A segunda novidade radical é que o computador automático é o nosso primeiro dispositivo digital em larga escala.  Nós tínhamos alguns  poucos  com  componentes  perceptivelmente  discretos.   Eu  mencionei a caixa registradora e posso acrescentar as máquinas de  escrever e os teclados com suas teclas individuais:  com um único pressionamento, você pode produzir um Q ou um W mas, embora suas teclas estejam perto uma da outra, não produzirá uma mistura dessas duas letras.  Mas tais mecanismos são a exceção e a grande maioria de nossos  mecanismos  é  vista  como  dispositivos analógicos cujo  comportamento é uma função contínua de todos os parâmetros envolvidos em  grande  parte  de  seu domínio: se pressionarmos a ponta do  lápis mais fortemente, obteremos uma linha um  pouco  mais  grossa;  se  o violinista   desloca   seu   dedo,  ele  tocará  ligeiramente  desafinado.  A isso devo acrescentar que, se nos considerarmos como mecanismos,  nossa  natureza é primordialmente  analógica:  se nos  esforçarmos um pouco mais, esperamos ser um pouco melhores.  Muito freqüentemente, o comportamento é mais que uma função contínua, é uma função monótona: para testar se  um martelo  é  adequado  a  um  conjunto de pregos, experimentamos com o menor e o maior prego e se o resultado dos dois experimentos for positivo, poderemos acreditar cegamente que o martelo nos atenderá em todos os outros casos.
       É possível e mesmo tentador considerar um programa  como  um  mecanismo  abstrato,  como  um dispositivo de um certo tipo.  Fazer  isso, contudo, é altamente perigoso: a analogia é muito pobre porque um programa  é,  como  mecanismo, totalmente diferente de todos os  dispositivos analógicos que nos são familiares desde a infância. Como acontece  com  toda  informação  codificada  digitalmente, ele  possui inevitavelmente a desconfortável propriedade que as menores perturbações possíveis, - isto é, mudanças de um único bit - podem ter as conseqüências mais drásticas.  (Para completar, acrescento que o quadro não muda essencialmente com a introdução de redundância ou correção de erros.)  No mundo discreto da computação, não existe métrica  significativa  na  qual  "pequenas" mudanças e "pequenos"  efeitos andam juntos, e não existirá jamais.  
       Essa segunda novidade radical compartilha o destino usual de  todas novidades radicais: ela é  negada,  porque  a  verdade  seria  muito desconfortável.    Não  tenho  idéia  de  quanto esta negação  específica e esse descrédito tem custado aos Estados Unidos, mas um milhão de dólares por dia parece ser um palpite modesto.
      Tendo descrito - admito que em termos genéricos - a natureza das novidades computacionais, devo agora prover a evidência de que tais novidades são de fato radicais. Devo fazê-lo explicando alguns fenômenos, que de outra forma seriam considerados estranhos, como os esforços  furiosos  -  mas,  que  agora  sabemos  condenados  ao  fracasso - de esconder ou mesmo negar os aspectos apavorantes do não familiar.
      Alguns desses fenômenos são encontrados na "Engenharia de Software".  Da mesma forma que a  economia  é  considerada  como  a  "Ciência miserável", a engenharia de software deveria ser conhecida como a "Ciência condenada", condenada porque ela sequer atinge seu objetivo,  uma  vez  que  este  é  contraditório.   A engenharia de  software, obviamente, se apresenta como uma causa respeitável, mas isso é  ilusório:  se  você  ler  cuidadosamente a sua literatura e  analisar o que seus devotos realmente fazem, você descobrirá que a engenharia de software tem aceitado como seu mote "Como programar, se você não pode".
      A popularidade de seu nome é bastante para torná-la suspeita. Nas consideradas "sociedades primitivas", é comum a supertição de  que se você conhece alguém por seu nome verdadeiro, você passa a ter um poder mágico sobre ele.  E nós também somos um tanto primitivos: Por que persistimos em atender o telefone com o inútil "alô" em vez do nosso nome ?    Nem  estamos  salvos  da  supertição  igualmente  primitiva  de  que  podemos  exercer  um certo controle sobre algum  demônio desconhecido e malicioso simplesmente chamando-o com um nome seguro, familiar e inocente como "engenharia".  Mas isso é totalmente  simbólico,  como  demonstrado  por   um   fabricante   de  computadores americano alguns anos atrás, quando contratou da noite para o dia centenas  de  novos  "engenheiros  de  software"  com  o  simples artifício de elevar todos os seus programadores à nobre categoria.  Demais para esse termo.
       A prática é mantida pela ilusão assegurada de que programas são dispositivos como quaisquer outros, a única diferença admitida é que a sua produção requer um novo tipo de artesão, o programador. Daí, um pequeno passo para se medir a "produtividade do programador" em termos do número de linhas de código produzidas por mês.  Esta é uma unidade de medida muito custosa porque encoraja a escrita de código insípido, mas atualmente estou menos interessado em quão tola uma unidade é, mesmo de um ponto de vista puramente gerencial.   Minha sugestão atualmente é que, se desejamos contar linhas de código, nós não devemos considerá-las "linhas produzidas" mas "linhas gastas";  a  sabedoria  convencional corrente é tão tola a ponto de  contabilizá-las nas colunas trocadas.
       Juntamente com a noção de produtividade, também a de controle de qualidade continua a ser distorcida pela  ilusão  assegurada  de  que se  funciona  com  outros dispositivos funcionará também com  programas.  Já fazem duas décadas  a  demonstração  de  que  testar  programa pode mostrar convincentemente a presença de erros, mas nunca a sua ausência.  No entanto, após citar devotamente essa constatação, o engenheiro de software retorna à sua mesa de trabalho e continua o refinamento  de  suas  estratégias  de  teste,  como  o  alquimista de outrora, que continuava a refinar suas purificações crisocósmicas.      O  desentendimento  impenetrável  aparece  mais  no  termo  "manutenção de software"; como resultado, muitas pessoas continuam acreditando que os programas - e mesmo linguagens de programação estão sujeitos a ficarem gastos com o uso.  Seu carro necessita manutenção, não é ?  Ficou famosa a história de uma companhia de petróleo que pensou que seus programas PASCAL não  durariam  tanto  quanto os seus programas FORTRAN "porque o PASCAL não tinha manutenção".
       Ainda no mesmo tema, devo chamar a atenção para a admirável aceitação com que a  sugestão  é  aceita,  de  que  o  problema  da  produção  de  software  decorre grandemente da falta de adequadas "ferramentas de programação".  (O termo revelador "workbench" -  cadeira de trabalho - rapidamente apareceu.)  Novamente, a analogia subjacente é muito pobre, apropriada à Idade Média.  Confrontado  com as "ferramentas" insípidas de "animação de algoritmos", meu julgamento não foi alterado; ao contrário, confirmei minha suspeita de que lidamos aí com mais uma dimensão do negócio óleo-de-cobra.
       Finalmente, para corrigir a possível impressão de que a inabilidade  de  enfrentar  a novidade radical está confinada ao mundo  industrial, deixe-me oferecer uma explicação para a popularidade ao menos americana - da Inteligência Artificial.  É razoável que o povo se sinta ameaçado pelos "cérebros  gigantes  ou  máquinas  que  pensam".     De  fato,  o  apavorante  computador  se  torna  menos  apavorante se ele for usado apenas para  simular um não-computador  familiar. Tenho certeza que essa explicação permanecerá controversa por muito tempo, uma vez que a Inteligência Artificial imitando a mente humana prefere se ver na linha de frente, enquanto a minha explicação a relega para  a  retaguarda.    (Os  esforços  de  usar  máquinas para imitar a mente humana sempre me pareceram tolos.  Eu as usaria para imitar coisa melhor.)
       Demais para a evidência de que as novidades computacionais são de fato radicais. E agora vem a segunda  -  e  mais  difícil  -  parte de minha palestra: as conseqüências científicas e educacionais do exposto acima.  As conseqüências educacionais são, é claro, mais  cabeludas, assim vamos postergar sua discussão e nos concentrarmos na ciência da computação.  O que é computação ?  De  que  trata  a ciência da computação ?   
       Bem, quando tudo já foi dito e feito, a única coisa que  os  computadores podem fazer para nós é manipular símbolos e produzir resultados de tais manipulações.  De nossas observações anteriores, devemos lembrar que isso se passa em um mundo discreto e mais, que tanto o número  de  símbolos  envolvidos  quanto  a  quantidade  de  manipulação  executada  é ordens de magnitude maior do que nós podemos imaginar:  eles confundem totalmente a nossa imaginação, portanto devemos tentar não imaginá-los.
       Porém, antes de um computador estar pronto para realizar uma classe de manipulações significativas - ou cálculos, se você prefere - nós devemos escrever um programa.  Que é programa ?  Muitas respostas  são  possíveis.   Podemos encarar  o programa como sendo  aquilo que transforma um computador de propósito geral em um mani-  pulador de símbolos de propósito específico e faz isso sem necessidade de mudar um único fio. (Isto foi um aperfeiçoamento enorme em relação às máquinas onde o arranjo das fiações do painel era dependente do programa.)  Prefiro  descrevê-lo  de  outro ponto  de vista:  o  programa é um manipulador de símbolos abstrato, que pode  se concretizar ao se fornecer um computador para ele.    Afinal  de  contas, os programas não mais são feitos para instruir nossas máquinas; atualmente, o propósito das máquinas é executar nossos programas.  
       Assim, temos de projetar manipuladores abstratos de símbolos. Todos sabemos  como eles se parecem: programas ou - para usar uma terminologia mais geral  -  fórmulas  elaboradas  a  partir  de  um  sistema formal.  Realmente é útil ver um programa como uma fórmula. Primeiramente,  isso  coloca  a  tarefa  do  programador   em   sua  perspectiva  adequada: ele tem de deduzir essa fórmula.  Em segundo  lugar, explica porque  o  mundo  matemático  ignora  o  desafio  da  programação: os programas são fórmulas tão maiores do que as que  eles estão acostumados a ponto de não serem reconhecidas como tais. De volta  ao  trabalho do  programador:  ele  tem  de deduzir essa  fórmula, ele tem de deduzir esse programa.  Nós  conhecemos  apenas  uma maneira confiável de fazer isso, a saber: por meio de manipulação de símbolos.  E agora o círculo se fecha:  construímos  nossos manipuladores  mecânicos  de  símbolos  por  meio  de  manipulações  humanas de símbolos.       
        Assim, a ciência da computação está - e sempre estará - envolvida com a relação entre a manipulação mecânica e humana de símbolos,  usualmente  referidas  como  "computação" e "programação",  respectivamente.  Um benefício imediato dessa percepção é que ela revela a contradição em termos da "programação automática".  Outro benefício é que ela nos dá uma indicação clara de onde localizar  a  ciência da computação no mapa mundial das disciplinas intelectuais:  na direção da matemática formal e da lógica aplicada, só que muito mais distante  de onde elas estão atualmente, uma vez que a ciência  da computação está  interessada  no  uso    efetivo    dos  métodos  formais, em escala muito maior do que a verificada até então.  Uma vez que nenhum empreendimento é respeitado atualmente sem uma STL  ( = Sigla de Três Letras), eu proponho que adotemos para a ciência da computação, a IMF ( = Iniciativa dos Métodos Formais) e, por motivos de segurança,  devemos seguir os  exemplos iluminadores de  nossos líderes e registrar a marca.
        A  longo  prazo,  eu  espero  que  a  ciência da computação  transcenda  suas  disciplinas  ancestrais,  matemática  e   lógica,  realizando   efetivamente  uma  significativa  parte  do  sonho  de  Leibniz,  de  prover  um  cálculo  simbólico  como  alternativa  ao  raciocínio  humano.  (Por  favor, note a diferença entre "imitar" e  "prover uma alternativa a": as alternativas podem ser melhores.)   
        Desnecessário dizer que esta visão do que realmente seja a ciência  da  computação  não  é  universalmente  aplaudida.    Pelo  contrário,  ela  tem  encontrado  larga  -  e  algumas  vezes  mesmo violenta - oposição vinda de  todas  as direções.    Menciono  como  exemplos: (0) a corporação matemática, que continua a acreditar que o  sonho  de Leibniz é uma ilusão irrealista.         (1) a comunidade de negócios, que tendo comprado a idéia de que  os  computadores  fariam  a  vida  ficar  mais  fácil, fica mentalmente  despreparada para aceitar que eles  resolvem  os  problemas  fáceis  com o custo de criar outros muito mais difíceis. (2) a sub-cultura do programador compulsivo,  cuja  ética  prescreve que uma   idéia   vulgar  e  um  mês  de  codificação  furiosa  são  suficientes para torná-lo milionário a longo prazo. (3) a engenharia  de  computação,  que continua a agir como se tudo  se resumisse a maiores taxas de bits e mais comutações por segundo (4) os  militares  agora  totalmente  absorvidos  nos  negócios  de transformar  orçamentos de bilhões de dólares na ilusão da segurança automática    (5) todas  as  ciências  suaves  ("soft  sciences") para as quais a  computação funciona como um tipo de abrigo interdisciplinar. (6) os  empreendimentos educacionais que percebem que se tiverem de  ensinar matemática formal para seus alunos de ciência da computação, logo fecharão suas escolas.
       E com o sexto exemplo, eu atingi imperceptivelmente, mas também inevitavelmente,  a  parte  mais  cabeluda  dessa  palestra: as  conseqüências educacionais.  
       O problema com a política educacional é que ela raramente é influenciada por considerações científicas derivadas dos tópicos pensados e é quase inteiramente  determinada  pelas  expectativas combinadas dos alunos, seus pais e seus futuros empregadores, e a visão predominante sobre o papel da universidade: é o aborrecimento de treinar seus graduandos para o primeiro emprego, ou prover seus alunos com a bagagem intelectual e  atitudes  que  permanecerão com  eles nos  próximos  50 anos.  De má vontade, alocamos as ciências  abstratas numa esquina distante no campus, ou as reconhecemos como motor indispensável  da  indústria  da  alta tecnologia ?  Mesmo se  assim fizermos, reconheceremos uma indústria de alta tecnologia como tal, se a sua tecnologia pertence principalmente  à  matemática formal ?  As universidades oferecem para a sociedade as lideranças intelectuais que ela necessita ou apenas o treinamento que ela pede ?
       A retórica acadêmica tradicional prontamente dá a essas questões respostas  tranqüilizadoras,  mas não acredito nelas.  A título de ilustração de minhas dúvidas, em recente artigo "Quem regula o Canadá ?", David H. Flaherty repentinamente declara: "Ademais, a elite dos  negócios  despreza  os  acadêmicos  tradicionais  e   os  intelectuais, considerando-os totalmente irrelevantes e sem poder".
       Então, se eu olhar para  minha  enevoada  bola  de  cristal,  para ter  uma  idéia  sobre  o  futuro  da  educação  na ciência da  computação, vejo predominar o depressivo quadro de "negócios, como sempre".  As universidades continuarão sem coragem para ensinar a ciência austera ("hard science"), elas continuarão a desorientar os estudantes e cada novo estágio de infantilização do currículo será saudado como progresso educacional.      
       Eu já tenho minha enevoada bola de cristal por longo tempo. Suas previsões são invariavelmente sombrias  e  usualmente  corretas mas já estou suficientemente acostumado com elas e não me impedirão de dar-lhe algumas sugestões, mesmo se isso for meramente um exercício de  futilidade  cujo  único  efeito  é  fazer  você se sentir  culpado.        Nós poderíamos, por exemplo, começar limpando nossa linguagem não mais chamando "bug" de bug, mas de  erro.    É  muito  mais  honesto,  pois  coloca  a culpa exatamente em quem deve, a saber, o  programador que fez o erro.  A metáfora animista do inseto ("bug") que imiscui-se  maliciosamente  enquanto  o  programador  não  está  olhando é intelectualmente desonesta porque ela  tenta  esconder  o  fato de  que  o erro é criação do programador.  O aspecto agradável  dessa simples mudança de  vocabulário  é  que  ela  tem  um  efeito  profundo:  Enquanto,  anteriormente,  um programa com apenas um bug  era considerado "quase correto", agora um programa com um erro é simplesmente "incorreto" (porque está errado).
       A minha próxima sugestão lingüística é mais rigorosa.  É combater a síndrome: "Se-esse-cara-quer-falar-com-aquele-cara":  nunca  se refira a partes de programa  ou  peças   de   equipamento   com  terminologia  antropomórfica,  nem  permita  que seus alunos façam.  Esse aperfeiçoamento  lingüístico  é  muito  mais  difícil  de  ser  implementado do que você pensa, e o seu departamento pode considerar a introdução de multas por violação, digamos 25 centavos para estudantes  de  graduação,  50  para  estudantes de pós-graduação e 5  dólares para os professores;  no fim do primeiro  semestre  do novo regime,   vocês   terão  coletado  dinheiro  suficiente  para  dois  bolsistas.       
        A  razão  para  esta  última  sugestão  é  que  a metáfora  antropomórfica - cuja introdução se deve a John von Neumann - é um  enorme  obstáculo  para  toda comunidade  de computação que a tenha  adotado.  Tenho encontrado atualmente programas querendo  coisas,  conhecendo coisas, esperando coisas, acreditando em coisas etc, e em todos os casos  isso  deu  origem  a  confusões  evitáveis.    A  analogia  subjacente  a essa personalização é tão superficial que   além de enganar ela tem efeito paralisante.
        Ela engana, no sentido de sugerir que é adequado confrontar o discreto não familiar em termos do contínuo familiar, isto é: nós  próprios, oh não.  Ela paralisa no seguinte sentido: uma vez que as pessoas existem e agem  no tempo,  sua adoção efetivamente impede a desvinculação  com  a  semântica  operacional  e  assim  força as  pessoas a considerar os programas em termos de  seus  comportamentos computacionais,  baseados  em  um  modelo computacional subjacente.  Isso é ruim, porque o raciocínio operacional é uma  tremenda  perda  de esforço mental.  
       Deixe-me explicar para você a natureza dessa tremenda perda e me permita  tentar  convencê-lo  que  "tremenda  perda de esforço  mental"  não é  um exagero.    Por  um  instante,  devo  me  tornar  altamente  técnico,  mas não se  sinta  amedrontado: é o tipo de  matemática que se pode fazer com as mãos nos bolsos.  Devo salientar que se  temos  de  demonstrar  alguma  coisa  a respeito de  todos  elementos de um grande conjunto, é desesperançosamente ineficiente lidar com   todos  os  elementos  do  conjunto  individualmente:  o  argumento eficiente não se refere aos elementos mas é construído em termos da definição do conjunto.  
       Considere a figura plana Q definida como um quadrado de 8 por 8 do qual foram removidos os dois quadrados 1 por 1 em dois cantos opostos.  A área de Q é 62, igual à área combinada de 31 dominós de tamanho 1 por 2.    O  teorema  é  que  a  figura  Q  não pode ser  coberta com 31 dominós. 
      Outra  forma  de  enunciar  o  teorema é: se você tomar um  papel quadriculado e começar a cobri-lo colocando cada dominó em  dois quadrados adjacentes, nenhuma disposição dos 31 dominós fornecerá a figura Q. 
      Então, uma possível maneira de provar o teorema é gerar todas as possíveis configurações de dominós e mostrar que em cada disposição a figura Q não é obtida: um trabalho tremendamente cansativo.
      O argumento simples, contudo, é o seguinte: colorimos os quadrados do papel quadriculado imitando um tabuleiro de xadrez.  Cada dominó cobrindo dois quadrados adjacentes, cobrirá um quadrado branco e um preto, e por isso cada configuração cobrirá o mesmo número  de quadrados brancos e pretos.  Porém, na figura Q o número de quadrados brancos difere do número de quadrados pretos em dois - uma  vez que os cantos opostos estão na mesma diagonal - e por isso  nenhuma configuração dos dominós fornece a figura Q.      
      O simples argumento acima  não  apenas  é  muitas  ordens  de  magnitude menor que a exaustiva investigação das possíveis configurações de 31 dominós, mas é também  essencialmente  mais  poderoso,  uma vez  que  ele  permite  a  generalização  de  Q,  substituindo o quadrado original de 8 por 8 por qualquer retângulo    cujos  lados  tenham  comprimento  par. Uma vez que o número de tais retângulos é  infinito,   o   método   anterior   de   exploração   exaustiva   é  essencialmente inadequado para provar nosso teorema geral.
      E isso conclui meu exemplo.  Ele foi apresentado porque ilustra com   poucas   palavras   o   poder   da   matemática   básica;  desnecessário dizer que negar-se a explorar o poder dessa matemática básica  é como cometer suicídio intelectual e tecnológico.  A moral  da história é: trate todos os elementos de um conjunto ignorando-os e trabalhando com a definição do conjunto.
      Voltando à programação.  A declaração que  um  dado  programa  atende  a  sua  especificação  equivale  à  declaração a respeito de todas  as computações que podem ocorrer sob controle do programa. E uma vez  que  esse  conjunto  de computações é definido pelo dado  programa, nossa recente moral afirma: trate todas as computações possíveis sob controle de um dado programa ignorando-as e trabalhe com o programa.  Nós precisamos aprender a trabalhar com os textos de programas ignorando (temporariamente) que eles admitem a interpretação de código executável.
      Outra  maneira  de  dizer  a  mesma  coisa:  Uma linguagem de  programação, com sua sintaxe formal e as regras que definem  a  sua  semântica, é um sistema formal para o qual a execução do programa provê apenas um modelo.  É bem sabido que os sistemas formais devem ser tratados como um todo e não em termos de um modelo específico. E, outra vez, o corolário é que nós devemos raciocinar a respeito  de programas sem mencionar os seus "comportamentos".
      E isso conclui minha incursão técnica na motivação porque o raciocínio  operacional  a  respeito  de  programas é "uma tremenda  perda de esforço mental"  e  porque  na  ciência  da  computação  a  metáfora antropomórfica deve ser banida.
      Mas nem todos entendem isso suficientemente bem. Recentemente assistí uma demonstração de um suposto software educacional para um curso introdutório de programação. Com suas "visualizações" na tela, era um caso óbvio de infantilização de currículo, que seu autor deveria ser incriminado por "assédio ao corpo discente", mas  isso  é  pouco se  comparado  com  a finalidade das visualizações: elas eram  usadas para mostrar todas as espécies de computações invocadas pelo programa do estudante !  O sistema salientava precisamente o que o estudante precisa aprender a ignorar, ele  reforçava  justamente  o  que o estudante  precisa  desaprender.   Uma vez que desfazer-se de  antigos maus hábitos em vez de adquirir novos é a parte mais penosa  do aprendizado,  devemos  esperar  desse  sistema  um  dano mental permanente à maioria dos estudantes expostos a ele.
      Desnecessário  dizer,  aquele sistema esconde completamente o  fato que um programa por si só é uma  meia  conjectura.    A  outra  metade é a especificação funcional que o programa deve satisfazer. A tarefa do programador é apresentar essa conjectura completa como teoremas provados.
      Antes de terminar, gostaria  de  convidá-lo  a  considerar  a  seguinte maneira de se encarar a novidade radical da programação em um curso introdutório.    
      Por  um  lado,  ensinamos  algo  parecido  com  o cálculo dos  predicados, mas o fazemos de maneira muito diferente da usada pelos  filósofos.    A  fim  de  treinar  o programador novato a manipular  fórmulas não interpretadas, nós ensinamos o cálculo dos predicados mais como álgebra booleana, familiarizando o estudante com todas as propriedades algébricas dos conectivos lógicos.  Para cortar os vínculos com a intuição, renomeamos os valores { verdadeiro,falso } do domínio booleano para { preto,branco }.
      Por outro lado, ensinamos uma linguagem de programação imperativa simples e limpa, com as instruções básicas de salto e atribui-  ção múltipla, com uma estrutura de bloco para as variáveis locais, o ponto-e-vírgula como operação de composição de instruções, uma construção alternativa adequada, uma repetição e, se desejado, uma chamada de procedimento.  A isso acrescentamos um mínimo  de  tipos  de dados, a saber: booleanos, inteiros, caracteres e cadeias.  O essencial  é  que,  seja  o  que  for  introduzido,   a   semântica  correspondente é definida pelas regras de prova que vão junto.
      Desde o início e sempre no curso reforçamos que a tarefa  do  programador  não  é apenas escrever um programa, mas apresentar uma  prova formal de que o  programa  proposto  atende  a  especificação  igualmente formal.  Projetando provas e programas simultaneamente, o estudante obtém ampla oportunidade de aperfeiçoar a sua habilidade com o cálculo dos predicados.  Finalmente, com o objetivo de reforçar a idéia que esse curso introdutório é primordialmente um curso de matemática formal, é preciso que a linguagem de programação em questão não  tenha sido implementada no campus, protegendo assim os  estudantes da tentação de testar seus programas. E isso conclui o esboço de minha proposta para um curso introdutório de programação.      
       Esta é uma proposta séria e muito sensata. A  única desvantagem é ser radical para muitos, que impossibilitados de aceitá-la,  são forçados a inventar uma razão rápida para desconsiderá-la,  não importando o quão inválida.  Darei a você algumas razões rápidas.  
       Você não precisa levar a minha proposta a sério porque ela  é tão ridícula que obviamente eu devo estar totalmente desvinculado  do mundo real.  Mas essa pipa não voa, pois  conheço  muito  bem  o  mundo real: os problem aplicar suas soluções efetivas. Então tentemos novamente.       
       Você não precisa levar a minha proposta a sério porque é ttalmente  irrealista  a  tentativa  de  ensinar  esse material para  jovens universitários.  Não teria um  jeito  mais  fácil  ?    Você  considera  que  isso seria muito difícil.  Mas essa pipa também não  voa porque foi provado que a sua consideração está errada: desde o início dos anos 80 tal curso introdutório de programação vem sendo dado com sucesso todos os anos para centenas de calouros.  ( Uma vez que, em minha experiência, dizer isso uma única vez não é sufciente, a frase anterior deve ser repetida ao menos duas vezes.) Então, tentemos novamente.
       Admitindo com relutância que talvez isso possa ser ensinado para estudantes suficientemente dóceis, ainda assim você rejeita a minha proposta porque tal curso desviaria demais do que os estudates de 18 anos estão acostumados e considera que infligir isso a eles seria ato de irresponsabilidade educacional: isso apenas frutraria  os  estudantes.   Desnecessário dizer, essa pipa também não  voa.  É verdade que o estudante que nunca manipulou fórmulas não interpretadas rapidamente reconhece que está diante de algo totamente diferente de tudo que ele já viu antes.  Mas felizmente as regras de manipulação neste caso são tão poucas e simples que muito cedo ele faz a descoberta excitante de que está começando a dominar  uma ferramenta que, com toda a sua simplicidade, dá a ele um poder que ultrapassa em muito seus maiores sonhos.
       Ensinar aos jovens o uso efetivo dos métodos formais é uma das alegrias da vida  porque  é  extremamente  recompensador.    Em  poucos meses eles encontram suas posições em um novo mundo com um nível de confiança radicalmente novo para  eles;  em  poucos  meses  seus conceitos de cultura intelectual adquirem uma dimensão radicamente nova.  Para o meu gosto e estilo, isso é a educação.  As unversidades não devem ter medo de ensinar as novidades radicais; pelo contrário, devem agradecer  a  oportunidade  de  fazê-lo.    A  sua  prontidão em fazê-lo é nossa salvaguarda contra as ditaduras, sejam do proletariado, dos estabelecimentos  científicos  ou  das  elites  corporativas.
       Edsger Wibe Dijkstra