Archive for the 'Teoria' Category

Mais brincadeiras com bits

Há algum tempo atrás, escrevi aqui algumas curiosidades sobre Ponto Flutuante, bits afins. Semana passada, tive que corrigir alguns pequenos bugs no meu código de leitura de buffers de bytes, e descobri outra curiosidade com operação de bits em Java. Resolvi compartilhar com vocês, apesar de saber que a grande maioria dos programadores hoje em dia considera este tipo de conhecimento inútil, já que raramente se trabalha diretamente com bits. Verdade, raramente. Mas se aconteceu comigo, pode acontecer com qualquer um. E conhecimento nunca é demais.

Vamos lá!

Em Java, todo tipo primitivo de dados (byte, short, int, long, float e double) é sinalizado, o que significa que seus valores podem ser positivos ou negativos. Um byte pode ter valor de -128 a 127, um short varia de -32768 a 32767, e assim por diante.

Já em C, tipos primitivos podem ser sinalizados ou não sinalizados. Um byte sinalizado em C pode assumir os mesmos valores que um byte em Java, mas um byte não sinalizado pode assumir valores entre 0 e 255.

Assim sendo, quando se escreve um programa em Java que deve ler dados gerados por um programa em C, é importante saber se estes dados são sinalizados ou não. O mais divertido disso tudo é que não existe forma de saber isso apenas analizando os dados, porque eles são idênticos: um byte sinalizado continua tendo 8bits e podendo armazenar 255 valores.

Neste ponto me parece interessante explicar como um número negativo é armazenado em um tipo básico. Primeiro conceito: em tipos sinalizados, o bit mais a esquerda indica o sinal: 0 positivo, 1 negativo. Mas para se obter o inverso de um número, não basta apenas mexer no bit mais a esquerda. É necessário usar um segundo conceito: complemento de 2! Para se obter o complemento de 2 de um número, basta inverter os bits e somar 1. Por exemplo, se N = 7 = 00000111, o seu complemento de 2 será 11111000+1 = 11111001. Para se obter a representação binária de um número negativo, basta gerar o complemento de 2 da representação binária do seu valor positivo! Assim sendo, -7 em binário é representado por 11111001.

Este mecanismo foi criado para facilitar as operações aritméticas nos processadores, pois elimina a necessidade de um circuito específico para subtração: o processador precisa calcular apenas o complemento de 2 do subtraendo, e efetuar a soma. Por exemplo

7 - 2 = 0111 - 0010 = 0111 + 1110 = 0101 .

Muito bem, voltemos portanto ao problema original…

Quando passamos um valor sinalizado de C para Java, não há problemas. Se eu leio um byte gerado pelo programa em C em um byte em Java, ou em um short (16 bits), ou em um int (32 bits), ou em um long (64 bits), o resultado será exatamente o esperado. Agora, se queremos ler um valor não sinalizado gerado por um código em C em um programa Java, é necessário escrever os bits em um tipo primitivo de tamanho maior.

Para escrever bits em um tipo primitivo, existem dois mecanismos: ou fazemos um AND binário com o endereço de destino contendo somente bits com valor 1, ou fazemos um OR binário com o endereço de destino contendo apenas bits com valor 0.

00000000 | 0110 = 00000110
11111111111 & 0110 =11110110

Por exemplo, supondo byte 11111001. Já vimos anteriormente que esta sequência de bits corresponde ao valor -7, mas também correspondeao valor 249 em um byte não sinalizado. Se quisermos obter o valor 249 em Java, teremos que gerar uma variável igual ou maior que um short.

E agora vem a curiosidade que motivou este texto (sim, todo o resto era apenas preparação, espero que tenha sido proveitoso) .

Pelo o que eu disse acima, para gerar o short com o valor 249, ambos os códigos abaixo seriam equivalentes:

short s1 = 0×0000 | 0xF9

ou

short s2 = 0×00FF & 0xF9

correto?

Errado!

Se eu mandar imprimir s2, o resultado será 249, mas se eu mandar imprimir s1, verei que o resultado será -7. Porque???

