Storytelling sobre carga cognitiva em times de tecnologia: um caso real

7 min readJan 9, 2025

Olá!

Hoje eu gostaria de compartilhar um aprendizado de análise de dados que acredito que possa ser útil na comunicação de alguns problemas comuns em times de tecnologia.

O que é carga cognitiva?

É uma teoria relacionada ao aprendizado e foi popularizada pelo psicólogo John Sweller na década de 1980. Ela possui a seguinte definição:

Carga cognitiva refere-se ao esforço mental total necessário para processar informações, especialmente em contextos que envolvem raciocínio e tomada de decisões. Esse conceito é fundamental para entender como as pessoas aprendem e interagem com as informações, considerando as limitações da memória de trabalho, que só consegue armazenar uma quantidade limitada de informações de cada vez.

De uma maneiral geral, essa teoria é facilmente relacionável com o contexto de desenvolvimento de software. Os tipos de carga existentes são:

Intrínseca: Refere-se à complexidade inerente de uma tarefa ou conceito. Essa carga é o esforço mental necessário para entender e processar informações específicas. No contexto de software, é a complexidade inerente ao domínio em questão. A recomendação é que ela seja simplificada, mas é impossível eliminá-la completamente.

Extrínseca: Este tipo é causado por fatores externos que não contribuem para a aprendizagem. Em contexto de software, podem ser interfaces confusas, dívidas técnicas que complicam a operação, ausência de processos maduros de desenvolvimento e similares. Os jovens chamam isso de Toil. A recomendação para esse tipo é reduzir o máximo possível.

Pertinente: Esta carga é relacionada ao conhecimento relevante que a pessoa deve processar para atingir os objetivos de aprendizagem. É a carga que ajuda na construção de esquemas mentais úteis e está alinhada com o que é pertinente ao aprendizado. Também pode ser chamada de Germânica. Como exemplo, temos: estudar para obter uma boa compreensão dos fundamentos de algoritmos, sistemas distribuídos e outras práticas relevantes ao ofício de desenvolvimento. Ou seja, é basicamente o que eu costumo escrever por aqui. A recomendação para esse tipo é maximizar.

Desenho bonitão para fixar na memória

Mas o que uma teoria de aprendizado tem a ver com software? Bom, praticamente tudo. A expressão “dar manutenção em um sistema”, basicamente tem como pré-requisito você aprender e entender como aquele sistema/linguagem/tooling funciona.

Sem isso, tudo acaba sendo prejudicado. Por isso que interrupções e demais ações que são consideradas danosas para o aprendizado de uma maneira geral, prejudicam grandemente a produtividade de uma pessoa desenvolvedora. Porém, antes que eu acabe reescrevendo os argumentos do Team Topologies aqui, gostaria de compartilhar uma ideia que apliquei para explicar o que é carga cognitiva e que achei os resultados satisfatórios.

Contexto

Stakeholders não técnicos não sabem muito bem o que é carga cognitiva, logo, cabe a nós — profissionais de desenvolvimento — explicar para eles. Uma das formas que encontrei de ilustrar com números, foi literalmente, contar linhas de código por sistema.

Eu queria resolver a seguinte situação: um time específico está com muitos sistemas sob sua responsabilidade. Logo, como explicar para pessoas de outras áreas que isso é um problema devido a alta carga cognitiva?

Com alguns passos simples e um pouco de paciência junto ao chatgpt, saiu algo útil. Vou compartilhar o meu processo nos passos abaixo, espero que te ajude, caso passe por um problema semelhante.

Step 1: Download dos repos

Comecei baixando todos os repositórios de código da empresa localmente.

Detalhes importantes: usar o fine-grained tokens do Github não funcionou para baixar repositórios privados. No momento que escrevo isso (jan/25), a feature está em preview, então estou assumindo que pode ser algum bug. Usei o token do modo classic e deu bom.

A opção de tokens está dentro do menu de Developer Settings

O script de download é bem simples, ele basicamente se conecta à API do github, lista os repos privados e vai executando o comando git clone em cada um, salvando os arquivos em um diretório local:

import os
import subprocess
import requests

def clone_github_repos(org_name, output_dir, token=None):
"""
Clones all private repositories from a GitHub organization.

Args:
org_name (str): The name of the GitHub organization.
output_dir (str): Directory where repositories will be cloned.
token (str, optional): GitHub personal access token for authentication (required for private repositories).
"""
if not token:
print("A GitHub token is required to fetch private repositories.")
return

headers = {"Authorization": f"Bearer {token}"}

api_url = f"https://api.github.com/orgs/{org_name}/repos"
params = {"per_page": 100, "page": 1, "type": "private"}

repos = []

# Fetch all private repositories from the organization
while True:
response = requests.get(api_url, headers=headers, params=params)

if response.status_code != 200:
print(f"Error fetching repositories: {response.status_code} - {response.text}")
return

data = response.json()
if not data:
break

repos.extend(data)
params["page"] += 1

if not os.path.exists(output_dir):
os.makedirs(output_dir)

os.chdir(output_dir)

# Clone each repository
for repo in repos:
clone_url = repo["clone_url"]
repo_name = repo["name"]

print(f"Cloning {repo_name}...")

try:
subprocess.run(["git", "clone", clone_url], check=True)
except subprocess.CalledProcessError as e:
print(f"Failed to clone {repo_name}: {e}")

if __name__ == "__main__":
org_name = input("Enter the GitHub organization name: ")
output_dir = input("Enter the directory to clone repositories into: ")
token = input("Enter your GitHub token: ").strip()

clone_github_repos(org_name, output_dir, token)

Agora que temos todos os arquivos necessários, podemos ir para o próximo passo.

