# 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](https://www.python.org/dev/peps/pep-0257/) ou na documentação do Python em [4.8.7. Documentation Strings](https://www.google.com/search?q=https://docs.python.org/3/tutorial/controlflow.html%23documentation-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:

```python
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.

```python
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**:

* [**Numpydoc**](https://numpydoc.readthedocs.io/en/latest/format.html)
    
* [**reStructured Text**](https://docutils.sourceforge.io/rst.html)
    
* [**Google Docstrings**](https://sphinxcontrib-napoleon.readthedocs.io/en/latest/example_google.html)
    
* [**Epytext**](https://epydoc.sourceforge.net/epytext.html)
    

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:
    
    ```bash
    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:
    
    ```bash
    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.
        
3. **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:
        
        ```python
        meu_projeto/
        ├── docs/
        │   └── conf.py
        └── src/
            └── meu_mensageiro/
                └── __init__.py
                └── core.py
        ```
        
        Você adicionaria:
        
        ```python
        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:
        
        ```python
        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:

```python
# 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](https://www.datacamp.com/tutorial/docstrings-python).

4. 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:
    
    ```plaintext
    .. 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`:
    
    ```plaintext
    .. toctree::
       :maxdepth: 2
       :caption: Conteúdo:
    
       meu_mensageiro
    ```
    
5. Gerando a documentação:
    
    Volte para o diretório docs/ no seu terminal e execute:
    
    ```bash
    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)](https://blog.ricardotenv.dev/como-criar-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!
