Documentação do algoritmo Ruby com AsciiDoc e Knitr
Publicados: 2022-03-11Todo projeto não trivial precisa de documentação e precisa ser envolvente com ótimas explicações e até ilustrações, para que seja realmente lido e usado. Engenheiros fazem software para resolver problemas de negócios, geralmente sem ter uma vasta experiência nesse negócio específico, então documentar o negócio é tão importante quanto documentar o software.
A documentação pode ser parafusada após o fato, mas acho que escrever uma especificação funcional antes da codificação é uma grande ajuda. Uma especificação funcional é uma fonte de verdade para todos os membros da equipe em todas as disciplinas e força o design de alto nível antes da implementação, evitando o desperdício de esforços. Neste post, vou passar por um projeto de exemplo de prototipagem para escrever uma especificação funcional para um exemplo de projeto Ruby on Rails para descrever o que o aplicativo deve fazer e ser uma referência durante o desenvolvimento. Meu objetivo é mostrar que projetos Ruby podem usar AsciiDoc e R para:
- Prototipe facilmente novos cálculos, algoritmos, etc. usando R
- Mostre facilmente os resultados do R em sua especificação funcional e outra documentação escrita do AsciiDoc
- Vincule-o ao processo de compilação para que a documentação seja sempre atualizada com os dados e algoritmos mais recentes
Uma especificação funcional não é um substituto para documentar sua API com RDoc ou YARD – é uma adição vital que pode ser usada como referência para todas as partes interessadas (programadores e não programadores) em um projeto.
Protótipo
Eu gosto de pescar salmão e quero uma maneira para mim e para os outros acompanharem e compartilharem detalhes sobre os peixes que estão pescando. Ele também precisa de um placar para mostrar os principais usuários. No momento existem fóruns usados para esse fim, mas dados estruturados com placar são bem mais legais.
Eu poderia fazer um protótipo em Ruby, mas Ruby não tem o melhor suporte para gráficos, então vou usar R. Usar R me dá muitas maneiras fáceis de brincar com matemática e visualização, e é plataforma.
# Read in some example data data <- read.csv("func_spec/example_user_data.csv") # Compute the score, weighted by base-10 log of number of reports score <- mean(data$Fish.Caught) * log(length(data$Date)) / log(10)
Em apenas duas linhas, li alguns dados de exemplo e calculei uma pontuação usando minha pontuação proprietária. R pode fazer isso e mostrar um gráfico com uma instalação vanilla, enquanto linguagens como Ruby ou Python exigirão mais código e pacotes extras para serem instalados.
Documentando o algoritmo
Depois de fazer meu sistema de pontuação, eu poderia ir direto para o código. Na verdade, eu poderia ter ignorado a prototipagem em R e apenas prototipado diretamente no meu aplicativo Ruby on Rails. No entanto, a prototipagem em R foi rápida e muito próxima da matemática subjacente. Veja como vou configurar a documentação:
-
kingfisher/
-
Rakefile
-
doc/
-
func_spec.Radoc
-
-
Meu exemplo de projeto Rails é chamado kingfisher, e estou colocando a documentação em uma pasta “doc”. Não vou passar pela sintaxe do AsciiDoc, pois o site Asciidoctor tem uma grande documentação para isso, mas aqui está como colocar um gráfico no AsciiDoc com knitr:
//begin.rcode freq_change, fig.asp=0.618, fig.width=12, fig.align="center" times_fished <- 1:50 plot(times_fished, 5 * log(times_fished) / log(10), ylab="User score when average 5 catches per trip", xlab="Number of fishing trips in the past 12 months") //end.rcode
Coloque isso em func_spec.Radoc
, execute knitr e AsciiDoc, e você obterá algo assim em sua documentação:

Espero que a maioria dos desenvolvedores entendam intuitivamente que a pontuação aumentaria logaritmicamente com o número de vezes pescado; mesmo assim, esta é uma ótima maneira de exibir isso apenas para ter certeza. Em torno deste gráfico, eu teria algum texto explicando por que isso é desejável para que os desenvolvedores que não pescam possam entender o que está acontecendo aqui. Este exemplo é artificial, mas eu usei esse tipo de prototipagem e documentação no passado para outros projetos (por exemplo, finanças, estimativa de construção) onde os resultados dos cálculos podem nem sempre ser óbvios.
Agora que a partitura está prototipada e temos um gráfico para colar na documentação, tudo o que resta é transformar o AsciiDoc de entrada para algum tipo de formato de saída. Eu uso algumas regras no meu Rakefile para transformar em HTML:
require 'asciidoctor' require 'pathname' task docs: %w[doc/func_spec.html] rule '.adoc' => '.Radoc' do |t| Dir.chdir(Pathname.new(t.name).dirname) do sh "R -e 'library(knitr);knit(\"#{Pathname.new(t.source).basename}\", " + "\"#{Pathname.new(t.name).basename}\")'" end end rule '.html' => '.adoc' do |t| Dir.chdir(Pathname.new(t.name).dirname) do Asciidoctor.convert_file Pathname.new(t.source).basename, backend: :html5, to_file: true, safe: :safe end end
Agora eu posso executar “rake docs” e obter a documentação para construir e estar sempre atualizado, mesmo se eu alterar os dados subjacentes ou o cálculo de pontuação.
Outras soluções
Para qualquer coisa envolvendo Ruby on Rails, documentar com AsciiDoc é uma ótima opção, independentemente de haver gráficos personalizados na documentação ou não. O AsciiDoc oferece uma maneira nativa do Ruby de escrever em um formato de marcação maravilhoso. Dito isso, existem outras ótimas ferramentas de documentação que serão um pouco mais difíceis de gerenciar e vincular ao seu processo de construção de um projeto Rails.
Sphinx processa reStructuredText (também um bom formato de marcação) e pode incorporar a saída do Matplotlib. Para um projeto Python, isso é perfeito – Sphinx + Matplotlib oferece uma maneira nativa do Python de produzir uma boa documentação com gráficos personalizados. No entanto, se você estiver trabalhando em um projeto Rails, é menos do que desejável ter que gerenciar vários conjuntos de dependências para um ambiente separado apenas para produzir sua documentação.
Existem muitas outras soluções para produzir documentação, incluindo programas como doxygen e LaTeX, que podem exigir mais ou menos cola para se encaixar em seu sistema de compilação. Se você precisa de um sistema como o LaTeX, use-o; se você tem um projeto Rails bastante padrão e tem apenas um pouco de matemática que deve ser documentada, use AsciiDoc e R.
Conclusão
Ruby e AsciiDoc formam uma ótima equipe, e é fácil incluir R na mistura para fazer boas visualizações em sua documentação. Você pode lançar qualquer pacote no ecossistema R, como ggplot2, para obter belos gráficos em sua documentação.
O material de origem para este post pode ser encontrado em seu repositório GitHub. A partir da publicação, esse repositório não contém um projeto “real”, mas pode no futuro!
Se você quiser falar um pouco mais sobre Ruby, eu recomendo aprender Metaprogramação com Ruby Metaprogramming Is Even Cool Than It Sounds .