quarta-feira, 23 de dezembro de 2009

Bjarne Stroustrup também lê o "Micos"

Lembram-se dos posts recentes sobre o desencontro entre universidade e indústria? Pois parece que o criador do C++, Bjarne Stroustrup, também leu e resolveu escrever a sua versão, que aparece na Communications of the ACM de Janeiro 2010. O artigo se chama "What should we teach new software developers? Why?" (obrigado Guilherme pelo share no Reader).

Se você se interessa pelo tema, leia o artigo agora ou durante o feriado. É bem legal e mais bem escrito que os meus, apesar dos meus serem mais precisos e menos genéricos em suas colocações, modéstia a parte.

Um bom Natal para todos!

quinta-feira, 17 de dezembro de 2009

Papai Noel, me dê usuários no Natal

Sim, Dezembro é um mês lento para os miquinhos que só conseguem sonhar com sonecas debaixo de coqueiros em praias tropicais. Enquanto isso não acontece, vamos falar sobre aqueles que são ao mesmo tempo a bênção e a maldição de todo sistema: os usuários.

Ter usuários é uma benção. Se você não tem usuários, todo seu esforço foi em vão, inútil, jogado fora. Todo sistema quer ter usuários pra provar pra si mesmo que merece existir. Não ter usuários resulta em aposentadoria precoce.

Ao mesmo tempo, ter usuários é uma maldição terrível. A partir do instante em que o primeiro deles clica o primeiro botão no seu sistema novinho em folha e recém-lançado, seus problemas começam. Os problemas são:

1. Dados

Enquanto não há dados de ninguém no seu sistema além das coisas engraçadinhas que você colocou lá nos seus testes, você pode mudar e desmudar o que quiser. Quando aparece a primeira informação de verdade, você passa a ter problemas. Não é mais possível fazer aquelas pequenas ou grandes mudanças sem pensar no efeito das mudanças sobre os dados que estão lá. Infelizmente o efeito é muitas vezes devastador: além de mudar seu sistema, você precisa transformar os dados existentes em dados que tem as propriedades novas que você quer. Tudo isso, é claro, enquanto seus usuários não param de jogar dados que você não quer pra dentro do seu banco de dados.

A solução: ao projetar seu sistema, antecipe as dificuldades de migração de dados e crie mecanismos para fazê-la facilmente. Por exemplo, garanta que sua camada de modelo é capaz de duplicar toda escrita em dois canais diferentes e ler de ambos também. Assim, você conseguirá fazer uma transição suave durante a qual tudo é escrito nas duas bases de dados. Quando isso estiver funcionando, você pode desligar a escrita na base antiga e ir copiando os dados para a base nova, enquanto o sistema continua funcionando e lendo das duas bases.

2. Comportamentos

Seus usuários vão se esforçar pra aprender a usar seu sistema. Como não desistiram, presumo que seu sistema seja bom. Acontece que se você mudar qualquer coisa que atrapalhe o esforço que eles investiram no aprendizado, eles vão te odiar, mesmo que a mudança tenha sido pra melhor. Aliás, não importa o que você faça, alguém sempre vai odiar.

Imagine que seus usuários tinham um limite ridiculamente pequeno de dados que podiam guardar no seu site. Imagine agora que de um dia pro outro você acabe com os limites e permita uso ilimitado. Toda funcionalidade permaneceu inalterada. Eu aposto o dinheiro que você quiser que algum infeliz vai reclamar e dizer que preferia quando tinha limites, pois forçava ele a se organizar melhor. A vida é assim.

A solução: como eu queria ter uma solução pra esse problema... o máximo que se pode fazer é tornar cada  atualização a menor possível. Se você quer fazer várias atualizações, contenha-se e faça uma de cada vez para dar aos usuários o tempo pra se acostumarem com a nova forma de se usar o sistema. Se você quer fazer mudanças radicais, permita que os usuários retornem ao modo antigo de ser, pelo menos durante um tempo.

3. Comunicação

Você mudava qualquer coisa e só tinha de virar pro lado e avisar pro seu colega que a mudança estava pronta. Agora não é mais tão simples assim. Os usuários não entendem quando coisas mudam sem explicações. Toda vez que alguma coisa relevante mudar (tipo toda semana) você vai ter de dar um jeito de explicar aos usuários. O problema é que é difícil ser ouvido. Ninguém quer ler seu blog e ninguém lê as mensagens que você coloca na página de login. Se você deixa um espaço na página principal do seu sistema pra avisos importantes, os usuários logo desenvolvem cegueira seletiva e param de ver o que está lá.

A solução: se quiser mesmo comunicar com seu usuário, varie. A regra básica é colocar seu comunicado o mais próximo possível do local em que o usuário vai usar o que está escrito. Se é uma funcionalidade nova, coloque um "novo!" discreto ao lado do botão ou seja o que for. Um balão estilo estória em quadrinhos apontando para a novidade também é uma boa. Deixe que o comunicado seja uma surpresa. Outra coisa importante é deixar que o usuário retire o comunicado da tela e que ele não apareça mais.



Há outros problemas, é claro, mas esses ficam pra outros posts. Os micos de realejo vão dar uma parada para os feriados e férias, mas voltaremos no final de Janeiro a todo vapor.

Boas festas!

sexta-feira, 4 de dezembro de 2009

Quem faz a manutenção do seu sistema?


Saiu um artigo sobre manutenção de software na Communications of the ACM de Novembro. Manutenção é um dos meus assuntos favoritos, porque é bem mais difícil cuidar de sistemas existentes do que criar sistemas novos.

Só pra definir e situar todo mundo, manutenção de software é o nome que se dá para a fase do ciclo de vida de um sistema que começa no instante em que o sistema é colocado em funcionamento. É comum se classificar em três os diferentes tipos de manutenção. O primeiro tipo é a manutenção corretiva, ou seja, corrigir bugs. O segundo tipo é a manutenção evolutiva, ou seja, acrescentar novas funcionalidades. O último tipo é a manutenção adaptativa, que significa mudar o sistema para se adaptar a mudanças no ambiente em que ele funciona - por exemplo, porque saiu o Internet Explorer 9 e seu sistema ficou todo quebrado.

Não gostei do artigo. Os problemas que os autores usam para motivar seus argumentos não são reais. O artigo até seria bom se tivesse sido escrito em 1989, mas vinte anos depois as coisas são diferentes. Na era da internet, todo software é software em evolução. Não existe mais o conceito de software que não é criado com a evolução e manutenção em mente. Nunca trabalhei em uma empresa que não achasse isso importante e não tentasse planejar de acordo.

É claro que existem problemas interessantes envolvendo a manutenção de software. Hoje vou falar sobre um deles: quem deve fazer a manutenção. Na semana que vem falarei sobre outros.

Primeiro, preciso fazer uma confissão. Eu adoro fazer manutenção. Corrigir bugs então, nem se fale. Posso passar dias, principalmente bugs em código que eu não escrevi. Não, eu não estou sendo irônico, eu sei que a maioria dos programadores detesta isso. Pois pra mim não tem nada mais divertido. Quando estou procurando bugs em código que eu não conheço, eu me sinto um detetive investigando um mistério. Preciso tentar descobrir o que o código faz, por que faz o que faz, o que estava passando pela cabeça do programador que o escreveu. E no final tem um prêmio concreto: remover o bug! Bom demais.

Também gosto muito de fazer a evolução de código que eu não escrevi. Gosto de olhar para o design do sistema e tentar pensar em um design mais adequado à mudança que eu quero fazer. Não tenho a mesma motivação para mudar código que eu mesmo fiz. Eu olho para aquilo e penso no trabalho que já deu pra escrever, e não quero mudar tudo de novo. Quando o código não é meu, não tenho esse bloqueio.

Bom, voltando ao assunto. É comum entregar a manutenção de sistemas existentes aos desenvolvedores menos experientes, deixando os programadores que tem super-poderes livres para trabalharem nas novas idéias que vão render um trilhão de dólares. Para mim, isso é um erro. Deixar a evolução nas mãos de pessoas que não conhecem bem os motivos por trás das decisões que levaram o sistema a ser como é leva inevitavelmente à degradação acelerada da qualidade do código. O desenvolvedor que faz mudanças pontuais sem levar em consideração o design geral do sistema torna o código cada vez menos estruturado.

Quando projetamos um sistema novo, temos um grau elevado de liberdade para tomar decisões técnicas. Existe um número quase infinito de caminhos corretos que vão levar ao sistema que queremos construir. Fazer manutenção, por outro lado, implica em trabalhar com muitas restrições. Existem muitas maneiras de se fazer o que precisa ser feito, mas poucas maneiras corretas.

A não ser que seu objetivo seja abandonar o sistema a curto prazo em prol de um novo sistema que está sendo desenvolvido, deixe que os melhores programadores cuidem dele. Assim ele vai crescer com saúde e alegria.

Ah, tem uma exceção: eu acho que corrigir bugs é a melhor forma de introduzir um novo desenvolvedor a um sistema existente. É uma tarefa concreta que exige que o programador aprenda muito sobre as entranhas do código e sobre o design dos componentes. É só garantir que todas as mudanças serão revisadas por um desenvolvedor experiente para que o exercício não vire um problema depois.

terça-feira, 1 de dezembro de 2009

Se Fernando Pessoa também fosse mico

Se Fernando Pessoa fosse um mero micoderealejo, ao invés de escrever isso, ele talvez escreveria isso:
Fazer um software e reconhecê-lo mau depois de feito é uma das tragédias da alma. Sobretudo é grande quando se reconhece que essa obra é a melhor que se podia fazer. Mas ao escrever um software, saber de antemão que ele tem de ser imperfeito e falhado; ao está-lo escrevendo estar vendo que ele é imperfeito e falhado _isto é o máximo da tortura e da humilhação do espírito. Não só as linhas que escrevo sinto que me não satisfazem, mas sei que as que estou para escrever me não satisfarão, também. Sei-o tanto filosoficamente, como carnalmente, por uma entrevisão obscura e gladiolada. (...) E o maior castigo é o de saber que o que escrevo resulta inteiramente fútil, falhado e incerto. Em criança escrevia já meus códigos. Então escrevia-os muito maus, mas julgava-os perfeitos. Nunca mais tornarei a ter o prazer falso de produzir o programa perfeito. O que escrevo hoje é muito melhor. É melhor, mesmo, do que o que poderiam escrever os melhores. Mas está infinitamente abaixo daquilo que eu, não sei porquê, sinto que podia _ou talvez seja, que devia_ escrever. Choro sobre os meus códigos maus da infância como sobre uma criança morta, um filho morto, uma última esperança que fosse.
Vai me dizer que não concorda com o nosso Fernando Pessoa imaginário?

