Boas práticas de programação
1. Técnicas de programação
Programação defensiva é o reconhecimento de que os programas terão problemas e serão modificados
Oferece um conjunto de técnicas para prevenir potenciais problemas de código e tem como objetivo produzir códigos resilientes que respondam adequadamente em situações inesperadas e que seja compreensivel e fácil de dar manutenção
Técnica | Descrição |
---|---|
Estilo e Desing | Comentarios (linhas, paragrafos, funções e estruturas de controle), nomes de variáveis, métodos e classes significativas |
Priorizar a clareza ao inves da concisão | Tornar o código um livro e sempre priorize a simplicidade do código |
Não deixe os outros mexerem onde não devem | Abuse de encapsulamentos privados ou publicos e etc... |
Verifique todos os valores de retorno | Os testes devem verificar todos os valores possíves de retorno, utilize uma amostragem pequena que engloba praticamente todos os casos |
Manipule recursos | Sempre que abrir um arquivo ou conexão ou etc... feche-o |
Inicialize todas as variáveis ao declarar | Todas as variáveis devem ser inicializadas |
Declare as variáveis o mais tarde possível | Sempre declare elas o mais perto possível de seu uso. |
Use sempre recursos padrões da linguagem | Não reinvente a roda, a menos que seja necessário |
Use um sistema de logging | Abuse dos logs/prints e etc... |
Siga o idioma da linguagem | Códifique em inglês sempre. |
Verifique os limites númericos | Faça um código defensivo que não quebre em um determinado limite númerico |
Use constantes | Acabe com os números mágicos |
Decomposição em funções atômicas | Sempre deixe as funções com o minimo de código possivel realizando apenas o que ela deve realizar. |
Utilize paragrafos de função | Dentro de uma função separe-a em paragrafos |
Utilize tipagem | Se a linguagem for de tipagem dinâmica tente arranjar um jeito de fazer o usuário usar somente o tipo desejado com código defensivo, exceções por exemplo. |
Cabeçalhos e docstring | Documente seu código |
Tratamente de erros apropriados | Trate os erros em nível apropriados usando exceptions |
Assertivas | Use em partes do código em que o erro não pode ser permitido, tendo que fechar a aplicação caso ocorra. |
Assuma o pior | Sempre assuma que o pior pode acontecer no seu código e prepare-o para suportar esses eventos. |
2. Comentários e Docstring
Sempre tenha como prioridade manter os comentários atualizados com as mudanças no código, e sempre comente em ingles!
Comentar linha individual
- Quando a linha de código é extremamente complicada e não há como simplificar
- Quando registrar um erro já ocorrido em uma linha
Comentar paragrafo de código
- No máximo duas linhas e escreve o por que em vez de como,
- Utilize o comentário para preparar o leitor para o que vem a seguir,
- Se for por motivo de performace, deixe claro o beneficio
Comentar declaração de variáveis
- Descrever aspectos da variável que o nome não consegue representar,
- Por exemplo, unidade de medida, o intervalo permitido para valores númericos, documentar variáveis globais
- Devem ser separados da variável por pelo menos dois espaços.
Comentar estruturas de controle
- Para estruturas de decisão como if e case, pode-se comentar o motivo da decisão e um resumo do resultado obtido,
- No caso de loops, pode ser indicado o seu propósito, inclua sempre antes da estrutura de controle
Docstrings
- Escreva docstrings para todo módulo, função, classe e método público.
- Elas não são necessárias para métodos "privados", mas é recomendável ter um comentário que explique o que ele faz.
- Este comentário deve estar logo após a declaração do método privado.
3. SOLID
Alta coesão
É fator de qualidade de projeto e representa que cada classe tem sua respectiva responsabilidade bem definida
Baixo acoplamento
É fator de qualidade em um projeto que busca a medida de interdependência entre modulos, modulos com baixo acoplamento são mais independentes.
Single responsability principle
Cada classe/metodo devem ter responsabilidades únicas, logo uma classe Conta não é responsavel por fazer transferencias, ela deve designar essa responsabilidade a classe de fazer transferencias, tornando as classe mais coesas.
Open-closed principle
Uma classe deve ser aberta a extensão (herança) e fechadas a modificações, é basicamente deixar sua classe ser extensivel, por exemplo, crio a classe Carro e crio várias outras classe que herdam de carro para extender essa classe, por exemplo, CarroSedan, CarroPopular, CarroQuebrado, CarroFeio, e etc... cada um responsavel por suas modificações.
Liskov substitution principle
O cliente deve usar o serviço da classe abstrata (geral) sem saber que ta usando um serviço especifico concreto, por exemplo temos a classe Carro abstrata e as classes concretas Gol e Palio que herdam dessa abstrata, o cliente pode usar o Carro sem saber se o carro é um Gol ou um Palio, isso é mais usado em linguagens com tipagem estática que não é o caso do python.
Interface segregation principle
Uma interface não deve obrigar quem a implementar a implementar métodos que não agrega valor a ela, por exemplo, a classe Mamifero tem os métodos que deve ser implementado por Pessoa e Cachorro que são mamiferos, andar e falar, porém cachorro não fala, logo ele não deve ser obrigado a implementar esse método, ele deve criar seu método latir
Dependency Inversion Principle
Uma classe deve depender de classes abstratas/interface e não de suas classes concretas que ta a implementação, é basicamente igual ao Liskov substitution, porém voltado a dependencia uma frabrica de carros deve depender da classe abstrata Carro e não das concretas Gol ou Palio.
5. Testes
Teste: processo de detectar o erro inicial
-
Para rodar os testes execute:
make test
-
Para roda o coverage:
make report
-
Para roda o coverage em html:
make html