terça-feira, 2 de março de 2010
Pesquisa sobre remuneração de programadores
A equipe do Micos de Realejo está escrevendo um grande post sobre o estado atual da remuneração na indústria de software. No entanto, estamos sentindo falta de dados concretos e contamos assim com a colaboração dos leitores.
Elaboramos uma pesquisa curta que deve levar cerca de 3 minutos para responder. A pesquisa é destinada apenas àqueles que de alguma forma trabalham com programação.
A pesquisa é totalmente anônima, todas as questões são opcionais e dados individuais não serão divulgados. Divulgaremos apenas resultados agregados.
Por favor divulguem para seus colegas para que possamos obter uma quantidade significativa de dados para análise.
O link para a pesquisa é: http://bit.ly/9FpAPV
Obrigado,
Torsten
quarta-feira, 24 de fevereiro de 2010
Complexidade
Relendo o excelente artigo Anatomy of a Crash, fiquei impressionado de novo não só com a rapidez com que uma batida é tratada, mas também com a complexidade do sistema todo. O texto narra a reconstrução de uma batida simulada como parte de um estudo em segurança de veículos:
0 milliseconds - An external object touches the driver's door.
1 ms - The car's door pressure sensor detects a pressure wave.
2 ms - An acceleration sensor in the C-pillar behind the rear door also detects a crash event.
2.5 ms - A sensor in the car's centre detects crash vibrations.
5 ms - Car's crash computer checks for insignificant crash events, such as a shopping trolley impact or incidental contact. It is still working out the severity of the crash. Door intrusion structure begins to absorb energy.
6.5 ms - Door pressure sensor registers peak pressures.
7 ms - Crash computer confirms a serious crash and calculates its actions.
8 ms - Computer sends a "fire" signal to side airbag. Meanwhile, B-pillar begins to crumple inwards and energy begins to transfer into cross-car load path beneath the occupant.
8.5 ms - Side airbag system fires.
15 ms - Roof begins to absorb part of the impact. Airbag bursts through seat foam and begins to fill.All over in the blink of an eye
17 ms - Cross-car load path and structure under rear seat reach maximum load.
Airbag covers occupant's chest and begins to push the shoulder away from impact zone.
20 ms - Door and B-pillar begin to push on front seat. Airbag begins to push occupant's chest away from the impact.
27 ms - Impact velocity has halved from 50 km/h to 23.5 km/h. A "pusher block" in the seat moves occupant's pelvis away from impact zone. Airbag starts controlled deflation.
30 ms - The Falcon has absorbed all crash energy. Airbag remains in place. For a brief moment, occupant experiences maximum force equal to 12 times the force of gravity.
45 ms - Occupant and airbag move together with deforming side structure.
50 ms - Crash computer unlocks car's doors. Passenger safety cell begins to rebound, pushing doors away from occupant.
70 ms - Airbag continues to deflate. Occupant moves back towards middle of car.
Engineers classify crash as "complete".
150-300 ms - Occupant becomes aware of collision.
Imagine um site moderno, que tem código rodando no browser e código no servidor (números inventados de cabeça mas não totalmente irreais):
0 ms - usuário digita o endereço de uma página do seu site
1 ms - o código do cliente determina o que fazer com a URL e dispara uma chamada ao servidor solicitando dados
16 ms - front-end do site recebe o pedido, determina que parte do site deve ser executada a partir da URL e dos dados da requisição HTTP
17 ms - serviço responsável por tratar a parte do site que o usuário quer recebe o pedido, decodifica parâmetros e dispara chamadas remotas a dezenas de back-ends
20 ms - cada back-end envolvido no serviço recebe uma requisição e acessa alguma forma de banco de dados para buscar as informações necessárias
25 ms - serviço recebe os dados de volta e calcula resposta a ser enviada de volta para o cliente, empacota tudo em algum objeto e retorna
40 ms - browser recebe resposta HTTP, chama callback do cliente para tratar os dados
42 ms - cliente preenche interface com os dados recebidos, montando a árvore DOM para a próxima interação
45-150ms - enquanto imagens carregam, usuário começa a ler o texto que já está disponível, possivelmente tomando a próxima ação (se o usuário está no IE6, a primeira requisição provavelmente só foi disparada pro servidor agora...)
Essa descrição é propositadamente superficial. Alguns dos detalhes omitidos são autenticação, serialização e desserialização de pedidos e respostas, caching em vários níveis do sistema, sharding e balanceamento de carga, logging, validação de entrada no cliente e no servidor, o modelo ou esquema de armazenamento de dados para acesso eficiente, bordinhas redondas e degradês em todos os browsers, monitoramento, XSS, XSRF, cookies, injeção de dependências, internacionalização, e as pilhas do sistema operacional e de rede de todas as máquinas envolvidas no processo. Além disso, cada front-end e back-end envolvido tem suas próprias camadas de complexidade, ou abstração. Ah, e tem um bug aqui e outro ali.
A grande vantagem pra quem trabalha na engenharia de software sobre outros tipos de engenharia em termos de confiança no sistema é que se tem a oportunidade de testar exatamente o código que vai rodar em produção durante o desenvolvimento. Nós podemos inflar o airbag que vai ser instalado no próximo carro da linha de produção, acender cada fósforo que vai entrar na próxima caixinha. O perigo de confiar totalmente nisso é que a soma da compreensão das partes não é a compreensão do todo.
E quando tudo falhar em produção, teremos aquela grande imagem cheia de detalhes para depurar; analisando várias partes descobriremos que aquele airbag que nós sabíamos que funcionava não foi inflado. Onde no meio de tantas interações ficou faltando o disparo do airbag praquele usuário que teve uma batida a um ângulo de 23ᵒ, trafegando a 45km/h com 2 passageiros numa tarde de sábado de um ano bissexto?
Só não se sente intimidado por um site moderno, ou pelos bugs que podem aparecer nele, quem não sabe como ele funciona.
terça-feira, 2 de fevereiro de 2010
20 lições importantes
Segue abaixo então minha tradução livre do artigo. Aliás, livre até demais: eu mantive as 20 lições intactas, mas os comentários são meus.
- Decida quanto tempo você quer gastar com um problema antes de começar. Ao invés de ficar pelejando por uma semana com um problema que deveria levar um dia pra resolver, como eu fiz na semana passada, decida antecipadamente quanto tempo você vai dedicar a ele. Pode ser uma semana, um dia, uma hora, 30 minutos, não importa. Se você não conseguir resolver o problema no tempo em que você se permitiu trabalhar nele, procure ajuda ou repense suas prioridades ao invés de tentar ser o super-programador.
- Uma linguagem é uma linguagem é uma linguagem. Um sábio professor uma vez me disse que o problema que o seu programador mais júnior está tendo com a namorada tem mais impacto no sucesso do seu projeto do que a linguagem de programação que você escolher. Ele tinha razão. Escolha uma linguagem que te dê conforto, e pronto.
- Não exagere nos design patterns. Pense duas vezes antes de usá-las - se houver uma solução mais simples, use-a.
- Faça backups do seu trabalho diariamente.
- Você não é o melhor programador. Conforme-se com isso. Sempre tem alguém melhor que você. Aprenda com eles ao invés de tentar ser melhor.
- Aprenda a aprender mais. Se você não está gastando pelo menos 50% do seu tempo aprendendo, sua produtividade está piorando. Sim, parece um paradoxo, mas não é.
- Mudanças são constantes. O que você sabe hoje não vai ser tão importante amanhã. Diversifique seus conhecimentos.
- Apoie os menos experientes. Ajudar os programadores da sua equipe a se tornarem melhores é o melhor investimento a longo prazo que você pode fazer.
- Simplifique seu algoritmo. Quando terminar, volte atrás e veja o que você pode fazer para tornar seu código mais simples e fácil de ler. O futuro agradece.
- Documente seu código. De novo, o futuro agradece. Aliás, quem provavelmente mais agradecerá será você mesmo.
- Teste, teste, teste.
- Celebre cada sucesso. Não espere uma data longínqua para se dar os parabéns. Programar é cansativo. Comemore cada passo a frente e cada bug removido, da maneira que preferir. Só não comemore comendo chocolate, como eu faço.
- Faça revisões de código. No Google cada linha de código que é escrita é revisada por pelo menos um outro programador. Nenhuma outra atividade é tão importante para se garantir a qualidade dos sistemas. Mesmo que você não chegue a esse extremo, peça a seus colegas que revisem as partes importantes e ofereça-se para fazer o mesmo.
- Estude seu código antigo. Leia código que você escreveu quando ainda não era tudo isso e maravilhe-se com o quanto você aprendeu desde então.
- Tenha senso de humor. Ha ha.
- Evite trabalhar com programadores possessivos ou prepotentes. O possessivo é aquele que não permite que ninguém altere ou critique seu código; ele pode arruinar seu projeto. O prepotente é aquele que tem sempre a última palavra; ele vai prejudicar sua auto-estima.
- Nenhum projeto é simples. Nenhum. Não existe nada de qualidade em computação que possa ser feito "rapidinho, em dois dias".
- Cuidado com o excesso de confiança. Enquanto não estiver funcionando e aprovado, nunca está 90% completo. Os 10% que faltam em geral levam o mesmo tempo que você gastou com os 90%.
- Software nunca está pronto. Leia o post Persistir ou jogar tudo fora?
- Paciência é uma virtude. Saiba esperar a hora certa de implementar; antes tente entender seu problema. Quando as coisas derem errado, procure entender por que ao invés de sair tentando qualquer coisa.
quarta-feira, 23 de dezembro de 2009
Bjarne Stroustrup também lê o "Micos"

quinta-feira, 17 de dezembro de 2009
Papai Noel, me dê usuários no Natal
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?
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
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?