Simples: antes de efetuar uma operação binária, a JVM efetua um casting implícito de todas as variáveis para int. Como Java não entende tipo não sinalizado, ele faz casting do nosso byte levando em conta o valor -7, que em um int de 32 bits fica sendo 0xFFFFFFF9. O short 0×0000 passa a ser 0×00000000, e o short 0×00FF passa a ser 0×000000FF. Assim sendo, as operações descritas acima na verdade são:

short s1 = 0×00000000 | 0xFFFFFFF9 = 0xFFFFFFF9 = -7

e

short s2 = 0×000000FF & 0xFFFFFFF9 = 0×000000F9 = 249

——————————————————-

Adendo do autor:

Para aqueles que tenham dificuldades de entender notação hexadecimal, e como converter isso para binário e vice-ver, eis uma dica:  um símbolo em hexa pode assumir 16 valores (0,1,2,3,4,5,6,7,8,9,A,B,C,D,F,). Sendo assim, cada símbolo em hexa corresponde exatamente ao valor de 4 bits, e portanto são necessários dois símbolos em hexadecimal para descrever um byte.

Bricando com bits: Ponto flutuante

Nos últimos tempos tenho trabalhado na integração de dois sistemas, um em C (legado) e um e Java. A integração consiste em em ler mensagens enviadas pelo programa em C através de um socket e gerar objetos e ações correspondentes do lado Java. Nada de muito excepcional, é um cenário bastante comum. O divertido da coisa é que eu estou tendo que descer bem baixo na manipulação dos bits, e estou tendo que relembrar vários conceitos que aprendemos algum dia na faculdade e que consideramos como sendo inúteis pro resto da nossa vida, já que boa parte é resolvida por alguma API.

Ontem acabei de me deparando com um probleminha interessante, e que me fez relembrar o conceito de representação de números em ponto flutuante. Vou tentar explicar aqui a parte teórica da coisa, e no final apresento o problema e a solução. Se você não gosta de teoria, pode pular pro último parágrafo.

Muito bem. Suponha que você tenha o seguinte código em Java:

int i = 15;
float f = (float)i;
System.out.println(i+”, “+f);

O resultado da impressão será 15, 15.0.

Até aí nenhum novidade. O casting faz com que o número passe a ser tratado como ponto flutuante, mas mantém o valor inteiro. OK. Alguém aí já parou pra olhar como estes números são representados binariamente, por baixo do pano?


15 inteiro = 00000000 00000000 00000000 00001111
15 float = 01000001 01110000 00000000 00000000

Para alguns talvez isto não seja novidade, e para outros uma descoberta. E para alguns como eu era algo que eu já imaginava, mas nunca olhei a fundo.

No caso do 15 inteiro, nenhuma novidade: 15 = 2^3 + 2^2 + 2^1 + 2^0 = 8 + 4 + 2 + 1 = 15.

No caso do 15 float, é necessário entendermos o padrão que rege a representação dos números de ponto flutuante: IEEE 754. Resumindo: segundo o padrão, um número de ponto flutuante pode ser representado com precisão simples (32 bits, float em Java) ou precisão dupla (64 bits, double em Java). A IEEE define apenas a precisão de 32 bits como obrigatória, as outras sendo opcionais.

No caso da representação simples, o layout dos bits é o seguinte: o primeiro bit representa o sinal (0 positivo, 1 negativo), os 8 bits subsequentes representam o expoente e o restante (23 bits), a parte fracionária (chamada de mantissa). O desenho abaixo, obtido da wikipedia, ilustra este layout:

O expoente pode mapear valores entre -127 a 127 (no caso de um expoente de 8 bits). Para evitar o uso de bit de sinal, que pode dificultar certas operações, foi definido que o valor armazenado seria e + 127, onde e é o real valor a ser considerado.

A mantissa armazena um valor fracionario, e pode ser traduzido como 1.<padão de bits da mantissa>. Se a nossa mantissa for 1000000 00000000 00000000, é equivalente a 1.1000000 00000000 00000000. Aqui vale ressaltar mais um ponto: estamos considerando números binários, portanto os valores após às virgulas podem ser considerados como potências negativas de 2 (assim como números fracionários na base 10). No caso do exemplo, 1.1 é equivalente à 1 + 2^(-1) = 1 + 0.5 = 1.5.

