Book cover

Página Principal | Modo Dark

Fundamentos de Manutenção de Software

Marco Tulio Valente

3 Documentação de Código

Comments should describe things that aren't obvious from the code. ― John Ousterhout (A Philosophy of Software Design)

Este capítulo começa apresentando justificativas e motivos para a escrita de comentários (Seção 3.1). Em seguida, tratamos de ferramentas para geração automática de documentações a partir de comentários, como a ferramenta Javadoc (Seção 3.2). Então, na Seção 3.3, descrevemos um tipo importante de comentários, que chamamos de públicos, isto é, comentários que vão constituir a documentação de referência de uma biblioteca ou subsistema e que, portanto, documentam elementos de código que serão usados por terceiros. Depois, na Seção 3.4, tratamos de um segundo tipo de comentário, que chamamos de comentários privados, pois eles são usados para explicar partes internas de um método. Na Seção 3.5. tratamos de outros tipos de comentários, como comentários com licenças de uso e comentários para declarar uma dívida técnica. Após estudar e ter uma visão dos vários tipos de comentários, na Seção 3.6 vamos mudar de foco e tratar de anti-padrões de comentários, isto é, comentários que devem ser evitados. Por fim, a Seção 3.7 trata de comentários de APIs Web, especificamente de APIs REST.

3.1 Introdução

Como vimos no capítulo anterior, devemos nos esforçar para escrever código que seja legível. Por exemplo, devemos adotar um guia de estilo de forma sistemática, escolher nomes que revelem claramente o seu propósito no programa, implementar funções coesas e desacopladas e modularizar o tratamento de exceções, dentre outras práticas.

Porém, temos que reconhecer que nem todo código é auto-explicativo, principalmente para futuros leitores. Na verdade, como o código é escrito usando uma linguagem de programação ― ou seja, uma notação operacional e formal ― é esperado que leitores tenham certa dificuldade para entender as nuances e detalhes de sua lógica. Por isso, é importante documentar certos elementos de código usando comentários, pois é mais fácil entender uma explicação em português, do que entender os detalhes de um código escrito em uma linguagem de programação, principalmente quando esse código possui uma lógica mais complexa.

Especificamente, dois tipos de código merecem receber comentários:

Para resumir, documentamos código para facilitar seu uso e sua mudança no futuro!

Literatura Científica: Em 2009, Oliver Araft (da Siemens) e Dirk Riehle (da SAP Research) publicaram um artigo sobre a densidade de comentários em uma amostra de mais de cinco mil projetos de código aberto (link). Densidade de comentários é o resultado da divisão entre o número de linhas de código que são comentários pelo total de linhas de código de um sistema. A densidade média obtida pelos autores foi de 19%. Mais recentemente, em 2019, Hao He, da Universidade de Pequim (China), publicou um estudo semelhante, mas com uma amostra de 150 projetos populares do GitHub (link). Os resultados foram parecidos, obtendo-se uma densidade de comentários de 21%, na média. Portanto, ambos estudos reforçam a importância da documentação de código por meio de comentários. Na média, de cada cinco linhas de código de um sistema, uma linha é um comentário.

3.2 Geradores de Documentação

Toda linguagem de programação possui uma sintaxe para escrita de comentários. Por exemplo, em Java, podemos escrever comentários como a seguir:

// soma dois números
public int soma(int a, int b) {
  return a + b;
}

Porém, existem ferramentas que geram automaticamente uma documentação a partir de certos comentários do código fonte. Por exemplo, em Java temos uma ferramenta chamada Javadoc para esse fim. Então, se pretendemos gerar uma documentação automaticamente, o comentário anterior deve ser escrito da seguinte forma:

/**
 * Soma dois inteiros
 * @param a primeiro número inteiro
 * @param b segundo número inteiro
 * @return soma de a com b
 */
public int soma(int a, int b) {
  return a + b;
}

Supondo que esse método pertence a uma classe Calculadora, temos também que chamar em seguida:

javadoc Calculadora.java

Será gerado, então, um arquivo HTML como o seguinte:

Logo, a ferramenta Javadoc recupera os comentários de um arquivo e gera uma página HTML com todos eles, usando uma formatação que facilita a leitura. A principal vantagem é que para acessar a documentação de uma biblioteca não precisamos acessar seu código, mas apenas abrir uma página em um navegador Web.

