Já falamos aqui no blog da Zup sobre design de código e a importância de desenvolver estratégias que reduzam o cognitive load dos nossos códigos para garantir seu entendimento por todos. Foi desse raciocínio que nasceu o conceito de Cognitive-Driven Development (CDD) desenvolvido através de pesquisas acadêmicas dentro da Zup.
Se interessou em conhecer mais sobre essa teoria e em como aumentar a qualidade do seu código? Então continue lendo!
Um pouco de background sobre a psicologia da cognição
Descobrir quais são as nossas limitações de entendimento e como a nossa mente atua nessa questão é tema de estudo de longa data. O artigo mais influente nessa área vem de 1956 e foi escrito pelo psicólogo George A. Miller, da universidade de Harvard. O título da famosa publicação é “The Magical Number Seven, Plus or Minus Two: Some Limits on our Capacity for Processing Information“.
Neste artigo, Miller explica que provavelmente nós temos uma severa limitação na hora de processar informações. No resumo do resumo, é explicado que temos um limite de itens a serem entendidos em determinado momento que varia entre 5 e 9. Por isso o título +-7. Essa ideia foi fortemente explorada e é bem aceito hoje em dia que realmente temos essa limitação.
Para se ter uma visão mais moderna do estado do estudo da arquitetura da nossa mente no que diz respeito ao nosso processo de entendimento, você também pode consultar o material referente a Teoria da Carga Cognitiva.
A principal referência no assunto é o pesquisador John Sweller. Esta teoria explica que existem certos tipos de elementos que podem dificultar nosso entendimento e que, entre estes elementos, existem os que compõem a carga intrínseca do material.
Um trecho retirado do artigo referenciado diz o seguinte: “The load is called ‘intrinsic’ if it is imposed by the number of information elements and their interactivity.”
Em tradução livre, temos: “A carga é chamada de ‘intrínseca’ se for imposta pelo número de elementos de informação e sua interativida”.
E é da ideia de carga intrínseca que nasce a proposta de design de código orientado a entendimento. Caso a gente considere que um pedaço de código é um material que precisa ser entendido, como podemos diminuir de maneira eficaz a carga intrínseca dele?
Afinal, o que é Cognitive-Driven Development (CDD)?
Antes de avançar, precisamos trazer a definição de Cognitive-Driven Development (CDD).
Cognitive-Driven Development (CDD), ou em português desenvolvimento orientado a cognição, é uma estratégia para reduzir a sobrecarga cognitiva durante o desenvolvimento ao melhorar o design do código.
Na Zup realizamos pesquisas empíricas sobre o qualidade de código e aplicações de Cognitive-Driven Development (CDD com regularidade. Ainda neste artigo você vai poder conhecer com detalhes sobre esses experimentos. O resultado disso? Já temos dois artigos apresentados em conferências acadêmicas e publicados sobre o tema.
Mas isso é só o começo! ?
Limitando a carga intrínseca do código ou Ponto de Complexidade Intrínseca (ICP)
Uma das bases do Cognitive-Driven Development (CDD) é analisar e buscar limitar a complexidade de um código. Para que a gente consiga, de fato, ter uma maneira interessante de limitar a carga intrínseca do código que escrevemos, precisamos seguir alguns passos.
A primeira tarefa do time é decidir qual vai ser a unidade de código que será analisada. Por exemplo, se falarmos de uma linguagem orientada a objetos temos algumas possibilidades de definição de unidade de código, como, por:
- método dentro de uma classe;
- classe;
- arquivo.
O que mais foi explorado até agora é usar o arquivo como uma unidade de código a ter sua carga intrínseca limitada. Isso implica que se tivermos duas classes dentro do mesmo arquivo, vamos somar as cargas intrínsecas de cada uma e essa vai ser a carga total do arquivo.
Uma vez que a unidade de código a ser analisada foi definida, é importante que a equipe do projeto entre em um acordo sobre o que vai influenciar na carga. É o que chamamos de Intrisc Complex Point (ou Ponto de Complexidade Intrínseca) no Cognitive-Driven Development. Para facilitar, vamos referenciar estes pontos como ICP.
Aqui não existe regra, o objetivo do Cognitive-Driven Development (CDD) não é achar uma composição de Ponto de Complexidade Intrínseca (ICP) que forme uma métrica perfeita. A ideia é que a equipe, considerando suas características, encontre os ICP que façam sentido para aquele contexto.
E qual o limite de ICP que podemos ter então por unidade de código? Atualmente a nossa sugestão é que você tenha um número que seja o dobro ou maior ao número de ICP escolhidos. No exemplo citado temos cinco itens, então o limite por unidade de código seria dez ou mais.
Visão prática sobre o Ponto de Complexidade Intrínseca (ICP)
Por exemplo, a equipe de engenharia da Zup Edu definiu que para os projetos em Java que escrevemos, vamos considerar os itens abaixo como ICP:
- branches de código padrões (if, else, loops, when, case do when, try, catch);
- funções como argumento;
- condicionais;
- acoplamento com classes específicas do projeto;
- herança de classe abstrata ou concreta (extends).
Cada equipe pode definir seu conjunto de ICP e revisitá-lo com frequência. Até porque a combinação de níveis de habilidade da equipe pode influenciar no escopo do projeto e em vários outros fatores que afetam a qualidade e complexidade do código. Outro detalhe muito interessante é que o conjunto de itens influencia diretamente no estilo de código.
Algumas dicas práticas para escolher e trabalhar melhor com ICPs:
- Herança foi escolhida como ICP? O recado é: Use com moderação.
- Condicional foi escolhida como ICP? O recado é: Não crie if com várias condicionais
- Função como argumento foi escolhida como ICP? O recado é: Não exagerar em transformação de coleção.
- Apenas acoplamento com classe específica foi escolhido como ICP? O recado é: Saiba das tecnologias que sustentam o projeto, vamos usar sem moderação.
A definição do limite de ICP por unidade de código ainda precisa de muita exploração. O importante para o Cognitive-Driven Development (CDD) é que exista um conjunto de itens claros que a equipe considere que dificulta o entendimento, assim como um limite estabelecido.
Benefícios de criar um entendimento sobre complexidade
Com um conjunto de ICP claro e um limite definido, muitas atividades e debates são facilitados no intervalo de tempo em que o combinado estiver valendo:
- Esse código está complexo? Se o número de ICP estiver abaixo ou igual ao limite, a resposta é não.
- Esse código vai passar no review? Se o número de ICP estiver abaixo ou igual ao limite, a resposta é sim.
Não importa se a pessoa é junior, plena, sênior ou qualquer outro nível. Ninguém vai escrever um código que passa do limite de complexidade.
Quaisquer outras discussões sobre complexidade agora têm uma regra clara. Entendemos que isso facilita bastante o dia a dia de comunicação dentro do projeto no que diz respeito à análise do código em si.
Como o Cognitive-Driven Development se relaciona com o que você já utiliza hoje em dia?
Importante notar que o Cognitive-Driven Development (CDD) não vem com a ideia de ser a principal referência dentro do design do seu código. Limitar a dificuldade de entendimento é algo que pode ser útil em qualquer ponto do projeto.
Imagine que você está escrevendo um caso de uso inspirado na arquitetura proposta pelo Clean Architecture. Se a equipe tiver definido os pontos de complexidade intrínseca (ICP) e o limite, você vai conseguir ter um caminho claro de como separar o código de modo a fazer o caso de uso e ainda manter o nível de carga cognitiva necessário para entendimento adequado com os padrões da equipe.
Olhando ainda para as ideias de camadas propostas pela Clean Architecture, você pode encontrar situações semelhantes na camada de entidades. As classes que estão no núcleo da sua aplicação tendem a ser transversais ao sistema todo. Elas podem ganhar mais atributos, métodos etc.
Então como fazer para saber o limite daquele código no que diz respeito a facilidade de entendimento? Mais uma vez a ideia do Cognitive-Driven Development (CDD) pode ser aplicada para facilitar.
A mesma linha de raciocínio pode ser aplicada quando você está se inspirando no Domain Driven Design, pensando no princípio da responsabilidade única etc.
Experimentos aplicando CDD realizados na Zup
Queremos trabalhar em cima de uma tese de design que demonstre real valor quando for testada sob condições controladas. Até agora, rodamos dois experimentos na Zup.
O primeiro experimento foi em cima de uma atividade de refatoração. Um grupo de pessoas tinha que refatorar dois códigos de negócio usando as técnicas convencionais de design. Já o outro grupo precisava refatorar usando o Cognitive-Driven Development (CDD) como linha mestra de design, ou seja, sabiam dos ICP daquele contexto e do limite.
O resultado é que as refatorações que foram feitas via Cognitive-Driven Development (CDD) acabaram com códigos muito melhores quando analisados pelas métricas formais como, por exemplo, coesão, quantidade de linhas de código, complexidade ciclomática etc.
Já o segundo experimento foi focado na fase de construção inicial de código. Aqui afunilamos o experimento. Informamos a todos os grupos quais eram os itens que deviam ser considerados na análise de complexidade do código. Só que para três grupos, estabelecemos um limite, como indicado pelo Cognitive-Driven Development (CDD). Já para outros três, não estabelecemos um limite. A hipótese era que o limite ajudaria as pessoas a dividirem melhor a complexidade do código.
O resultado, mais uma vez, foi favorável. Os códigos produzidos via CDD tiveram suas unidades de código com complexidades mais parecidas, enquanto que os códigos produzidos pelos outros grupos apresentaram uma divisão pior.
O interessante é que a média de complexidade por métrica não foi muito diferente entre os grupos, a diferença foi realmente a dispersão. A conta básica aqui é: 5 e 5 dá 5 de média. Só que 0 e 10 também dá 5. Porém a primeira média pode ser considerada mais real e é exatamente algo nessa linha que você espera no código. Que a complexidade esteja espalhada pelas unidades e não concentrada.
Trabalhos futuros sobre Cognitive-Driven Development (CDD)
Entendemos que existem algumas possibilidades para expandir o trabalho em cima do Cognitive-Driven Development (CDD). Algumas ideias que temos e que ainda vão ser exploradas são:
- Será que vale a pena começar a limitar a complexidade cognitiva imposta pelos elementos de determinada arquitetura?
- Qual a relação que existe entre a combinação de habilidades de times e as métricas (conjunto de ICP) que podem ser derivadas?
- Como serão as métricas para linguagens funcionais?
- Será que conseguimos sugerir uma refatoração automática em função da limitação de entendimento?
- Será que um código que foi desenvolvido com as ideias do CDD realmente vai controlar o aumento de complexidade com o tempo?
Enfim, estamos animados quando olhamos para frente e entendemos que tem bastante caminho para ser explorado.
A Zup é uma empresa que apoia a pesquisa acadêmica real
Gostaria de aproveitar esse espaço final para falar do papel essencial da Zup nesse processo. Infelizmente não estamos acostumados a ver empresas apoiarem de maneira concreta a pesquisa acadêmica real.
Geralmente o trabalho acadêmico exige mais investigação, mais tempo e não necessariamente gera retorno a curto prazo, o que afasta grande parte das empresas.
Por outro lado, apoiar a investigação com viés científico é olhar para o futuro e ter a intenção de se posicionar como um lugar que é real gerador de conhecimento. Não existe inovação real sem investigação profunda.
Estamos encontrando o ritmo ideal para acomodar a velocidade necessária para andar em um mercado extremamente competitivo, como o de tecnologia, sustentado cada vez mais pelo olhar crítico que a academia tem sobre o mundo.
O que achou do Cognitive-Driven Development (CDD)? Conta para a gente nos comentários!
Inspirações para o texto:
- Software aging.
- Design erosion: problems and causes.
- Dynamics of Software Maintenance.
- ISO/IEC 25010:2011.
- O mágico número 7.
- Sobre a teoria da carga cognitiva.
- Toward a Definition of Cognitive-Driven Development – The International Conference on Software Maintenance and Evolution (ICSME) 2020. Leia aqui (em inglês).
- Cognitive-Driven Development: Preliminary Results on Software Refactorings – The International Conference on Evaluation of Novel Approaches to Software Engineering (ENASE) 2021. Leia aqui (em inglês).