Skip to main content

Command Palette

Search for a command to run...

O poder de uma boa documentação em Python

Updated
10 min read
O poder de uma boa documentação em Python

Acho difícil alguém discordar o quão delicioso é para um desenvolvedor quando uma ferramenta necessária é devidamente documentada. E é ainda mais difícil alguém discordar da importância da documentação no desenvolvimento de API's, bibliotecas ou frameworks. A documentação é uma parte crucial do processo de desenvolvimento de software; uma ferramenta mal documentada pode não atrair desenvolvedores entusiastas e isso pode impactar diretamente no sucesso do seu projeto. Agora que chegamos a um acordo, aposto que você está pensando: "Eu comento todo o meu código, então eu não preciso ler esse artigo sobre documentação". E é por isso que eu preciso explicar:

A diferença entre documentação e comentários

Uma documentação é a receita de bolo do seu projeto. Ela diz para o usuário como usar a sua ferramenta sem que seja necessário acessar e entender o seu código. Comentários, por outro lado, são notas para você e outros desenvolvedores que estarão olhando o código-fonte. Eles explicam o porquê de uma determinada lógica, um workaround específico, ou marcam TODOs.

A documentação é voltada para o usuário da sua biblioteca, API ou framework. Os comentários são para os mantenedores e contribuidores do código.

Documentando no Python

Agora que você já entendeu que documentar é uma parte importante do processo. E você que é menos experiente deve estar se perguntando, como fazer isso e o custo de uma boa documentação. Eu trago boas notícias, uma documentação pode ser gerada automaticamente, e neste artigo vou te mostrar como e até o final da leitura você será um expert.

Antes de qualquer coisa eu gostaria de explicar o porquê da minha escolha por Python, já que a maioria das linguagens possui ferramentas para gerar documentações. A resposta é bem simples, primeiro, é a linguagem que eu mais tenho domínio, e fica mais fácil para mim abordar esse tema considerado tão importante, segundo, é uma das melhores linguagens quando se trata de documentação.

Docstrings

O coração da documentação em Python são as docstrings. Podem ser encontradas na PEP-257 Docstring Conventions ou na documentação do Python em 4.8.7. Documentation Strings. Resumindo a documentação, uma docstring é uma string literal que precede a primeira declaração em um módulo, função, classe ou método, tornando-se o atributo especial __doc__ (ou como chamamos dunder __doc__) desse objeto.

Existem dois formatos de docstrings:

One-line vs Multi-line docstrings

O primeiro caso é usado para descrições mais óbvias e resumos e tudo deve estar na mesma linha, a abertura e fechamento de aspas triplas e o texto. Veja esse exemplo tirado da própria documentação:

def kos_root():
    """Return the pathname of the KOS root directory."""
    global kos_root
    # ...

O segundo caso deve-se quebrar uma linha após a abertura de aspas triplas e o texto pode ser mais elaborado tendo o fechamento das aspas triplas na próxima linha.

def complex(real=0.0, imag=0.0):
    """Form a complex number.

    Keyword arguments:
    real -- the real part (default 0.0)
    imag -- the imaginary part (default 0.0)
    """
    if real == 0.0 and imag == 0.0:
        return complex_zero
    # ...

Agora que você já entendeu como funciona, vamos ver como a mágica acontece.

Gerando documentação com Python

Eu vou criar um exemplo de uma biblioteca de código de um mensageiro fictício e vamos gerar a documentação desse exemplo com Sphinx. Mas antes vamos entender as:

Convenções de documentação e formatadores de docstrings

Não existem muitos critérios e nem regras para a escolha da convenção ou o formatador, fica por sua escolha mas é importante que você escolha um formato que seja compatível com a ferramenta que irá gerar o site da sua documentação. Segue uma lista com os principais formatadores e todos são compatíveis com Sphinx:

Eu deixei o link para você estudar essas convenções no futuro, mas por enquanto não precisa focar nisso, todas são muito parecidas, com algumas pequenas diferenças. Nesse exemplo usaremos o reStructured Text pois é o padrão do Sphinx e é muito parecido com Markdown.

Gerando uma documentação com Sphinx

Como mencionei anteriormente, vou criar um exemplo de uma biblioteca de código de um mensageiro fictício e vamos gerar a documentação desse exemplo com Sphinx. Mas antes de botar a mão na massa, vamos entender o que é o Sphinx e por que ele é tão popular na comunidade Python.

O que é o Sphinx?

Sphinx é uma ferramenta poderosa que transforma arquivos de texto simples em diversos formatos de saída, como HTML, PDF, ePub e mais. Ele foi originalmente criado para a documentação da linguagem Python e, desde então, tornou-se a escolha padrão para muitos projetos Python e até mesmo para projetos em outras linguagens. Sua principal força reside na capacidade de processar reStructuredText (e Markdown, com extensões), uma linguagem de marcação fácil de ler, e integrá-lo perfeitamente com o código Python para extrair docstrings automaticamente.