Para ficar claro, não existem duas documentações, no sentido de que a documentação canônica é aquela que faz parte dos comentários do código fonte. Se tais comentários mudarem, devemos gerar novamente a documentação HTML, chamando a ferramenta Javadoc.

O leitor já deve ter percebido que comentários Javadoc sempre iniciam com um /** e terminam com um */. Ou seja, apenas comentários que seguem esse padrão são considerados pela ferramenta. Na prática, é mais comum que eles ocupem mais de uma linha, como abaixo:

/**
 *  
 * [Texto do comentário] 
 * 
 */
[código]

No texto do comentário, podemos ainda usar marcadores para indicar parâmetros (@param), valores de retorno (@return), exceções (@throws), blocos de código ({@code ... }), etc.

Nesta seção, usamos o Javadoc como exemplo, mas existem ferramentas parecidas para Python (Sphinx e pydoc), Javascript (JSDoc), C/C++ (Doxygen), Rust (rustdoc), etc.

3.3 Comentários Públicos

Esses comentários vão constituir a documentação de referência de uma biblioteca, subsistema ou API. Por isso, eles devem ser escritos no formato Javadoc ou no formato de uma ferramenta similar, no caso de sistemas implementados em outras linguagens de programação. No nosso contexto, o termo referência significa que esses comentários são escritos para consumo externo, isto é, para serem lidos por outros desenvolvedores, via acesso à versão Web da documentação.

Três elementos de código principais, quando declarados como públicos, devem receber comentários de referência: métodos, campos e classes. Iremos comentar sobre cada um deles a seguir.

3.3.1 Comentários de Métodos Públicos

Esses comentários servem aos desenvolvedores que precisam chamar um método. Ou seja, ao escrever esses comentários, a pergunta que devemos responder é a seguinte: existe algo que o desenvolvedor precisa saber para chamar este método e que não está óbvio na sua assinatura? Se existir, devemos documentar essa informação em um comentário antes da assinatura do método. O objetivo também é claro: se esse comentário não existir, o desenvolvedor vai ter que ler e entender o código do método, para obter a informação de que precisa, o que pode exigir um certo esforço.

Comentários de métodos públicos possuem uma ou duas frases que explicam o seu objetivo. Depois, devemos documentar cada parâmetro, valor de retorno, exceções lançadas, pré-condições e possíveis efeitos colaterais.

Segue um exemplo referente ao método substring da classe String de Java.

/** 
 * Returns a string that is a substring of this string. The
 * substring begins at the specified {@code beginIndex} and
 * extends to the character at index {@code endIndex - 1}.
 * Thus the length of the substring is {@code endIndex-beginIndex}.
 * <p>
 * Examples:
 * <blockquote><pre>
 * "hamburger".substring(4, 8) returns "urge"
 * "smiles".substring(1, 5) returns "mile"
 * </pre></blockquote>
 *
 * @param      beginIndex   the beginning index, inclusive.
 * @param      endIndex     the ending index, exclusive.
 * @return     the specified substring.
 * @throws     IndexOutOfBoundsException  if the
 *             {@code beginIndex} is negative, or
 *             {@code endIndex} is larger than the length of
 *             this {@code String} object, or
 *             {@code beginIndex} is larger than
 *             {@code endIndex}.
 */
public String substring(int beginIndex, int endIndex) { 
  ... 
}

Esse comentário inclui quase todos os itens que mencionamos antes. Particularmente, a pré-condição para chamada desse método está comentada, ou seja, os parâmetros de chamada devem satisfazer à seguinte condição: 0 <= beginIndex <= endIndex <= length. Se essa pré-condição não for satisfeita, a chamada de substring retorna uma exceção do tipo IndexOutOfBoundsException.

De forma interessante, o comentário inclui dois exemplos de chamadas, com seus respectivos retornos. Esses exemplos ajudam a deixar o funcionamento do método ainda mais claro.

Perguntas Frequentes

1. Todo método público precisa de um comentário Javadoc? Sim, pois essa é a melhor maneira de informar ao mundo que um sistema oferece esse método para consumo externo. Ou seja, se um método não faz parte da documentação de referência de um sistema é improvável que ele seja descoberto por outros desenvolvedores. Porém existe pelo menos uma observação importante a fazer: alguns métodos são públicos, mas apenas para dentro de um sistema. Ou seja, eles constituem APIs internas, como veremos no Capítulo 4, e portanto não devem ser incluídos na sua documentação externa.

