Sobre tecnologias, conceitos e aborígenes

Mapa do Estreito de Torres (fonte: Wikipedia)

Entre a Austrália e Papua-Nova Guiné existe um canal de apenas 150 quilômetros de extensão conhecido como Estreito de Torres. Várias pequenas ilhas pontuam o estreito. Foram elas que permitiram, mesmo sem grandes tecnologias de navegação, o desenvolvimento de uma rede de comércio e troca de informações entre uma massa de terra e outra. Apesar disso, durante muito tempo enquanto os habitantes do sul do estreito (a ponta australiana) levavam a vida como caçadores-coletores, os do norte já tinham fazendas de agricultura intensiva, cerâmica e criações de porcos.

As embarcações a que eles tinham acesso eram bem primitivas. Então as tecnologias tinham que ser passadas de ilha em ilha através do estreito até chegar à Austrália. Só que nem todas as tecnologias que faziam sentido no ambiente de uma ilha, faziam sentido no da próxima. O resultado é que nem todas as invenções conseguiam completar a travessia. Como se não bastasse, as tecnologias que acabavam conseguindo atravessar o estreito eram sempre modificadas no caminho. Foi isso o que aconteceu com a agricultura, a cerâmica e os porcos.

O mesmo mecanismo afeta as tecnologias que usamos como programadores. Conceitos vão “saltando” de uma comunidade para outra, de uma biblioteca para outra, de uma linguagem para a outra, até nos atingir. Uma pessoa pode ser apresentada a programação funcional através de Python, outra através de Clojure, outra através de Elixir, outra através de Haskell. Uma pessoa pode ser apresentada a injeção de dependências através de Smalltalk, outra de C#, outra de Javascript. Cada uma dessas ideias tem uma “árvore genealógica”: o caminho através das ilhas do estreito é diferente para cada uma delas. Mas o importante é que o que precisamos aprender é o conceito e não a implementação dele em determinada tecnologia.

Assim como as técnicas de agricultura e cerâmica são modificadas a cada “salto” de uma ilha para a outra, os conceitos tecnológicos são absorvidos por cada pessoa em um contexto diferente. Na maior parte dos casos, não temos como rastrear exatamente de que mente da Xerox Parc nos anos 60 saiu cada ideia. Então nossa melhor aposta é estudar tecnologias coerentes. Aquelas que têm um conceito norteador claro, que foram elaboradas para validar um conceito específico. Claro que dá para usar uma ferramenta desenhada por comitê, como Java, para resolver problemas práticos. Mas não é de resolver problemas que estamos falando aqui. Estamos falando de absorver a essência da coisa. Podemos sempre levar um conceito de um lugar para o outro quando o entendemos de verdade.

Mas para entender de verdade, é preciso beber direto da fonte. Os aborígenes do lado australiano do Estreito de Torres recebiam informação via telefone sem fio e, por causa disso, acabaram ficando sem tecnologias que poderiam facilitar bastante sua vida. O povo de cada ilha adotava as técnicas que lhes pareciam úteis a curto prazo e as adaptava a seu contexto.

A solução é construirmos o barco e atravessarmos o estreito. Vamos para a Papua-Nova Guiné. Vamos aprender orientação a objeto com Smalltalk, não com Java. Vamos aprender controle de versão distribuído com git, não com TFS. Vamos aprender NoSQL com CouchDB e Cassandra, não com PostgreSQL. Temos que aprender onde o negócio está em ebulição, não onde é apenas uma alternativa útil. Não onde é somente um checkbox numa lista de features.

Por favor, reinvente a roda

Evolução da roda

Tenho certeza de que você já ouviu a frase feita “não reinvente a roda”. Parece um bom conselho à primeira vista, certo? Devemos reutilizar o que temos a nossa disposição ao invés de reconstruirmos nós mesmos algo com a mesma finalidade.

Não faz muito tempo, descobri o httpie. Ele é um cliente HTTP para linha de comando. Algo como o curl ou o wget.

Mas… Peraí… Para que fizeram o httpie se já temos não só um mas dois clientes HTTP de linha de comando? Não faz sentido! Não reinvente a roda, certo?

Só que isso não é reinventar a roda. Há uma diferença entre reinventar a roda e uma evolução incremental. O curl foi importante para saber o que precisamos de um cliente HTTP de linha de comando, mas ele não tem a melhor usabilidade para um usuário moderno. O httpie é um (modesto) passo nessa direção.

Evolução.

Incremental.

Não reinventar a roda é um princípio extremamente válido. Mas o problema de princípios e valores é que eles parecem fáceis demais de entender. São óbvios até. Mas na verdade precisam ser entendidos a fundo para serem bem aplicados. Quando são reduzidos a uma frase de efeito, as pessoas deixam de pensar sobre o princípio que está por trás da frase e começam a usá-la superficialmente. Nessa hora morrem muitas boas idéias que são evoluções incrementais de outras, só porque não queremos “reinventar a roda”.

