Archive for the 'simplicidade' Category

A evidência definitiva da programação saudável

Como alguém pode saber que uma equipe de programadores desenvolve software com um processo saudável? Como podemos saber se as práticas adotadas pela equipe são suficientes para produzir software útil, correto e de fácil manutenção? Quais as evidências que devemos procurar para separar os bons projetos dos ruins?

Estas são questões fundamentais tanto para quem está procurando um fornecedor como para quem está projetando um novo selo ou certificado parecido com os milhares que já temos para identificar organizações que sabem desenvolver software. Quem se propõe a fornecer um selo desse tipo precisa observar o trabalho dos candidatos por algum tempo para tentar encontrar algumas evidências de um processo saudável e sustentável. Precisa procurar pelos rastros deixados por um trabalho bem feito.

Uma forma razoável de identificar estes rastros é projetar um processo de desenvolvimento que comprovadamente dá certo (pelo menos para alguns casos) e verificar o que uma equipe que usou este processo deixou pelo caminho. Alguns selos em uso atualmente fazem exatamente isso: eles certificam toda uma classe de processos que produzem os mesmos subprodutos que um processo original. As equipes que querem ser certificadas precisam aprender o modo de operação e repetí-lo, produzindo evidências concretas de que seguiram um processo aprovado pelo certificador. Documentos de requisitos, relações de casos de uso, matrizes de rastreabilidade, diagramas de relacionamento e relatórios de revisão são todos exemplos de evidências bastante tangíveis da existência de procedimentos definidos.

Porém nenhum desses documentos pode ser considerado uma evidência definitiva da qualidade do processo. Nenhum deles consegue provar sozinho que o processo de desenvolvimento funciona.

Nem mesmo todos eles juntos conseguem fazer isso.

A evidência definitiva de um processo de desenvolvimento de software saudável é bastante óbvia, mas isso não quer dizer que todo mundo consegue enxergá-la. O único produto suficiente e necessário para identificar que um processo realmente dá certo é simplesmente software funcionando.

Só isso.

Não são documentos de requisitos bem escritos, matrizes de rastreabilidade gigantescas, nem diagramas bonitos e coloridos. A maior evidência que se pode observar em projetos saudáveis é a simples entrega de software funcionando. Deve ser suficiente observar que uma equipe consegue entregar software funcionando a cada, digamos, uma ou duas semanas para saber que eles têm uma boa abordagem para desenvolvimento de software. Uma queda da velocidade de evolução do sistema é o que basta para saber que algo vai errado.

Nem todos os processos de desenvolvimento são projetados para entregar software funcionando dentro de períodos curtos de tempo. Por isso desenvolveram-se vários modelos que verificam subprodutos intermediários como diagramas de estado e especificações funcionais. É um caso clássico de quem não tem cão, caça com gato. Estes subprodutos servem como promessas, garantias, evidências de que em algum momento futuro o sistema será entregue como esperado. O problema é que nenhum subproduto desses é tão verificável quanto o produto final. Eles servem para tranqüilizar um pouco os clientes, que de um modo ou de outro recebem algumas garantias de que seu dinheiro está sendo bem gasto. Mas definitivamente não servem para dar certeza do sucesso do projeto, nem ao menos da transformação do produto em software funcionando.

Assinar acordos não é entrar em acordo

Toda equipe que desenvolve software já deve ter descoberto que “o entendimento dos requisitos deve ser alcançado.” Eles podem ter lido isso em algum lugar ou simplesmente enxergado algo que é óbvio demais para ser ignorado por qualquer mente saudável. Não importa como chegaram a tomar conhecimento disso, o importante é que qualquer pessoa que se propõe a resolver o problema de outra sabe que precisa entender razoavelmente bem o que está querendo solucionar. A questão interessante é desenvolver uma maneira eficiente de fazer isso.

Uma alternativa que faz muito sentido é tentar escrever e assinar junto com os clientes um belo documento que descreva detalhadamente os requisitos. Esta estratégia parece bastante natural porque a maioria das pessoas já está bem familiarizada com assinaturas e contratos. Afinal não é exagero dizer que este tipo de formalização vem sendo usado há séculos nos mais variados campos de atividade.