2. Métodos privados também devem receber comentários Javadoc? Não, pois mesmo que um método privado tenha um comentário que inicie com /** e termine com */, ele não vai ser incluído, por default, na documentação de referência gerada pela ferramenta Javadoc.

3. Precisamos de uma documentação tão completa como a do método substring? O método substring é um método muito importante de uma biblioteca também muito importante de Java (String). Logo, é natural ter um capricho maior na sua documentação. Por exemplo, o comentário Javadoc que mostramos inclui exemplos de uso. Por outro lado, métodos menos importantes podem ter documentações mais sucintas. Talvez, por exemplo, o objetivo dos parâmetros seja óbvio e, portanto, os marcadores \@param possam ser omitidos.

3.3.2 Comentários de Atributos Públicos

Esses comentários são usados para comentar um atributo de uma classe ou uma variável global, que faz parte da interface pública de um sistema, como no seguinte exemplo:

/**
 * Timeout (em milissegundos) para conexões com o banco de dados.
 * O valor zero indica um timeout infinito
 */
public static final int DB_CONNECTION_TIMEOUT = 0;

Veja que esse comentário documenta, principalmente, que o valor zero significa um timeout infinito.

3.3.3 Comentários de Classes Públicas

Classes surgem quando queremos agrupar dados e operações que possuem uma coerência conceitual. Por exemplo, uma classe Stack possui dados (os elementos da pilha) e operações (empilhar, desempilhar, etc). Por esse motivo, não basta documentar os métodos públicos da classe, de forma individual, como vimos antes. Esses métodos possuem um objetivo maior, que motivou a implementação deles na mesma classe. Logo, esse objetivo deve ser documentado antes da declaração da classe. A ideia é evitar que os desenvolvedores que vão usar a classe pensem que ela é uma coleção aleatória de métodos.

Segue um exemplo de comentário de uma classe Stack:

/* {@code Stack} é uma estrutura de dados do tipo LIFO, isto é, 
 * o último elemento a entrar, é o primeiro elemento a sair.   
 * Ela é também uma classe genérica, pois aceita elementos de  
 * qualquer tipo E.
 *  
 * Exemplo de uso:
 * 
 *   Stack<Integer> stack = new Stack<>();
 *   stack.push(10);
 *   stack.push(20);
 *   stack.push(30);
 *   System.out.println(stack.peek()); // 30
 *   System.out.println(stack.pop());  // 30
 *   System.out.println(stack.pop());  // 20
 *
 */
public class Stack<E> extends Vector<E> {
  ...
}

Nesse comentário, primeiro explicitamos a propriedade fundamental de pilhas, isto é, elas são estruturas de dados do tipo LIFO (Last In, First Out). E mencionamos que Stack é uma pilha genérica, ou seja, ela armazena elementos de um tipo genérico E. Por último, mostramos um exemplo, pois achamos que eles sempre colaboram para entender o uso de uma classe.

3.4 Comentários Privados

Esses comentários são escritos para ajudar outros desenvolvedores que, no futuro, terão que manter partes internas de um sistema. Consequentemente, eles não são escritos no formato Javadoc, pois não fazem parte da documentação de referência do sistema.

Esses comentários ficam no corpo da implementação de um método ou função e são usados para esclarecer detalhes de implementação que não ficam óbvio pela simples leitura do código. Por exemplo, suponha a seguinte função que retorna o tamanho, em número de páginas, de um artigo científico (cujos dados estão em uma estrutura do tipo Map):

int getArticleLength(Map<String, String> article) {
  if (article.containsKey("pages")) {
     return parsePageField(article.get("pages"));
  }
  String journal = article.get("journal");
  // Since this specific journal has no “pages” field, we were
  // forced to define a default value (10 pages)
  if ("Briefings Bioinform.".equals(journal)) {
     return 10; 
  }
  return 0;
}

O tamanho do artigo é calculado a partir de uma entrada do dicionário chamada pages, a qual armazena uma string contendo a página inicial e final. Porém, existe uma exceção: artigos publicados no periódico chamado Briefings Bioinform. não possuem a entrada pages. Ou seja, eles são uma exceção e acordou-se que iremos assumir que eles possuem 10 páginas. Um comentário de implementação documenta essa decisão e explica porque o tamanho dos artigos desse periódico é sempre igual a 10 páginas.

