Como gerar documentos do seu código em Go?

Como gerar documentos do seu código em Go?

Há algum tempo atrás, visando manter meu estilo generalista, mergulhei nos estudos de Go. Estava estudando, mas nunca tive a oportunidade de experimentar um projeto em produção para ajustar o treino ao jogo ⚽.

Durante essa jornada tive o prazer e o impacto de conhecer diferentes técnicas para resolver um problema. Sem dúvidas, me apeguei ao conceito da linguagem e decidi trocar uma aplicação pessoal que fiz em Elixir para Go. O objetivo deste artigo não é comparar 🫡, esse é um comentário para demonstrar o quanto cheguei à produtividade e maturidade que eu esperava.

Godoc

Deixando de lado as comparações! Assim como o Pyhton possui o pydoc, o Node.js possui o ESDoc. O Go também disponibiliza o pacote godoc para extração de documentação, o qual converte todos os comentários estruturados em uma versão HTML.

Sempre gostei dessa abordagem. Eu pessoalmente não vejo problemas entre o código e a documentação. Devemos nos lembrar que, assim como o Chat GPT, produzimos códigos para outros seres humanos. Por último, é importante manter a documentação atualizada.

O estilo de documentação é simplificado e sem muitas regras, deixando que você defina a sua forma de documentar os argumentos da função e seu retorno.

Bora para a prática!

Iremos criar uma simples aplicação http documentada que devolve dados de cartões aleatórios para o super hacker da geração, que usa a palavra "hack" para tudo, poder realizar transações e receber uma compra negada na sua cara.

O super hacker

Dependências

Iremos instalar duas bibliotecas oficiais o godoc e o pkgsite, que permitem a conversão dos comentários para HTML.

go install -v golang.org/x/tools/cmd/godoc@latest
go install golang.org/x/pkgsite/cmd/pkgsite@latest

Códigos

  • go.mod
💬 O pacote gofakeit oferece diversas implementações para gerar informações aleatórias, o que torna a preparação de ambientes de teste e fixtures mais fácil.
module github.com/williampsena/go-recipes/doc-app-example

go 1.22.4

require github.com/brianvoe/gofakeit/v7 v7.0.3 // indirect

  • main.go
// This package represents the application command for starting a web server.
package main

import (
	"github.com/brianvoe/gofakeit/v7"
	"github.com/williampsena/go-recipes/doc-app-example/web"
)

// This function is responsible for setting up the program before it runs
func init() {
	gofakeit.Seed(0)
}

// Application entrypoint
func main() {
	svr := web.BuildServer()
	web.ListenAndServe(svr)
}
  • Makefile
SHELL=bash

dev:
	go run main.go

docs-godoc:
	godoc -http=:4444

docs-pkgsite:
	pkgsite -http=:4444
  • web/server.go
// This package contains web server structures and functions responsible for handling HTTP application.
package web

import (
	"fmt"
	"net/http"
)

// Create an application web server mux with routes established
func BuildServer() *http.ServeMux {
	mux := http.NewServeMux()

	mux.HandleFunc("GET /health", HealthCheckEndpoint)
	mux.HandleFunc("GET /cards", CardGeneratorEndpoint)

	return mux
}

// Listening web server on port 4000
func ListenAndServe(mux *http.ServeMux) {
	fmt.Println("✅ The sever is listening at port 4000")
	http.ListenAndServe("localhost:4000", mux)
}
  • web/cards.go
package web

import (
	"encoding/json"
	"fmt"
	"net/http"

	"github.com/brianvoe/gofakeit/v7"
)

// Struct responsible for holding all card data, such as the holder's name and card number
type Card struct {
	HolderName string `json:"holder_name"` // card holder name
	Type       string `json:"type"`        // card type (master, visa, amex)
	Number     string `json:"number"`      // card number
	Cvv        string `json:"cvv"`         // card verification code
	Expiration string `json:"exp"`         // the expiration year + month
}

// Create a Fake Card Struct
func BuildCard() (*Card, error) {
	creditCard := gofakeit.CreditCard()

	card := Card{
		HolderName: gofakeit.Name(),
		Type:       creditCard.Type,
		Number:     creditCard.Number,
		Cvv:        creditCard.Cvv,
		Expiration: creditCard.Exp,
	}

	return &card, nil
}

// Endpoint is responsible for responding to a false card generation
func CardGeneratorEndpoint(w http.ResponseWriter, r *http.Request) {
	card, err := BuildCard()

	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		fmt.Fprint(w, "Sorry, something wrong happened!")
		return
	}

	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(card)
}

  • web/health.go
package web

import (
	"fmt"
	"net/http"
)

// Endpoint is responsible for responding to application health
func HealthCheckEndpoint(w http.ResponseWriter, r *http.Request) {
	fmt.Fprint(w, "I'm so healthy 😌!")
}
O propósito do artigo não é detalhar cada aspecto da implementação, mas sim examinar os comentários inseridos no código que serão traduzidos para a documentação HTML.

Vamos executar a aplicação super hacker 💀 que gera informações de cartões 💳.

make dev

# ou

go run main.go

A aplicação estará acessível na porta 4000, é possível executar os comandos a seguir para verificar suas rotas:

curl http://localhost:4000/health 

# I'm so healthy 😌!

curl http://localhost:4000/cards 

# {"holder_name":"Ephraim Hand","type":"American Express" "number":"6062825121549507","cvv":"857","exp":"08/25"}

Gerar documentação

Com a estrutura do projeto pronta, executaremos o godoc para verificar a documentação gerada.

make docs-godoc

# ou

godoc -http=:4444

A documentação está acessível na porta 4444.

Bom, como vocês podem ver no vídeo acima, a navegação não ficou tão objetiva como gostaríamos, certo?

Assim, se um pacote não atende aos gostos populares, essa nova geração cria um novo, correto (vide NPM packages)? O pkgsite possui uma documentação mais estruturada, com uma melhor experiência de navegação do que a do godoc, utilizada como frontend dos pacotes Go. Encontrei uma referências que indica um movimento de "deprecated" do godoc em favor do uso do pkgsite.

Sem mais delongas! Vamos agora ao pkgsite, nada precisa ser ajustado somente instalar e executar o pacote.

É hora de visualizar uma documentação com uma melhor experiência de navegação.

make docs-pkgsite

# ou

pkgsite -http=:4444

A documentação está acessível na porta 4444.

Como podemos perceber, a diferença começa nas cores do tema. Muitas pessoas amam o dark-mode, confesso que gosto de algumas aplicações no light, não me julgem. A leitura do código no modo (raw) facilita o nosso copy/paste 😜. Fato o pkgsite tem uma experiência de navegação superior.

Repositório

A implementação está disponível em meu repositório do Github:

go-recipes/doc-app-example at main · williampsena/go-recipes
Contribute to williampsena/go-recipes development by creating an account on GitHub.

Fim!

Por hoje é só, espero que o conteúdo possa aprimoar suas experiências em Go, mantenham o 🧠 kernel atualizado, com tudo que seja respeitável, justo, puro e de boa fama, se há alguma virtude ou louvor que isso habite em nossos pensamentos! 🕊️ Filipenses 4:8

Referências