Acordo ilusórioPor causa disso não é muito intuitivo pensar que esta abordagem tem um alto potencial para falta de entendimento. Como as coisas estão somente descritas e não há algo realmente tangível para guiar as opiniões, o entendimento depende totalmente da interpretação do texto e é possível que cada uma das partes tenha uma idéia diferente do objeto do acordo na hora da assinatura. Para que um acordo verdadeiro seja firmado, é essencial que ambas as partes estejam pensando na mesma coisa. Sem isso o máximo que se consegue é uma ilusão. Por causa do papel crucial da interpretação do texto, é comum que este tipo de engano ocorra ao usar apenas documentos. Apesar disso as assinaturas geralmente são aceitas como evidências de acordo.

Documentos fazem muito sentido quando o desenvolvimento do produto final precisa levar muito tempo. Quando isto é verdade o registro por escrito dos requisitos é uma opção aceitável. Há o risco de um acordo ilusório, mas ele é menos prejudicial para ambas as partes do que o cancelamento da empreitada. Porém quando os requisitos podem ser suficientemente pequenos e a equipe tem um processo de desenvolvimento suficientemente enxuto, as necessidades do cliente podem ser identificadas na segunda-feira e estarem materializadas em software rodando na sexta-feira seguinte (se é que software pode ser materializado). Quando isto é possível não faz mais sentido utilizar documentos e correr o risco de um falso acordo porque o produto final pode ser usado como objeto do acordo.

Software em execução é a forma mais incontestável de entendimento dos requisitos. Ninguém pode dizer que a equipe de desenvolvimento e o cliente não estão de acordo quando eles concordam sobre o produto final. Não há mais o que refinar, portanto não há mais onde discordar.

Bolas de chumbo

Você já deve ter visto muita gente copiar e colar código deliberadamente quando um pouco de senso crítico e abstração resolveriam facilmente o problema. Eu sei que eu já vi e o argumento para tamanha aberração tem sido sempre parecido: “Cara, eu e você sabemos que é melhor extraírmos o comportamento comum deste outro modo e que dá para enxugar o código desse outro jeito. Mas infelizmente não somos só nós dois que vamos trabalhar neste sistema. Acho que desse modo repetitivo fica mais fácil para o restante do pessoal que não é tão brilhante quanto a gente. Além disso, precisamos preparar a aplicação para ser mantida por qualquer tipo de idiota que a empresa resolva contratar no futuro.”

A idéia é bastante simples e, de um certo ponto de vista, parece até lógica: eliminar todo tipo de conceito que uma pessoa com uma semana de treinamento não vá entender. Assim é possível maximizar a quantidade de código que elas serão capazes de produzir, pois não vai ser preciso parar para aprender esses tais padrões de projeto e demais conceitos abstratos complicados que os concorrentes tanto usam. Pessoas pouco treinadas têm a tremenda vantagem de serem baratas. Deste modo, pode-se pagar bem pouco para cada programador e amontoar tantos quanto possível em grandes fazendas de cubículos para vomitar código repetido à maior velocidade possível. A maioria do código não vai servir para muita coisa, mas como a quantidade de gente à disposição é bem elevada, com um pouco de sorte dá até para produzir algo que o departamento de vendas consiga vender como útil. Quando nosso esquema estiver funcionando, podemos dizer que é uma “fábrica” e achar tudo muito bonito.

Eliminar todo tipo de conceito abstrato para permitir que qualquer pessoa com um mínimo de instrução possa trabalhar no sistema pode até parecer racional. Esse tipo de argumento é muitas vezes invocado em nome de algo que se chama de “pragmatismo”. Esta palavra está na muito na moda recentemente e, como toda boa palavra da moda, não são raras as vezes que é invocada do limbo apenas para defender uma idéia falida. O fato é que, sendo pragmatismo ou não, estas iniciativas servem muito bem ao intuito de nivelar a capacidade da equipe.

Por baixo.

Ao invés dos programadores mais versados na arte da escrita de código serem encorajados a passar seu conhecimento aos demais, eles são obrigados a correr com uma bola de chumbo amarrada aos pés para não ultrapassarem os outros. Eles perdem toda a energia que o design elaborado os proporcionava para que os demais possam continuar lentamente. Não gosto nem de imaginar o que isso pode fazer com a auto-estima deles e, conseqüentemente, com o futuro do projeto.

