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

Adriano Croco
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