Precisamos ter muito cuidado para diferenciar quando nossa reinvenção da roda é realmente uma reinvenção a partir de princípios básicos de quando é uma adaptação de uma idéia pré-existente. Afinal de contas, não só de completas revoluções vive esse nosso mundo da tecnologia. Na verdade, talvez estivéssemos melhor se mais gente se debruçasse mais sobre projetos de evolução incremental do que sobre grandes objetivos revolucionários. Ainda bem que algumas pessoas conseguem fugir dessa interpretação rasa do “não reinvente a roda”.

Porque o httpie é a reinvenção do curl, a Netflix é reinvenção dos canais de TV a cabo, computação em nuvem é reinvenção dos mainframes, e o podcast é a reinvenção das rádios-pirata.

Então, por favor, reinvente tudo!

Comentário bom é comentário apagado

Quando o assunto é comentário de código, eu concordo com o Juan Lopes:

maçãs verdes com rótulo de

Acho que comentários ficam desatualizados com uma facilidade incrível. É como se eles começassem a apodrecer assim que são escritos. Geralmente quando pensamos em incluir um comentário é porque o código está difícil de entender. Sentimos que está difícil de nos expressar com código e trocamos de linguagem. Nós acabamos cedendo e passamos de uma mídia de comunicação (o código) para outra (a linguagem natural).

Sim. O código é uma mídia de comunicação.

E não estou falando de comunicação com o computador. Estou falando de comunicação com seus colegas programadores. Se o código está difícil de entender, não escreva uma comentário, re-estruture o código! O que não faz sentido é você passar de uma linguagem deliberadamente projetada para eliminar ambiguidades para uma linguagem onde termos diferentes podem ter significados diferentes para pessoas diferentes.

Tendo dito isto, existe sim uma classe de comentários que acho extremamente útil e que venho utilizando cada vez mais.

São os comentários de tarefas pendentes.

Às vezes você está no meio de uma alteração e se depara com um pedaço de código pré-existente que poderia ser melhorado. Ou você sabe que o magic number que está usando deveria ser configurável. Ou então você toma uma atalho qualquer para validar a solução que está desenvolvendo com seu commit pequeno da vez, mas sabe que aquilo não pode ficar daquele jeito quando a funcionalidade estiver pronta.

Enfim, você identificou algo no código que ainda precisa ser trabalhado, mas não é algo diretamente ligado à modificação imediatamente atual. É aí que entram os comentários. Você os usa como lembretes de algo que ainda precisa ser feito, mas se desimpede para se concentrar em uma coisa de cada vez.

Os meus eu, inspirado em alguma tradição de programação milenar cuja origem desconheço, gosto de separar em duas classes: TODO e FIXME.

Os comentários TODO são usados quando quero assinalar algo que pode ser melhorado, mas que não impede o funcionamento correto da aplicação. Pode ir desde uma referência hard-coded a um webservice a uma idéia arquitetural para implementação de uma funcionalidade futura, dependendo do caso.

A palavra em ênfase aqui é “correto”.

É aí que entram os comentários FIXME. Esses eu uso quando preciso marcar algo em que não vou tocar agora, mas que considero que deva estar pronto para que a tarefa atual possa ser dada como concluída. Se os FIXME não forem consertados, a aplicação não funciona corretamente.

No fim das contas o ideal é não ter nenhum desses comentários “sujando” meu código-fonte. Mesmo que os TODO possam ser mantidos indefinidamente dentro da aplicação, o objetivo de vida deles, desde o momento em que nascem, é desaparecer. Nesse sentido, todos os comentários devem ser considerados temporários.

O que você não deve ter de jeito nenhum dentro do seu código são comentários assim:

# soma um com dois, dando como resultado três
r = 1 + 2

Isto é diretamente equivalente à figura das maçãs do início do texto. É um desastre esperando para acontecer!

O custo dos testes unitários

Os benefícios de uma boa suíte de testes unitários são inegáveis: código com menos acoplamento, segurança no refactoring (e principalmente na eliminação de código morto), ausência de erros de regressão, verificabilidade automática, etc. É até estranho pensar que alguém optaria por desenvolver software sem testes unitários automáticos.

Mas a verdade é que não existe almoço grátis. Não há muito o que discutir quanto a isso. Então qual é o custo associado a uma suíte abrangente de testes unitários?

O que os testes fazem é exercitar o código e verificar os resultados obtidos. E, mesmo que você não vá guardar seus testes para o futuro, de algum modo você os executa. Seja criando um programa de chamada e imprimindo os resultados para verificação manual. Seja rodando o código num REPL qualquer. Seja iniciando a aplicação e clicando em alguns botões. De algum modo você exercita seu código antes de subir as alterações para o repo. E você faz isso com vários dados de entrada até atingir um nível satisfatório de confiança.

Correto?

