Documentação e Doxygen

Introdução

editar

O que é documentação ?

A documentação de um software ou de um código fonte são documentos, textos, imagens ou até mesmos vídeos que descrevem o funcionamento e os detalhes da implementação do mesmo. Os textos, geralmente, estão intrínsecos no código, acompanhando uma classe, função ou um simples trecho de código e eles explicam a lógica por trás de partes complexas. As imagens, geralmente, consistem de diagramas que explicam o funcionamento do código como um todo ou de partes dele, como relações entre classes. Pode haver também manuais detalhados para ajudar o usuário a aproveitar o máximo do produto.

O que é doxygen ?

O Doxygen nada mais é do que um gerador de documentação, ou seja, ele é uma ferramenta utilizada por programadores que desejam automatizar e facilitar o processo de documentação de seus códigos.

A importância da documentação

editar

A documentação é uma prática de extrema importância para projetos códigos no geral, pois ela fornece informações essenciais para desenvolvedores, clientes e usuários acarretando em diversos benefícios para o desenvolvimento do trabalho.

Benefícios

editar
  • Compreensão e Colaboração eficiente

Em um ambiente de trabalho, ou seja, colaborativo, um código fonte bem documentado, além de ser mais legível, facilita a compreensão e o entendimento de cada parte do código para os outros desenvolvedores. Assim, promove a eficiência na comunicação e no trabalho entre os membros da equipe.

  • Identificação de problemas

Uma documentação que acompanhe o código permite um melhor entendimento do mesmo, assim facilitando que desenvolvedores encontrem problemas, bugs e erros atuais ou futuramente. Tal técnica também se torna essencial para a manuntenção do código, pois com um melhor entendimento do código ocasiona uma melhor compreensão lógica de sua estrutura facilitando o processo de manutenção no mesmo.

  • Acessibilidade

Um código bem documentado faz com que todos os membros do projeto consigam coomprender o funcionamento do software e com isso tomarem melhores decisões para o projeto. Além de facilitar o entendimento e a adaptação de novos membros da equipe com o código.

  • Qualidade

Programadores ao documentarem o seu código conseguem pensar minuciosamente cada parte dele, fazendo-o refletir sobre cada variável, função e estrutura lógica podendo alterá-los para obter um código mais limpo e eficiente

Exemplo

editar

A partir deste exemplo consegue-se perceber a grande importância de documentar o código. Aqui, como não há nenhum texto ou documentação indicando o que tal algoritmo faz ou o que cada variável representa, torna-se uma tarefa extremamente difícil para outros programadores e desenvolvedores entender a lógica e o objetivo deste algoritmo.

#include<iostream>
#include<vector>
#include<array>
using namespace std;

#define MAXP 32 

vector<vector<int>> bss; 
vector<array<int, MAXP>> ps; 
vector<int> ls, rs;
int c=0; 

void dfs(int a, int p) {
  ps[a][0] = p; 
  ls[a] = c++;
  for(int b : bss[a])
    if(b != p)
      dfs(b, a);
  rs[a] = c++;
}

int main() {
  ios_base::sync_with_stdio(false);cin.tie(NULL);  
  int qv, qq; 
  cin >> qv >> qq;

  bss.resize(qv);
  ps.resize(qv);
  ls.resize(qv);
  rs.resize(qv);

  for(int i=0; i<qv-1; i++) {
    int a, b; cin >> a >> b;
    a--; b--;
    bss[a].push_back(b);
    bss[b].push_back(a);
  }
  dfs(0,0);

  for(int j=0; j<MAXP-1; j++) {
    for(int i=0; i<qv; i++)
      ps[i][j+1] = ps[ps[i][j]][j];
  }

  for(int i=0; i<qq; i++) {
    int a, b; cin >> a >> b;
    a--; b--;

    if(ls[a] <= ls[b] && rs[b] <= rs[a]) 
      cout << a + 1 << '\n';
    else if(ls[b] <= ls[a] && rs[a] <= rs[b]) 
      cout << b + 1 << '\n';
    else {
      int u = a;
      for(int j=MAXP-1; j>=0; j--) { 
        int v = ps[u][j]; 
        if(ls[v] > ls[b] || rs[b] > rs[v]) 
          u = v;
      }
      cout << ps[u][0]+1 << '\n';
    }
  }
  return 0;  
}

O mesmo código, porém com documentação explicando o algoritmo, suas funções e variáveis. Percebe-se que tais informações são cruciais para que outras pessoas consigam compreender o código com mais facilidade.

/* LCA com Binary Lifting
 * é dada uma árvore com qv vértices enraizada no vértice 1
 * são dados também qq pares de vértices
 * para cada par, encontrar o menor ancestral comum
 */
