Pelemay Backendという Apache 2.0 License のOSSを開発しています.最初の小さなリリース に向けて鋭意開発を進めています. は2023年7月6日にできました!
このPelemay Backendのコンセプトは次の記事にまとめています.
一言で言うと,次のようなものです.
PelemayBackend: A memory-saving, fault-tolerant and distributed collection of Nx compilers and backends for embedded systems.
PelemayBackend: 組込みシステム用の Nx コンパイラとバックエンドの省メモリフォールトトレラント分散型コレクション
今は @mnishiguchi さんと一緒に開発を進めています.
ElixirのIoTフレームワークである,Nerves Projectのコアメンバーの1人です.
はじめてZoomでお話しして,Pelemay Backendの開発にお招きしたときに, @mnishiguchi さんは謙遜だと思うのですが,「私はプログラミングは苦手で,テストとドキュメントくらいしか書けない」というような趣旨のことをおっしゃっていました.
しかし,本日いただいたPull Requestを見て,私は驚嘆しました.
これは,テスト,リファクタリング,ドキュメント,PRの書き方のお手本にしたいPRだったのです! これで,プログラミングが苦手って,謙遜も謙遜,なかなかここまで書ける人いないと思いますよ.
この記事では,このお手本PRについて,私の視点で解説していきたいです.
PR の SubjectとDescriptionが簡潔ながら要点を得ていて,とても読みやすい!
まず目が行くのが,SubjectとDescriptionです.
refactor(NodeActivator): split module #146
Description
- factor out sub-modules
- Epmd
- Utils
- add module document for the top-level module
- add function documents
Notes
The sub-modules are private (@moduledoc false) as of now. Only the top-level module will show in the Hex document.
うーん美しい.このPRの目的と意図が明確に書かれていて,あとで読み返したときに意思決定や思想,文化を理解するのに十分な情報です.
思い切ったリファクタリングの方針
次に,先ほどのDescriptionの記述を見返しながら,具体的にどのような変更を加えたのか見てみましょう.
リファクタリングの方針として,メインモジュールである NodeActivator
には,思い切って run
関数のみを置いています.start_distributed_node
関数は,defp
と書いてあるように,プライベート関数なので,公開した時のドキュメントに記載されることはありません.
mix docs
コマンドで生成されるNodeActivator
モジュールのドキュメントを見てみると,次のようにシンプルです.
ごちゃごちゃ定義されていた関数群は,サブモジュールEpmd
とUtils
に機能的に分類されて配置されています.しかも,これらのサブモジュールについて,@moduledoc false
を指定することで,ドキュメントを生成しないように隠蔽しています.
的確なドキュメント
次に,@doc
に書かれたrun
関数の説明を見てみましょう.
run(node_name_prefix)
@spec run(binary()) :: {:ok, node()} | {:error, any()}
Turns a non-distributed node into a distributed node after ensuring that the
epmd
operation system process is running. Returns the name of the started distributed node. The node name will be generated by appending a random string to the providednode_name_prefix
string.This function does nothing when the distribution has already been started.
For more info, see Node.
Examples
{:ok, node_name} = NodeActivator.run("foo")
あえて,Google翻訳での日本語訳をそのまま載せます.
epmd
オペレーティング システム プロセスが実行されていることを確認した後、非分散ノードを分散ノードに切り替えます。 開始された分散ノードの名前を返します。 ノード名は、指定されたnode_name_prefix
文字列にランダムな文字列を追加することによって生成されます。すでに配信が開始されている場合、この関数は何も行いません。
詳細については、ノード を参照してください。
誤訳がほぼないですね.ErlangやElixirに慣れていない人にとっては,epmd
が何なのか,という点だけわからないと思いますが,それ以外については,どういう条件の時に何を行うのか,何を返すのかが明確です.また,引数にnode_name_prefix
と命名しているのもポイント高いです.これにより,この文字列を接頭辞(prefix)として用いてノードを命名することが明らかです.
Examplesに載せているコード例に,iex
をつけないことで,doctestとしてではなく,単なるサンプルコードとして見せている点にも注目です.こうすることで,実行するたびに毎回結果が異なるような,doctestに不向きのコード例を載せることができます.
テストの機能的な分類
次にテストコードを見てみましょう.
describe
で機能面での分類を,test
でそれぞれの機能に対するテストケースを記述しています.それぞれに書かれている名前も要点を簡潔に記述しています.Elixirにおけるテストケースの見本になっています.
assert
の対義語である refute
をうまく使っています.refute
を使わないと,例えば,次のように書いてしまいがちなところです.
test "generates unique atom" do
node_name1 = Utils.generate_node_name("test prefix")
node_name2 = Utils.generate_node_name("test prefix")
assert is_atom(node_name1)
assert node_name1 != node_name2
end
しかし,refute
を使って次のように書くのが推奨です.
test "generates unique atom" do
node_name1 = Utils.generate_node_name("test prefix")
node_name2 = Utils.generate_node_name("test prefix")
assert is_atom(node_name1)
refute node_name1 == node_name2
end
おわりに
Elixir中級者の人は,以上のようなポイントを押さえて,テスト,リファクタリング,ドキュメント,PRを書くと良いと思います.
@mnishiguchi さんがNervesコアメンバーに入っていることの理由の1つが,またひとつ,明らかになりました.