Tendo isso em mente, chegamos ao ponto central da questão: os testes unitários automatizados são somente o registro em código de algo que já ia ser feito de qualquer jeito. Se, ao invés de disparar a aplicação para conferir suas mudanças, você escrever um teste que acione o código e verifique os resultados, você vai levar o mesmo tempo. Não há nenhum custo adicional em fazer isso.

Mas por que eu tomei o cuidado de destacar o “adicional” no parágrafo anterior? Porque os testes unitários só saem “de graça” se você realmente está fazendo isso. Se você vai subir seu código para o repo sem executar, simplesmente porque você acredita que ele é muito simples e obviamente não tem como falhar, então já não estamos falando da mesma coisa. Estamos comparando maçãs com bananas.

Se você publica código sem verificá-lo, seus testes unitários terão um custo alto: o custo de saber que o código funciona.

Por que a cultura nerd tem que acabar

Este post foi publicado originalmente em inglês no blog de Pete Warden.
Não costumo fazer traduções aqui, mas este foi um assunto que me atingiu tão em
cheio que não pude evitar. Talvez você ache que o Pete chegou a uma conclusão um
pouco drástica, mas mesmo assim considere as idéias que o fizeram chegar lá.
Usando a analogia do Pete, não vamos deixar que os ideias da Aliança Rebelde
terminem por formar um novo Império.

Eu conheci minha primeira namorada através de um MUD, e tive que voar 7000
milhas para conhecê-la pessoalmente. Eu li uma versão impressa do Jargon File
em 1995 e ele virou minha bíblia. Só de ler suas descrições da Internet eu soube
que ela iria mudar o mundo, até mesmo antes da web, e assim que pude me
esgueirei para o laboratório de computação da minha universidade local com uma
conta emprestada para experimentar as maravilhas da Usenet, FTP e Gopher.
Escolhi minha faculdade porque Turing um dia ensinou lá, e o projetista do chip
ARM
seria um dos meus professores. Meu primeiro emprego quando saí da
faculdade foi ajudando a portar o Diablo original para o primeiro Playstation, e
passei cinco anos escrevendo games. Eu mergulhei fundo em programação de GPU. Eu
trabalhei por quase duas décadas tanto em grandes empresas de tecnologia quanto
em startups. Eu já passei incontáveis horas escrevendo sobre programação por
puro amor. Eu sou um homem crescido que ainda joga Dungeons and Dragons!

Meu ponto é que se alguém pode dizer que é um nerd, esse alguém sou eu. Como um
adolescente solitário que cresceu no interior da Inglaterra, ler o Portrait de
J. Random Hacker
me deu um maravilhoso choque de excitação e reconhecimento.
Eu nunca havia encontrado alguém assim, mas saber que havia outros como eu por
aí me deu esperança. Conforme eu avancei na graduação, comecei a descobrir
algumas pessoas que tinham um orgulho perverso de serem geeks, mas ainda era
raro e bastante distante da cultura mainstream. Ninguém realmente entendeu
porque eu aceitei um trabalho mal pago em programação de games ao invés de
entrar para um banco, e os olhos da maioria das pessoas se reviravam quando eu
mencionava que trabalhava com computadores. No decorrer dos anos eu gradualmente
montei um grupo de amigos que compartilhavam interesses em ficção científica,
quadrinhos, games e computadores. Foi a cultura nerd que nos reuniu e o suporte
deles foi salvador, mas foi difícil de encontrá-los, e nós ainda estávamos
bastante distanciados do mainstream cultural.

No decorrer da última década, isso mudou. Adaptações de histórias em quadrinhos
são a aposta mais segura em Hollywood. O Senhor dos Anéis e Game of Thrones
transformaram a fantasia em algo que qualquer um pode curtir sem
constrangimento. Talvez mais importante é que agora nerds têm dinheiro, poder e
status. Os dirigentes e funcionários das maiores e mais crescentes empresas do
mundo somos nós, e a cultura mainstream deixou de nos ridicularizar para nos
respeitar. Startups são sexy. Nós vencemos.

E é aí que está o problema. Ainda estamos nos comportando como a Aliança
Rebelde, mas agora somos o Império. Chegamos aonde estamos por ignorar intrusos
e acreditar em nós mesmos até quando mais ninguém acreditaria. As décadas
provaram que nosso jeito estava na maior parte certo e que os críticos estavam
errados, então nosso hábito de não escutar tornou-se profundamente arraigado.
Virou até meio que um ritual de aproximação a prática de atacar críticos da
cultura porque eles geralmente não entendiam o que estávamos fazendo além de
superficialmente. Não tinha muito problema porque ninguém além de um punhado de
leitores de fórum viam os discursos inflamados. Este mesmo reflexo torna-se
um grande problema agora que nerds têm poder real. O escândalo GamerGate me
deixou com vergonha de ser gamer, mas o assustador é que o comportamento
original de atacar críticos parecia algo que eu sempre via na nossa cultura, e
tolerava. Só chegou a me chocar quando cresceu tanto a ponto de virar ameaças
de estupro e morte, e vi corporações mainstream como a Intel se dobrando em
resposta à pressão que podemos exercer.