Em dois artigos recentes, Vitor Pamplona argumenta contra a busca do Santo Graal da Orientação a Objeto e preciso dizer que este argumento me parece bastante razoável. Mas como todo bom argumento ele pode ser interpretado de forma extrema e levar uma equipe a abominar completamente os objetos e padrões de projeto. Eles podem passar a considerá-los simples mecanismos para tornar uma aplicação mais difícil de entender. Apenas uma tentativa patética por parte dos mais escolados de manter a equipe dependente de seu conhecimento.

Esta opinião extrema parte do pressuposto falho que objetos e padrões são mais complicados do que código seqüencial, repetido e bagunçado em geral. Aqui é onde encontramos o principal ponto de discordância entre os que defendem o código elegante e os que estão do lado da bagunça compreensível. Ambos defendem que o seu estilo é mais legível. Os últimos simplesmente por empregar conceitos mais simples e os primeiros por dedicarem mais tempo aos aspectos estéticos do código.

Código que não é legível não é elegante. Se for preciso vagar por toda a base de código para entender a idéia geral de uma única linha, não importa a densidade de padrões de projeto por metro quadrado: o código é deselegante. Por outro lado, se preciso consertar um defeito sutil relacionado à mesma linha, espero que deva ser preciso dar uma olhada em uma quantidade razoável de código além dela. Mas quando estou apenas lendo, não.

Isso não quer dizer que código precise ser simplista para ser legível. Quando alguns conceitos um pouco mais elaborados são usados dentro de um contexto específico, podem tornar o código muito mais legível que a alternativa simplista. Tome como exemplo as interfaces fluentes. Muita gente ainda não ouviu falar delas, mas poucos fariam muito esforço para entender esta linha caso a encontrassem num teste:

mock.expects(once()).method("m").with("hello")

Apesar disso este pequeno trecho de código está fazendo uso de pelo menos um padrão de projeto (nominalmente o Builder) e de um estilo de código ao qual nem todo mundo foi formalmente apresentado (uma interface fluente). Este trecho é legível apesar de não ser nada que um novato escreveria. Ele funciona porque os conceitos são aplicados onde fazem sentido.

A encrenca começa a aparecer quando os garotos dos padrões entram em cena forçando soluções inadequadas para os problemas errados, fazendo de tudo para encaixar um cubo em um buraco com forma de círculo. Ou pior: quando eles começam a inventar problemas só para aplicarem suas soluções preferidas.

Melhor que a encomenda

Fazer somente o solicitado pode ser um suicídio completo em qualquer mercado competitivo e, a menos que você detenha algum tipo de monopólio, desenvolvimento de software é um desses mercados. Seus concorrentes muito provavelmente estão fazendo mais do que o estritamente necessário e ninguém quer ficar para trás. O inverso, entretanto, não é receita de sucesso. Fazer mais do que o requisitado pode levar a uma corrida sem fim por novas funcionalidades que vai drenar toda a energia da sua equipe e deixar muita coisa inacabada.

Se você tem uma capacidade de produção limitada (e quem não tem?), é melhor evitar corridas tresloucadas e tentar se destacar no essencial. Fazer menos coisas para que possa fazê-las com mais qualidade.

Acho que este é o exemplo mais batido da Internet hoje em dia (se bem que o iPod está se mostrando um adversário à altura), mas vou usá-lo assim mesmo. No ano 2000, enquanto um de seus maiores concorrentes, o Yahoo, tinha uma página repleta de links e funções, o Google (o sistema de busca, não a empresa) tinham apenas um campo de texto e um botão. Eles tinham uma única coisa para fazer, por isso podiam se concentrar. O resultado é que conseguiram se destacar, apesar dos concorrentes oferecerem mais serviços à época. Você sabe o que é um sucesso, quando uma marca começa a virar verbo. Hoje em dia eles já estão brigando para que a marca não passe para domínio público como sinônimo de busca.

Introduzir novos serviços não solicitados é um jogo de adivinhação e, a menos que você esteja no ramo da clarividência, este não é o tipo de jogo que você quer jogar. Por outro lado, fazer melhor do que o esperado pode colocar você no mesmo pedestal do “mais”, mas sem o risco associado.

Acho que a moral da história dessa vez é: faça melhor que a encomenda, não mais que a encomenda.