Por sugestão do Hermes, adaptei este texto de Fernando Pessoa substituindo 'versos' por 'linhas de código' ou apenas 'código'. Também substituí 'obra' por 'software' ou 'programa', e a parte que eu não consegui simplesmente aplicar um sed 's/verso/código/' | sed 's/obra/programa/' removi.

Por favor, não me crucifique pelo, digamos, plágio! Vai me dizer que nunca copiou-e-colou um código e aplicou alguns sed para acertar os detalhes?

sexta-feira, 27 de novembro de 2009

Pare de escrever testes inúteis

É bom testar seu código. Ninguém discute isso. Montar um conjunto de testes automatizados pode ajudar em muito a qualidade do seu sistema. O problema é que muitas vezes medimos a qualidade da nossa base de testes unitários pelo percentual de linhas de código que é exercitada pelos testes. Chegar a 100% de cobertura é o alvo sagrado quase inatingível. Infelizmente, essa batalha é a batalha errada por dois motivos.

Primeiro e menos grave, ter uma cobertura de testes alta dá uma falsa sensação de segurança. Se temos 80% de cobertura, então 80% do código não tem erros, certo? Não exatamente. O que estamos medindo é cobertura de comandos, que é a forma mais fraca de cobertura. Eis um exemplo simples:

if ((a > 0) || (b < 0)) {
    c = 0;
} else {
    c = 1;
}

Bastam dois testes, um com a==0 e outro com a==1 para cobrirmos todas as linhas. No entanto, se houver um erro na segunda cláusula (se tivesse de ser b > 0, por exemplo), nossos testes não detectarão o erro. Um testador experiente sabe que tem de testar as duas cláusulas, mas um inexperiente pode ser ludibriado pela medida de 100% de cobertura desse código e pensar que não há nada mais a fazer.

Segundo e mais grave, há testes que simplesmente não fazem sentido. Já vi inúmeros testes em que o testador está simplesmente repetindo todo o comportamento da classe sendo testada. Quando se usa frameworks como EasyMock ou Mockito, fica ainda mais fácil cometer esse erro. Esses frameworks nos permitem verificar se determinados métodos estão sendo chamados com certos parâmetros. Se só o que o método faz é chamar os métodos x, y e z, o que acaba acontecendo é que o teste unitário simplesmente verifica se x, y e z são chamados nessa ordem. Qual é o erro que pode ser encontrado por esse teste unitário? Nenhum. Só o que acontece é que quem modificar o método vai ter de modificar seu clone do mal nos testes unitários.

Imagine uma classe de modelo cujo objetivo é receber estruturas de dados internas e convertê-las em chamadas ao banco de dados. Como testar essa classe? Fazendo um mock do banco, chamando a classe com alguns valores concretos, e observando que o banco está sendo chamado com os valores corretos. Qual o valor de se fazer esse teste? Quase nenhum. O único valor é que você está efetivamente duplicando a funcionalidade que você fez na classe original e, se as duas implementações forem diferentes, você vai ter de olhar pra ver qual das duas está errada. É uma versão do fenômeno da segunda vez.

Quando faz sentido fazer testes de unidade, então? Pra mim, só quando a classe tem lógica interna, ou seja, toma decisões ou faz alguma computação real que pode ser observada externamente. O ideal é poder observar as mudanças no estado no sistema, e não o seu fluxo de controle.  Traduzindo:

int metodo(int a) {
  int b = w(a);
  z(b);
  if (b > 0) {
    return x(b);
  } else {
    return y(b);
  }
}

Como deve ser um teste para esse método? Deve ser um teste caixa-preta. O teste deve testar os valores retornados são compatíveis com diferentes valores de entrada de a. Nada mais. Para isso precisamos entender o que w(a)x(b) e y(b) retornam. E z(b)?  Como sempre é executado, não faz sentido testá-lo. E devemos verificar se x(b) ou y(b) foram chamados? Na minha opinião, não. Devemos é saber se os valores de retorno esperados são equivalentes aos recebidos.

O bom teste deve desafiar o código sendo testado. Deve criar várias situações distintas e observar se o código reage de acordo com o desejado. Quanto mais forte o desafio, mais útil o teste. Desafios fracos criam testes fracos.

E daí, onde quero chegar com tudo isso? daí que criar e manter testes tem um custo, e esse custo não é trivial. Vamos então à lei de Torsten sobre testes unitários:
Todo teste unitário deve trazer valor a longo prazo maior que seu custo de criação e manutenção.
Aqui, o valor do teste é proporcional ao desafio que ele faz ao código testado.

Resumindo, é OK não chegar nem perto de 100% de cobertura. Teste apenas o que faz sentido, lembre-se que nem todo teste é útil. E quando fizer sentido, teste direito, não se esqueça de testar nenhum caso importante só porque já cobriu todos os comandos.

quinta-feira, 26 de novembro de 2009

Ajude a definir seus direitos na internet, não deixe para o Frederico Pandolfo.

Participei na terça-feira de um painel sobre computação nas nuvens em um evento chamado internet do futuro, patrocinado pela Abranet e pelo ICANN. O painel foi legal, com presença da Microsoft, UOL, Locaweb e Google, mas mais legal ainda foi o painel que veio antes dele, sobre regulação da internet no Brasil.

Lá eu fiquei sabendo de uma iniciativa super interessante: o Marco Civil da Internet. O marco civil é uma iniciativa do governo em definir direitos e responsabilidades do usuário de internet no Brasil. É o contrário da Lei Azeredo, que queria começar definindo quais são os crimes antes de definir quais são os direitos.

O mais legal é que está sendo feito de forma realmente democrática. A proposta de projeto está publicada no site e qualquer pessoa pode inserir seus comentários em cada seção do projeto. Há um debate muito interessante acontecendo, mas acho que pouca gente ainda sabe disso. Durante o painel, um representante do Ministério da Justiça explicou o esforço sendo realizado e me pareceu que o governo está realmente atento ao debate e levando a sério. O resultado do debate será transformado em anteprojeto de lei e levado para votação.

Quem é Frederico Pandolfo? Ninguém sabe, mas ele é responsável por quase um quarto de todos os comentários no site. Se você não quer que o Frederico Pandolfo decida quais serão seus direitos legais, vá agora mesmo ler a proposta e deixe lá seus comentários.

sexta-feira, 20 de novembro de 2009

Faça outra coisa

Acordou hoje e aquela tarefa grande parece enjoada? Está há várias horas travado em um bug e não progride?

Use seu tempo para aprender outra coisa, escrever uma ferramenta que auxilie marginalmente sua equipe, desenvolver um projeto pessoal, escrever em um blog, atrapalhar todo mundo e conversar sobre a direção do seu projeto. Programação é uma tarefa que precisa ser executada com perfeição. Se você está sem paciência com o que tem em mãos agora, é muito provável que seu tempo seja melhor aproveitado em outra tarefa.

Prazos existem, mas gastar X horas fazendo um trabalho que depois precisará de Y horas para ser refeito é pelo menos tão ruim quanto postergar esse trabalho por Y horas e depois gastar alguma fração de X motivado.

terça-feira, 17 de novembro de 2009

Um dia depois do outro

Estou viajando e sem tempo de postar. Obrigado Ademir por ter mantido o Micos vivo na semana passada.

Viajar é bom mas é sempre difícil quando a gente volta, leva um tempo pra conseguir retomar as atividades. Aliás, nem é preciso viajar. Muitas vezes começar de manhã cedo já é complicado. Eu às vezes enrolo o quanto posso, lendo meu Google Reader, respondendo e-mail, tudo menos pegar no código.

Uma coisa que me ajuda muito a pegar firme de manhã é não terminar no dia anterior. Essa dica me deram quando eu estava escrevendo - pare um parágrafo no meio, sabendo como quer continuar, mas não continue. No dia seguinte, pegue aquele parágrafo pra terminar e fica fácil continuar escrevendo. A inércia está em começar algo novo.

O mesmo se aplica à programação. Eu agora nunca vou pra casa deixando o programa arrumadinho. Sempre fica algum erro de sintaxe, algum bug não corrigido, algum método sem terminar. No dia seguinte eu sei exatamente o que fazer e de repente me vejo trabalhando e não enrolando.

Sabe aquela vontade de "só terminar isso aqui que eu vou embora?" Não termine! Se você é do tipo procrastinador como eu, deixe pra terminar amanhã o que você começou a fazer hoje. Sua produtividade vai aumentar bastante.

quinta-feira, 12 de novembro de 2009

Remédio pior que a doença

Naquela manhã cheguei cedinho ao escritório para começa a codificar tudo o que eu tinha passado parte da minha noite pensando. Pensando, não, alternando entre curtos cochilos, momentos de completa euforia por ter achado a solução mais simples possível e momentos de decepção e desespero por ter esquecido um corner-case.

Vai me dizer que nunca teve uma noite destas?

O problema era trivial: fazer uma infraestrutura para reinserir dados que foram removidos do sistema por algum engano. Simples, não é? Pois é, a solução também deveria ser. Porém, 'dobrar' o sistema para fazer isso era muito complexo.

Os dados removidos tinham que ser re-gerados praticamente do zero e combinados da maneira correta com os pedaços que não haviam sido removidos. Eu nem preciso dizer o quão complexo e error-prone é 're-gerar' um dado fora do pipeline normal, não é? Sempre tem aquele campo que é preenchido por aquela função que é simplesmente impossível de desacoplar do sistema ou que ninguém sabe direito como ele é gerado. Credo, está dando enjôo só de lembrar do problema!

Na verdade, na minha cabeça, esta feature nem era necessária pois estes dados seriam naturalmente re-inseridos no sistema depois de alguns dias. Eu já havia feito a mudança para que o pipeline recolocasse-os de volta. Mudança simples, por sinal. Porém, segundo o resto do time, fazer a recuperação instantânea dos dados era crucial...

