Edited at
ElixirDay 13

Elixir + Nuxt.jsでExDocを使いやすくしてみた

この記事は Elixir Advent Calender 2018 13日目の記事です

みなさんElixirでドキュメント書いていますか?

僕はサボってます(懺悔)

まぁその理由は追い追い書きますがElixirでドキュメントを書く時(読む時)に少し不満があったのでNuxt.jsをフロントエンド、Elixir + Cowboyをバックエンドに独断と偏見でExDocをいい感じに書き直したドキュメントビューワを作ってみました


こんな感じ

screencast20181212223342_2.gif


やったこと

ExDocRefined という Elixir 標準の ex_doc 代替のドキュメントビューワを作りました。

たぶんElixirを使っている人ならex_docで出力したことはなくてもこういったドキュメントなら書いたことある人は多いんじゃないでしょうか。

@doc """

This is a document for function
"""

この状態でex_doc を依存に追加して mix docs コマンドを叩くとElixir公式リファレンスのようなドキュメントが出力されます(Elixir公式ドキュメントもex_docを使って出力されています)

$ mix docs

image.png


ExDocの問題点

image.png

複数人で開発するようなチーム開発の場合や1人で作る場合においても一年後の自分のためドキュメントを書くことは重要です。Elixirにおいてドキュメントを書くことは大事な文化の一つです。


Elixir treats documentation as a first-class citizen (公式ドキュメントより)


ex_docはモジュールに埋め込んだドキュメントをHTMLに変換してくれて見やすくしてくれます。

しかし ex_doc を使っている時にまず問題意識としてあったのは


  • 毎回mix docsを叩かないとドキュメントの変更がHTMLに反映されない (変更する度に想定したとおりに出力されているか確認するのがしんどい)

  • ドキュメントがモジュール毎にHTMLで出力されるため遷移が発生してフローが途切れる

  • 正直あまりUI/UXを意識した作りではないのでドキュメントを探すモチベーションが下がる

  • 基本的にローカルでの出力のみなのでドキュメントをホスティングしてチームに共有などする場合には別途ホスティングする仕組みが必要(hexdocs.pmのプライベートリポジトリを利用するなど)

  • Summaryとfunction詳細の説明に同じ内容が出力されていて冗長

というところでした。

細かい点ですが開発において、こういった些細なことこそが重要で、開発体験を大きく左右します。開発が進めば進むほどプロジェクトにおける時間の殆どは既存の機能のメンテナンスや他人の書いたコードを読むことになるため、少しでもコードやドキュメントを読む苦労が減るのはメンテナビリティを大きく左右するからです。

そこで多少冗長性を廃して、Developer Experienceにも配慮しつつClosedなソースを対象にしたドキュメントビューワを作りたいと思いNuxtをフロントエンド、ElixirでCowboyをバックエンドにしたドキュメントビューワを作りました。

なぜClosedなソースをターゲットにしたかというとExDocの仕組みや冗長な書き方はElixir公式のようなPublicなコードを想定しているのでは?という推測をしたからです。Publicなソースに限定されないのなら色々別なことも出来るなと考えました。


どうやって動作するか

elixir_cowboy.png

簡単なアーキテクチャとしては以上のようになり、CowboyへはNuxtからWebsocketで接続しています。

Websocketで接続後、動的にコンパイル済みのBEAMファイルからドキュメントを取得してきます。

APIベースでないのは以前作ったLogViewerというElixir向けのログビューワをベースに作ったのでその仕組みの再利用でしたが結果的にはSPAと相性がよくUXという点でいい結果になったかと思います。


出来ること

ExDocRefinedでは以下のことが出来ます


  • インタラクティブなElixirプロジェクトのドキュメント表示



    • mix docs不要, 都度コンパイル済みのbeamファイルからドキュメントを参照

    • Markdown形式, ElixirコードのSyntax highlight対応



  • Phoenixへの埋め込み (1.3, 1.4対応)


    • 開発サーバなどにドキュメントをホスティング可




  • ドキュメント上での対話的な関数の実行


    • 以前からドキュメントを見る→iexで実際に試してみるという動作の間に少し無駄があるなと思っていました。なのでドキュメント上から直接パラメータを渡して実行し結果を見ることが出来るようにしました

    • 任意の型(Integer, String, Atom, Map, List, Struct, Module, Function, etc...)を渡してドキュメント上で関数を実行出来ます

    • 関数も渡せるのでString.to_atom("foo")といった任意の関数callを渡しても大丈夫です(リモートサーバにデプロイする際は要認証機構)



image.png

実際に試してみたい方はExDocRefinedのドキュメントを参考にインストールしてみてください


作って学んだこと

2個程Nuxtを使ってElixirの足回りのツールを作ってみて学んだことなど


  • 単純な機能ならPhoenixを使わなくてもCowboyとPlugだけでも実装は可能

  • 文字列でもElixirが解釈可能ならASTに変換出来、強力な操作が出来る

  • Vue.jsのProgressiveにスケールするという発想とElixirの良い意味での型のゆるさが相性よくシームレスに作業出来る


今後の予定

今後やりたいことなど


  • ドキュメント取得箇所を自前で書いたが、ex_docの関数を使って取得するようにし公式の仕様変更に追従出来るようにする

  • 細かいUIの改善(モジュールの絞り込み, specの表示方法等)

  • オプションでドキュメント上での関数実行を切り替え出来るように


まとめ

ex_docをいい感じにしたいということでExDocRefinedというドキュメントビューワを作りました

最初はex_docのformatter behaviourに対応したサードパーティのformatterを作りSPAを出力しようかと思ったけど、結局mix docsコマンドを毎回叩かなきゃいけないことやformatterの内部実装に影響されそうということで完全にサードパーティとして作ることにしました

Elixirは最近はライブラリに困るということも少なくなってきたと思いますが、こういった足回りのツールがまだ少ないと思うところもあるので、これで少しでも何らかの貢献になれればありがたいです