Step 2: Contagem

Com o pré-requisito atendido, podemos começar a efetuar algumas análises.

O script abaixo conta quantas linhas de código cada pasta/repositório possuem e tem como resultado gerar um CSV com essas informações.

import os
import csv

def summarize_base_folders(directory, output_csv):
# Dictionary to hold line counts per base folder
base_folder_summaries = {}

# Traverse the directory
for root, _, files in os.walk(directory):
# Get the base folder name (relative to the input directory)
base_folder_name = os.path.relpath(root, directory).split(os.sep)[0]
if base_folder_name not in base_folder_summaries:
base_folder_summaries[base_folder_name] = 0

for file in files:
file_path = os.path.join(root, file)
try:
with open(file_path, 'r', encoding='utf-8', errors='ignore') as f:
base_folder_summaries[base_folder_name] += sum(1 for _ in f)
except Exception as e:
print(f"Error reading file {file_path}: {e}")

# Write summaries to CSV
with open(output_csv, 'w', newline='', encoding='utf-8') as csvfile:
writer = csv.writer(csvfile, delimiter=';')
writer.writerow(["base_folder_name", "line_count", "owner"])
for base_folder_name, line_count in base_folder_summaries.items():
writer.writerow([base_folder_name, line_count, ""])

if __name__ == "__main__":
# Specify the directory and output CSV file
input_directory = input("Enter the directory to summarize: ").strip()
output_csv_file = input("Enter the name of the output CSV file: ").strip()

summarize_base_folders(input_directory, output_csv_file)
print(f"Summary CSV has been generated: {output_csv_file}")

Eu adicionei uma coluna de Owner vazia para cada linha para facilitar, o motivo disso está no próximo passo.

Step 3: Classificação

Tendo os dados nos formato mencionado, agora que vem a parte trabalhosa. Classificar cada sistema por owner. Isso vai depender de quantos repositórios sua organização possui, obviamente.

Apesar de trabalhoso, foi uma análise interessante, ajuda a achar repois inutéis que podem ser deletados, sistemas com mais de um dono (A.K.A Shared Kernel) e similares.

O que irá gerar algo parecido com isso (os dados são fícticios):

project,line_count,owner
backend,2063,Owner A
mobile,2534,Owner B
backend_c#,11583,Owner C
java_legacy,12182,Owner D
crypto_libs,12231,Owner A
front_legacy,29791,Owner A
new_front,31462,Owner A
utils,189908,Owner E
iac_scripts,255099,Owner B
configs,555530,Owner F

Step 4: Visualização de dados

Com os dados classificados, você pode exibir os resultados de diversas formas. Porém, um formato que eu recomendo é o do script abaixo, que faz uma agregação por linhas/owners.

import pandas as pd
import matplotlib.pyplot as plt

# Load the data from the CSV file
csv_file = 'data.csv' # Replace with your actual CSV file name
data = pd.read_csv(csv_file, sep=',')

# Ensure the necessary columns exist
if not {'project', 'line_count', 'owner'}.issubset(data.columns):
raise ValueError("The CSV file must contain 'project', 'line_count', and 'owner' columns.")

df = pd.DataFrame(data)

# Group by owner and aggregate
summary = df.groupby('owner').agg(
total_lines=('line_count', 'sum'),
total_projects=('project', 'count')
).reset_index()

print(summary)

# Plot total lines and projects per owner
fig, ax1 = plt.subplots(figsize=(8, 5))

# Bar chart for total projects
ax1.bar(summary['owner'], summary['total_projects'], color='blue', label='Total Projects', alpha=0.7)
ax1.set_ylabel('Total Projects', color='blue')

# Line chart for total lines
ax2 = ax1.twinx()
ax2.plot(summary['owner'], summary['total_lines'], color='orange', label='Total Lines', marker='o')
ax2.set_ylabel('Total Lines', color='orange')

# Chart details
plt.title('Projects and Lines per Owner')
ax1.set_xlabel('Owner')
plt.show()

O script tem como output um resuminho e um gráfico:

output do summary

É um gráfico de barras e linhas. No caso, as linhas estão em laranja e os sistemas (repos) em azul:

Nesse exemplo, é possível interpretar que há uma power law (já comentei sobre isso aqui) em ação. O que indica que um único time (owner A), é responsável por 40% de todos os sistemas. Porém, o time owner F é responsável pelo sistema maior em quantidade de linhas, o que pode ou não ser algo relevante. De uma maneira geral, esse comportamento de poucas causas para muitos efeitos é um sinal de que algo está errado e precisa ser revisto. Geralmente, algo relacionado a cultura do herói.

Obviamente que transformei os dados reais em dados fícticios aqui para não expor a empresa que trabalhei, mas eu me deparei com o mesmo cenário quando fiz essa análise em um caso real.

Step 5: Comunicação

Com esse tipo de visualização em mãos, agora é mostrar e explicar para as pessoas, com base nos dados, porque isso é um problema.

Lembre-se de evitar jargões técnicos para pessoas não técnicas, tratar outras pessoas com respeito, ouvir bastante e demais boas práticas de comunicação.

Com isso, espero que você consiga argumentar com sucesso que a estrutura de times está precisando de mudanças.

Lembrando que esse formato de storytelling é o mínimo recomendado para qualquer pessoa que queira gerar mudanças reais em qualquer empresa. Seja o mais data-driven que você puder ser, afinal:

Brinks, não mintam com dados! Já basta os políticos fazendo isso

Espero que o texto seja útil para você de alguma forma.

Até!

Você gostou do conteúdo e gostaria de fazer mentoria comigo? Clique aqui e descubra como.

--

--

Adriano Croco
Adriano Croco

No responses yet