Foi por isso que o comentário de Marc Andreessen que o Vale do Silício é cultura
nerd e que os nerds são os inimigos naturais dos bros
pareceu tão errado. Sim,
nós éramos pertubados ou ignorados pelos bros, mas isso era quando não tínhamos
dinheiro nem poder. Agora que temos status, os bros não têm problema de nos
tratar como amigos ao invés de vítimas, a ponto de ser difícil pensarmos neles
como bros. Eu conversei com a maioria das empresas de VC do Vale uma hora ou
outra, e muitos dos sócios veêm das áreas de negócios ou finanças. Existem nerds
lá, claro, e eles controlam sim a cultura, mas eles também se dão perfeitamente
bem com os MBAs e suas formalidades. O mesmo vale para toda a indústria de
tecnologia – eles podem ter tentado roubar nosso almoço vinte anos atrás, mas
agora eles estão bem felizes tocando a parte de negócios enquanto nós cuidamos
da engenharia.

Uma das coisas que adoro na cultura nerd é o quanto ela valoriza evidência e
verificação de fatos. Quando estou otimizando código, minha intuição de que
partes são mais lentas em geral está largamente errada, então eu aprendi do
jeito difícil que tenho que rodar o profiler loucamente antes de tentar
consertar qualquer coisa. É uma habilidade essencial para lidar com
computadores, nossos pressentimentos iniciais em geral não funcionam em um
domínio tão deslocado, então o ceticismo vira hábito. O que me surpreendeu é
como nós abandonamos esse hábito quando confrontados com evidência sobre nós
mesmos. Praticamente toda estatística que conseguimos acompanhar mostra
menos mulheres obtendo diplomas em ciência da computação e trabalhando como
engenheiras em comparação com os anos 80. É fato elementar que somos uma
indústria desbalanceada de todo tipo de forma, de raça a classe e gênero, e
estamos piorando.

Eu não estou dizendo que sei as respostas, mas você não precisa ser um guerreiro
da justiça social para notar que algo está muito errado em algum lugar. Até o
Jargon File admitiu, parafraseando, que hackers rotineiramente se comportam
como babacas
. É loucura demais imaginar que essa tolerância profundamente
arraigada de comportamento ruim pode afastar as pessoas?

Quando olho ao redor, eu vejo a cultura que construímos se transformar de uma
revolução libertária em uma incumbência repressiva. Nós construímos dispositivos
mágicos, mas não ligamos o suficiente para proteger gente normal de se machucar
quando os usam
. Não ligamos que muitas crianças por aí com potencial para
se tornar hackers incríveis são afastadas em cada estágio do processo larval.
Não ligamos para as pessoas que se perdem quando balançamos o mundo, só para os
vencedores (que tendem a parecer bastante conosco).

Eu sempre esperei que fôssemos mais virtuosos que o mainstream, mas no fim das
contas só nos faltava poder para causar muito dano. Nosso senso de vitimização
internalizado tornou-se uma justificativa perversa para a perseguição. É por
isso que estou pedindo um tempo da cultura nerd. Ela fez coisas maravilhosas,
mas hoje em dia é como uma base de código legada rastejante tão impregnada
de problemas que a única decisão racional é jogar fora e construir algo melhor.

Com o que algo melhor se pareceria? O movimento Maker me dá esperanças,
porque a inclusão de todas as crianças que estamos sentindo falta é feita desde
o início. Qualquer seja o futuro, o importante é que precisamos valorizar ser um
ser humano decente muito mais do que valorizamos agora. Nossa tolerância de
comportamento babaca deve terminar, e é uma parte tão essencial da cultura nerd
que aniquilar a coisa inteira da face da terra é o único jeito de garantir.

Anatomia de um bom commit

Commits, check-ins, patches. Não importa o nome que você (ou seu sistema de controle de versão) usa, eles são parte essencial da sua imagem como dev. Commits desleixados queimam seu filme e commits bem organizados mostram que você se importa com sua profissão. Mas isso não os impede de serem muitas vezes renegados. Depois de algum tempo desenvolvendo, você cria um certo instinto para o que faz um bom commit. Aqui está minha lista confessadamente incompleta do que faz um bom commit.

Tamanho interessa sim

Bons commits são pequenos. Ponto.

Passar uma semana sem commitar e na sexta-feira fazer um braindump de tudo aquilo que se acumulou na sua máquina? Não é legal. Você deve de preferência commitar mais de uma vez ao dia, mas uma boa frequência mínima é de um commit por dia. São raras as instâncias em que você vai precisar de mais de um dia de trabalho dedicado para chegar a uma versão compilável e funcional do código que avança um pouco na direção da solução final.