#include<iostream>
#include<vector>
#include<array>
using namespace std;

// MAXP representa a quantidade de linhas da matriz de "pulos"
// deve ser pelo menos o teto do log do tamanho do maior "pulo" possível no problema
// MAXP >= log(10**9)
#define MAXP 32 

vector<vector<int>> bss; // bss[a] representa a lista de adjacência do vértice a
vector<array<int, MAXP>> ps; // matriz de "pulos": ps[a][j] representa o 2**j-ésimo ancestral do vértice a
vector<int> ls, rs; // ls[a] e rs[a] representam respectivamente o tempo inicial e final da DFS no vértice a
int c=0; // contador de tempos para a DFS

void dfs(int a, int p) {
  ps[a][0] = p; // incializa o primeiro ancestral de a como o pai na DFS
  ls[a] = c++;
  for(int b : bss[a])
    if(b != p)
      dfs(b, a);
  rs[a] = c++;
}

int main() {
  ios_base::sync_with_stdio(false);cin.tie(NULL);  
  int qv, qq; // quantidade de vértices e quantidade de consultas
  cin >> qv >> qq;

  // define o tamanho dos vetores
  bss.resize(qv);
  ps.resize(qv);
  ls.resize(qv);
  rs.resize(qv);

  // lê as arestas
  for(int i=0; i<qv-1; i++) {
    int a, b; cin >> a >> b;
    a--; b--;
    bss[a].push_back(b);
    bss[b].push_back(a);
  }

  // aplica a DFS partindo do vértice zero, fazendo com que a árvore seja enraizada nesse vértice
  // aqui, o zero no segundo argumento é muito importante, pois faz com que o ancestral da raiz seja ela mesma
  // isso garante que ficaremos na raiz em caso de "pulos" maiores que a altura da árvore
  dfs(0,0);

  // inicializa a matriz de "pulos"
  // cada linha da matriz é construída a partir das informações da linha anterior
  for(int j=0; j<MAXP-1; j++) {
    for(int i=0; i<qv; i++)
      ps[i][j+1] = ps[ps[i][j]][j];
  }

  // processa as consultas
  for(int i=0; i<qq; i++) {
    int a, b; cin >> a >> b;
    a--; b--;
    if(ls[a] <= ls[b] && rs[b] <= rs[a]) // a é ancestral de b
      cout << a + 1 << '\n';
    else if(ls[b] <= ls[a] && rs[a] <= rs[b]) // b é ancestral de a
      cout << b + 1 << '\n';
    else { // a e b não são ancestrais um do outro
      // usamos a matriz do binary lifting para buscar pelo último ancestral de a que não é um ancestral de b
      // durante a busca, representaremos esse ancestral pela variável u
      int u = a;
      for(int j=MAXP-1; j>=0; j--) { // para cada tamanho de "pulo" começando pelo maior (essa ordem é importante)
        int v = ps[u][j]; // v é o 2**j-ésimo ancestral de u
        if(ls[v] > ls[b] || rs[b] > rs[v]) // v não é ancestral de b, podemos continuar a busca em v
          u = v;
      }
      // ao final da busca, o menor ancestral comum de a e b é o ancestral direto (pai) de u
      cout << ps[u][0]+1 << '\n';
    }
  }
  return 0;  
}

Doxygen

editar

Como visto acima, o doxygen é um gerador de documentação que abrange diversas linguagens como C++, python, C, C#, Java, PHP, Fortran, Objective-C, etc. Ele possui compatibilidade com sistemas Unix, Windows e Mac Os.

Possui múltiplos formatos para a geração de documentação como HTML, PDF, Latex, Word e XML. Esta flexibilidade permite que o desenvolvedor escolha o melhor formato para o seu projeto. O doxygen também pode gerar representações gráficas como diagramas, facilitando a visualização de classes, suas hierarquias e relações.

O doxygen produz um arquivo de configuração, no qual os usuários podem customizar o processo de geração de documentação. Diversas customizações estão disponíveis como o formato do output, quais arquivos incluir, a linguagem a ser utilizada, etc.

O doxygen é um software livre.

Como utilizar o Doxygen

editar

O doxygen extrai a documentação do código diretamente dos comentários no arquivo fonte. Neste exemplo e por padrão utiliza-se o formato de comentários QT para C++, no entanto há diversos outros formatos. Os comentários devem utilizar a seguinte sintaxe:

  /*! O comentário do código
   * deve estar entre esses 
   * símbolos 
   */
  
  //! Comentário de uma linha
  
  /*! Por padrão os comentários
   * são antes das variáveis ou
   * funções, porém podemos faze-lo
   * de outra forma 
   */
  int quantidade_rodadas //! Variável que guarda a quantidade de rodadas da partida