Tendo estes elementos em mão é fácil calcular o resultado final: f = (sinal) * 2^(e -127) * 1.<mantissa>.

No caso do número 15, vamos ver como fica a coisa:

  • sinal = 0 = +1
  • expoente = 10000010 = 130. Portanto e = 130 - 127 = 3.
  • mantissa = 1110000 00000000 00000000, portanto 1.111 = 1 + 2^(-1) + 2^(-2) + 2^(-3)  = 15/8
  • Resultado = +1 * 2^3 * 15/8 = 8 * 15/8 = 15.

Muito bem. Mas a pergunta: porquê eu estou me preocupando com isso???

Simples: eu tenho que ler um fluxo de bytes, seguindo um descritor de mensagem, e reconstituir certos tipos de dados (ints, booleanos, campos de bits, etc…). Como eu tenho que ler e extrair alguns campos de bits perdidos no meio de bytes, resolvi implementar uma estratégia de baixo nível, lendo byte a byte e concatenando quando necessário em tipos de dados maiores. Além disso, estou usando como repositório temporário destes bits uma variável do tipo long, que possui 64bits, o que é mais do que necessário para armazenar qualquer dado que eu receba. A operação é simples: recebo um byte, e “colo” ele no long usando operações SHIFT e OR binários.

Agora suponha que o programa em C me mande o número 15 em ponto flutuante de 32 bits, como definido acima, e que eu armazene os bits recebidos em um long. Se ao final da leitura, eu pegar a variável temporária  e fizer um casting para float direto, a JVM vai pegar o valor do long (no caso 1097859072) e simplesmente converter para o padrão IEEE 754 correspondente, o que me resultaria num float com valor 1097859072.0, o que definitivamente não me interessa. O que eu preciso é de uma função que receba um long ou um int, seja capaz de olhar para o dado apenas como um repositório de bits e gere o float o double correspondente. No caso, os métodos Float.intBitsToFloat(int) e Double.longBitsToDouble(lont).

PS: Quem estiver interessado em ter uma leitura mais teórica e aprofundada sobre o tema pode ler o artigo What Every Computer Scientist Should Know About Floating-Point Arithmetic.

Especial de Natal Log4Dev: construindo um site de notícias usando Python - Parte 2

Vamos dar uma olhada nos nossos requisitos, e apresentar algumas questões de tecnologia:

  • O site tem que ser capaz de autenticar e identificar unicamente cada usuário que deseja cadastrar links.
  • Deve ser capaz de manter uma lista de quem foi o primeiro a enviar um link, além da data que o link foi enviado.
  • Deve ter um sistema que permita ao usuário indicar se gostou (aprovou) ou não gostou (rejeitou) um link enviado por qualquer pessoa que utilize o serviço.
  • Deve permitir que cada link enviado possua um fórum de discussão.
  • Deve permitir que uma pessoa possa iniciar um tópico de discussão, sem enviar um link. No caso, vamos fazer o seguinte: se o usuário preencher apenas os campos de título e comentário em um formulário de link, mas deixar o campo para a URL em branco, vamos criar um link para um item dentro do próprio site.
  • Deve permitir ao usuário enviar um lote de links a partir de uma fonte que ele já conheça. Isso vai servir para que o sistema, no futuro, tenha uma grande base de links prévios para aprender rapidamente.
  • Deve permitir que o usuário faça o seu voto (aprovado/rejeitado) sem sair da página que está. Para isso, vamos usar uma pitada de AJAX.

Tendo os requisitos delineados, podemos ver que vamos precisar dos sistemas comumente usados em aplicativos web: um banco de dados, um servidor web, um sistema para geração de páginas dinamicamente. Além disso, teremos que usar alguma biblioteca para importar links e parsear RSS.

A parte de programação já foi definida no título: vamos usar Python. É o que estou usando ultimamente para meus outros projetos, é uma linguagem elegante, divertida (sim, diversão conta), dinâmica, com bibliotecas fartas e bem documentadas como parte da biblioteca-padrão. Se nada disso serviu como argumento, diga para o seu chefe que você vai aprender Python pois ficou sabendo que o pessoal do Google usa, e tudo que eles usam tem que ser bom, não é mesmo?