Commits pequenos também ajudam seus companheiros de equipe. É muito mais fácil integrar a sua modificação em andamento com a minha modificação em andamento se cada alteração é bem focada em um único objetivo. Não tem coisa pior do que fazer uma integração “big bang” e ter que rememorar uma ou duas semanas de trabalho para explicar para seu colega qual era a intenção de alterar um trecho de código qualquer.

Revisões ficam mais fáceis também. Se você faz commits pequenos, o revisor pode facilmente acompanhar sua linha de raciocínio como se estivesse do seu lado quando você escreveu o código. As revisões futuras quando você tiver que conferir o histórico para caçar um bug qualquer também ficam mais fáceis. Isso nos leva ao nosso próximo ponto:

Deixe migalhas de pão para você mesmo

Esta é uma transcrição de um trecho do episódio 174 do podcast Ruby Rogues:

ERIC: Outra coisa que eu comecei a fazer recentemente é escrever bem mais nos meus commits e fazer commits bem menores. Algumas vezes eu revejo o histórico quando encontro um teste falhando e digo “Tá certo, porque essa linha está se comportando desse jeito?” E se for uma linha em um commit de 200 linhas com uma mensagem de commit de duas frases, não tem jeito de eu saber o que eu estaria pensando na hora em que modifiquei aquela linha, ou se era importante. Mas quando eu faço um commit de 10 ou 20 linhas e escrevo um parágrafo sobre ele, quando volto nele eu posso dizer “Isso é exatamente o que eu estava pensando quando escrevi isso.” Então tenho uma noção muito melhor de quais eram minhas idéias quando escrevi aquilo e porque aquela linha pode ser importante.

JAMES: Você aprendeu a ser legal com você mesmo.

ERIC: Sim.

[Risos]

JAMES: Isso é excelente. É algo em que todos nós podemos melhorar, concorda?

ERIC: É, deixar migalhas de pão para mim mesmo.

JAMES: Isso é muito bom.

ERIC: Eu me pego fazendo bastante leitura do histórico do código. e quando há mais commits no histórico, a leitura fica bem mais fácil do que “teve essa alteração aqui que tocou em todas as linhas. E agora eu tenho que dar um jeito de rastrear para descobrir para onde essa linha foi.” É super irritante para reproduzir o que você fez e o que você não fez. Quando tenho esses commits bonitos e pequenos, eu penso “Eu sei o que eu fiz” na mesma hora. Não leva 10 ou 15 minutos extras para refazer os passos e descobrir que commit é relevante e depois torcer para que tenha uma mensagem relevante.

Vamos encarar: cedo ou tarde você vai precisar ler o histórico do código. Seja para diagnosticar um caso em produção que a versão atual do código não poderia ter gerado de jeito nenhum ou para analisar a melhor solução para um bug.

Eu argumentaria até a favor de integrar a leitura do histórico no seu ferramental normal de resolução de bugs. Quando você detectar um bug ou quando chegar um relato de ocorrência em produção, tente rastrear que commit introduziu o bug e porque a pessoa fez isso. Com certeza ninguém colocou o bug lá de propósito, mas como efeito colateral de alguma outra alteração. Se começar a fazer isso, você vai passar a entender o que precisa fazer hoje para facilitar sua vida no futuro.

Nunca quebre o build

Nunca, mas nunca mesmo, em hipótese alguma, quebre o build.

E se quebrar, conserte rapidamente.

Seu código deve estar sempre minimamente compilando e com os testes rodando. Não estou falando aqui de nunca commitar bugs (até porque isso é impossível), mas de ter um padrão de qualidade mínimo dos seus commits. Não force os seus colegas de equipe a parar para corrigir esse tipo de erro primário que pode ser facilmente evitado apertando um botão no seu ambiente de desenvolvimento. Adquira o hábito de compilar e rodar os testes antes de apertar o botão de subir o código para o repo.

Isole modificações “de perfumaria”

Às vezes você está no meio de uma modificação e esbarra num comentário que está mostrando caracteres estranhos por algum erro de encoding. Ou então você nota que a tabulação está feita com hard tabs. Ou até mesmo encontra algum trecho de código que pode ser reduzido a uma única chamada se for usada uma função da biblioteca padrão.

Este tipo de alteração não vai mudar o comportamento do sistema, mas deve ser feito. Por outro lado, se você subir esta modificação junto com a sua, quem precisar ler o código vai ter uma carga cognitiva maior para conseguir entender o que você estava querendo fazer. Principalmente se você fez algum tipo de refactoring do código. Portanto, isole as modificações que não alteram o comportamento do sistema em seus próprios commits.

Você pode até combinar com sua equipe um padrão de título para commits de perfumaria. Assim quem precisar ler o histórico vai poder ignorar aquele commit em segurança, já que ele não afeta o comportamento do sistema.

Não repita o diff na mensagem de commit

Boas mensagens de commit são um assunto à parte. Mas a maioria das mensagens de commit seriam mais úteis se os devs atentassem para um fato simples: EU POSSO VER O DIFF! Então não precisa escrever na mensagem que aquele commit está acrescentando a rotina R à classe C.