Para documentar funções podemos utilizar algumas ferramentas do doxygen que facilitam a documentação da função, dos seus parâmetros e do retorno da função utilizando:

  /*! 
   * \brief: Descrição da função
   * \param: Descrição dos parâmetros
   * \return Descrição do retorno
   */

Outros comandos estruturais implementados no doxygen são:

  /*! 
   * \struct: Descrição de uma struct.
   * \union: Descrição de uma união
   * \var: Descrição de uma variavel
   * \def: Descrição de um define
   * \typedef: Descrição de uma definição utilizando typedef
   * \file: Descrição de um arquivo utilizado
   * \package: Descrição de pacote em Java
   * \interface: Descrição de uma interface
   */

Exemplo de código

editar

Os comentários para gerar a documentação pelo doxygen podem ser colocados em qualquer parte do código. Ademais, uma das principais partes do código que devem ser comentadas é o header, pois nele contém diversas funções e variáveis que podem ser utilizadas ao longo do código.

#ifndef Fantasma
#define Fantasma
#include <iostream>
#include <fstream>
#include <random>

class fantasma{
    private:
        int x_fantasma;
        int y_fantasma;
        double probabilidade;
        char direct_fant;

    public:
        /*!
        *\brief Método: fantasma
        * Irá criar a classe fantasma
        */
        fantasma();
        /*!
        *\brief Método ~fantasma
        *Irá destroir a classe fantasma.
        */
        ~fantasma();
        /*!
        *\brief Método: set_posicao_fantasma
        * Irá atribuir as variaveis x_fantasma e y_fantasma as coordenadas x e y (linha e coluna, respectivamente)
        * da matriz aonde se encontra o fantasma ou a nova posicao do fantasma.
        * 
        * \param x_fantasma: (int) Representa a coordenada x (linha) da matriz aonde se encontra o fantasma (ou a nova posicao)
        * \param y_fantasma: (int) Representa a coordenada y (coluna) da matriz aonde se encontra o fantasma (ou a nova posicao)
        */
        void set_posicao_fantasma(int x_fantasma, int y_fantasma);
        /*!
        *\brief Método: get_x_fantasma
        * Irá retornar a coordenada x (linha da matriz - vertical) do fantasma.
        * 
        * \return retorno: (int) Retorna um número que indica a coordenada da linha da matriz aode se
        * encontra o fantasma
        */
        int get_x_fantasma_();
        /*!
        *\brief Método: get_y_fantasma
        * Irá retornar a coordenada y (coluna da matriz - horizontal) do fantasma.
        * 
        * \return retorno: (int) Retorna um número que indica a coordenada da coluna da matriz aode se
        * encontra o fantasma
        */
        int get_y_fantasma_();
        /*!
        *\brief Método: direcao_f
        * Irá gerar um número pseudo-aleatório dentro do intervalo [0,1], que irá indicar a posição que
        * aquele fantasma vai se mover. Intervalo [0,0.25] irá para a esquerda, [0.25, 0.5] irá para cima, 
        * [0.5, 0.75] irá para direita e [0.75, 1] irá para baixo.
        * 
        * \return retorno: (char) retorna o caracter que indica qual será o proximo movimento do fantasma
        * 'a'-esquerda,'d'-direita,'w'-cima,'s'-baixo. 
        */
        char direcao_f();
};
#endif


 

Como gerar a documentação

editar

Para usuários de Windows e Mac o Doxygen inclui uma interface gráfica, doxywizard, extremamente prática para gerar a documentação.

 

Em sistemas Linux, caso deseje uma interface gráfica, deve-se instalar o doxygen-gui. Contudo, pode-se executar tudo pela linha de comando, basta executar os comandos:

sudo apt install doxygen

#Este comando serve para gerar um arquivo de configuração, nele o desenvolvedor pode escolher a configuração desejada
doxygen -g

#Gera a documentação do código
doxygen Doxyfile

Extensões

editar

Por se tratar de um software livre, há uma grande comunidade que contribui para o desenvolvimento e aprimoramento do doxygen. Através de inúmeras extensões criadas pela comunidade o doxygen consegue abranger outras linguagens como possuir algumas funcionalidades a mais. Tais extensões podem ser vistas no site do doxygen em https://www.doxygen.nl/helpers.html

Referências

editar

https://www.doxygen.nl/index.html

https://en.wikipedia.org/wiki/Doxygen

https://pt.wikipedia.org/wiki/Documenta%C3%A7%C3%A3o_de_software