Para o servidor de banco de dados: PostgreSQL. Maduro, estável, bastante documentação. Outros bancos de dados serviriam, mas escolhi PostgreSQL por pura comodidade. Se você quiser portar os scripts SQL que eu colocar aqui para seu banco de preferência, creio que não terá dificuldades.

Para a parte de AJAX, vamos favorecer a prata da casa: Juice Lib é uma biblioteca pequena, mas com funcionalidades bem pensadas para a parte de comunicação assíncrona com o servidor. Eu tenho enchido um pouco o saco do Miguel na questão de manipulação de DOM (a juice faz isso através de extensão de métodos sobre string, o que pode vir a te causar dor de cabeça se o seu código Javascript começar a crescer muito), mas o resultado geral é poderoso o suficiente para que possamos ter o esquema de apresentação da votação em pouquíssimas linhas de Javascript.

Resta falar sobre qual sistema vamos usar para formarmos uma “Aplicação Web” propriamente dita. Controle de sessão, classes controllers, formas para acessar o banco de dados, apresentação de páginas construídas dinamicamente, etc, etc, etc.

Eu já disse que odeio frameworks. O que eu quero é algo que pudesse funcionar como um único módulo ou biblioteca, que pudesse ser importado a partir de um shell Python e me oferecer as funcionalidades necessárias para um webapp.

O que vamos usar, então, é um sistema que seja o anti-framework: esse sistema, para mim, é o web.py

O que diferencia o web.py dos outros frameworks para aplicações web desenvolvidas em Python?

Simples: a filosofia.

Muita atividade ocorreu na comunidade de desenvolvedores Python, buscando uma resposta para o sucesso do Ruby On Rails. Começaram então a pensar em implementar um framework que pudesse ser tão “pragmático” e “rápido” quanto o Ruby On Rails.

E isso levou a uma febre de grupos desenvolvendo frameworks para Python. Sistemas que fazem mapeamento OR. Que abstraem sua camada de dados completamente. Que abstraem a camada de apresentação completamente. Que abstraem a camada de controle completamente. Que escrevem elogios na tela enquanto eles fazem tudo automaticamente para você.

O problema: abstrações excessivas falham. Cada um dos grupos dos grandes frameworks (Turbogears, Pylons, Django) tinha o seu próprio dialeto para o desenvolvimento de aplicações web, alguma coisa parecida com Python, mas não exatamente Python.

Faltava uma solução que se propusesse a alavancar os conhecimentos tradicionais que as pessoas acumulam ao trabalhar com sistemas web.

O web.py tem essa filosofia. Por exemplo: ao invés de se preocupar em implementar um módulo que faça mapeamento OR para você, o web.py te dá um módulo que serve para facilitar o acesso ao banco de dados, diretamente e de forma segura. Ao invés de expor objetos em Python para uma camada de apresentação, o web.py facilita o trabalho de construir uma resposta HTTP. Ao invés de impor uma disciplina de trabalho, ele oferece as funcionalidades básicas para que você use seu conhecimento acumulado com outros problemas que você teve que resolver.

(Justiça seja feita: o Django parece ter aprendido parte dessa lição. Muito dos esforços recentes do Django para que ele chegue na versão 1.0 está sendo feito no sentido de retirar o que é chamado de “código mágico”.)

Isso não quer dizer que o web.py é perfeito. Não é. A última versão lançada possui algumas coisas no design que você pode até estranhar, e vou falar deles. Espero para ver se a próxima versão irá corrigir mesmo esses problemas. De qualquer forma, por se tratar de uma biblioteca de recursos auxiliares - ao invés de um framework - a ginástica necessária para contornar esses problemas é muito menor.

Chega de escrivinhar. Amanhã, vamos ao código.

Sobre Frameworks…