O comentário de implementação anterior é interessante porque ele ilustra que, muitas vezes, é mais relevante documentar porque um código existe no sistema, em vez de documentar como ele foi implementado.

Segue um segundo exemplo de comentário de implementação, extraído da biblioteca Google/Guava:

public String toString() {
  // racy single-check idiom, safe because String is immutable
  String result = toString;
  if (result == null) {
     result = computeToString();
     toString = result;
   }
   return result;
}

O comentário alerta futuros mantenedores de que a implementação usa um idioma de sincronização conhecido como racy single-check. Em outras palavras, o código segue uma solução conhecida para evitar problemas caso o método seja executado por múltiplas threads. Então, se tivermos que manter esse código, já temos uma excelente dica: melhor começar estudando o idioma racy single-check, caso a gente ainda não o conheça

3.5 Outros Tipos de Comentários

3.5.1 Comentários com Licenças de Uso

Esses comentários ficam no topo de um arquivo e são usados para explicitar a licença de uso do sistema. Eles são mais comuns no caso de sistemas de código aberto, implementados usando-se licenças como MIT, GPL, Apache, etc. Eles também seguem um texto padrão, que pode ser obtido nos sites de origem da licença.

Sistemas com licenças comerciais também podem incluir comentários para declarar que seu código é de propriedade e uso exclusivo de uma empresa.

3.5.2 Comentários TODO

Esses comentários começam com expressões como TODO, FIXME ou HACK. Eles são usados para documentar uma implementação que ainda não está perfeita e sugerir que, no futuro, ela seja melhorada. Em outras palavras, eles são uma maneira de declarar uma dívida técnica, conforme iremos estudar no Capítulo 8.

Por exemplo, a biblioteca Pytorch de Python, pelo menos por um tempo, incluía o seguinte comentário:

# TODO If this code path becomes popular, it may be worth 
# taking a look at optimizing it -- for now a simple 
# implementation is used.

O comentário deixa claro que a implementação de uma certa funcionalidade ainda não é a ideal, até porque os desenvolvedores da biblioteca não tinham certeza de que ela seria muito usada. Mas, se ela ficar popular, o comentário lembra que devemos refatorar o código atual.

Se usados com parcimônia, não consideramos que esses comentários sejam ruins, tal como os tipos de comentários que iremos apresentar na próxima seção.

3.6 Anti-Padrões de Comentários

Nesta seção, vamos apresentar alguns anti-padrões de comentários, isto é, comentários que devem ser evitados.

3.6.1 Comentários Redundantes

Esses comentários apenas repetem o que já está claro a partir da leitura do código, como nos seguintes exemplos.

// Converte a string para minúsculo
nome = "Maria".lower()

// Cria uma  nova instância da classe Carro
carro = new Carro("Corolla", "GXG-1077")

// Cria um ArrayList
ArrayList<Integer> minhaLista = new ArrayList<>();

// Loop pelos números de 0 a 4
for (int i = 0; i < 5; i++) {
  minhaLista.add(i);
}

public class Retangulo {
  private int largura;  // largura do retângulo
  private int altura;   // altura do retângulo

  public Retangulo(int largura, int altura) {
    // Seta o valor da largura
    this.largura = largura;
    // Seta o valor da altura
    this.altura = altura;
  }
    
  public int calcularArea() {
    // Multiplica largura por altura
    return largura * altura;
  }
}

Todos esses comentários são redundantes, pois nada agregam ao código. Na verdade, eles poluem e sobrecarregam o código com informações que os leitores já sabem.

3.6.2 Comentários Públicos que descrevem Detalhes de Implementação

Conforme estudamos na Seção 3, comentários públicos existem para consumo externo, isto é, para ajudar desenvolvedores que precisam chamar um método, acessar um atributo ou instanciar uma classe pública. Portanto, esses desenvolvedores não estão interessados em detalhes de implementação de tais elementos. Por exemplo, eles não precisam e nem querem conhecer a estrutura de dados ou o algoritmo usados na implementação do elemento de código que vão chamar, instanciar ou acessar.

Logo, um anti-padrão de comentário é deixar que detalhes de implementação façam parte de comentários públicos, como no seguinte exemplo:

/**
 * Este método calcula a média de uma lista de números inteiros.
 * Primeiro, ele verifica se a lista está vazia e, caso esteja, retorna 0.
 * Em seguida, inicializa uma variável chamada 'soma' com o valor 0.
 * Ele percorre cada inteiro na lista usando um loop for-each.
 * Em cada iteração, adiciona o valor à variável 'soma'.
 * Após o loop, divide 'soma' pelo tamanho da lista para obter a média.
 * Por fim, retorna o resultado como um número inteiro.
 */
public int calcularMedia(List<Integer> numeros) {
  ...
}

Neste exemplo, o comentário descreve com bastante detalhe o algoritmo usado para calcular a média de uma lista de números inteiros, o que é desnecessário em um comentário para consumo externo.

3.6.3 Comentários que Documentam Código Ruim

Existe uma frase famosa de Brian Kernighan — um dos criadores das primeiras versões do sistema operacional Unix e da linguagem de programação C — e P. J. Plauger que recomenda o seguinte: “Não comente código ruim, reescreva-o". Em outras palavras, não devemos usar comentários para explicar um código ruim; o melhor a fazer nesses casos é remover o problema pela raiz, isto é, reescrever o código.

Um exemplo ocorre quando usamos comentários para explicar o funcionamento de trechos de código internos a um método, tal abaixo:

// calcula descontos
...
descontos = ...

// calcula impostos
...
impostos = ...


// calcula frete
...
frete  = ...

precoFinal = preco - descontos - impostos - frete; 

Neste caso, podemos remover os comentários e extrair os trechos de código para métodos com nomes que revelam claramente o propósito deles:

double descontos = calcularDescontos(); 
double impostos = calcularImpostos(); 
double frete = calcularFrete();
precoFinal = preco - descontos - impostos - frete; 

Assim, trocamos comentários por chamadas de métodos cujos nomes revelam o que eles fazem. Consequentemente, chegamos a um código mais enxuto e fácil de entender.

3.6.4 Comentários para Excluir Código

Comentários para evitar a execução de algumas linhas de código constituem uma prática comum quando modificamos uma funcionalidade, mas não temos certeza de que a mudança irá funcionar. Então, deixamos a versão antiga comentada, para facilitar sua restauração, se necessário. Por outro lado, se a nova implementação funcionar, devemos deletar o código antigo, o quanto antes, para que ele não fique ocupando espaço de forma desnecessária.

Alguns autores são enfáticos ao criticar esses comentários. Por exemplo, Robert Martin diz o seguinte:

Eu fico louco ao ver trechos de código comentados. Quem sabe há quanto tempo estão ali? Quem sabe se ainda são relevantes ou não? No entanto, ninguém os apaga, porque todos assumem que outra pessoa precisa deles ou tem planos para usá-los. (Clean Code, page 287)

Então, concluindo, código comentado não deve chegar no repositório central de um sistema, pois caso seja necessário recuperar a versão antiga de um arquivo podemos usar comandos do próprio sistema de controle de versões, como git restore.

Literatura Científica: Em 2018, Lucas Grijó e André Hora publicaram um artigo no Workshop Brasileiro de Manutenção e Visualização de Software no qual analisaram a prevalência de comentários para excluir código (link). Os autores, após usarem scripts para recuperar os comentários de 100 sistemas Java de código aberto, concluíram que 4.7% deles, na mediana dos sistemas analisados, referiam-se a comentários de código. Portanto, no mundo real, alguns desses comentários acabam chegando nos repositórios centrais dos projetos. Porém, esse número é baixo, se comparado com o total de comentários em cada sistema. Ou seja, esses comentários não são comuns, o que reforça nossa decisão de classificá-los como um anti-padrão.

3.7 Documentação de APIs REST

Na Seção 3.3, quando tratamos de comentários públicos, nosso foco estava em sistemas monolíticos. Nesses sistemas, a comunicação ocorre por meio de chamadas de métodos. Por exemplo, um módulo de vendas pode ter que chamar métodos de um módulo de contabilidade. Por isso, precisamos documentar os métodos públicos do sistema de contabilidade, para facilitar a chamada deles por outros módulos.

Por outro lado, em certas arquiteturas de software, vendas e de contabilidade são sistemas separados e independentes. Ou seja, nesses casos, a comunicação entre eles não ocorre mais por meio de chamada de métodos. Em vez disso, o sistema de contabilidade deverá implementar uma API remota para acesso de outros sistemas, como o sistema de vendas do nosso exemplo. Por exemplo, o sistema de contabilidade pode implementar uma API REST, que é um tipo de API que usa o protocolo HTTP para comunicação entre clientes e provedores de um serviço.

