今回から新たなテーマ「RubyGemsとRDocの密結合を解消する」になり、今回が実質初回になります!(1回目のライブはネットワークトラブルで中止に…)
初回の今回は issue として挙がっている「RubyGemsとRDocの密結合」について、その問題点と解決のためにどんなアプローチが取れるのか?について触れていきます。
RubyGems における RDoc への依存
gem install XXX
や bundle install XXX
などで開発者は gem を自身の環境にインストールしてくることができます。gem のインストールにおけるコアな処理は大まかには以下のような感じです。
- 対象の
.gem
をダウンロードしてくる - ダウンロードをした
.gem
を展開する - 展開したファイルを適切な場所に配置する
これで gem 自体は使える状態にはなるのですが、ただインストールしただけではやや不便な状態です。そこで RubyGems は開発者なら gem をインストールしたときに多くの人が必要としているであろうことを自動でやってくれています。
その中の一つとして RDoc によるドキュメントの生成を行なっています。
RDoc とはソースコードから HTML や Markdown 形式などのドキュメントを生成してくれるツールです。ネットに公開されているものだと Ruby on Rails API なんかは RDoc により生成されたドキュメントの例です。
RDoc により生成されたドキュメントを参照すれば、インストールしたての gem の使い方を簡単に知ることができて便利!なので RubyGems は自動でやってくれているというわけですね。
RubyGems が RDoc によりドキュメントを生成する処理は以下のコードの部分にあります。
# frozen_string_literal: true
require_relative "../rubygems"
begin
require "rdoc/rubygems_hook"
module Gem
RDoc = ::RDoc::RubygemsHook
end
Gem.done_installing(&Gem::RDoc.method(:generation_hook))
rescue LoadError
end
RubyGems の中から RDoc のメソッドを直接呼び出してこの処理を実現していることがわかります。この部分が RubyGems の RDoc への依存、言い換えれば密結合になっているというわけです。
密結合であることの問題点
密結合であることの問題点はメンテナンス性の悪さにあります。
もし RDoc 側が RubyGems でも使用している定数の名前を変更したくなったらどうでしょうか??
RDoc のメンテナーは自身のコードベースだけを見ていてもそれが RubyGems で使われているかどうかを気づくことができません。うっかり破壊的な変更を行なってしまえば RubyGems が動かなくなってしまうかもしれません。
運よく問題に気づいたとしてもコードは RubyGems 側にあります。メンテナンスする場合は RubyGems 側のメンテナーに修正を依頼して…と煩雑なやり取りが必要になります。密結合なアーキテクチャはこのようにどんどんと変更が難しいものになってしまうのです。
密結合を解消するアプローチ: Plugins
RubyGems は他のモジュールを使って自身を拡張することができる Plugins という機能があります。
インストールされた gem の中に rubygems_plugin
というファイルがあれば、そこをエンドポイントにして RubyGems から拡張機能を実行することができるというものです。
拡張機能はインタラクティブに呼び出されるようなものもありますが、Hooks を使うことで gem のインストール前に実行する、といったように RubyGems が行う処理のフローの中に Plugins で実現される処理を埋め込むことも可能です。
今回はこれを利用して密結合を解消していくことになります。RDoc 側のコードベースに rubygems_plugin
を作成して、 Hooks により gem の install 後にこの Plugin が実行されるようになっていれば良いわけです。
こうすることで RDoc によるドキュメント生成の処理は全て RDoc 側に寄せられます。今後は RubyGems 側のコードを意識することなく RDoc のメンテナーはコードをメンテナンスすることができます。
コメント