Eu odeio frameworks. Não um ódio assim que faz pensar em mandar emails ameaçadores ao criador do ASP.NET, nem um ódio que me faça pensar colocar um vírus no computador de algum líder do projeto Jakarta que só permita que ele edite seu código usando Notepad (ou edlin) para o resto da vida. É um ódio de quem tem a sensação de que algo está fundamentalmente errado na forma como os desenvolvedores produzem e consomem frameworks de software.

Quando eu digo isso, a reação tradicional é: “Lullis, você quer o quê? Que todo mundo reinvente a roda? O que você sugere?”

Só posso responder com uma outra pergunta: você conhece o Método Socrático? Maiêutica?

Se você sabe, ótimo. Como eu não tenho como conferir sua resposta, vou tentar dar a minha explicação: o método socrático é um modo de tentar produzir novas idéias (complexas) a partir de um jogo de perguntas e respostas para conceitos mais simples que pertencem ao mesmo contexto.

Por exemplo, suponha que você esteja querendo ensinar cálculo de potências para uma criança. Como um matemático “formal” tentaria transmitir esse conhecimento? Apresentando uma série de colorários, princípios gerais e tentando mostrar todas as definições para a criança, até que ela consiga repetir todos os métodos utilizados pelo seu professor na obtenção de respostas para os problemas pré-estabelecidos.

Um professor que estivesse usando o método socrático certamente começaria fazendo perguntas para as quais os alunos já soubessem. “Usando notação matemática, como vocês fariam para escrever ‘quatro vezes quatro vezes quatro’”? “E se eu quisesse repetir a multiplicação 10 vezes?”. “E se eu quisesse multiplicar infinitamente?”. “E se eu quiser dividir repetidas vezes, ao invés de multiplicar?”. “Quanto é 1 multiplicado por 1?” “Quanto é 1 multiplicado por 1 multiplicado por 1… 100 vezes? E 1000 vezes? E 10?”. Ao deixar as crianças responder essas perguntas, elas mesmas passam a observar os princípios gerais por trás das fórmulas
matemáticas. Através da intuição, elas desenvolvem quase que por conta própria uma nova “unidade de conhecimento”, ao invés de tê-la transmitida através de um mestre. Um professor socrático atua muito mais como um guia, do que como uma bússola.

Qual sistema é melhor? Muito depende do seu objetivo. Alunos das duas escolas conseguirão responder que A^(-x) é igual (1/A^x). Um o fará quase que por instinto, condicionamento mental. O outro pode até não ter isso cravado em sua cabeça, mas chegará à resposta se tiver desenvolvido a habilidade de saber fazer as perguntas certas. “Se ao incrementar o expoente eu multiplico a base, o que aconteceria se eu diminuísse?”

Computadores são inúteis. Eles só sabem dar respostas.

No espiríto do Método Socrático, eu pergunto: o que acontece numa situação em que as perguntas não possuem uma resposta catalogada?

Provavelmente, o aluno de métodos mais tradicionais (digamos, alguém que passou tempo demais estudando Kumon) vai travar, ou voltar para o seu mestre, na esperança de obter as respostas que faltam. Ainda que ele seja capaz de responder por reflexo a equações derivadas de segundo grau, ele não saberá por onde começar caso tenha que jogar Petals around the Rose.

Certo. E o que isso tem a ver com frameworks?

Escreva “define: framework” no Google. Um dos termos que você encontrará é “sistema de regras, idéias ou princípios que é usado para planejar ou decidir algo.”

Olha só que interessante: ao tentar explicar para você sobre o Método Socrático, eu acabei achando uma das melhores formas de explicar o meu desgosto por frameworks de desenvolvimento.

Frameworks, em sua essência, acabam sendo um “pacote fechado” de soluções prontas para alguém que tem um problema a ser resolvido. “Se você está desenvolvendo um aplicativo e precisa de uma integração Web, use o framework XYZ que te dá autenticação de usuários, geração de código HTML a partir dos seus dados, servidor HTTPS e no fim do dia ainda te faz uma massagem nas costas”. “Se você quer desenvolver software para sistemas embarcados, use o nosso DevKit e você terá um emulador em seu computador, configuração de diversos setups em software, cross-compiler e no fim do dia ainda te daz uma massagem nas costas.”