A mensagem de commit serve para acrescentar informação ao diff, não para repeti-lo. O diff mostra o “o quê”, a mensagem deve ser usada para explicar o “porquê”. Eu consigo ver no diff que você acrescentou uma rotina R a uma classe C. O que eu preciso saber é porque diabos você acrescentou essa rotina. O que você estava pretendendo fazer com a nova rotina.

Revise sua alteração antes de subir

Nunca suba um commit antes de revisar o que está subindo. Sua IDE pode ter criado um arquivo de controle por trás dos panos… Você pode ter esquecido um print que estava usando para debug… O encoding dos arquivos de texto pode ter sido trocado acidentalmente… Milhões de coisas podem dar errado e fazer com que você suba lixo para o repo.

Além desses casos óbvios de lixo que você não quer que suba, há a questão semântica. Você pode querer criar vários commits para deixar mais explícita a evolução do código e/ou o raciocínio que usou para escrever aquilo.

Ferramentas atuais de controle de versão permitem que você separe facilmente os commits antes de subir (o git em especial é excelente nisso). É até aceitável que o primeiro dos commits quebre o build quando considerado isoladamente. Desde que seja uma alteração atômica e que suba para o repo junto com outros commits que o complementem e “consertem o build”.

Antes de publicar seu commit pense “Eu gostaria de revisar este commit numa sexta-feira à noite depois que todo mundo foi para casa e eu sou a última linha de defesa entre um bug e a aniquilação total da base de produção?”

Um laboratório agile a céu aberto

Se você apresentar o agile a um desenvolvedor experiente hipotético que ainda não o conhece, é bem possível que a reação seja: “tá, mas você só tá dando um nome ao que a gente já faz.”

É uma reação natural, afinal de contas agile é exatamente isso desde o início. O próprio manifesto foi escrito por desenvolvedores experientes para botar um nome naquilo que eles já estavam fazendo. As abordagens incrementais onde o software funcionando é a principal ferramenta de comunicação com o cliente tinham surgido independentemente várias vezes. Esse tipo de abordagem é o que os desenvolvedores adotam naturalmente se forem deixados em paz.

Isso é ótima notícia para quem já é experiente: para estar por dentro dessa buzzword basta continuar trabalhando normalmente. Mas e para quem está começando e quer aprender? E para quem sempre foi forçado a trabalhar com um modelo cascata e quer aprender? Seria ótimo se existisse algum tipo de fazenda de formigas onde você pudesse soltar um monte de devs, não impor restrições e ver como eles naturalmente se organizam. Onde você pudesse ver os devs agile trabalhando e aprender com eles.

Boa notícia para quem quer aprender: isso existe! E o nome é comunidade open source.

O open source de hoje já tem muito mais suporte corporativo do que o de dez ou quinze anos atrás. E junto com o suporte vem a interferência. Mas felizmente os projetos de hobby não são tão difíceis de encontrar. Até mesmo os projetos com suporte corporativo são bastante espelhados nos projetos de hobby. Ninguém quer contribuir com um projeto burocrático, então ou eles imitam os hobbistas ou simplesmente não recebem contribuições.

Um projeto de hobby é um exemplo perfeito de deixar os desenvolvedores em paz para se organizarem naturalmente: como estão fazendo algo porque querem, e não porque tem alguém pedindo ou pagando, o modo como vão se coordenar vai ser escolhido para beneficiar eles próprios. A partir deste modo de pensar emergem práticas atualmente identificadas com o agile. As práticas são interessantes, mas o mais importante é estar inserido nesta mentalidade. Porque é a partir dela que as práticas podem ser avaliadas criticamente e é a partir dela que novas práticas surgem.

Um dos valores do manifesto agile mais claramente adotado pelos projetos open source é o “software em funcionamento mais que documentação abrangente”, traduzido diretamente no “talk is cheap, show me the code” do Torvalds. Ninguém vê um projeto open source que passa meses “levantando requisitos” e escrevendo documentação antes de escrever ao menos uma prova de conceito ou um protótipo do sistema final. Há sempre uma versão que roda do sistema. Depois que os projetos começam, cada um dos commits modifica um pouco o código, mas sempre se mantém o sistema rodando. Não se quebra o build em projetos open source. Não se quebra o build em projetos agile.

Temos na comunidade open source um laboratório de agile a céu aberto com as portas escancaradas. Todo esse processo pode ser observado e esmiuçado por quem quer aprender. Basta fuçar as pull requests, bugzillas e gits da vida. A fazenda de formigas está aí. Basta ter a curiosidade de olhar.

(A propósito… Eu usei o tempo todo agile com ‘A’ minúsculo porque o Agile com ‘A’ maiúsculo é um termo extremamente sobrecarregado hoje em dia. Não estou falando de práticas específicas, de reuniões de pé, de TDD, nem de quadros com post-its. Estou falando do mentalidade ilustrada pelo manifesto. É triste isso de termos que deixar de usar a palavra que escolhemos para nomear este mentalidade, mas infelizmente é o estado em que nossa indústria chegou.)

