Em 1975, Frederick P. Brooks escreveu o revolucionário The Mythical Man-Month. Quarenta anos depois, esta série de artigos pretende revisar as afirmações e os argumentos do autor. Quanto o ofício da Engenharia de Software evoluiu desde então?

Capítulo 6: Passing the Word

Num sistema pequeno pode parecer fácil manter a integridade conceitual, mas o que dizer de um grande projeto ou até um gigante com 10 arquitetos e 1000 desenvolvedores?

Neste capítulo, Brooks revisita alguns pontos pendentes do capítulo anterior, especificamente sobre técnicas para manter uma comunicação efetiva no decorrer do projeto, “levando a palavra” a todos os envolvidos.

A argumentação do autor do livro e meus comentários pessoais estão intercalados no texto, pois este ficou um pouco extenso e deixar os comentários para o final quebraria o ritmo do artigo. Considere as ideias apresentadas usando a expressão “o autor” ou invocando o nome próprio dele como retiradas do livro e as demais como contribuições minhas.

O manual

Mesmo com uma equipe grande, as decisões precisam ser formalizadas por uma ou duas pessoas, para que as decisões como um todo sejam consistentes.

O autor evoca o conceito de um manual do sistema como peça central da solução para o problema de comunicação. Uma boa especificação escrita, precisa e coerente, levaria todos a seguirem a mesma filosofia no decorrer do projeto.

Não confunda com manual do usuário.

Esse documento funcionaria como a especificação externa citada no capítulo anterior que guia, e não dita, como o sistema deve funcionar.

No manual, o arquiteto deve prover pelo menos uma forma de implementação para cada funcionalidade, mas é dos desenvolvedores a palavra final sobre a melhor implementação.

Entretanto, Brooks afirma que apenas uma ou, no máximo, duas pessoas devem escrever esse documento. Ele cita como exemplo de sucesso desse modelo um grande projeto que envolveu milhares de pessoas e diversos arquitetos, porém todas as ideias foram colocadas no manual por apenas dois arquitetos, de forma que o documento era consistente como um todo, embora muitos houvessem contribuído de várias formas.

Deixando pontos em aberto

É importante deixar claro quais partes de uma arquitetura não são prescritas tão cuidadosamente quanto as que são.

Algo que vejo vez ou outra sendo discutido sobre arquitetura de sistemas é a importância do que não deve ser definido de início, isto é, postergar decisões para um momento mais apropriado quando houver mais conhecimento sobre o problema.

O fundamento desse pensamento é simples: à medida em que se trabalha no projeto a equipe passa a ter uma visão mais clara de onde quer chegar, tendo então condições de tomar decidir melhor sobre a arquitetura. Portanto, em teoria, quanto mais decisões forem tomadas no início do projeto, mais chances haverá de ter que mudar e refazer coisas, o que custará mais tempo e dinheiro. O inverso também é verdadeiro, ou seja, decisões mais tarde no decorrer do projeto tendem a ser mais alinhadas com as necessidades reais.

Claro que algumas observações aqui são necessárias. Postergar decisões sobre a arquitetura inicial não significa ignorar problemas só para mais tarde ter surpresas no projeto. Tampouco significa que está tudo bem fazer o planejamento de qualquer maneira para depois dar um “jeitinho” lá na frente.

Concordo com o autor quando ele defende que é importante documentar as decisões não fixadas no início do projeto de forma consciente e precisa.

Em geral isso ocorre quando os arquitetos e demais envolvidos estão a par do problema e tem algumas possíveis soluções em mente. Entretanto, devido a algumas incertezas, eles deixam isso documentado para uma melhor decisão no futuro. Essa decisão deve ser tomada antes daquele item se tornar um problema para o projeto, portanto deve ser monitorado.

Por exemplo, suponha que está desenvolvendo um sistema web que precisa de armazenamento de dados na nuvem. Você não tem uma ideia clara do quanto será demandado por cada usuário, portanto não sabe qual serviço será mais adequado. Você tem opções como Amazon S3, Dropbox e outros. Cada um oferece benefícios e custos diferenciados dependendo do tipo e da quantidade de dados. A decisão de qual serviço utilizar pode ser postergada para quando um estudo mais apurado sobre a utilização esperada for realizado, mas deve ser tomada em tempo hábil para não atrasar a publicação do projeto para os usuários finais.