Se ao menos as promessas de massagem fossem verdade…

O problema, ao meu ver, é que alguém (indivíduo ou grupo associado) que decide implementar um framework se coloca na posição de detentor de um pilha de conhecimento como se fosse “a única verdadeira solução”, quando na verdade esse alguém possui apenas uma compilação de regras e receitas usadas na resolução dos problemas dele. Ou, pior, é uma empresa que está tentando criar a solução definitiva. E, devemos saber, isso
não existe
.

Outra coisa a se pensar - ao menos para os desenvolvedores web - é que a velocidade do surgimento de tecnologias é muito rápida. Mais rápida até do que a capacidade do grupo de assimilar e sedimentar qualquer forma de conhecimento que possa se transformar em um “pacote fechado.” Aí, logo depois que qualquer sistema começa a se consolidar, já haverá parte do grupo tentando forçar a adoção das novas tecnologias e paradigmas, levando ou a um sistema que é abandonado e preterido em favor da Próxima Grande Tecnologia, ou haverá um produto torto, sem identidade. Jack of all trades, Master of none.

E os desenvolvedores que são usuários desses frameworks, meu Deus? Passam tanto tempo aprendendo a lidar com os problemas, aprendem todas as formas de contornar as falhas de design, decoram tantos lotes de informação que, no fundo, acabam tendo que reaprender sistemas inteiros. Tornar-se verdadeiramente produtivo com o tal framework é quase tão trabalhoso quanto implementar você mesmo as funcionalidades prometidas. Que vantagem há nesse processo?

Qual a alternativa?

Seguindo a analogia, o nosso Software Socrático não é desenvolvido em cima de uma plataforma ou de um framework, mas utilizando pequenos componentes mais simples e que já são conhecidos suficientemente. Esses elementos menores seriam as unidades de conhecimento necessárias para que, através da intuição, possamos chegar a uma solução que produza o resultado esperado.

Um guia, não uma bússola.

Por dentro das Expressões Regulares

Aproveitando os dois últimos posts sobre expressões regulares, Regexp Nossa de Cada Dia! (de minha autoria) e Usando Regexp (do Leo), encontrei o link do artigo “How Regexes Work“, que explica de forma bem clara o funcionamento de um algoritmo de regexp. Bom para saciar a curiosidade daqueles que gostam de saber como as coisas funcionam.

Cursos Livres no MIT

Em 2001 o MIT anunciou a criação do OCW (MIT OpenCourseWAre). Esta é uma iniciativa que procura utilizar a internet para avançar o conhecimento e educar estudantes das mais diferentes áreas em todo o mundo - seguindo a missão da instituição. Através de seu site, o OCW publica gratuitamente materiais dos cursos utilizados no MIT, incluindo notas de aulas, conjuntos de problemas, vídeos e demonstrações.

O primeiro piloto, com 50 cursos surgiu em 2002. Em 2003 o projeto foi oficialmente lançado, contando com cerca de 500 cursos. De acordo com as informações do site, em 2007 praticamente todos os cursos do MIT foram publicados. É uma excelente fonte para aqueles que têm interesse de aprender algo novo, aprofundar seus conhecimentos e manter-se atualizado. Vale lembrar que de acordo com o ranking de universidades citado pelo Raphael, a instituição é considerada como sendo a décima melhor universidade do mundo.

Esta iniciativa inspirou diversas outras universidades do mundo, que então criaram o OpenCourseWare Consortium, que agrega desde renomadas instituições dos Estados Unidos, Europa e Japão, até instituições de países como Vietnã e Colômbia (não há nenhuma universidade brasileira no consórcio).

Cabe notar que a disponibilização do material não garante certificação de nenhuma espécie,  e tampouco corresponde fielmente a todo o material dos cursos. De qualquer forma, é uma excelente fonte por aqueles ávidos por conhecimento. Eu mesmo já comecei a consultar o material de três cursos bastante interessantes: Introdução à probabilidade e estatística, Algoritmos para Biologia Computacional e Análise Econômica para Decisões de Negócios. Mas se você preferir, pode fazer um curso sobre Imperialismo Europeu nos séculos XIX e XX, Alemão (língua) ou Biomedicina Aeroespacial e Engenharia de Suporte à Vida. São várias as possibilidades.