Nosso objetivo principal nesta seção é lembrar que APIs remotas também precisam ser documentadas, para facilitar o seu uso por parte de outros sistemas. Porém, não vamos disponibilizar um tutorial sobre como implementar tais APIs, mas sim mostrar quais elementos e aspectos das mesmas devem ser documentados.

Vamos começar lembrando que uma API REST é formada por um conjunto de endpoints (ou endereços HTTP, de forma simplificada), os quais são semelhantes a métodos, pois possuem parâmetros de entrada e saída. Porém, os valores passados para esses parâmetros são documentos textuais no formato JSON.

Para cada endpoint de uma API é importante prover uma documentação como a seguinte:

Parâmetro Tipo Obrigatório Descrição
messages array sim Prompts que serão enviados para o modelo
model string sim Modelo a ser usado
max_tokens integer não Número máximo de tokens da resposta
temperature float não Controle de aleatoriedade (0 a 1, padrão: 0.7)
system string não Instruções do sistema para o Claude
{ "messages": [
    {
      "role": "user",
      "content": "Quais são as três maiores cidades brasileiras?"
    }
  ],
  "model": "claude-3-sonnet-20240229",
  "max_tokens": 1000,
}
{ "id": "msg_123abc",
  "type": "message",
  "role": "assistant",
  "content": [
     {
       "type": "text",
       "text": "As três maiores cidades do Brasil em população são:.."
     }
  ],
  ...
}
Código Descrição
200 Sucesso
400 Requisição com parâmetros inválidos
401 Requisição não autorizada: chave inválida
429 Muitas requisições: limites de acesso excedidos

Como vimos, a documentação de APIs REST tem certas peculiaridades. Por exemplo, os valores de entrada e saída são documentos JSON. Além disso, temos que documentar decisões que são importantes em sistemas Web, tais como os mecanismos de autenticação que serão usados, códigos de erro HTTP e limites de acesso impostos pela implementação da API.

Existem também iniciativas para criar linguagens para definição dos elementos de APIs REST. Um exemplo é uma linguagem conhecida como OpenAPI Specification, a qual propõe uma sintaxe, na forma de um arquivo YAML, para definição dos endpoints de uma API, incluindo nome, URL, parâmetros de entrada, parâmetros de saída, etc. Nessa linguagem, existe também um campo chamado description que permite documentar, de forma textual, cada elemento da API. Feito isso, existem ferramentas que leem as especificações (arquivo YAML) e geram automaticamente uma documentação Web. Algumas dessas ferramentas permitem também acessar os endpoints da API, para fins de testes e melhor entendimento das suas entradas e saídas.

Bibliografia

John Ousterhout. A Philosophy of Software Design, Yaknyam Press, 2018.

Robert C. Martin. Clean-Code. A Handbook of Agile Software Craftsmanship, Pearson Education, 2009.

Exercícios

1. Comentários também precisam de manutenção. Explique porque essa afirmação é verdadeira.

2. Por padrão, a ferramenta Javadoc gera documentação apenas para membros públicos e protegidos. Porém, se quiser incluir métodos privados, você pode usar a opção -private ao chamar a ferramenta. Descreva um cenário no qual seria interessante gerar também documentação para membros privados e protegidos.

3. Estude de novo a documentação do método substring que mostramos na Seção 3.3.1. Seja também o seguinte código que chama substring com uma string vazia:

String vazio = "";
String resultado = vazio.substring(0, 0); 
System.out.println("Resultado: \"" + resultado + "\"");
System.out.println("Tamanho: " + resultado.length());

Sobre este código responda:

(a) Ele levanta uma exceção do tipo IndexOutOfBoundsException? Se não levantar, responda o que será impresso por ele.

(b) A documentação do método ajudou você a entender o funcionamento do código acima? Explique e detalhe a sua resposta.

(c) Você sugere alguma melhoria na documentação do método substring?

4. Qual o problema com os seguintes comentários?

// Cria HashMap com informações de usuários
HashMap<String, Object> usuario = new HashMap<>();

// Insere o nome do usuário
usuario.put("nome", "João");

// Insere o sobrenome do usuário
usuario.put("sobrenome", "Silva");

// Insere a idade do usuário
usuario.put("idade", 30);