Envolvendo a equipe na arquitetura

Além disso, é importante que nem todos os pontos da arquitetura que precisam ser implementados de uma forma específica.

Por exemplo, o arquiteto, tendo conhecimento de uma integração com sistemas de terceiros, prescreve que se deve implementar tal integração usando o protocolo SOAP. Não tem outro jeito de fazer, é assim e pronto.

Por outro lado, se dois subsistemas internos daquele projeto precisam se comunicar remotamente, sendo ambos implementados pela mesma equipe, o arquiteto pode deixar a cargo dos desenvolvedores decidir qual tecnologia será usada, que geralmente vai ser aquela que eles possuem mais conhecimento e afinidade.

O importante até aqui é que a decisão de não decidir deve estar devidamente documentada e clara.

Particularmente, acredito que o arquiteto faz bem em delegar o máximo que puder para a equipe. Não para deixar de fazer o trabalho dele, mas para empoderar todos os desenvolvedores, enquanto os ajuda e orienta a tomar tais decisões.

Incluir os membros da equipe nas decisões arquiteturais tem inúmeros benefícios:

  • Aumenta a confiança da equipe na solução.
  • Incentiva a aprendizagem.
  • Maior produtividade, já que eles refletem sobre o problema antes de começar a implementação.
  • Desenvolve habilidades de arquiteto, inclusive permitindo que eles vejam como o arquiteto trabalha.
  • Aumenta o comprometimento da equipe com a solução, pois ela foi escolhida por todos e não imposta.
  • Fomenta discussões técnicas cotidianamente, elevando o nível técnico da equipe.
  • Acompanhar a participação de cada membro da equipe nas discussões técnicas permite avaliar o nível de cada um e quais as suas habilidades principais, independente do cargo ou tempo de experiência.

Texto em prosa e definições formais

É necessário tanto uma definição formal de um projeto, para haver precisão, como também uma definição textual para compreensibilidade.

Aqui começamos a entender do que é constituído o manual que Brooks propõe. O autor faz um contraste entre nossa língua cotidiana e representações formais para chegar a um consenso sobre como produzir a documentação adequadamente.

Uma língua como Inglês ou Português possui contradições e ambiguidades, depende de interpretação e não vai direto ao ponto. Por outro lado, ela consegue expressar melhor as razões de algo existir.

As definições formais, tal como fórmulas da matemática, apresentam conceitos de forma precisa e concisa, mas são limitadas ao contexto ao qual se aplicam e mais complexas de manipular.

Nós veremos especificações no futuro consistirem de definição formal e definição textual.

Brooks prevê que a documentação no futuro seria um misto de texto e especificação formal. E não é que ele acertou em cheio?

Existem muitas técnicas formais para se expressar requisitos, mas elas são de aplicação limitada e geralmente acadêmica, enquanto que quase a totalidade dos projetos adota algum nível de documentação em forma de texto recheado com diagramas UML, variados tipos de representação visual, gráficos, etc.

O exemplo mais óbvio são especificações de caso de uso, onde você geralmente vê uma mistura de prosa e definição formal através de diagramas UML, tais como Diagrama de Sequência e Diagrama de Atividades, além do texto detalhando cada um deles numa tabela ou algo do tipo.

O texto é necessário para o entendimento detalhado dos requisitos, enquanto os diagramas contribuem para o entendimento mais preciso de alguns aspectos.

Isso é verdade mesmo se você trabalha com estórias de usuário coladas num quadro Kanban e tem algum documento ou página eletrônica com o detalhamento.

Não estou dizendo que UML é a melhor ferramenta sempre, nem um quadro Kanban, nem advogando que devemos seguir aquele modelo acadêmico de ficar gerando dezenas de diagramas como alguns professores de engenharia de software pedem em cursos de TI. Voltarei a este assunto mais a frente, nas considerações finais.