Bom, se era necessário, tinha que ser feita, não é?

Abri meu Vi e comecei a implementar aquelas linhas que já tinham me custado várias horas de sono.

A fase 1, a mais trivial, estava quase pronta, com testes e tudo. Para a fase 2, conversei com um colega que conhecia melhor o sistema e confirmei: minhas horas de sono não foram gastas em vão. A solução ia funcionar!

Peguei um copão de café, voltei para minha mesa, reatachei meu screen, adrenalina total, escrevi duas linhas de código e, simplesmente, parei.

Parei pois me veio à cabeça a imagem do Torsten saindo todo feliz de uma reunião com os PMs (Product Managers) e falando: "Pronto, eliminei mais três features, agora só faltam mais duas!". Acho que não digitei nenhum caracter a mais, virei para o lado e falei com o colega que havia me dado as dicas: "Eu acho que não vale a pena implementar esta feature. É tão complexa! É a única solução possível, mas é complexa de mais, não encaixa no sistema. Ele não foi feito para isso! Vai gerar overhead de complexidade e de manutenção que realmente não vai valer a pena.". Ele disse: "É mesmo.".

Pronto, agora era só convencer o resto do time que qualquer solução era pior que o próprio problema e o meu final de semana estava salvo.

Resultado: conseguimos convencer o resto do time, o sistema ficou muito melhor sem a feature, pude gastar meu tempo melhorando outras partes e implementando features realmente necessárias.

O que fiz no final de semana seguinte? Dormi as horas de sono que haviam ficado pendentes.

sexta-feira, 6 de novembro de 2009

O que você faria diferente?

Essa semana não deu pra postar no blog: feriado, depois muito trabalho. Vamos ver se semana que vem eu consigo, ou quem sabe meus colegas de blog dão as caras.

Semana passada estive na PUC pra falar aos alunos formandos em sistemas de informação sobre a carreira deles. Na verdade eu só falei mesmo sobre a minha carreira, que é a única que eu conheço bem, mas espero que tenha ajudado.

O que eu falo pra eles se resume no seguinte:
  1. Faça o que você gosta. Nao adianta ganhar dinheiro ou ter prestígio se você vai passar a maior parte das horas da sua vida fazendo coisas que não quer.
  2. Fazer o que gosta não é suficiente. É preciso ter certas competencias como gostar de aprender, comunicar-se bem em português e inglês, saber trabalhar em equipe e, naturalmente, ter uma base forte de fundamentos da computação, principalmente algoritmos e estruturas de dados.
  3. Se quiser fazer mestrado, faça agora. Se quiser fazer uma pós latu sensu, faça daqui a cinco anos quando tiver mais experiência. Doutorado, só se você quiser muito mesmo.
  4. Não tema o desemprego, tema sim as fracas condições de trabalho e salários oferecidos ao profissional de informática. Cabe a você informar o mercado de que esse profissional não é uma peça intercambiável da sua empresa. É melhor estar desempregado do que em um emprego ruim, pois ficar em um emprego ruim mostra ao mercado que empregos assim são aceitáveis.
Uma aluna fez um comentário dias depois: "eu queria ter escutado essa palestra no primeiro período".

Isso me fez pensar: o que eu faria diferente na minha carreira? Achei difícil responder essa pergunta. Foi mais fácil pensar o que eu NÃO faria diferente: 
  1. Eu não faria um MBA.
  2. Eu não deixaria de fazer meu doutorado, apesar de não ter seguido carreira acadêmica.
  3. Eu não trocaria de profissão.
Talvez eu tivesse seguido a carreira acadêmica se houvesse uma oportunidade interessante. Infelizmente, nenhuma das oportunidades que eu vislumbrava me interessou.

Acho que o que eu teria feito diferente seria escrever mais código. Meu doutorado de 7 anos foi composto de alguns grandes esforços bem concentrados, separados por longos períodos de nada. Eu devia ter enchido meus períodos de nada participando de algum projeto open source.

E você? Faria alguma coisa diferente?

quinta-feira, 29 de outubro de 2009

Do desencontro entre universidade e indústria - parte 3 - seus professores

Existe uma desconfiança generalizada daqueles professores de computação que tem pouca ou nenhuma experiência prática com grandes projetos de software. Isso se aplica à maioria dos professores em universidades que são fortes em pesquisa e a muitos professores das universidades focadas em ensino. Esses professores muitas vezes ficam sem credibilidade frente a alunos que questionam se o professor sabe mesmo sobre o que está falando. Afinal, como ele pode saber se nunca trabalhou?

Porque veja bem, ensinar não é trabalho. Eu mesmo me cansei de ouvir alunos perguntando se eu "trabalhava ou só dava aulas?"  Tanto que parei de dar aulas e fui trabalhar, mas isso é outra estória.

O fato é o seguinte: fazer e ensinar são duas coisas completamente diferentes. Para ser bom em um não é preciso ser bom no outro, nem vice-versa. O fato da sua professora que te ensina design patterns nunca ter de fato usado um design pattern para resolver um problema que ela teve no trabalho dela é totalmente irrelevante. As questões são: ela sabe o que está falando? ela sabe te mostrar um exemplo que te ajude a entender o que ele está falando? quando você não estiver entendendo nada, ela sabe te pegar pela mão e te fazer perguntas e mostrar o caminho até você entender? Pois é isso que ela precisa saber.

Muito maior do que o problema da falta de experiência prática dos seus professores é a falta de incentivo para que sejam bons professores. Em universidades de pesquisa isso é gravíssimo. Há excelentes professores, mas excelentes porque querem ser e não porque ganham algo com isso. Se um professor de repente tem uma reunião cancelada e tem o dia inteiro livre pela frente, é muito melhor para a carreira dele investir aquele dia em pesquisa do que investir em melhorar as disciplinas que ele leciona. Não há incentivo para a excelência no ensino.

Nas universidades de ensino também não há incentivos. Qual a diferença em termos de carreira entre um professor que faz o mínimo para não ser mandado embora e um que dá o seu sangue e seus fins de semana para garantir que os alunos estão tendo a oportunidade de aprender algo importante? A resposta é que não há nenhuma diferença.

Se você é aluno, você tem professores que passam seus dias pensando em formas melhores de educar. Se você se importe com a falta de experiência de mercado deles, esqueça isso e comece a pensar em incentivos para eles se dedicarem mais a vocês, porque hoje eles tem poucos.

quarta-feira, 28 de outubro de 2009

Do desencontro entre universidade e indústria - parte 2 - o mundo real

Continuando o post de ontem, hoje vou falar sobre outra queixa frequente da indústria de software sobre o ensino de computação nas universidades: o fato dos alunos não adquirirem habilidades que são importantes no "mundo real." Veja as queixas do Joel:
Where are students supposed to learn about version control, bug tracking, working on teams, scheduling, estimating, debugging, usability testing, and documentation? Where do they learn to write a program longer than 20 lines?
Dá pra resumir em uma frase: "os alunos não aprendem a desenvolver sistemas de médio/grande porte."

É claro que não. Só há uma forma de aprender a se trabalhar em uma equipe que faz um sistema de grande porte - trabalhando. Trabalhando durante meses e meses a fio. Se envolvendo com requisitos, projeto, repositórios de controle de versões, rastreamento de bugs, deadlines, milestones e tudo mais. Um professor pode até falar a respeito dessas coisas para introduzir o vocabulário, mas não haverá fixação sem a prática.

E por que não fazer isso na sala de aula? Por que não dedicar o último semestre de um curso de quatro anos inteiramente a um grande projeto realizado por todos os alunos em uma grande equipe? Os professores seriam os clientes e gerentes. Creio que com uns oito professores trabalhando juntos, conseguiríamos tocar uma equipe de 40 desenvolvedores inexperientes. Por que não fazer isso? Não parece uma boa idéia?

Primeiro problema: avaliação individual.

O objetivo de uma universidade não é só ensinar. É também entregar atestados chamados "diplomas" que atestam a quem interessar possa que o indivíduo que o carrega tem certas competências. É por isso que até hoje fazemos provas escritas quando todo mundo está careca de saber que essa é uma das piores formas de se avaliar competências - ainda não encontramos forma melhor que funcione quando temos mais de 5 alunos por professor.

Mesmo que cada um dos oito professores use o tempo que lhes sobra depois de gerenciar a equipe (se é que vai sobrar algum) para avaliar os alunos em algum quesito como qualidade do código, uso do repositório, produtividade, adesão à especificação, etc., etc., continua dificílimo avaliar cada aluno individualmente. As tarefas que cada um fará nunca serão homogêneas ou equivalentes, mas os alunos tem de ser avaliados segundo os mesmos critérios.


Segundo problema: qual projeto?

Coloque-se por um instante no lugar de um dos professores que está planejando esse lindo curso de um semestre. Antes do semestre começar, você e seus colegas tem de resolver as seguintes questões:
  1. Especificar detalhadamente um sistema que possa ser desenvolvido por 40 pessoas trabalhando 20 horas por semana durante 4 meses. Não erre suas estimativas nem pra mais, pois os alunos não podem ficar ociosos no final do semestre, nem pra menos, pois os alunos devem ser capazes de concluir o projeto para ficarem motivados.
  2. Preparar um laboratório com o ambiente de desenvolvimento, instalando e configurando todas ferramentas de controle de versões, acompanhamento de bugs, IDEs de desenvolvimento e tudo mais.
  3. Elaborar cronogramas detalhados com entregas bem definidas distribuidas por todo o semestre.
  4. Definir os critérios de avaliação e dividir as tarefas de gerência entre os professores participantes.
Lembre-se que no semestre seguinte você terá de fazer tudo de novo, pois não quer que os alunos copiem o trabalho dos alunos dos semestres anteriores.


Terceiro problema: caos

Um projeto de 40 pessoas é caótico, não adianta querer que seja diferente. É preciso lidar com problemas pessoais, atrasos de umas equipes que prejudicam outras, problemas no ambiente de desenvolvimento, conflitos interpessoais e dezenas de outras coisas que acontecem no mundo real. Só que um curso universitário precisa de ordem e previsibilidade, caso contrário nada funciona.

