Os 3 vieses do Desenvolvimento de Software - Número 2: Cronologia
Desenvolver um software não é a mesma coisa que usar um software, e precisamos reconhecer isso.
No meu último post, falei sobre como o hábito de dividir o software em camadas pode nos levar a trabalhar em uma camada de cada vez, produzindo o indesejado efeito BDUF (Big Design Upfront). Desta vez, vamos falar sobre como um fluxo imaginário do usuário pode nos levar a seguir cegamente um fluxo de desenvolvimento predefinido.
Entendendo o Viés da Cronologia
Lembro da primeira vez que joguei Mario Bros no console NES que meu pai me deu quando eu tinha 4 anos: o controle retangular absurdamente não ergonômico, a alegria de jogar um jogo com um personagem que tinha o mesmo nome que eu... Foi incrível!
O jogo era muito linear: 8 mundos com 4 fases cada. Você começa na Fase 1-1 e termina o jogo depois de vencer a fase 8-4. Existiam atalhos que eu podia pegar para pular algumas fases, mas eu nunca podia voltar para jogar uma fase já terminada.
Desenvolver software sob um Viés de Cronologia é como jogar aquele jogo do Mario Bros, exceto que não é tão divertido. Você começa desenvolvendo o mundo 1-1 porque é o que o usuário jogará primeiro. Depois desenvolve o mundo 1-2, e assim por diante. Se seguirmos esse caminho, claramente não estamos caindo no Viés da Estratificação, porque estamos criando todas as camadas para cada fase (não estamos terminando o design de todos os níveis antes de implementar o mecanismo do jogo, por exemplo). Com isso poderíamos coletar feedback do cliente após desenvolver cada fase e usar isso para criar melhores fases no futuro. Mas ainda assim... estamos perdendo algumas boas oportunidades.
Sabe o que é engraçado? Essa progressão linear estilo Mario aparece em todo lugar no desenvolvimento de software. Pegue a tela de login, por exemplo - ela praticamente se tornou nossa "Fase 1-1". É quase como se houvesse uma regra não escrita que diz "Implementarás a autenticação primeiro" só porque é a primeira coisa que os usuários veem. E na maioria das vezes, esta é a primeira coisa que uma equipe de desenvolvimento de software implementa quando começa a desenvolver um novo produto. Você já fez isso? Eu fiz, inúmeras vezes.
Mas qual é o problema dessa abordagem?
Problemas, eu diria. No plural.
O mais óbvio é que não estamos nos beneficiando totalmente de uma abordagem ágil se estamos seguindo um caminho predefinido. Depois de revisar a Fase 1-1, teremos alguma flexibilidade sobre como desenvolver a fase 1-2, mas não sobre o que devemos desenvolver em nossa próxima iteração. Além disso, todas as nossas conversas sobre o produto deixarão aquele gosto amargo de tempo perdido porque o caminho já está definido. Esse sentimento é bastante comum entre desenvolvedores em Times Scrum durante o Planning e a Review quando estão caindo neste viés.
E se a fase 6-2 for a mais valiosa para meu usuário? Eles terão que esperar 26 iterações para finalmente poder jogá-la!
Outro problema será a mitigação de riscos. Se estou construindo um jogo do Mario, talvez eu tenha algumas ideias ousadas que quero validar primeiro, como um mundo aquático, um castelo com quebra-cabeças ou um chefe muito desafiador. Até mesmo o chefe final!
Então a solução parece direta: basta desenvolver recursos em qualquer ordem que forneça mais valor, certo? Poderíamos construir a fase 4-3 antes da fase 1-2, seguindo as prioridades do usuário em vez da ordem sequencial.
Bem... acontece que frequentemente esbarramos em um obstáculo familiar: dependências. Mas é aqui que outro clássico dos games nos oferece uma alternativa iluminadora...
Quebrando o Viés da Cronologia (e as dependências)
Voltando à minha infância e meu console NES, havia um jogo que eu amava ainda mais que Mario Bros: MegaMan. Em todo jogo do MegaMan você podia selecionar qual fase queria jogar, e uma vez que você derrotava o chefe da fase, você ganhava acesso à sua arma e podia usá-la pelo resto do jogo.
Então, você podia escolher lutar contra o Fireman primeiro e usar sua arma de fogo contra o Iceman, ou o contrário. Depende de você. Não havia absolutamente nenhuma sequência predefinida. Mas... o que acontece se tentarmos usar a mesma abordagem no desenvolvimento de software? Bem, às vezes vamos ouvir e dizer coisas como:
"Não podemos desenvolver um relatório sem criar um CRUD para inserir os dados primeiro, afinal não existe relatório sem dados!"
Ok, vamos desafiar isso: Como poderíamos desenvolver um relatório sem ter uma interface para inserção de dados? Bem, mockando os dados. Imagine que vamos construir um jogo da Forca. Alguém poderia dizer que a primeira coisa que precisamos fazer é criar um dicionário de palavras que podemos usar durante o jogo, porque ter uma palavra para jogar é um pré-requisito!
Então, se cairmos nessa armadilha, provavelmente vamos gastar algum tempo desenvolvendo algo como:
Não parece muito, mas requereu algum tempo para pesquisar uma maneira de gerar uma palavra aleatória, ler a documentação da API, criar uma conta, obter uma chave de API, escrever o código, testá-lo e refatorá-lo um pouco. Mas o mecanismo do jogo é muito mais importante, e se pudéssemos economizar algum tempo aqui, poderíamos usar esse tempo para desenvolvê-lo melhor. E uma maneira de fazer isso é estabelecendo uma interface simples.
Quando eu chamo a função get_word
, recebo uma palavra, e não me importo realmente de onde ela veio. Se fizermos isso, poderíamos criar nosso Dicionário assim:
Sim, a palavra sempre será ELEFANTE
.
Mas não estou dizendo que devemos lançar o jogo assim! Tudo que estou dizendo é que agora, em vez de mostrar ao usuário uma tela que gera um monte de palavras aleatórias, vamos mostrar um jogo da Forca totalmente funcional que sempre usa a palavra ELEFANTE
. E fazendo isso, nossa revisão do produto se tornará mais interessante porque agora temos uma pergunta muito poderosa para fazer: O que devemos fazer a seguir?
Poderíamos decidir implementar o Dicionário, ou o cliente poderia pedir outra coisa, como um sistema de pontuação para o jogo ou um mecanismo de dicas. Teremos opções. Não estamos jogando Mario Bros, estamos jogando MegaMan.
E como começo a fazer isso?
Antes de qualquer coisa, liste todas as suas suposições de dependência e comece a questioná-las. Eu gosto de usar a construção "Como poderíamos / sem" para fazer isso:
Como poderíamos autenticar o usuário sem uma tela de login?
Como poderíamos gerar um relatório sem ter uma maneira de popular o banco de dados?
Como poderíamos mostrar esta informação sem usar gráficos?
Segundo e mais importante: certifique-se de que sua equipe sabe trabalhar com interfaces. Isso é fundamental para evitar retrabalho e quebrar coisas.
Lembre-se: para nos adaptar às mudanças com sucesso, devemos aprender a fazer isso sem aumentar os custos de desenvolvimento. Assim como no MegaMan, o melhor caminho nem sempre é o mais óbvio - às vezes você precisa lutar contra o Fireman antes do Iceman, e às vezes você precisa construir aquele sistema de pontuação antes de implementar o algoritmo perfeito de seleção de palavras.
O Viés da Cronologia, assim como seu primo o Viés da Estratificação, nos engana a seguir um caminho predeterminado quando deveríamos estar nos perguntando aquela simples mas poderosa questão: "O que devemos fazer a seguir?". Afinal, desenvolvimento de software não é sobre completar níveis em uma ordem predefinida - é sobre criar valor da maneira mais efetiva possível.
Em breve teremos o post final desta série, onde exploraremos nosso último viés: a Modularidade.
Ah! E se você chegou até aqui, obrigado por ler!