Um padrão é preciso

Dentre a definição formal e textual deve haver um padrão, o outro sendo derivado. Ambas as definições podem assumir esse papel.

Brooks lembra que muitas vezes há conflito entre a especificação textual e formal.

Você já deve ter visto documentações cujo texto dizia uma coisa e o diagrama representava outra.

Nesses casos, deve-se adotar um padrão, por exemplo de que no caso de divergência vale o que está escrito.

Além da documentação

Uma implementação, incluindo uma simulação, pode servir como definição arquitetural. Mas podem haver desvantagens consideráveis.

Brooks vai além de defender apenas um documento como fonte para o funcionamento do sistema. Ele diz que a especificação pode ser o próprio código, afinal uma especificação usando linguagem formal geralmente representa uma implementação e disso para chegar ao próprio código é um passo.

O autor cita o desenvolvimento das primeiras arquiteturas de hardware, cujas novas versões deveriam ser compatíveis com as anteriores e muitas vezes isto era feito de forma pragmática, observando o comportamento da versão anterior.

O manual está vago em algum ponto? Pergunte à máquina! Um programa de teste poderia ser concebido para determinar o comportamento.

Aqui ele fala sobre um programa de teste que poderia ser usado para confirmar se a nova versão apresenta o mesmo comportamento esperado da versão anterior.

Seria isso o início do TDD já nos anos 70?

scared-baby

Claro, existe o risco da implementação existente apresentar comportamentos inesperados. O autor menciona o sistema operacional que ele desenvolveu, onde foram registrados mais de 30 usos inesperados do sistema pelos usuários, que não poderiam ser removidos das versões posteriores.

O autor não entra em assuntos como uso de comentários como documentação, código auto documentado (tão fácil de entender que não precisa de explicação), APIs fluentes e outras formas de documentação que fazem parte do código e assim evitam a discrepância entre código e uma documentação escrita à parte. Pense que isso não era uma opção viável na época, já que linguagens dinâmicas e uma variedade de processadores de código exigiria hardware bem mais potente e software mais avançado do que o existente nas décadas de 60 e 70. No entanto, muitos dos conceitos que ele apresenta podem ser transportados para ferramentas e padrões modernos que são muito mais práticos de se trabalhar.

Reuniões e comunicação

Grandes projetos demandam muitos encontros. Não vou entrar em detalhes, mas resumidamente os princípios de Brooks são:

  • Reunir-se com os arquitetos semanalmente para discutir os pontos importantes.
  • Preparar tudo o que vai ser falado antecipadamente.

Em suma: evite perder o tempo de quem não precisa estar na reunião e não enrole quem está presente. Não é horrível várias pessoas esperando quem vai coordenar a reunião procurar algo no computador, arrumar projetor, enviar anexos para os presentes e editar documentos de última hora? Pior, o apresentador estar despreparado e resultar num encontro totalmente infrutífero. Tudo isso deve ser feito com antecedência!

O autor sugere distribuir material impresso, tal como versões atualizadas do manual do sistema, antes das reuniões.

É importante permitir a interpretação de um arquiteto via telefone em resposta a perguntas dos desenvolvedores; é imperativo registrar e publicar essas consultas através de um meio apropriado.

Brooks sugere manter um histórico das perguntas feitas ao arquiteto via telefone, a fim de reusar o conhecimento como uma espécie de FAQ (perguntas e respostas frequentes).

Obviamente, registrar chamadas telefônicas e distribuir cópias impressas de um manual semanalmente são práticas que desconexas da realidade atual. Se ainda são feitas, deveriam ser abandonadas para dar lugar a meios de comunicação digitais mais rápidos, eficientes e econômicos.

Lembre-se, nos anos 70 não haviam sistemas de comunicação interna e troca de mensagens instantâneas. Hoje isso fica muito mais fácil usando aplicações na intranet ou mesmo na nuvem.

Até agora este é um dos poucos pontos do livro que se tornaram desconexos da realidade diária do desenvolvimento de software moderno. Entretanto, note que os mesmos princípios relacionados à complexidade e efetividade da comunicação ainda valem, somente os meios mudaram.