Por que escolher o Sphinx?

  • Automação: Ele pode extrair automaticamente a documentação das docstrings do seu código Python usando a extensão autodoc. Isso significa que sua documentação e seu código permanecem sincronizados com mais facilidade.

  • Formatos de saída múltiplos: Precisa de um site HTML? Um PDF para impressão? O Sphinx cuida disso.

  • Referências cruzadas extensivas: Crie links facilmente entre diferentes partes da sua documentação, módulos, classes e funções.

  • Temas e extensibilidade: Customize a aparência da sua documentação com temas (como o popular sphinx_rtd_theme usado pelo Read the Docs) e adicione funcionalidades com uma vasta gama de extensões.

  • Suporte a reStructuredText e Markdown: Embora o reStructuredText seja o padrão e ofereça mais funcionalidades, o Sphinx também pode lidar com Markdown através de extensões, oferecendo flexibilidade.

  • Ampla adoção: Muitos projetos grandes utilizam o Sphinx, o que significa uma comunidade grande, muitos recursos e tutoriais disponíveis.

Mãos à obra: configurando o Sphinx

  1. Instalação:

    Primeiro, você precisará instalar o Sphinx. Recomendo também instalar o sphinx_rtd_theme para um visual moderno:

     pip install sphinx sphinx-rtd-theme
    
  2. Iniciando o projeto de documentação:

    Navegue até o diretório raiz do seu projeto Python e execute o assistente de configuração do Sphinx:

     sphinx-quickstart
    

    Este comando fará uma série de perguntas para configurar seu projeto de documentação. Algumas das opções importantes:

    • Nome do projeto: O nome da sua biblioteca ou aplicação.

    • Nome do autor: Seu nome ou o nome da sua organização.

    • Versão do projeto: A versão atual do seu projeto.

    • Extensões: Aqui é crucial habilitar algumas extensões. Pressione 'y' para:

      • sphinx.ext.autodoc: Para incluir documentação de docstrings.

      • sphinx.ext.napoleon: Se você planeja usar docstrings no estilo Google ou NumPy.

      • sphinx.ext.viewcode: Para adicionar links para o código fonte.

      • sphinx.ext.githubpages: Se você planeja hospedar no GitHub Pages.

Após responder a todas as perguntas, o sphinx-quickstart criará um diretório docs (ou o nome que você escolheu) com vários arquivos, incluindo:

  • conf.py: O arquivo de configuração principal do Sphinx. É aqui que você define o tema, ativa extensões, e mais importante, informa ao Sphinx onde encontrar seu código Python.

  • index.rst: A página inicial da sua documentação.

  • Makefile (ou make.bat no Windows): Arquivos de utilidade para construir sua documentação.

  1. Configurando o conf.py:

    Abra o arquivo docs/conf.py e faça algumas edições essenciais:

    • Descomente e ajuste o sys.path: Para que o autodoc encontre seus módulos Python, você precisa adicionar o diretório do seu código ao sys.path. Se sua estrutura de projeto for algo como:

        meu_projeto/
        ├── docs/
        │   └── conf.py
        └── src/
            └── meu_mensageiro/
                └── __init__.py
                └── core.py
      

      Você adicionaria:

        import os
        import sys
        sys.path.insert(0, os.path.abspath('../src')) # Ajuste conforme sua estrutura
      
    • Defina o tema HTML: Para usar o tema Read the Docs:

        html_theme = 'sphinx_rtd_theme'
      
    • Verifique as extensões: Garanta que sphinx.ext.autodoc está na lista extensions.

Exemplo prático: Documentando nossa biblioteca de mensageiro fictício

Vamos supor que temos um módulo core.py dentro de src/meu_mensageiro/ com o seguinte conteúdo:

# src/meu_mensageiro/core.py

"""
Módulo principal do Mensageiro Fictício.

Este módulo contém as funcionalidades centrais para enviar e receber mensagens.
"""

MAX_MESSAGE_LENGTH = 1024
"""Constante que define o tamanho máximo de uma mensagem."""

class Message:
    """
    Representa uma mensagem no sistema.

    :param sender: O remetente da mensagem.
    :type sender: str
    :param content: O conteúdo da mensagem.
    :type content: str
    :raises ValueError: Se o conteúdo da mensagem exceder `MAX_MESSAGE_LENGTH`.
    """
    def __init__(self, sender: str, content: str):
        if len(content) > MAX_MESSAGE_LENGTH:
            raise ValueError("Conteúdo da mensagem muito longo.")
        self.sender = sender
        self.content = content
        self.is_sent = False

    def send(self) -> bool:
        """
        Envia a mensagem.

        Simula o envio de uma mensagem. Em um cenário real, isso se conectaria
        a um serviço de mensageria.

        :return: True se a mensagem foi enviada com sucesso, False caso contrário.
        :rtype: bool
        """
        print(f"Mensagem de {self.sender} enviada: {self.content}")
        self.is_sent = True
        return True