Turing completeness (Pra que linguagens de programação?)

Pessoal, primeiro queria me desculpar por minha ausência neste blog nos últimos tempos… Infelizmente eu acho que eu sou o colaborador mais esparso por aqui e não tenho grandes perspectivas de melhorar minha taxa :-/ De qualquer forma, como o Miguel ainda não me expulsou, continuo na ativa para a felicidade (ou não) dos dois leitores deste blog (não fossem os comentários de outras pessoas e as estatísticas do blog eu chegaria a acreditar piamente que só o Raphael e o Bruno lêem este blog nos últimos tempos… obrigado pela participação de todos!). :)
Como todos devem saber, o Raphael e o Bruno vêm há algum tempo em uma discussão (às vezes) quase religiosa com dezenas de comentários sobre o artigo “Viva a diversidade!” do Miguel. Muita gente deve estar cheia de ler os comentários deles! Eu, inclusive, já passei por uma fase assim, mas acabei lendo todos os comentários em batch depois. Acho que é isto que levou o Miguel a “censurar” (será?) os dois. :) De qualquer forma, acho que este blog deve ser um meio livre de expressão. Se eles querem se matar discutindo um assunto que, a meu ver, não tem muito sentido, deixa eles lá.

De certa forma, discussões grandes como esta acabam gerando ligações com assunto muitas vezes nada a ver com a discussão principal. E foi exatamente isso que me chamou a atenção neste comentário do Raphael. Mais especificamente, a seguinte parte me chamou a atenção: “Em última análise, TODAS as linguagens são possíveis de se fazer QUALQUER tipo de construção lógica. Se não fosse assim, elas não seriam Turing-Complete, tampouco mereceriam o nome “Linguagem de Programação”.”

Isso me lembrou de um fato que eu aprendi há muito tempo e que é uma daquelas coisas que não mudam sua vida porque provavelmente você nunca mais vai ter que lembrar dele no seu dia-a-dia mas fazem com que tudo faça sentido (se um dia você estiver buscando a essência das coisas, como eu acho que o Raphael estava quando ele escreveu esta frase).

Turing completeness é um conceito que, na verdade, estrapola linguagens de programação. Qualquer máquina abstrata ou linguagem de programação que seja capaz de executar qualquer tarefa computacional é classificada como turing complete.

Quando você desce o nível, das linguagens de programação de alto nível para as coisas mais essenciais, como assembly e linguagem de máquina, você vai descobrir que ser turing complete nada mais é do que ser capaz de executar pouco mais de meia dúzia de instruções. Descendo mais o nível, veríamos que para projetar um circuito lógico capaz de executar todo este conjunto de instruções você precisaria de apenas um tipo de portas lógicas: ou só NANDs ou só NORs. Você não vai precisar de mais que dois transistores para fazer cada uma destas portas lógicas. Duvida? Aqui e aqui.

Desta forma, eu acho que toda esta discussão sobre qual linguagem de programação é melhor realmente é inócua. Parodiando o célebre post de Linux Torvalds, homens de verdade precisam apenas de máquinas turing complete. Nada mais!

E é por isso que eu conclamo todos vocês a largarem toda esta porcariada de frameworks, modelos de programação, orientação à objeto, programação funcional, lambdas e o escambal e passemos todos a projetar tudo que precisamos fazer em termos de NANDs (por um gosto pessoal eu prefiro o NAND ao NOR, mas, para não parecer inflexível, acho que podemos liberar o NOR também). Caso alguém realmente precise de algo de mais alto nível, são permitidos os instructions set mínimos ou, já que eu sou uma pessoa benevolente, o uso da linguagem Whitespace, que, segundo o artigo sobre instruction set mínimo, chega perto de algo minimalista (mas não deixa de ser uma linguagem de alto nível, na minha opinião, então use com parcimônia). Coisas como Path language nem pensar. Elas não são suficientemente minimalistas, por mais que a home page dela te faça pensar o contrário.