Eu havia planejado incluir neste tópico um estudo de caso de como a comunicação interna é feita na empresa onde trabalho, a Atlassian. Entretanto, enquanto escrevia, o texto fugiu de controle, multiplicou-se indiscriminadamente e acabou indo parar num artigo próprio, a ser publicado na próxima semana. 🙂

Jogando de acordo com as regras

Quando partes de um projeto são desenvolvidas em paralelo, cada equipe sendo responsável por uma delas, todos devem respeitar os padrões definidos senão as partes não funcionarão em conjunto quando forem integradas. Segundo o autor, limitar-se pelo “bem maior” é bom no sentido de que evita mudanças frequentes e arbitrárias no projeto.

Eu acrescentaria o lado negativo, que é o da difícil evolução das APIs no caso de melhorias que exigem mudanças legítimas.

Uma técnica de grande escala usada por empresas como Google para manter a integridade conceitual enquanto ainda possibilita uma evolução rápida do código é colocar todos os projetos num único repositório, conhecido como monorepo. Entre outras coisas, isto permite refatorar vários projetos ao mesmo tempo, inclusive alterando suas APIs, e ver quase que instantaneamente o impacto em todos os projetos dependentes. Para saber um pouco mais veja a palestra técnica do Google abaixo:

O princípio geral deste tópico é ser mais fácil manter a integridade conceitual do projeto quando se respeita um plano global ao invés de cada um tentar fazer melhorias independentemente de acordo com suas preferências.

Um exemplo negativo de como isso pode acontecer é quando são colocados no projeto desenvolvedores que possuem um modo peculiar de trabalho e criticam quem não segue a mesma linha. Pode ser uma linguagem ou framework específico, fora do que eles não tem muito conhecimento. Num projeto diferente, eles acabam atrapalhando a equipe tentando forçar mudanças que não fazem sentido naquele momento, por simples questão de gosto pessoal.

Porém, a maturidade do profissional é demonstrada quando ele consegue entrar no meio de um projeto em qualquer linguagem e adotando qualquer estilo e dar sua contribuição dentro dos limites impostos, sem acrescentar mais gambiarras e sem criar algo desconexo e gritante, mas que se funcione harmoniosamente com o restante da arquitetura.

A equipe de qualidade

O melhor amigo do gerente é seu adversário frequente, uma equipe independente de teste do produto.

A última “ferramenta” que Brooks diz ser o maior amigo do gerente, é ter uma equipe independente de qualidade que faça algum tipo de auditoria a fim de garantir a aderência de todas as equipes às especificações do projeto.

Note que não estamos falando aqui de criar testes ou colocar testadores na equipe. Seria mais algo como uma equipe de Garantia de Qualidade (QA – Quality Assurance) independente.

Incrivelmente, esta é a estratégia que muitas empresas sérias e grandes estão adotando hoje.

Manter testadores em tempo integral para cada equipe e projeto é pouco viável e, mesmo realizado, não dá um retorno proporcional ao investimento. Durante o desenvolvimento já é difícil testar de forma compreensiva, ainda mais se considerarmos as modificações de um produto em seu período de manutenção.

Portanto, a estratégia que várias empresas adotam é manter uma equipe independente de qualidade que participa do planejamento acompanhamento dos projetos.

O principal objetivo dessa equipe de qualidade não é realizar testes em si, mas fazer o levantamento de riscos (risk assessment), isto é, identificar os maiores problemas e riscos que poderiam ocorrer para cada funcionalidade implementada. Em geral os membros da equipe de QA devem ter conhecimentos abrangentes, mas não profundos, sobre os produtos da empresa, as tecnologias e as normas que devem ser seguidas.

A equipe de desenvolvimento usa o feedback da equipe de QA para planejar a infraestrutura e o esforço investido em testes. A regra é simples: pouco risco menos teste, muito risco mais testes.

Direcionar os esforços dos testes para aquilo que importa é muito mais eficiente do que tentar testar todo o sistema sem critérios objetivos. Com a abordagem errada, a equipe acaba com uma massa de testes sem valor que tende a ser logo uma barreira para a evolução do insistem e, portanto, logo é descartada.