Imagine os professores se reunindo para avaliar os alunos ao final do projeto:

Prof. Feliz: "Ufa! Não saiu nada como planejamos mas foi ótimo porque os alunos entenderam como funciona o mundo real. Mas que nota vamos dar pro Zé? Ele não fez nada."
Prof. Chato: "Ele não fez nada porque o João atrasou a entrega e ele teve de esperar. Não podemos penalizá-lo por isso."
Prof. Feliz: "Então que nota vamos dar pro João por ter atrasado?"
Prof. Chato: "Tem de ser altíssima apesar do atraso, só não atrasou mais porque o João carregou a equipe dele nas costas depois que a Vó da Elaine ficou doente. Ele é o melhor de todos."
Prof. Feliz: "Mas ninguém gosta dele! Ele quer fazer tudo e tolhe os colegas. Temos de levar isso em conta."

Sentiram? São nuances demais para se transformar em uma nota objetiva entre 0 e 100.

Até daria pra se fazer algo desse tipo em uma universidade, não é impossível. Só que nenhuma universidade que eu conheço tem os recursos necessários para se implementar um projeto desses com sucesso, e nenhum professor recebe o suficiente pra passar pela dor de cabeça que isso vai dar.

Tem ainda outro argumento que eu não usei mas que foi usado em um painel de discussões que assisti a muuuitos anos atrás, em que meu prof. José Nagib respondeu da seguinte forma a um comentário de um representante da indústria, semelhante ao comentário do Joel:
"Nós não sabemos ensinar isso que vocês querem. Vocês é quem tem de ensinar."
Acho que é um bom jeito de encerrar o tópico de hoje.

Amanhã falarei sobre a capacitação dos professores.

terça-feira, 27 de outubro de 2009

Do desencontro entre universidade e indústria - parte 1 - conhecimento inútil

Eu adorava ler Joel on Software. Até comprei o livro com a coletânea dos melhores posts. Só que de uns anos pra cá o Joel perdeu totalmente a inspiração e, de vez em quando, me faz perder meu tempo. O último post dele fala sobre o desencontro entre o que alunos aprendem nas universidades e o que a indústria de software realmente precisa. Outro que foi pela mesma linha recentemente, dessa vez em uma auto-crítica partindo de um membro do meio acadêmico, foi o Prof. Geraldo Xexéo da UFRJ, que pede mudanças radicais no ensino de computação.

Ora, tem mais de vinte anos que eu escuto a mesma ladainha e, francamente, já me cansei. Os argumentos da indústria de software, representada aqui pelo Joel, são os seguintes:
  1. Os alunos só aprendem teorias que não tem utilidade prática
  2. Os alunos não aprendem a colaborar, a trabalhar em grupo, a depurar código, a documentar, a usar ferramentas, ou qualquer coisa que faça parte de um projeto real de software
  3. Os professores não tem nenhuma experiência com engenharia de software "de verdade."
A indústria parece pensar que a universidade deveria ser uma máquina de produzir desenvolvedores que vão sair de lá prontinhos pra trabalhar nos calabouços deles. Nada disso. O papel da universidade é outro. Dá pra falar tanto sobre esse assunto que vou dividir minha resposta em três partes. Na de hoje, vamos falar sobre o primeiro ponto - "os alunos só aprendem teorias sem utilidade prática."

Qualquer professor de computação já se deparou com um aluno que acha inútil o que ele está ensinando, ou mandando ele fazer. Eis alguns exemplos de queixas de alunos:
  • "Por que eu tenho de implementar uma pilha? Qualquer linguagem de programação moderna já vem com pilhas prontas e eu nunca nunca nunca vou ter de implementar uma pilha na vida."

    O bom professor então dá um tapa na cabeça do aluno e diz, "É claro que não. Você precisa é aprender a escrever uma estrutura de dados; a encapsular informações; a definir uma interface; a manipular apontadores. É isso que você está fazendo. Vai trabalhar e para de reclamar."

  • "Por que eu estou aprendendo Scheme? Ninguém no mercado usa Scheme!"

    Porque programação funcional não é restrita a uma linguagem. É uma forma pensar e estruturar programas extremamente útil que pode ser feita em qualquer linguagem. Se você conseguir programar em Scheme, temos uma chance de você entender que forma é essa.

  • "Eu trabalho e sei que na prática ninguém segue esses processos todos, é impossível."

    Claro que ninguém segue. Você não vai usar esses processos do jeitinho que vem no livro. O que você vai fazer é destilar de lá algumas boas práticas que vão te ajudar a resolver problemas específicos em momentos diferentes. E mais, vai aprender o vocabulário necessário pra entender o que te dizem quando estiverem falando sobre projetos de verdade.
O ensino de informática/computação nas universidades tem muitos críticos, mas o fato é que nenhum deles foi até agora capaz de propor um modelo de ensino que seja viável e melhor que o vigente. É claro que é preciso manter os currículos sempre atualizados, mas os fundamentos da área mudam pouco com o passar dos anos.

Continua na parte 2.

terça-feira, 20 de outubro de 2009

Sistema operacional 100% livre de erros? Bah!

Olha só as bobagens que diz a imprensa: "Primeiro sistema operacional 100% livre de erros está pronto."

O artigo descreve um sistema operacional embarcado desenvolvido por seis desenvolvedores em seis anos que "está 100% livre de erros de programação". Mais adiante no artigo encontramos a frase chave: "O sistema de verificação garante que o kernel atende inteiramente a toda a sua especificação." Se você ainda não viu a falácia no argumento, leia o post "a mesa errada".

Estar de acordo com a especificação não dá a menor garantia de que um programa não tem erros. O que garante é que há duas descrições equivalentes de um sistema - a especificação e o código. Se houver erros na especificação, haverá erros no código. Pior - a especificação é certamente uma abstração do código, ou seja, há inúmeros detalhes no código que não são tratados na especificação. Qualquer erro presente nesses detalhes não será apanhado pela verificação.

Não estou dizendo que a verificação formal é inútil, muito pelo contrário. É útil, como aponta o artigo, para garantir certas propriedades, como por exemplo garantir que um loop nunca terá valores fora de um intervalo específico, ou talvez garantir que todo objeto alocado será liberado mais tarde. Mas dizer que garante que o sistema não tem bugs é uma grande bobagem. Certamente é culpa do repórter, nenhum pesquisador sério alegaria isso sobre seu trabalho.

O artigo deveria se chamar "primeiro sistema operacional com 100% de conformidade à sua especificação está pronto" ou, melhor ainda, "primeiro sistema operacional que teve alguma especificação está pronto!"


ATUALIZAÇÃO: De fato, os autores do artigo original sabem o que estão falando e não falam nada sobre ausência de bugs - http://www.cse.unsw.edu.au/~kleing/papers/sosp09.html

Cadê os clássicos da "literatura de códigos"?

Muito bem, concordo que alunos de computação e cursos afins precisam aprender a ler código. Muito mais do que acostumá-los com a sintaxe, queremos ensiná-los a compreender o que estão lendo, a tirar da leitura mais do que se vê superficialmente.

Por exemplo, o que diz essa função?

void saveAgendaAsCSV(List agenda) {
  String csv = new StringBuilder(MAX_CSV_SIZE);
  for (user in agenda) {
    csv.append(user.name);
    csv.append(",");
    csv.append(user.phone);
    csv.append(",");
    csv.append(user.email);
    csv.append("\n");
  }
  return csv;
}


O novato diz que ela itera sobre os membros de uma lista de usuários e retorna um string com todos os dados dos usuários, um por linha. O programador experiente diz que ela converte uma lista de usuários ao formato CSV, para ser exportada. O grande programador sabe que essa função implementa a liberdade de dados que a aplicação permite. O novato sabe como a função trabalha. O experiente sabe o que a função faz. O grande sabe por que ela existe.

Todo código conta uma estória. O programador precisa saber ler além das simples linhas de código e entender a estória. Que estória esse trecho de código conta?

if (userId != 0) {
  associarUsuarioAoGrupo(userId, groupId);
} else {
  throw new RuntimeException("User id should not be zero.");
}


Desiste? A estória é a seguinte: um dia, houve um bug que levou horas para encontrar. O culpado era um id de usuário no banco de dados que valia zero, quando isso deveria ser impossível. Ao invés de descobrir como o problema aconteceu e corrigir o erro real, garantindo que isso nunca mais aconteça, o programador preferiu acreditar que o erro acontecerá de novo e está se defendendo para a próxima vez.

O que queremos estudar é a compreensão de textos, algo muito mais complexo do que sintaxe. Na escola estudamos o livro O Velho e o Mar, que pode ser apenas um conto de pescador, mas aprendemos que é uma alegoria que permite inúmeras interpretações sobre a condição humana. Assim precisa ser com a leitura de código - precisamos ensinar ao aluno a enxergar no código não só a estrutura de comandos, mas o projeto e arquitetura do sistema, assim como seus requisitos.

Só que implementar isso é bem mais difícil do que parece. Não acho que é suficiente uns alunos lerem o código dos outros. Como disse a Guta, eles precisam ler bons códigos. Mas de onde vamos tirar esses bons códigos?

Talvez eles venham da comunidade de código aberto, mas a verdade é que ainda não temos a resposta para essa pergunta. A comunidade acadêmica precisa coletar uma amostra significativa de bons sistemas para serem estudados - o equivalente a uma biblioteca de clássicos da literatura. Esses sistemas podem ser estudados por várias gerações de alunos e servirem como bons exemplos.

Vai dar um trabalhão, mas quanto mais esperarmos pra começar, mais vai demorar. Mãos à obra, então!

domingo, 18 de outubro de 2009

Fred Brooks no Brasil esta semana

Depois de falarmos tanto em Fred Brooks, parece até que ele nos ouviu e veio parar no Brasil. Segue mensagem do prof. Fabio Kon divulgando uma palestra que ele vai proferir.  Se algum leitor deste blog for ao evento, por favor nos escreva contando como foi!



Fred Brooks estará no IME/USP para lançamento da versão em português de seu clássico livro "O Mítico Homem-Mês". Ele irá proferir (em inglês) a palestra "Colaboração e Telecolaboração em Projetos: o quanto o modelo Bazar se aplica".