def receive_message(user: str) -> Message | None:
    """
    Simula o recebimento de uma nova mensagem para um usuário.

    :param user: O nome do usuário para verificar mensagens.
    :type user: str
    :return: Um objeto :class:`Message` se houver uma nova mensagem, ou None caso contrário.
    :rtype: Message or None
    """
    # Em um sistema real, haveria uma lógica para buscar mensagens
    if user == "ricardo":
        return Message("servidor_central", "Bem-vindo ao Mensageiro Fictício!")
    return None

Neste exemplo, usamos o formato reStructuredText para as docstrings, como discutido. Observe como descrevemos parâmetros (:param:), tipos (:type:), o que é retornado (:return:, :rtype:) e exceções (:raises:). Informações detalhadas sobre como escrever docstrings podem ser encontradas em tutoriais como o do DataCamp sobre docstrings em Python.

  1. Criando arquivos .rst para o autodoc:

    Agora, vamos dizer ao Sphinx para gerar documentação para o nosso módulo core. Crie um arquivo chamado meu_mensageiro.rst dentro do diretório docs/ com o seguinte conteúdo:

     .. automodule:: meu_mensageiro.core
        :members:
        :undoc-members:
        :show-inheritance:
    
    • .. automodule:: meu_mensageiro.core: Diz ao Sphinx para documentar o módulo meu_mensageiro.core.

    • :members:: Inclui todos os membros públicos (funções, classes, variáveis) do módulo.

    • :undoc-members:: Inclui membros que não têm docstrings (use com cautela, o ideal é documentar tudo).

    • :show-inheritance:: Mostra as classes base para as classes documentadas.

Agora, adicione este novo arquivo ao seu toctree principal no arquivo docs/index.rst:

    .. toctree::
       :maxdepth: 2
       :caption: Conteúdo:

       meu_mensageiro
  1. Gerando a documentação:

    Volte para o diretório docs/ no seu terminal e execute:

     make html
    

    Se tudo estiver configurado corretamente, o Sphinx processará seus arquivos .rst e as docstrings do seu código, gerando a documentação em HTML no diretório docs/_build/html/. Abra o arquivo index.html nesse diretório para ver sua documentação em ação!

    Você verá uma página bem formatada com a descrição do seu módulo, a constante MAX_MESSAGE_LENGTH, a classe Message com seus métodos, e a função receive_message, tudo extraído das docstrings que você escreveu.

Dicas para uma documentação de qualidade com Sphinx:

  • Seja consistente: Escolha um estilo de docstring (reStructuredText, Google, NumPy) e mantenha-o em todo o projeto. A consistência é fundamental para a legibilidade.

  • Documente a API pública: Foque em documentar a interface que outros desenvolvedores (ou você mesmo no futuro) usarão. Uma boa documentação de API é crucial.

  • Inclua exemplos de uso: Docstrings são um ótimo lugar para pequenos exemplos. Para exemplos mais complexos, considere criar seções separadas na sua documentação ou até mesmo um diretório examples/.

  • Mantenha atualizado: Documentação desatualizada é pior do que nenhuma documentação. Faça da atualização da documentação parte do seu processo de desenvolvimento.

  • Use referências cruzadas: Sphinx facilita a criação de links para outras partes da sua documentação usando roles como :mod:, :func:, :class:. Isso torna a navegação muito mais fluida.

  • Explore extensões: O ecossistema de extensões do Sphinx é vasto. Precisa de diagramas? Suporte a Jupyter Notebooks? Provavelmente existe uma extensão para isso.

A documentação é uma parte vital de qualquer projeto de software, grande ou pequeno. Mesmo que você esteja trabalhando em projetos mais simples, como explorar a criação de um site com Python puro, sem framework (usando CGI), entender como articular a funcionalidade do seu código é uma habilidade valiosa que se reflete na qualidade da sua documentação.

Conclusão

Dominar ferramentas como o Sphinx e adotar boas práticas de escrita de docstrings pode parecer um esforço extra inicialmente, mas os benefícios a longo prazo são imensos. Uma documentação clara, concisa e abrangente economiza tempo, reduz a frustração, facilita a colaboração e, em última análise, contribui significativamente para o sucesso e a adoção do seu projeto Python.

Lembre-se: um código bem documentado não é apenas um presente para os outros, é um presente para o seu eu futuro. Invista tempo em documentar seu trabalho, e você colherá os frutos.

Espero que este guia tenha convencido você do poder de uma boa documentação em Python e o tenha preparado para começar a documentar seus próprios projetos como um verdadeiro expert!