Com estas tecnologias (e apenas com elas!) acho que daqui há uns 200 anos conseguiremos chegar num nível tecnológico suficiente para termos blogs funcionando novamente. Quem sabe assim eu não ganho tempo suficiente para pensar no meu próximo artigo… :)
Nota: Antes que alguém me acuse de reacionário: esta é uma obra de ficção. Qualquer relação dela com seu autor ou com qualquer outra pessoa é azar deles.

Kata para programadores

Kata - Um conjunto estilizado de movimentos que simulam uma variedade de defesas e ataques contra um inimigo invisível. Um kata é utilizado para aperfeiçoar o estilo, aprender concentração, assim como demonstrar ataques, defesa e contra-ataques. ( Extraído de http://la.essortment.com/karateterminolo_raan.htm - tradução livre )

Dojo - literalmente “lugar do Caminho”. Também “lugar da iluminação”. ( Extraído de http://www.aikido.itu.edu.tr/dictionary.htm - tradução livre )

Com certeza, todos o leitores com mais de 20 anos lembram-se do Daniel Larusso (vulgo Daniel Sam), aquele rapaz com cara de bebê chorão e chassi de pernilongo, destruindo seus adversários no “All Valley Karate Tournament”. E tudo isso graças aos gloriosos ensinamentos do Sr Miyagi, que iam de pintura de paredes e enceramento de carros, a dancinhas esquisitas à beira da praia, vulgo Kata. Provavelmente, baseado nesse incrível exemplo, algumas pessoas como Dave Thomas resolveram aplicar esta prática ao mundo dos programadores. De acordo com Dave, assim como em outras áreas, para desenvolvermos nossas habilidades precisamos de muito treino. Baseado nisto, ele desenvolveu uma série de katas para programadores - pequenos exercícios para treinar nossas habilidades de programação, lógica, estrutura de dados, etc.

Baseado neste mesmo conceito, um grupo de pessoas criou um Dojo virtual, para que as pessoas se reunam para a prática de katas. Este Dojo ainda está engatinhando, e atualmente contém somente cinco (em 04/09/2007) katas cadastrados. Mas certamente irá crescer.

Pessoalmente, gostei muito desta idéia. Muitos programadores têm o interesse e a vontade de aperfeiçoar suas habilidades, mas não sabem como fazê-lo. Desenvolver pequenos projetos sozinho, ou em grupos (comunidade open-source) é uma boa alternativa, mas nem todos têm tempo para se comprometer suficientemente para tais atividades. Além disto, nem sempre se consegue exercitar as diferentes habilidades úteis a um programador faixa-preta quinto dan.

Como gostei muito desta idéia, tentarei à medida do possível colocar uns katas aqui. E aqueles que quiserem, podem entrar em contato pelo alexandre(at)log4dev.com, que teremos prazer em divulgar suas sugestões, e dar-lhes sempre todo o crédito.

Nota: falando em dar o devido crédito, a idéia deste post surgiu a partir de um artigo de Amr Elssamadisy do InfoQ

Powered by ScribeFire.

Algoritmos de Ordenação

Existem aqueles que pensam que teoria de computação, complexidade, estruturas de dados e algoritmos são perda de tempo. É bem verdade que no dia a dia do desenvolvimento de aplicações webs comuns (basicamente CRUD), estes problemas são em geral irrelevantes. Além do mais, a grande maioria das linguagens já possui bibliotecas com implementações muito boas destes algoritmos e estruturas de dados.

Outros, como eu pensam que saber este tipo de coisas pode ser um diferencial, e que conhecimento nunca é demais. Sem contar que as vezes nos deparamos com problemas difíceis a serem resolvidos, e ter uma bagagem teórica (uma caixinha de maldades, como diria um ex professor da faculdade) abrangente pode ser o pulo do gato. Para aqueles que são como eu, e que querem revisar os algoritmos de ordenação, aconselho este site: http://linux.wku.edu/~lamonml/algor/sort/sort.html.

Joel, sobre codificação de caracteres

Hoje descobri este artigo do Joel Spolsky sobre codificação de caracteres e UNICODE.

Bem didático e interessante, sobretudo quando se desenvolve interfaces pra Web.