Código “team-friendly”

Já pensou em deixar seu código mais padronizado entre o time e mais amigável para novos desenvolvedores? Existem diversas formas de se fazer isto e o que eu mostrarei aqui são apenas os métodos que funcionaram comigo. Não existe “jeito certo”, apenas o jeito que seu time melhor se adapta. Aliás, muitas pessoas do seu time podem não se adaptar ao seu método e cabe a você identificar qual é o mais vantajoso para o projeto em geral, forçar um método ou atender ao apelo dos membros do time.
O papel de “policiar” a padronização de código muda para toda as empresas. Algumas colocam a responsabilidade para um dev senior, outras dão a tarefa para um code-reviewer, tech-lead, etc. Não importa qual seja sua posição, padronizar código pode ser uma tarefa árdua. Sempre existirão pessoas que não aceitam o método, outras que não entendem que nem sempre o melhor método é o melhor para o projeto como um todo, etc. Padronizar para alguns significa que você esta “oprimindo” ou “cortando as asas”, etc.
Você, como responsável pelo código, as vezes tem que pensar no bem do projeto, da empresa, etc. E isto é algo que envolve muito mais do que preferências pessoais de alguns devs… Envolve treinamento, troca de pessoal, etc. Quanto mais amigável for seu código para um novo membro do time, mais fácil é para você crescer o time sem perder centenas de horas em treinamento.
Muitas empresas se baseiam na documentação como forma primária de auxiliar o novo dev, mas existem coisas ainda melhores que podem agilizar o processo. Usar a IDE como aliada é uma delas.
TRIGGER WARNING: Se você é um dev e não gosta de opiniões sobre como codar, dê meia volta. 🙂
Para entender tudo a seguir, tente considerar a visão de uma pessoa nova no projeto e, especialmente, uma pessoa menos experiente que você.
Todos já passamos por isto: Um dev entra no time e ninguém tem tempo de treiná-lo, apresentá-lo ao código, explicá-lo porque algo foi feito de tal forma, etc. O dev fica desmotivado porque ele quer produzir e se sentir útil. Para outros devs pode parecer que ele não está fazendo nada e, as vezes, a própria chefia fica com esta mesma opinião. Como resolver isto? Bom, eu tenho 2 mantras pra isso… “‘Codar’ para os outros lerem, não você.” e “Usar a IDE como documentação.”
Documentando pelo nome de variáveis
Considere um caso muito comum: Você tem um função com alguns argumentos e eles tem que estar em certa ordem.
# sentences.py def explain_lunch(a, b, c): print(f"{a} cooked {b} and {c} for lunch.")
Como você pode ver, a função faz parte de um módulo “sentences.py”, ou seja, normalmente o código desta função não está em exibição na tela. Uma pessoa nova no projeto, importando esta função, não teria a menor ideia do que ela faz. Veja o que acontece quando usamos a função em uma IDE como o PyCharm e deixamos a IDE apresentar o popup com a documentação da função:
O popup não ajuda muito, não é? O que é “a, b, c”? Esta pergunta obrigará o dev a consultar o código de origem. Parece algo simples mas toma muito tempo, ainda mais quando temos centenas de funções como esta.
Então como melhorar? Vamos começar apenas renomeando as variáveis. Isto é o que qualquer manual de boas práticas já te aconselha a fazer.
# sentences.py def explain_lunch(name, food1, food2): print(f"{name} cooked {food1} and {food2} for lunch.")
Ok, agora o popup de documentação já ajuda um pouco mais:
Vendo este popup, o dev novo no projeto já saberá que terá que passar um nome e dois tipos de comida como argumentos sem ter que olhar o código da função.
explain_lunch("Mary", "rice", "beans") # Mary cooked rice and beans for lunch.
Mas agora se coloque no lugar de outro dev que está apenas lendo o código acima. Sem que ele coloque o mouse sobre a função para ver o popup, como ele saberá o que significa “Mary”, “rice” e “beans”. A resposta? Não saberá.
Apesar da IDE ajudar quem está escrevendo o código mostrando os nomes dos argumentos enquanto ele digita a função, o código em si não ajuda o leitor. Se você abrir este código em um editor de texto comum, já mais saberia o que estes argumentos representam sem que também abrisse o arquivo “sentences.py” para ler seu código.
Como melhorar isto? Bom, isso não depende apenas da IDE. Depende de uma mudança da sua forma de pensar e codar. Você precisa codar pensando na experiência de quem esta lendo seu código, não a sua. Você, obviamente, entenderá o que você escreveu mas outra pessoa pode ter dificuldades, principalmente se ela for menos experiente.
O Python possui o recurso de argumentos nomeados, o que facilita muito a leitura do código e seu entendimento assim que você põe os olhos nele:
explain_lunch(name="Mary", food1="rice", food2="beans") # Mary cooked rice and beans for lunch.
– Mas isso dá mais trabalho!
– Dá sim.
– Mas fica muito verboso!
– Exatamente.
– Mas os devs não vão querer aderir!
– Com certeza!
– Então porque usar?
– O próximo dev que ler esta linha já tem toda a informação necessária para usar a função. Ele já sabe o nome de cada argumento e já tem um exemplo do que enviar como valor para tais argumentos.
– Ainda não estou convencido… Se os devs tem que digitar mais, não estou perdendo produtividade?
– É simples: devs saem do projeto e novos devs entram no projeto, mas seu código permanece o mesmo. Se você tem interesse em manter um projeto de fácil manutenção, incluir rapidamente pessoas no time e diminuir o processo de ensino, você tem que se preocupar mais com o seu código e menos com preferências pessoais.
75% dos devs com menos de 10 anos de experiência terão uma reação negativa parágrafo acima.
Fonte: Achômetro
A verdade é que se você tem um aplicativo que depende de um time para desenvolvê-lo, você precisa de organização de projeto e facilidade de ensiná-lo ao ponto de conseguir trocar um membro do time sem ter que gastar dezenas de horas com treinamento.
A única forma de fazer isto é com documentação. Mas a documentação tradicional também é lenta para os padrões de hoje. E é neste caso que podemos usar a IDE e o próprio código como aliados neste treinamento.
Mindset não funcionou? –force
As vezes nos deparamos com vários egos na área de desenvolvimento. Sempre existem aqueles devs que não trabalham da forma que são solicitados e em todo code-review você nota que ele nunca faz o que foi pedido. Em Python, existe uma ótima forma de “solicitar adesão” de forma mais enfática: o “*”.
def explain_lunch(*, name, food1, food2): print(f"{name} cooked {food1} and {food2} for lunch.")
Com um simples * nos argumentos da sua função, você demanda que todos os argumentos após ele sejam nomeados. Veja o que acontece na IDE quando você força esta configuração. A própria IDE reclama e ajuda você a “convencer” o seu dev teimoso. 🙂
Pronto, agora todas as chamadas a esta função precisam ter seus argumentos nomeados. Com certeza, seus devs menos dispostos a colaborar reclamarão deste método. Mas é muito provável que este método facilite sua vida e de suas próximas contratações.
Modo de documentação extrema!!!!
Whoa… Você ainda está aqui? Então você realmente gosta de documentação e não tem medo de lágrimas. Então vamos mudar nossa função para sua forma final:
def explain_lunch(*, name: str, food1: str, food2: str): """ Prints a sentence explaining someone's lunch. :param name: name of the person :param food1: some food that the person cooked that day :param food2: another food that the person cooked that day """ print(f"{name} cooked {food1} and {food2} for lunch.")
Aqui usamos mais 2 formas de documentação: O tradicional comentário no código e type hinting.
Vantagens? A documentação tradicional no corpo da função é identificada pela maioria das IDEs atuais e exibida automaticamente quando o mouse está sobre a função. Isto é uma grande ajuda para que o dev não tenha que navegar entre arquivos para entender a função com mais detalhe.
Além disto, type hinting também ajuda o dev a entender que tipo de argumento passar. Algumas IDEs até avisam caso o argumento passado esteja em um tipo incompatível.
Bem melhor não é? Imagine-se no lugar de um novo membro do time. Com estes simples passos ele já tem toda a informação necessária para usar esta função sem nunca ter sequer aberto o arquivo de onde ela foi importada.
Classes aka Namespacing
Em Python, e em programação em geral, sempre existe o cansativo debate sobre orientação a objeto e programação funcional. Eu, particularmente, tenho mais tendência a usar OO, mas não sou contra FP. Meu argumento para usar OO em Python está mais para a função de “namespace” do que propriamente uma classe.
Digamos que você tenha uma classe de funções utilitárias para tratar strings:
# my_utils.py def to_uppercase(text: str): pass def to_lowercase(text: str): pass def to_foo(text: str): pass def to_bar(text: str): pass
Se você precisar usar estas funções, você precisa importá-las do módulo my_utils.
from my_utils import to_uppercase, to_foo, to_bar
Agora veja isto pelos olhos de uma pessoa nova no projeto. Sem uma análise prévia do código de my_utils esta pessoa sequer saberia quais funções importar.
Um método controverso que pode ajudar a agrupar funções que são similares é usar classes como namespaces.
class StringUtils: @staticmethod def to_uppercase(text: str): pass @staticmethod def to_lowercase(text: str): pass @staticmethod def to_foo(text: str): pass @staticmethod def to_bar(text: str): pass
Qual é a diferença? Se você perguntar para diversos devs, cada um terá a sua opinião, seja ela técnica ou apenas ideológica. Mas, na prática, não há uma grande diferença. O “ganho” deste formato, se olharmos pelo prisma da documentação e de usar a IDE como aliada é que é muito mais fácil aproveitar os recursos da IDE para descobrir as funções que tenho disponíveis em StringUtils.
from string_utils import StringUtils as su print(su.to_lowercase("HELLO"))
Não viu vantagem? Você não será o único…
Olhe novamente:
Como você pode ver, usando a classe como um namespace para “agrupar” todas as funções relacionadas, você não precisa lembrar o nome de cada função que quer importar. Basta lembrar que você precisa de StringUtils e a IDE vai lhe ajudar com o resto.
Novamente, muitos desenvolvedores terão opiniões divergentes sobre este método. Cabe a você e e ao seu time chegar a um consenso sobre qual método usar. De qualquer forma, sempre lembre de colocar os “interesses do projeto” acima de interesses próprios pois apenas desta forma você garantirá uma longa e calma administração da sua base de código.