====== Desenvolvimento de sistemas: boas práticas ====== Tentei reunir aqui boas práticas que gosto de usar para programar. São dicas pessoais que alguns podem preferir não usar, mas as obtive de várias fontes e muitas são de consenso geral. Algumas são avaliadas para considerar se o código é bom. Algumas dicas são genéricas, outras mais adequadas a uma ou outra linguagem. Quando comecei a escrever estava programando principalmente em python, mas também frequentemente em shell (principalmente bash) e as vezes em php. No passado já programei em C, pascal, perl, fortran e talvez alguma outra linguagem que não estou lembrando agora. Veja também: * [[:boas_praticas_de_programacao_shell_script|Boas práticas de programação shell]] * [[ti_publica:dicas_python|Dicas para Python]] =====Dicas gerais===== * Use um [[https://en.wikipedia.org/wiki/Lint_(software)|lint(ou linter)]] pra checar vários aspectos do código. Ex: [[https://www.pylint.org/|Pylint]] (python), [[https://www.shellcheck.net/|shellcheck]] (shell) * Crie testes automatizados * Não use linhas maiores que 80 caracteres * Crie e use funções, classes, bibliotecas * Não faça blocos de código longos * Primeira linha de um código interpretado (linha shebang): * Em ambientes Unix like (Linux, BSDs, AIX, Solaris, Mac OS etc) * prefira: #!/usr/bin/env python * do que: #!/usr/bin/python * fica mais flexível, mais chance de funcionar em ambientes distintos * **não serve** caso precise de um interpretador específico que não o padrão do sistema * Se for publicar seu código publique em inglês ===IDE=== Eu uso o vim, mas essas funcionalidades provavelmente poderão ser encontradas em outras IDEs. * Checagem de sintaxe e auto complemento no VIM * [[https://github.com/vim-syntastic/syntastic|vim-syntastic]] * [[https://github.com/ycm-core/YouCompleteMe|vim-youcompleteme]] * Configurações no .vimrc: * set textwidth=80 * set wrapmargin=8 * set columns=80 ===Reuso=== * Ao criar classes/códigos reusáveis, defina a versão (no nível da classe, não da instância) * Ao criar número de versão no código use tipo string ===Documentação=== Um projeto de software certamente necessita de arquivos somente de documentação com temas como escopo, regras de negócio, cronograma, papéis e responsabilidades da equipe, requisitos, licenças etc. Em projetos menores muitas vezes isso tudo pode estar num único arquivo LEIAME.txt ou, seguindo a tendência do [[https://help.github.com/pt/github/writing-on-github/basic-writing-and-formatting-syntax|github]], README.md, que pode ser escrito com [[https://pt.wikipedia.org/wiki/Markdown|Markdown]] e será apresentado ao acessar um diretório via web num repositório GIT. Isso tudo, porém, não exclui uma boa documentação no próprio código, que é do que falo aqui. * Use um cabeçalho em cada arquivo de código: * Descrição do propósito, parâmetros, requisitos, etc * Autor * Histórico * A fazer * Comente os blocos: funções, classes, métodos, loops, variáveis ... * Pylint pede doc para o arquivo, funções e classes, por exemplo * vim-youcompleteme fornece as docs de funções ao digitar seus nomes **Exemplo de cabeçalho padrão (python):** #!/usr/bin/env python3 # -*- coding: UTF-8 -*- # # A segunda linha acima permite o uso de acentuação no arquivo # # # Historico (mais recente em cima) # 27.11.2018 - - Criação # 13.12.2018 - - Lorem Ipsilum # # A Fazer # - Tarefa 1 # - Tarefa 2 # - subtarefa 2.1 ===Variáveis=== * Dar nomes descritivos a variáveis e funções, usar sempre mesmos verbos e substantivos * Adotar camelCase ou snake_case para nomear variáveis e funções e manter coerência num mesmo código * Adotar maiúsculas para constantes * Não usar números diretamente, crie uma constante que diga no nome o que ele é (ex: PI, RAIO_DA_TERRA, etc) * Evitar variáveis globais * Para definir valores default pode usar a passagem de parâmetro pra função ===Funções / Objetos=== * Descrever todas as funções nelas mesmas * Criar funções pequenas, segmentando o código * Eliminar flags booleanos * Ordem das funções de acordo com uso * Nomes * Nomes bem descritivos, como com as variáveis * Procurar usar sempre os mesmos verbos pras mesmas ações, não usar obter, pegar, get, ... escolher um. * Evitar parâmetros desnecessários * DRY (evitar ser repetitivo) * Evitar efeitos colaterais * Evitar variáveis globais!!!! (vale repetir) ===Formatação=== Lembre-se que outra pessoa pode mexer no seu código mesmo que você não preveja isso inicialmente. Além disso você mesmo pode não lembrar mais o que você fez. * Indente sempre bem ou pode entender errado que comandos estão dentro de que estruturas. Com uma IDE isso é bem fácil * O uso de um lint(er) pode ajudar a identificar algumas faltas de padrão * Um formatador, [[https://github.com/ambv/black|como o black pra Python]], ajuda a manter o código coerente (formatando coisas opcionais sempre da mesma forma) e legível ===Testes automatizados=== * Algumas linguagens já tem frameworks prontos para adiantar esse trabalho, como o [[https://docs.pytest.org/en/latest/|pytest para Python]], [[https://github.com/kward/shunit2|shUnit2]] ou [[https://liw.fi/cmdtest/|cmdtest/yarn]] para Shell, [[https://phpunit.de/|PHPUnit]] etc * Criar funções ou classes que recebam e retornem parâmetros testáveis, independentes das demais funções no mesmo código * Criar outro programa que teste, com os testes programados ou preparar trecho do programa para atuar nos testes * Não executar nada caso o programa seja carregado por outro. Isso em geral significa criar uma função ou área "main" que não é executada a não ser que o programa seja diretamente acionado. * Em Python pode se usar if __name__ == "__main__": * Em Bash (shell) pode se usar $(return >/dev/null 2>&1) if [ "$?" -ne "0" ]; then ===Senhas hardcoded=== Em algumas situações seu programa precisa utilizar senhas. Se sua execução for agendada e não houver uma pessoa para passar a senha na hora, como fazer? Colocar a senha hardcoded? E se seu código estiver sendo guardado num sistema de controle de versão, o que é uma boa prática? * crie um arquivo de configuração * coloque nele apenas permissão de leitura e apenas para o usuário necessário * no programa original, opcionalmente, verifique o proprietário e permissão necessária do arquivo de configuração, abortando para garantir acerto se alguém alterar acidentalmente * não coloque o arquivo de configuração no sistema de controle de versão ou coloque-o com um pré-nome, tipo config-sample Na prática criei uma função numa biblioteca geral para carregar variáveis de configuração, por conta disso meu arquivo de configuração é homônimo ao programa original adicionado de uma extensão padrão. =====Internacionalização de código===== =====Referências===== * [[https://en.wikipedia.org/wiki/Zen_of_Python|Zen of Python]] * [[https://github.com/ryanmcdermott/clean-code-javascript|Clean code javascript]] * Referência boa de livros de algumas linguagens populares: https://goalkicker.com/ * Vídeo [[https://www.youtube.com/watch?v=HTLu2DFOdTg|Python's Class Development Toolkit]] - bom para programar classes reutilizáveis, muitas dicas próprias de python. * Cursos gratuitos da USP no Coursera: * [[https://www.coursera.org/learn/ciencia-computacao-python-conceitos|Introdução à Ciência da Computação com Python Parte 1]] * [[https://www.coursera.org/learn/ciencia-computacao-python-conceitos-2|Introdução à Ciência da Computação com Python Parte 2]]