Programar deveria ser fácil

Em julho deste ano, os físicos do LHC anunciaram a descoberta de uma nova partícula consistente com o bóson de Higgs. Eu não entendo nada de nada sobre física de partículas, mas gosto de acompanhar as descobertas da área para tentar absorver um pouco do entendimento que esses super-humanos têm da natureza. Quando soube do anúncio, não pude deixar de pensar que são essas pessoas que estão fazendo o trabalho duro de verdade.

Eu, aqui programando regras arbitrárias e tentando formar um universo artificial consistente? Nem tanto. Comparado com o trabalho desses caras, o meu é muito fácil. Mesmo porque na maioria das vezes minhas regras não se encaixam tão bem assim e passam longe de ser consistentes.

Até se trabalhássemos sempre para fazer programas totalmente consistentes e sem defeitos, nosso trabalho como programadores deveria ser mais fácil do que é. Mas porque tanta gente acha que programar é difícil?

Vamos voltar à Física por um instante. O objetivo de um físico é descrever as regras da natureza da forma mais simples possível. Há um conjunto de regras que já existe e funciona muito bem e eles tentam fazer a engenharia reversa do universo inteiro. Eles não possuem nenhuma documentação, diagrama, esquema ou planta fundamental além do que aquilo que os físicos anteriores descobriram. Para deixar a coisa mais complicada ainda, nem nessas descobertas anteriores eles podem confiar cegamente. A física newtoniana, por exemplo, não funciona nem nas escalas quânticas nem nas velocidades próximas à da luz. E eles tiveram que descobrir isso quebrando a cara.

O problema essencial é que há um conjunto de regras pré-estabelecidas que se quer conhecer.

Contraste isso com o Desenvolvimento de Software. Quando programamos, estamos definindo regras a partir do nada e temos controle total do funcionamento do “universo”. Sim, nós também precisamos subir nos ombros de gigantes e usar bibliotecas, frameworks e linguagens de programação que não fomos nós que inventamos. Mas as regras destas ferramentas que usamos também foram escritas do zero, tudo montado a partir de uma álgebra fundamental de bits. O que nós tentamos fazer é justamente o inverso do que os físicos fazem. Enquanto eles partem de um conjunto de comportamentos observáveis para extrair as regras de funcionamento, nós escrevemos as regras de modo a gerar o comportamento.

Programadores definem como um universo em particular deve funcionar partindo de regras já conhecidas. Físicos definem regras de modo a explicar um universo conhecido.

É como se os físicos estivessem tentando decifrar o código-fonte de um programa sem ter acesso nem aos binários. Se fazer decompilação não é coisa simples, imagina ter que fazer isso só com o resultado de testes!

Tendo isto em mente, fica mais difícil ter alguma compaixão pelos programadores. Enquanto os físicos precisam enfrentar uma complexidade inerente ao objeto de estudo deles, toda a complexidade que enfrentamos ao programar é culpa exclusivamente nossa como classe. Obviamente às vezes também precisamos modelar objetos e processos do mundo real inerentemente complexos, mas essa é uma conversa para outra hora (e minha impressão é que muitas vezes tornamos o pedaço de mundo real que estamos tentando modelar mais complexo do que ele realmente é). O que importa é que fomos nós que criamos este monstro complexo ao não dar a devida atenção ao design. Enfileirar bits de modo que um computador consiga seguir as instruções é até fácil. Fazer isto elegantemente é que é difícil. E por negligenciar essa parte difícil não temos a facilidade que deveríamos ter.

Bagunça pode ser tudo o que você precisa

Já notou que sempre bangunçamos o ambiente em que estamos trabalhando? Se você não fizer um esforço bem consciente para organizar tudo enquanto trabalha ou quando termina de fazer o que precisa, as chances são que as coisas estejam um pouco mais bagunçadas do que no início. Já notou também que mesmo que tudo pareça bagunçado, você (quase) sempre consegue se achar na sua bagunça? E que se alguém fizer o “favor” de “organizar” as coisas para você há uma boa chance de piorarem sua situação? Isso acontece porque a bagunça era a sua bagunça.

E também porque provavelmente não era uma bagunça.

Por trás desse tipo de bagunça aparente, há sempre uma ordem não óbvia. Para usar um exemplo bastante simples discutido no livro Uma bagunça perfeita de Eric Abrahamson e David H. Freedman (prometo publicar uma resenha apropriada em breve), uma pilha de papéis jogados sobre uma mesa está ordenada por ordem de uso: os mais usados ficam no topo e os menos usados no fundo. Isso acontece naturalmente se você sempre devolver os papéis que precisou da pilha para o topo. Do mesmo modo, se você pedir a alguém para realizar alguma tarefa rotineiramente, as pessoas sem nem perceber acabam bolando procedimentos de modo a facilitar o trabalho, aproveitar melhor o tempo e tornarem-se produtivas. Por isso bons programadores acabam chegando a algo parecido com XP se não forem podados.