A equipe de QA pode também realizar auditorias ou investir em ferramentas de automação que detectem problemas no código ou nos ambientes, evitando situações de risco automaticamente.

Um exemplo simples disso seria adicionar regras no repositório que alertam o desenvolvedor se ele introduzir código potencialmente perigoso, tal como esquecer de dar escape numa String ao escrever uma variável numa página web, o que potencialmente levaria a uma vulnerabilidade de cross-site scripting ou XSS.

Documentar ou não documentar: eis a questão!

O manual proposto por Brooks é um conceito que se transformou muito ao longo do tempo, tanto que nos parece estranho.

Documentar o sistema é importante, entretanto hoje temos variadas formas de fazer isto, seja através de documentação automática em comentários no código, de ferramentas UML, JavaDocs, APIs fluentes, etc.

Mas só a menção da palavra “documentação” gera sentimentos conflitantes. Há quem acredite que nenhuma documentação deve ser feita, outros que ter um documento texto que descreva desde as necessidades de negócio até a arquitetura básica com exemplos de código é essencial.

A verdade é que precisamos chegar a um equilíbrio e nos guiar por alguns princípios que vou mostrar estarem alinhados com os objetivos de Brooks ao falar sobre o tal "manual".

Primeiro, ser contra documentação é correto. Nenhum documento desnecessário deveria existir só por existir. Gastar tempo criando documentos não usados é jogar dinheiro no lixo.

Por outro lado, existem motivos legítimos e razoáveis para se criar documentação.

O primeiro é colocar no papel, de forma organizada, a sua proposta de solução para o problema do cliente, de forma que ele entenda o que você vai fazer.

O segundo é orientar outras pessoas que vão participar do projeto, porém não estão nele desde o início. Documentar as decisões tomadas até o momento, as razões e as alternativas desconsideradas é muito importante. Dessa forma, se alguém questionar porque não está se fazendo isto ou aquilo de outra forma, ela pode seguir o raciocínio novamente e evitar de ter que refazer o trabalho ou perder tempo com uma solução já comprovadamente ineficaz. Além do mais, isso deve ser documentado porque nenhuma pessoa normal vai conseguir passar verbalmente essas informações para toda uma equipe todo o tempo.

Para chegarmos ao fim da polêmica, basta entender duas coisas:

  1. A documentação legítima é o mínimo que você precisa para satisfazer os critérios de comunicação do cliente, da empresa e da equipe.
  2. Documentar não consiste necessariamente ou primariamente em escrever documentos texto ou diagramas UML. Ela deve vir à existência no formato mais conveniente, compacto e direto possível.

É provável que você acabe enviando algum documento Word para o cliente com protótipos das principais telas do sistema até que se possa chegar a um acordo sobre custos e prazo. Nenhum problema com isso, faz parte do ramo de negócios e não tente levar a discussão para o campo técnico ou filosófico que não vai funcionar.

No entanto, hoje temos disponíveis ferramentas que podem automatizar boa parte da documentação se bem configuradas. Podemos usar o próprio código como documentação, páginas e sistemas na intranet, arquivos JSON ou até rascunhos na mesa, todas são formas de comunicação interna eficientes dentro do seu contexto.

Portanto, podemos dizer que se o meio utilizado permite a comunicação eficaz dos objetivos do sistema e da filosofia de desenvolvimento, ele cumpre o papel do manual que Brooks defende.

Outras considerações

O capítulo se concentrou no “manual” e no seu conteúdo, mas não deixou de lado os aspectos e princípios mais importantes para comunicação do que é crítico para o projeto. Tudo com o objetivo de manter uma comunicação eficaz.

Infelizmente, as dicas mais práticas não se aplicam à realidade do século XXI, mas, novamente, podemos transpor os princípios fundamentais e aprender muito com isto.

Não incluí muitos exemplos modernos de ferramentas e técnicas de comunicação aqui, mas preparei um outro artigo com foco exclusivo nesta área. Aguarde! 😀