Inscrições gratuitas em http://www.caelum.com.br/brooks

 Autor de O Mítico Homem-Mês chega ao Brasil para o lançamento da edição comemorativa

No dia 21 de outubro, em São Paulo, a editora Campus-Elsevier promove ações para o lançamento do clássico da literatura sobre Engenharia de Software. Frederick Brooks fará palestra no evento, que tem início às 14h, ministrada em inglês, com o tema “Colaboração e Telecolaboração em Projetos: o quanto o modelo Bazar se aplica", no auditório Antônio Gilioli, do IME-USP, na Cidade Universitária. Este evento conta com o apoio de Caelum, CCSL-USP e Locaweb. O autor também participa da noite de autógrafos, que acontece, às 19h, na livraria Saraiva, do Shopping Higienópolis. Os interessados pela palestra poderão se inscrever gratuitamente através do site www.caelum.com.br/brooks.

O Mítico Homem-Mês foi considerado a primeira obra literária de grande impacto que expôs claramente as peculiaridades da indústria de software. Nesta edição, ampliada, o autor apresenta três novos capítulos e os pensamentos mais atuais sobre o tema, além de uma retrospectiva sobre as principais mudanças ocorridas desde o lançamento da primeira edição, em 1975.

Com uma rica mistura de fatos sobre o assunto e opiniões que provocam reflexão, Brooks oferece sua visão e experiência para todos aqueles que lidam com a gestão de projetos complexos. Comemorando 20 anos desde a publicação original, ele adicionou novos pensamentos e conselhos. De acordo com especialistas, o clássico se tornou leitura indispensável à formação de todos os profissionais que estão envolvidos diariamente com projetos de software e seu gerenciamento.

Conhecido como o “pai do sistema IBM /360”, tendo atuado em seu desenvolvimento como gestor de projeto e, depois, como gestor do projeto de software do sistema operacional /360 durante sua fase de arquitetura, Frederick P. Brooks Jr. é professor patrono de Ciência da Computação na Universidade da Carolina do Norte, em Chapel Hill, nos Estados Unidos.  Graças a esse trabalho, Brooks, Bob Evans e Erich Blow receberam a Medalha Nacional de Tecnologia em 1985. Em Chapel Hill, Dr. Brooks fundou o Departamento de Ciência da Computação, do qual foi presidente entre 1964 e 1984. Atuou no Comitê Nacional de Ciência e no Comitê Científico de Defesa. Atualmente, suas áreas de ensino e pesquisa estão relacionadas à arquitetura de computadores, aos gráficos moleculares e aos ambientes virtuais.

sexta-feira, 16 de outubro de 2009

Objetivos te ajudam a dizer não

No último post sobre medidas eu mencionei o GQM, goal-question-metric, que me fez lembrar de outra coisa que é difícil de fazer - traçar bons objetivos. A gente aprende que pra qualquer coisa ser bem-sucedida - um projeto, uma empresa, a vida - é preciso ter objetivos claros, senão como é que a gente vai saber se foi ou não bem-sucedido?  Com um objetivo claro em mente, a gente deveria conseguir tomar decisões mais facilmente, fazer bons planos e ter mais foco. O objetivo nos mostra o que fazer, certo?

Errado. O objetivo do objetivo (ha!) é delimitar o que você NÃO deve fazer. Quanto mais ações o seu objetivo excluir, melhor e mais útil ele será.

Vamos a alguns exemplos de objetivos que não são úteis:

"Nosso objetivo é ser o melhor site de XYZ do mundo"
O que quer dizer ser "o melhor"? Objetivos não mensuráveis são inúteis.
"Nosso objetivo é ajudar as bibliotecárias a serem mais produtivas"
Um pouco mais concreto, mas ainda vago demais. Se você conseguir quantificar o que quer dizer com "mais produtivas", pode ser bom.
"Nosso objetivo é alcançar 10 mil usuários semanais ativos até o fim do ano"
Esse parece perfeito, não parece? É bem claro, nada ambíguo e facilmente mensurável. Qual o problema, então? O problema é que ele não é útil para se tomar decisões no dia-a-dia. Pense em todas as decisões pequenas ou grandes que você toma no seu trabalho. Agora pense que a pergunta que norteia cada decisão é, "isso vai me ajudar a ter 10 mil usuários ativos?"  A resposta honesta em quase todos os casos é "sim," pois presumo que você está decidindo sobre algo que vai melhorar seu sistema, e pode-se argumentar sobre qualquer tipo de melhoria que ela ajudará a atrair novos usuários. Se seu objetivo não te ajuda a dizer "não" durante uma decisão, ele não é útil.
"Nosso objetivo é aumentar o tempo médio diário de uso por usuário do sistema em 20%"
O mesmo caso do exemplo anterior. Em que esse objetivo me ajuda a tomar alguma decisão importante?
Ruins mesmo são muitos objetivos em forma de "mission statements" que você vê por aí, mais ou menos assim:

"Nosso objetivo é alavancar as sinergias existentes explorando esforços e infraestrutura interdepartamentais através da integração profunda de produtos de uso interno."
Sem comentários.
O que é um objetivo bom, então? Um objetivo bom é aquele que te ajuda a excluir possibilidades. Ele delimita e restringe as decisões possíveis. Ele traz foco.

"Nosso objetivo é reduzir o tempo de resposta médio de todas as queries em 20%, no mínimo."
Ah, muito bem. Então não é pra melhorar a usabilidade, nem criar novas funções, nem reduzir o número de erros, nem... entendi.
"Nosso objetivo é aumentar o número de conversas que nossos usuários tem na internet."
Esse não é tão fácil de se medir, mas dá um foco claro. Quero incluir joguinhos tipo quebra-cabeça no site. Devo? Bom, isso vai ajudar as pessoas a conversarem mais? Provavelmente não. Então não deve.
Quanto menos abrangente um objetivo, mas útil ele lhe será, tanto no trabalho quanto na vida. Opa, me desculpem, trabalho é vida, mas isso é tópico pra outro post.

quinta-feira, 15 de outubro de 2009

Medidas são úteis, sim

Alguns amigos comentaram comigo que ficou parecendo no meu post sobre métricas que eu acho que métricas não servem pra nada. Assim, vamos a outro post pra corrigir essa minha falha. Além disso, nos comentários daquele post o Peter chama a atenção para o GQM (goal-question-metric), uma metodologia para uso correto de métricas, e me corrige no uso do termo, pois hoje é mais bem aceito o termo "medida" ao invés de "métrica".

Muito bem, se medidas não servem para tomar decisões, pra que servem, então?

Em primeiro lugar, como diz o GQM, serve para validar as decisões que você tomou. O GQM prega que você deve primeiro traçar seus objetivos, depois formular questões cujas respostas indiquem se os objetivos estão ou não sendo alcançados, e finalmente determinar medições a serem feitas para responder às questões formuladas. Notem que no GQM a medida vem depois da decisão tomada. Sem a medida, você não tem como saber se seus objetivos estão sendo alcançados e não sabe se precisa mudar suas estratégias para alcançá-los.

Em segundo lugar, servem para alertá-lo da existência de problemas. Se de repente todos seus usuários pararam de enviar mensagens, alguma coisa está errada. Se você não está medindo, pode demorar tempo demais até que você fique ciente de que há algum problema. O que é preciso entender é que a medida mostra a existência do problema, mas não a causa. É fácil esquecer que correlação não implica causalidade e essa é uma das origens frequentes de decisões erradas.

Finalmente, ter as medidas é importante como insumo para a compreensão do seu sistema, dos seus desenvolvedores e dos seus usuários. Uma vez que se tenha muitos dados, é possível fazer inúmeras análises sérias que podem ensinar muito e evitar que decisões erradas sejam tomadas no futuro. Só tome muito cuidado com as conclusões que você vai tirar da análise de dados. São poucas as conclusões com fundamentos reais e é fácil fazer saltos de lógica para "explicar" a causa de cada fenômeno.

Reforçando os pontos do post original: é muito fácil usar medidas de forma incorreta e assim justificar decisões erradas; e sempre devemos pensar antecipadamente em como vamos reagir às possíveis variações nos dados que medimos, para se evitar decisões reativas e apressadas. Métricas ou medidas são úteis, mas use-as com cuidado.

ATUALIZAÇÃO 1: Me esqueci de avisar desde o início que estou falando de medidas DE USO de um sistema e não medidas DE DESENVOLVIMENTO do sistema, que são bem mais inúteis.

ATUALIZAÇÃO 2: Faltou uma utilidade óbvia - dimensionamento de capacidade. Depois que você mede algo por algum tempo, muitas vezes consegue extrapolar valores futuros para a medida, o que te ajuda a planejar a quantidade de recursos de que você vai precisar.

quarta-feira, 14 de outubro de 2009

Malcolm Gladwell e os usuários que não sabem inovar

Outro dia mesmo falei sobre como você não deve depender dos seus usuários para inovar e hoje por coincidência assisti a esse vídeo do Malcolm Gladwell, autor dos excelentes The Tipping Point, Blink e Outliers, sobre a variabilidade nas opiniões das pessoas, e ele fala examente sobre isso:
"Na década de 70, se você perguntasse às pessoas que tipo de molho de espaguete elas queriam, nenhuma delas teria dito que queria um molho grosso com pedaços de tomate, mas era isso mesmo que um terço delas queria."


terça-feira, 13 de outubro de 2009

Quem são seus ídolos na engenharia de software?

Quem foi meu aluno já me viu fazer esta pergunta. Em geral na graduação eu pergunto quem são os ídolos na computação como um todo. A pergunta é exatamente porque eles conhecem pouquíssimos cientistas ou engenheiros que foram os responsáveis pelo estado da arte da nossa disciplina hoje. Então agora vai a pergunta para vocês: dentro da engenharia de software que ainda é uma disciplina na sua infância, quem são os seus ídolos? Quem você admira profundamente? 

Por exemplo, é impossível estudar computação, programação e não admirar Knuth. Aliás, conhecem o trabalho dele no livro 3:16? E no livro "Things a Computer Scientist Rarely Talks About"? Pois é, a contribuição do Knuth é muito maior do que "The Art of Computer Programming". Bom, mas o Knuth é um cientista muito conhecido. E engenheiro de software muito conhecido? Você conhece algum?  Alguém que se entitula engenheiro de software de formação não vai ter ninguém, mas e de vocação?