Mas este é um blog sobre desenvolvimento de software para programadores e o trabalho do programador é justamente eliminar a bagunça do trabalho das pessoas, escrever programas que as ajudem a se organizar melhor, identificar “processos de negócio” e coisa e tal, certo?

Errado, se o seu ego conseguir aceitar que as pessoas que estão lá fazendo o trabalho no fim das contas sabem muito mais dele do que você.

Muitas vezes o que precisamos não é bem organizar o que as pessoas estão fazendo. Às vezes precisamos somente tornar a bagunça mais eficiente. Quando se tenta organizar muito os processos de trabalho das pessoas a coisa acaba ficando engessada demais. O resultado são sistemas que atrapalham mais do que ajudam e gente que passa mais tempo tentando agradar os sistemas corporativos do que resolvendo problemas dos clientes. Já ouviu a célebre frase “eu entendo, mas o sistema não deixa” quando tentou algo minimamente fora do comum com um banco ou uma operadora de telefone? É disso que estou falando. Resultado dos sistemas paralisantes. Resultado da organização demasiada.

Por outro lado sistemas caóticos terminaram sendo alguns dos exemplos de maior sucesso em nossa indústria. O Unix, por exemplo, é descrito por Martin Fowler como a maior aglomeração de coisas coladas umas nas outras que o mundo já viu. A web, por sua vez, é uma imensa bagunça de documentos, links e referências em escala global. Os dois sistemas têm em comum a filosofia de fazer pouca coisa, mas fazer bem o que escolheram fazer, e permitir que os usuários façam o que bem entenderem utilizando essa fundação. Eles não tentam organizar cada mínimo aspecto da rotina das pessoas. Eles aceitam o fato de que nunca vão conhecer o trabalho das pessoas tão bem quanto elas mesmas e se concentram em permitir que elas tenham liberdade para fazer o que quiserem do jeito que quiserem.

Todo programador deveria estar escrevendo jogos

Encomendei um livro chamado A theory of fun for game design de Raph Koster. Apesar do que possa parecer, eu não pretendo escrever jogos de computador num futuro próximo. Pelo menos não no sentido comum da palavra “jogo”. Então porque diabos eu iria querer ler um livro desses?

A resposta está estampada no título do livro: uma teoria da diversão. Este é um livro que tenta explicar, a partir do entendimento da diversão em si, o que torna alguns jogos divertidos enquanto outros são chatos. Ele tenta decifrar o que torna as coisas divertidas. E praticamente qualquer coisa pode ser divertida, não só jogos. Acontece que o objetivo final dos jogos é quase que exclusivamente a diversão. As pessoas jogam e brincam para se divertir. Bons jogos podem fazer mais do que isso, como exercitar habilidades sociais e ensinar novas idéias. Mas na maioria das vezes o que você quer fazer quando procura um jogo é simplesmente se divertir.

Para outros tipos de programas de computador a diversão não é o objetivo principal. Algumas vezes nem de longe. Mas diversão pode ser uma característica bastante atraente em muitas outras aplicações. Jogos precisam ser envolventes e divertidos se quiserem sobreviver. Se quiserem ser jogados. Se quiserem ser usados. É neste sentido que todo programador deveria escrever jogos. Não é porque uma aplicação não é vista prioritariamente como um jogo que ela não deva ser divertida, que seus autores não precisam se preocupar em entreter quem vai usá-la.

Vamos tomar o Stackoverflow como exemplo. Ele é um site de perguntas e respostas sobre problemas de programação. À primeira vista isso não se parece nada com um jogo, mas o sistema foi propositalmente concebido como um. Alguns aspectos foram inspirados especificamente no sistema de façanhas do Xbox 360 (ou como quer que os jogadores de Xbox traduzam “achievement”). Os pontos de reputação que você recebe como prêmio pela participação no site também são um aspecto que dá um ar de jogo à experiência e estimula uma competição saudável. Por causa dessa recompensa (que, por sinal, não passa de um direito de se gabar) mais perguntas são respondidas e com melhor qualidade. O aspecto de jogo ajuda o sistema, e a comunidade como um todo, a atingir a sua meta.

Aplicações divertidas são usadas com mais freqüência e dedicação. No fim das contas o trabalho do usuário acaba saindo melhor se ele se divertir no processo. Como diria a Kathy Sierra, ajudar seus usuários a arrasar deveria ser sempre seu objetivo, não?

Então quando estiver projetando alguma aplicação, talvez faça sentido pensar em como tornar a experiência mais divertida. Talvez você possa até incorporar recursos normalmente encontrados em jogos de computador para ajudar seus usuários a tirarem mais proveito da experiência. Talvez seja você possa pensar no sistema todo como um jogo.