Rustのマクロのユーティリティを組んだ
まえがき
当記事では、cargoよりインストールできる自作のOSS、to-syn-errorについての説明等を述べます。当記事及び、当リポジトリへの指摘は歓迎します。
リポジトリへのリンクは以下になります。
なお、当記事では詳細な解説はありません。仕組み自体が単純なので、これといって取り上げる部分がないためです。
目次
使用例
基本的には、エラーハンドリング用の列挙型に対してDeriveするだけです。これによって、列挙型のバリアントにメソッドとして、synクレートのエラー型に変換するものが追加されます。
let input: syn::parse::ParseStream; let span = input.span(); let error_syn = ParseError::Something.to_syn_error(span);
README.mdより一部抜粋
他にも、インストールの際に依存しているクレートの一部を手動で追加インストールせねばならないなど、いくつか注意点はありますが、すべて当リポジトリのREADME.mdに記述していますので、詳しくはそちらを参照してください。
ただこれだけのクレートなので、内部のコードも非常にシンプルです。これをベースにアレンジして扱うのもよいでしょう。
モチベーション
以下ではなぜ、このように単純なクレートを公開したか、ということについて述べます。
責任問題の分割
該当するコードが担保すべきロジックの範囲を、俗称として責任と呼ぶことがあります。
これはコード分割を行う際の基本的な基準の一つであり、どこまで分割するか、といったものも含めた責任に関する議論を責任問題と呼ぶこともあります。
ここでまず、コード分割にて行える責任の分割について述べます。
コード分割にて行える責任の分割は、主に単体テストの行いやすさにおいて威力を発揮します。バグが発生した際に追いかけやすい、可読性が向上するといった側面もありますが、ケントバック氏のTDD本によると、挙げた二つの特徴はTDDを行うことによって自動的に発生するそうです。
よって、コード分割はTDDになぞらえて行うのが最も効果的と言えるでしょう。
メンテナンスの責任
上記ではコード分割における責任問題について論じました。
けれども責任はロジックの担保だけでなく、メンテナンスという側面からも考えることができます。
たとえばあるプロジェクトにおいて、ユーティリティを内部に保持していたとします。これにバグが見つかった場合、ユーティリティに対してチケットを切らねばなりません。
ここで起こりうる問題は、プロジェクトのユーティリティのバグを直す、といったチケットだと非明示的であることです。
当然ユーテリティの何を直すのか、といった詳細なチケットの命名が期待されます。けれども、これではつけられるであろう名前は長すぎることがあり、応じて可読性が低くなりがちです。グローバルCSSの命名規則のように、ひたすらに長い命名をしていくのは苦痛でしかなく、できればファイルスコープ等などを用いて、名前空間を狭めて短く名付けたいものです。
そのファイルスコープに近しいものが、プロジェクトレベルにも存在します。
それこそがリポジトリであり、ユーテリティのそれぞれを別リポジトリに切っていれば、そこへ、〇〇を修正、といった短い名前付けがチケットに対して可能なのです。
そもそも、本流のプロジェクトはユーテリティがどうなっているかなどまったく関与しません。どういった履歴でどのようにユーテリティが修正されたかを知る必要はありませんし、むしろ混ぜてしまえば歴史が煩雑となってしまいます。
そこでコードレベルではなく、もう少しマクロな視点から責任を分割することが重要なのだと、筆者は考えます。
to-syn-errorの隔離
上述の論で責任分割の重要性は理解して頂けたかと思います。
その上で、当クレートに話を戻しますと、正に先項で挙げた例の通りで、メインプロジェクトから隔離したのがこのクレートなのです。
ですので、当クレートは汎用性と利便性のみを追及して隔離されています。
何も考えたくない
この項では結論を述べたいと思います。
上記のように責任問題を回避するためにクレートを隔離したのがto-syn-errorです。けれども結局のところ、メンテンナンスを考えたり、煩雑なコーディング以外の処理に頭を悩ませたくない、すなわち何も考えたくないという思いこそが根源のモチベーションです。
プログラマにとっての美徳は怠惰である、というのは有名な言葉ですが、筆者が行った別リポジトリへの隔離もまた、怠惰の延長線上にあるものでした。
要するに、面倒くさいことは改善してしまうに限る、この精神がきっかけで当クレートを公開しました。
あとがき
実のところ、先日書いた記事のクレートにしろ、当クレートにしろ、jestの自動MockのようなものをRustに持ち込みたく、そこで枝状に生えたタスクをこなすために実装されています。
といいますのも、本筋のプロジェクトでRustを使ったツールが必要になり、それの単体テストにPathBufが深く関与しているためです。
ただ、現在本筋のプロジェクトで、そもそもそのRust製のツールはいらないのでは? という本末転倒というか、抜本的すぎる結論に至ってしまったので、筆者が近いうちにこれらを使うことはないでしょう。
それでも、汎用的なロジックを外部に切り出せたことはよいと感じています。
いずれ、また面倒くさくなったときにこれらを思い出して使えればそれで重畳である、ということにしておきました。
Discussion