Eu diria que o meu ídolo na engenharia de software é sem dúvida o Michael Jackson pelas contribuições dele à engenharia de software como um todo, mas principalmente por tornar muito clara a definição de requistos e especificações de software conforme o post da mesa errada. Michael Jackson é o melhor autor de se ler na engenharia de software. Após conhecer as idéias dele sobre a engenharia de software como um todo eu passei a compartilha-las e divulgá-las. Apesar do Michael Jackson ter atuado fortemente na indústria de desenvolvimento de software eu diria que atualmente ele se concentra mais na academia. Então minha outra pergunta é: quem é seu ídolo praticante de engenharia de software? Ou seja, quem está na indústria de desenvolvimento que você admira muito por suas contribuições ao corpo de conhecimento da Engenharia de Software?

Minha resposta é o Martin Fowler. Tive a oportunidade de ver o Martin Fowler falar em diversas OOPSLAs e ele é muito convincente sobre a prática da engenharia de software pois vive os problemas no seu dia-a-dia de desenvolvedor.  Pelas suas contribuições em termos de padrões de análise, de arquitetura, refatorações e injeção de dependência, ele também é meu ídolo. E você, quem são seus ídolos na engenharia de software?  Vou listar alguns engenheiros famosos, escolha o seu: David Parnas, Bertrand Meyer, Grady Booch, James Rumbaugh, Ivar Jacobson, Tom deMarco, Barry Boehm,
Kent Beck, Fred Brooks, a "gangue dos quatro" (Gamma, Helm, Johnson, Vlissides), Rebecca Wirfs-Brock, Pamela Zave, Mary Shaw... devo estar me esquecendo de vários. Quem mais você colocaria nessa lista?

Saiba o que fazer com suas métricas

Uma das minhas grandes birras é com métricas. A gente aprende que é preciso ter insumos para se tomar decisões, e que medindo as ações dos usuários podemos saber o que fazer para acertar. CMMs e modelos afins pregam que sem medir não há qualidade.

Até aí tudo bem. Acredito que os números não mentem. Se suas medições indicam que seu site leva em média 2 segundos para servir uma página, então é isso aí. Se você fizer uma mudança e de repente ele leva só um segundo para servir, então sua mudança funcionou. Perfeito.

O problema é a parte de usar os dados para tomar decisões. Aí o buraco é beeeem mais embaixo, e merece a formulação da primeira lei de Torsten para métricas em software:
Qualquer decisão errada pode ser justificada com base em dados reais.
Deixe-me exemplificar. Suponha que meu sistema permite que os usuários façam duas coisas: peneirar e espetar. Minhas métricas mostram que as pessoas peneiram com frequência 10 vezes maior do que espetam, e mostram também que a medida que o tempo passa, os usuários estão peneirando e espetando cada vez menos por dia, em média.

Agora suponha que eu preciso decidir o que fazer nos próximos seis meses, dentre as seguintes três opções:
  1. Melhorar a função de peneirar.
  2. Melhorar a função de espetar.
  3. Implementar uma nova função, sacudir.
Eis como eu justificaria cada decisão:
  1. As pessoas preferem peneirar, então se melhorarmos essa função, vão peneirar muito mais e o ganho será muito maior;
  2. A função de espetar está claramente ruim quando comparada com a de peneirar, então se a melhorarmos teremos um grande ganho;
  3. Peneirar e espetar não tem mais a mesma atração, então precisamos de algo novo para atrair os usuários.
Meu ponto é que os dados não me ajudaram em absolutamente nada na tomada de decisão, pois apoiam qualquer uma das três decisões. Pior, os dados atrapalharam e muito, porque o que acontece na prática é que o detentor do poder no projeto tem uma preferência qualquer sobre o que fazer e acha apoio nos dados para justificar a sua preferência, evitando assim a discussão racional envolvendo outros fatores, como o custo para se implementar cada solução. Alguém sempre chega e diz, "Ora, os dados claramente indicam que ESSA é a melhor decisão, assunto encerrado, mãos à obra."

Por isso eu sempre travo quando me pedem pra implementar novas métricas. Daí vem a segunda lei de Torsten sobre métricas:
Uma métrica só deve existir quando se sabe como ela será usada para tomar decisões
e sua corolária:
Métricas não associadas a decisões são prejudiciais ao projeto.
Suponha que você queira medir quantas pessoas clicam em um botão. Muito bem. O que você vai fazer se zero pessoas clicarem? O que você vai fazer se todas as pessoas que visitam a página clicarem? Se você não sabe a resposta para essas perguntas, responda-as antes de começar a implementar. Se a resposta for "não vou fazer nada," então você não precisa da métrica. Ótimo! Um número a menos pra ficar te confundindo diariamente e pra atrapalhar as decisões complicadas que você vai ter de tomar no futuro.

Métricas não são grátis. Tem um custo para se implementar e para se manter. Antes de investir nelas, tenha certeza que o investimento terá retorno garantido.

sexta-feira, 9 de outubro de 2009

O usuário não sabe inovar

"Nosso plano é guiar o público ao invés de perguntar a eles que produtos eles querem. O público não sabe o que é possível, mas nós sabemos." --- Akio Morita, co-fundador da Sony
"Se eu tivesse perguntado aos meus clientes o que eles queriam, eles teriam dito que queriam um cavalo mais rápido." --- Henry Ford, fundador da Ford Motor Co.
A conhecida frase do Ford e a não-tão-conhecida frase do Morita dizem a mesma coisa - se você quer inovar, não consulte seus usuários. Desde que comecei a trabalhar com sistemas que são feitos para milhões de usuários, já vi centenas de respostas para a pergunta "o que você gostaria que o sistema tivesse?" e nunca, NUNCA, vi uma resposta que fosse extremamente útil, original, criativa, e que já não estivesse na nossa lista de coisas para fazer.

Os usuários tem 3 tipos de idéias para te dar:
  1. Melhorias no sistema atual - em geral o usuário tem certas dificuldades em realizar tarefas com seu sistema, e sabe sugerir maneiras de reduzir as dificuldades. Em geral esse tipo de comentário é muito útil para você achar deficiências no sistema, mas via de regra as sugestões de solução que o usuário tem pra dar não são boas - leia "a mesa errada" pra entender isso.
  2. Integrações - "bem que podiam integrar esses dois sistemas" é super comum. Em geral o usuário não sabe bem o que teria a ganhar com a tal integração; o que eles querem é não ter de ir aos dois sites. O problema é que o site que você usa para controlar sua dieta não tem nada a ver com o site do bolão do campeonato.
  3. "Seria legal" - essa é a mais perigosa; o usuário vislumbra uma possibilidade concreta e revolucionária, que ninguém usaria. "Seria legal demais se o orkut mandasse um scrap de aniversário para os meus amigos automaticamente!"  Seria sim. Assim você não ia ter de mandar parabéns pra ninguém, e no dia do seu aniversário você receberia 200 mensagens idênticas, uma de cada amigo seu, e passaria o dia que deveria ser feliz xingando porque tem de ficar apagando o lixo que apareceu na sua página de recados. Leia "voce está fazendo errado".
Antes que digam que eu estou desprezando o usuário, eu não estou. O usuário lhe é indispensável para muitas coisas, dentre elas:
  1. Mostrar que o seu sistema não é tão fácil de usar quanto você imaginava. Já assisti a testes de usabilidade dos meus sistemas e é desesperador - de repende você percebe que aquele botãozinho que você julgava trivial de se entender não quer dizer nada pra ninguém.
  2. Mostrar que sua idéia não é tão boa assim. Use a estratégia do açougueiro, que é a seguinte: sempre que você for comprar carne no açougue, pergunte ao açougueiro se a carne está boa; se ele disser que não está, não compre. Da mesma forma, discuta sua idéia inovadora com o maior número de pessoas que você puder. Se a grande maioria te disser que não se interessaria, então não implemente. Se disserem que é interessante sim e que usariam, não acredite e pergunte mais. Não tenha medo, ninguém vai roubar sua idéia, ela não é tão boa assim.
O que eu estou dizendo é que você não deve deixar que seu usuário dite o caminho que seu sistema vai seguir. Se você perguntar ao usuário o que ele quer, ele vai responder. O problema é que se você fizer o que ele está pedindo, vai perder a oportunidade de fazer algo novo, criativo e inovador, porque o que ele vai te sugerir certamente não será nenhuma dessas coisas.

Confie no seu taco, valide suas idéias com seus usuários, e bola pra frente.

quarta-feira, 7 de outubro de 2009

A programação orientada a aspectos está morrendo

"Como assim?" Eu ouço você pensando. "Algum dia ela esteve viva?" Pra mim, sim.

A programação orientada a aspectos (POA) surgiu oficialmente com esse nome em um artigo de 1997, mas é fruto de diversos trabalhos anteriores. A idéia da POA é simples e vem do conceito de metalinguagem. Qualquer chamada de método pode ser interceptada e substituida por outra. Por exemplo, você pode criar um cache simplesmente interceptando todas as chamadas ao seu modelo (no sentido MVC) e, antes de executá-las, verificar se o dado solicitado está no cache. Isso permite que você insira e retire funcionalidades no seu sistema sem alterar sua arquitetura.

Eu comecei a me interessar pela área em 1995, quando comecei meu doutorado. Acompanhei bem de perto e fiz minha dissertação nessa área. De volta ao Brasil, escolhi a POA como tema de uma disciplina de tópicos em engenharia de software, que lecionei três vezes na PUC. Ainda tenho a apostila que escrevi online se alguém se interessar, mas aviso que está desatualizada.

Depois disso, perdi o contato com a área e outro dia resolvi ver como estava progredindo. O que encontrei não foi muito animador. A POA ainda existe como área de pesquisa em universidades mas na prática não acontece muita coisa. A única conferência na área, a International Conference on Aspect-Oriented Developement, continua acontecendo mas parece haver pouco interesse. Na edição desse ano foram 19 artigos acadêmicos e 4 vindos da indústria, mas os autores são praticamente os mesmos que eu via na década passada, ou seja, a área atraiu pouca gente nova.

O pior, no entanto, é a evidência dada pelo Google Trends:


O interesse na busca "aspect-oriented programming" tem caído constantemente desde 2004, e olhe que em 2004 eu já sentia o interesse bem menor do que em 1999-2001, quando o tema estava mais em voga. Infelizmente a indústria nunca abraçou a POA, imagino eu que pela necessidade de um compilador específico. Eu mesmo já vi nos projetos de que participei várias oportunidades de se empregar a POA com sucesso, mas trocar o compilador do projeto inteiro para resolver alguns pequenos problemas? Acho que não.

Pelo menos a área deixa um legado. Hoje há técnicas como dependency injection que são derivadas diretamente dos conceitos introduzidos pela POA, chegando a frameworks modernos como o Guice. Mesmo assim, é triste ver algo no qual investi tanto tempo sumindo por falta de interesse. Até que a idéia era boa.

A lição que fica é: não se apaixone por novas tecnologias, pois é bem provável que elas desapareçam daqui a dez anos.

segunda-feira, 5 de outubro de 2009

É melhor concentrar sua literatura em bons códigos

Sim Ademir, escrever código que os outros entendam é difícil, mas algum dia alguém te ensinou a ler código? Os seres humanos primeiro aprendem a ler e depois aprendem a escrever em uma linguagem natural. Por quê quando queremos aprender uma nova linguagem de programação vamos diretamente para o passo de escrever programas para experimentar a linguagem e nunca paramos para aprender a ler programas? Existe algo que pode ser feito dentro da universidade para ensinar a ler programas?

Eu ensino revisão de código em engenharia de software. Nesse momento os alunos precisam parar de escrever código e precisam ler e entender código. Isso só é feito bem no final do curso quando eles já estão perto de se formarem. Será que se eu ensinasse aos alunos primeiro a ler e entender código (leitura de texto seguida de compreensão de texto) para depois ensiná-los a escrever código (redação de texto) eles escreveriam códigos melhores ou mais fáceis de serem compreendidos?

Em linguagem natural, quanto mais livros você lê, melhor você passa a escrever, pois tem uma gama variada de estilos para seguir. Código também não é diferente. Quanto mais experiente você fica na leitura do código melhor você entende e pode escrever ou dar manutenção no código dos outros. Vejam o resumo deste artigo do David Garlan e outros:
Pouco se sabe sobre como desenvolvedores pensam sobre o design durante tarefas de mudanças em código, ou sobre como o conhecimento de design de desenvolvedores experientes os ajuda a trabalhar de modo mais eficaz. Realizamos um estudo de laboratório em que treze desenvolvedores trabalharam por três horas tentando entender o design de uma aplicação de código livre com 54 mil linhas de código. Os participantes tinham entre 0 e 10.5 anos de experiência e foram agrupados em três "experts" e dez "principiantes." Observamos que os participantes passaram seu tempo aprendendo, criticando, explicando, propondo e implementando fatos sobre o código, como "getFoldLevel tem efeitos." Os fatos serviam vários papéis, como sugerir mudanças, restringir mudanças e prever o tempo de investigações adicionais necessárias para se efetuar uma mudança. As diferenças entre experts e novatos incluiram o fato de os experts terem explicado a causa fundamental do problema de design e terem feito mudanças para consertá-lo, enquanto as mudanças dos novatos atacavam apenas os sintomas. Os experts não leram mais métodos mas também não visitaram alguns métodos não-relacionados em que os principantes perderam tempo tentando entender. Experts falavam sobre o código em termos de abstrações como "caching", enquanto os novatos descreviam o código de comando em comando. Os experts foram capazes de implementar uma mudança mais rapidamente que os principiantes. Também perceberam problemas que os principiantes não encontraram e foram capazes de explicar fatos que os principiantes não conseguiram. Todos esses achados tem implicações interessantes para futuras ferramentas.

Se você entende código melhor com o passar dos anos e com a experiência adquirida, eu acredito que você também automaticamente passa a escrever código melhor. Isso com certeza porque você já leu muito mais código e eu espero que seja código de qualidade que você está tendo acesso para leitura. Infelizmente, por mais que eu possa explicar isso para os alunos na universidade, são só os anos de leitura e compreensão de código que os tornarão melhores escritores de código.

A mesa errada



Já falei do Brooks e do Lehman, mas meu filósofo favorito na engenharia de software é o Michael Jackson. Não é esse Michael Jackson que você está vendo aí ao lado, é outro, um gentleman inglês dos mais legítimos que escreveu a obra-prima Software Requirements and Specifications. Entre outras coisas, ele me ensinou que para se fazer qualquer sistema direito é preciso entender os requisitos do sistema, e que os requisitos são uma descrição do problema que o sistema deve resolver no mundo real, e não uma descrição da solução do problema - isso seria a especificação do sistema.



Se você é matematicamente orientado, pense assim: os requisitos delimitam o universo total de soluções aceitáveis para um problema, e a especificação determina um ponto específico nesse universo.


Ninguém, mas praticamente ninguém mesmo na minha experiência entende bem e põe em prática essa diferença. Todo mundo começa descrevendo a solução - escrevem "deve haver uma janela para fotos e outra para vídeos" ao invés de "fotos e vídeos não devem ser misturados visualmente". A primeira frase já assume muitos fatores a respeito da solução. A segunda deixa em aberto a forma como o efeito desejado (separar fotos e vídeos) vai ser implementado.


Se não temos bem claro em nossas mentes qual o problema que queremos resolver, as chances são enormes de implementarmos a solução errada. Passei anos absorvendo o conceito de que primeiro temos de entender o que o sistema deve fazer para depois decidir como fazê-lo. Mesmo assim, na hora de colocar em prática, fiz tudo errado. Foi assim:


Quando voltamos do Canadá, trouxemos nossas mesas de trabalho. Eram mesas simples, feitas de um suporte de metal com quatro pernas e uma tampa de madeira parafusada em cima do suporte. Acontece que na hora de despachar a carga, um dos suportes teve de ficar pra trás e veio um suporte e duas tampas.


Aí eu chamei um serralheiro pra me construir um novo suporte. Me achando muito espertinho, dei a ele o suporte que veio e disse que queria outro exatamente igual àquele. Assim ele fez e algum tempo depois, muito mais do que havia prometido, é claro, ele me entregou um suporte que era idêntico ao primeiro nos mínimos detalhes.


Imagine minha surpresa ao perceber que os furos dos parafusos do suporte novo não alinhavam com os furos da tampa de madeira. Irado, já ia ligar para o serralheiro quando resolvi tentar com a outra tampa de madeira... e os buracos se alinhavam perfeitamente. As duas tampas de madeira eram ligeiramente diferentes.


Entenderam meu erro? Eu especifiquei ao serralheiro a solução para o meu problema - quero um suporte igual ao outro. Ao invés disso, eu deveria ter especificado o problema - preciso de um suporte de metal que sirva com essa tampa de madeira, e que tenha 80cm de altura, pra alinhar com a outra mesa. Eu achei que sabia a solução, mas a solução estava errada dado o problema.


Incontáveis sistemas de software são inúteis porque seus desenvolvedores não entendem o problema que o software vai ser usado para resolver. E o seu?

sábado, 3 de outubro de 2009

É melhor ser esquecido

"Escrever código que computadores entendem é fácil.
Difícil é escrever código que humanos entendem"

Em algum momento - provavelmente quando eu ainda era estudante - alguém me disse isso. E foi muito antes de ler os milhões de blog posts que comparam programação ao ato de escrever um texto qualquer. Mas o fato é que estas palavras ficaram na minha cabeça e hoje, trabalhando em uma grande empresa, com muitos engenheiros, vejo a importância de se expressar claramente com o seu código.

Como bem lembrou o nosso amigo Torsten, o sistema será sempre modificado e consequentemente alguém precisará alterar o seu código muito em breve.

Neste momento, entender o que você quis dizer com aquele emaranhado de if blocks aninhados até o quinto nível transformará uma simples tarefa em um pesadelo. Por isso, recomendo, preze pela clareza do seu código, escreva para os outros entenderem, não para você.

Leia, releia, leia, releia! Tenha certeza que o que está escrito é o que você quis dizer. Mesmo nos momentos de emergência. Lembre-se, emergências sempre existirão, o projeto sempre estará atrasado, mas quem vai pagar o preço das linhas de código mal escritas será você... ou o próximo micoderealejo.

Infelizmente, todo este esforço será em vão. Codificar bem é uma tarefa ingrata: você raramente será lembrado pela sua clareza, pelo seu cuidado. Ou melhor, será lembrado, sim, mas após anos de trabalho consistente.

Por outro lado, bastarão poucas linhas mal escritas para que você seja odiado. E durante as horas perdidas para entender, consertar ou melhorar aquelas linhas que, por alguma emergência do momento, você decidiu escrever de qualquer maneira, desejarão que seus dedos sejam dilacerados, um a um, lentamente, para que nunca mais você escreva uma linha de código se quer!

Por isso, quando estiver programando, não espere recompensa maior do que ser esquecido. Sua reputação será construída no infinito.

sexta-feira, 2 de outubro de 2009

Síndrome do N-ésimo Sistema

A Guta escreveu sobre o Fenômeno da Segunda Vez, pelo qual um software escrito pela segunda vez é muito melhor do que a versão original, e eu descaradamente me ofereci pra escrever sobre um fenômeno com raízes similares, mas com efeito negativo.


Quando minha equipe estava começando a reescrever um sistema grande para torná-lo mais fácil de gerenciar e estender, conversávamos empolgadamente sobre nossas ideias para a nova arquitetura. Fomos interrompidos por um membro de outra equipe: "vocês não têm medo de cair na Síndrome do Segundo Sistema"?


Fred Brooks define a Síndrome do Segundo Sistema assim:


[Um arquiteto que desenha seu primeiro sistema] sabe que não sabe o que está fazendo, e então o faz com cuidado e de forma reprimida. Enquanto desenha seu primeiro trabalho, ocorre-lhe um enfeite após o outro. Ele vai guardando esses enfeites para usá-los "da próxima vez". Cedo ou tarde o primeiro sistema é terminado, e o arquiteto [...] está pronto para construir um segundo. Esse segundo sistema é o mais perigoso que um arquiteto desenha. [...] A tendência geral é exagerar no projeto, usando todos os enfeites e ideias que foram cuidadosamente descartados da primeira vez.


Embora não tenhamos caído na Síndrome do Segundo Sistema, acabamos caindo numa versão generalizada do problema que eu chamo de Síndrome do N-ésimo Sistema (N > 2). O desenvolvedor que sofreu com o (N-1)-ésimo projeto usa sua experiência recente para dizer: "Não vou cometer nenhum dos erros daquele outro projeto. Agora tudo vai ser diferente".


Nessa síndrome, os ex-membros de um projeto conhecem todos os seus defeitos e pontos de falha. Sabem como o contato de diferentes pessoas e novos requisitos com o código afeta sua qualidade. E decidem, "na-na-não; dessa vez nós vamos fazer tudo direitinho". No processo de tentar fazer tudo direitinho, acaba-se introduzindo uma hipertrofia de inovações, verificações e restrições que permitem que a complexidade do sistema "caiba" na cabeça de quem o projeta. Os ex-sofredores com aquele código ruim e processo esquisito do (N-1)-ésimo sistema tentam melhorar seu ambiente de trabalho e criam novas regras e restrições também no N-ésimo processo de desenvolvimento para melhorar sua vida.


Na prática, como diz meu gerente favorito, isso significa que os erros cometidos no N-ésimo projeto são totalmente novos. As restrições no processo cujo objetivo era melhorar a vida de todos acabam criando grilhões que tornam os desenvolvedores insatisfeitos e menos produtivos. A nova arquitetura faz com que a qualidade do código comece bem, mas logo chegam aqueles novos requisitos que vão transgredir essa arquitetura só um pouquinho, mas cujo custo-benefício é obviamente vantajoso para o usuário.


Com o tempo, o lado "custo" da balança de vários pequenos requisitos vai se somando e ficando mais pesado, e o N-ésimo sistema vira um monstro pior do que o anterior - ele não só contém tantas transgressões à arquitetura original quanto o projeto N-1, mas a nova arquitetura e o novo processo de desenvolvimento são tão restritivos e complexos que o código e o ambiente de trabalho ficam piores do que os do sistema anterior.

O Fenômeno da Segunda Vez

Oi, eu sou a Guta, a miquinha de realejo. Meus colegas micos me convidaram a escrever minhas macaquices aqui nesse blog. Então, vamos lá!

O artigo do Torsten sobre o Oráculo de Requisitos me fez lembrar do meu professor número um de requisitos: Dan Berry. Em várias situações de discussão sobre desenvolvimento de software eu me lembro dele se referindo ao fenômeno da segunda vez. Este fenômeno diz que a primeira vez que você escreve o software você está realmente é pensando e entendendo melhor sobre o problema. Na segunda vez é que você consegue acertar a solução do problema pois já o entendeu de forma mais abrangente e profunda e agora sabe de todas ou quase todas as suas implicações.

Fui então pesquisar se o Dan tinha alguma vez publicado sobre o fenômeno da segunda vez. Encontrei um artigo dele com a Jeannette Wing, uma pesquisadora famosa na área de métodos formais que eu também admiro muito. Bom, o artigo deles é de 1985 e foi publicado na Lecture Notes in Computer Science, volume 186, e pode ser encontrado neste link.

Os seguintes parágrafos do artigo descrevem bem a idéia do fenômeno da segunda vez:

“Nós observamos um número de projetos de software bem sucedidos. Alguns foram desenvolvidos através de um método que nós chamamos de especificação e outros foram desenvolvidos por um método que nós chamamos de prototipagem e outros ainda foram desenvolvidos por outros métodos que nós não discutimos neste artigo. ... Em um primeiro estágio do desenvolvimento, o produto do método utilizado, tanto a especificação quanto o protótipo, foram completamente verificados com o auxílio de uma ferramenta automática e possivelmente até mesmo executados. O segundo estágio do desenvolvimento de ambos foi a implementação, na qual o que foi aprendido no primeiro estágio foi aplicado para produzir uma versão de produção do software. O que foi comum aos dois métodos é o que chamamos de fenômeno da segunda vez. Isto é, a qualidade do software de produção que foi entregue representa a segunda passada sobre o problema que segue a primeira passada feita com uma descrição formal e verificada por uma máquina. No caso da especificação, ela foi feita formalmente e foi verificada com o auxilio de um programa de verificação. No caso do protótipo, o seu programa é formal e foi verificado por um compilador ou interpretador, pelo ambiente de execução e pelos usuários rodando o programa.

Nós nos perguntamos se o fator mais importante no sucesso destes projetos era o fato de o software entregue ser uma segunda iteração depois de uma primeira iteração verificada por uma máquina. Ou seja, nós sugerimos se este fenômeno da segunda vez é mais crítico para determinar o sucesso de um projeto do que qualquer outro fator que pode surgir dos métodos de especificação e prototipação em si. “


Então, na minha opinião o fenômeno da segunda vez do Dan Berry e da Jeannette Wing e o que disse o Fred Brooks, "Planeje jogar um sistema fora, você jogará de qualquer jeito" são conclusões bastante semelhantes.

quinta-feira, 1 de outubro de 2009

Persistir ou jogar tudo fora?

Apesar de ser fã do Fred Brooks e suas leis do desenvolvimento de software, bacanas mesmo são as leis de Lehman sobre a evolução de software:

  1. Lei da mutação contínua: um sistema em uso deve sofrer modificações constantes ou degradar em sua eficácia;
  2. Lei da complexidade crescente: um programa de computador que é modificado se torna cada vez menos estruturado; as mudanças aumentam a entropia e complexidade do programa.
A justificativa da primeira lei é brilhante. Um sistema de computação é desenvolvido para resolver um problema existente no mundo real. No entanto, quando o sistema é colocado em operação, ele muda o mundo real, pois agora está inserido nele. Como o mundo real mudou, os problemas que o sistema foi criado para resolver também mudam, exigindo que o sistema seja modificado para atender à nova realidade. Quando o sistema modificado entra no ar, ele muda o mundo real... e assim por diante.

A segunda lei é mais difícil de se justificar, porém fácil de se observar na prática. Todo desenvolvedor já viu código que começou bem, mas com o tempo foi virando uma macarronada difícil de acompanhar. Existem técnicas como a refatoração que visam reduzir a entropia introduzida por mudanças. Refatorar ajuda a diminuir o ritmo da degradação sim, mas não resolve. Um dia você olha e simplesmente não dá mais pra fazer aquela mudança aparentemente simples que te pediram pra fazer.
 
As duas leis são antagônicas: a primeira diz que você precisa evoluir o seu software, ou ele se torna menos útil; a segunda diz que se você evoluir o software, ele se torna pior.

O que fazer? Em geral as pessoas priorizam a primeira lei. Tem mudanças que precisam ser feitas, e pronto. A prioridade continua valendo até que alguém dá um basta, pois simplesmente não dá mais pra se fazer mudança nenhuma.

Faz pouquíssimo tempo eu mesmo participei de um esforço desses - reescrevemos um sistema gigante que já estava insustentável. Todo mundo reclamava do código todos os dias. Os adjetivos usados não podem ser reproduzidos aqui em um blog que é lido por menores de idade.

No final do esforço, que foi imenso, todo mundo feliz, satisfeito com um código novinho em folha que usa tecnologias modernas e todas as boas práticas de desenvolvimento que a gente conseguiu descobrir, e mais algumas. Lindo mesmo, extensível, testável, modificável...  e enquanto reescreviamos, a primeira lei ficou em segundo plano e o sistema, que não evoluiu durante meses, se tornou cada vez menos útil.

E o pior: dou quatro anos pra começarem a usar os mesmos adjetivos pra se referirem à gente que a gente usava pra se referir a "eles," os autores do código original. Em quatro anos vai estar uma bela porcaria de novo, lento, impossível de consertar uma coisa sem quebrar outra. Lehman já dizia isso em 1974, trinta e cinco anos atrás, e nada mudou desde então. E o ciclo se repetirá.

O que fazer, então? Como evitar que se tenha de gastar centenas de milhares de dólares daqui a quatro anos, fazendo tudo de novo?

A resposta: não priorize a primeira lei, nem a segunda. Explicando melhor: faça apenas as mudanças que você antecipou e guarde as outras pra depois. 

Quando você escreve seu sistema, você antecipa inúmeros pontos de extensão e deixa no código os ganchos para as funções que você sabe (ou suspeita) que virão a ser necessárias. Enquanto as mudanças que você precisa fazer se encaixam bem nos pontos de extensão do sistema, tudo bem, lindo, seu código evolui graciosamente.

O problema é quando chega a primeira necessidade de mudança que você não antecipou e que exige uma adaptação na sua arquitetura. Fazer essa mudança vai degradar seu código. Cada mudança desse tipo vai piorando a sua situação até ela ficar insustentável.

Resista a essas mudanças. Guarde-as no seu caderninho e vá acumulando todos os requisitos que exigem mudanças arquiteturais o máximo que você conseguir. Quando estiver ficando insustentável e a primeira lei estiver te avisando que a utilidade do sistema está ficando baixa demais, é hora de projetar a próxima versão do sistema, de começar tudo de novo e reescrever o sistema do zero. Só que dessa vez você vai construir uma arquitetura que comporte tudo que o sistema atual faz e mais aqueles requisitos que você guardou no seu caderninho.

Assim, você atende em parte às necessidades da primeira lei: atualiza os requisitos, desde que não sejam necessárias mudanças arquiteturais. Também mantém a segunda lei sob controle: faz apenas mudanças que não degradam o código.

Quando for começar a reescrever, seu código ainda não vai estar degradado. Parte da equipe pode continuar atualizando a versão existente enquanto outra parte cria a nova versão. 
Talvez a diferença entre o sistema atual e o novo seja pequena o suficiente pra você conseguir aproveitar grande parte do sistema atual (que ainda está bom!) e construir a nova versão rapidamente. Talvez não. O importante é aceitar o fato de que você vai ter de reescrever tudo um dia. Esperar até a situação ficar insustentável e jogar tudo fora não é uma boa idéia. Assim que o código começar a cheirar mal, essa é a hora.