RuboCop Oracleをリリースした

RuboCop Oracleを実装してリリースした。

github.com

長年 RDBMSOracle (Active Record Oracle enhanced adapter) を使った運用をしているが、これは無停止リリースを行うにあたってのマイグレーションの tip を cop にして含んでおいたもの。

最初の v0.1.0 リリースで含んでいるのは Oracle/OnlineIndex cop 単品。これは CREATE INDEX の際に ONLINE オプションをついていないマイグレーションファイルを検知する cop です。

docs.oracle.com

Oracle/OnlineIndex cop

データベースのインデックス追加を行う際は ONLINE オプションを付けないと OLTP (オンライントランザクション処理) が有効にならず、オンライン稼働のままインデックス作成を行おうとするとオンライン処理とそれぞれ処理待ちになりうる (結果としてオンラインサービス影響が起きうる) 。

この Oracle/OnlineIndex cop の bad と good は以下。options: :online を付与することで OLTP が有効になる。

# bad
add_index :table_name, :column_name

# good
add_index :table_name, :column_name, options: :online

マイナス面としては OLTP を有効にしたときよりも処理が遅くなるといったことがありうるが、無停止でサービス影響なしで進めるのを第一に ONLINE オプションを付けておこうという判断をするプロジェクトには有効だと思う。

また Oracle/OnlineIndex cop のオプションとして MigratedSchemaVersion というものがある。たとえば、RuboCop Oracle 導入以前に db/migrate/202104130150_add_title_index_to_articles.rb まで本番環境に適用済みであれば、それ以前のマイグレーションファイルへの ONLINE オプションの付与を検知したくない場合に、適用済みのマイグレーションバージョンを記すことで、適用済みのマイグレーションファイルへの検出を防ぐことができる。

Oracle/OnlineIndex:
  MigratedSchemaVersion: '202104130150'

git による並列開発で、必ずしもマイグレーションバージョンのタイムスタンプが過去から未来へと流れているわけではないが、だいたいはうまくいくだろう。bin/rails db:migrate:status あるいはその内部 API を使えばさらに誤検知を防げるだろうが、静的解析の域を超えるので実装はしないことにしている。そのあたりはコードレビュー掛け合わせになるだろう。

開発雑記

RuboCop Oracle の開発構想自体はずいぶんと前からあって、一番の悩みは名前だった。Active Record Oracle enhanced adapter をもう少し前面に出した名前にするか悩んだが、gem で公開するときの名前をシンプルにしたかったのと、gem + RuboCop の世界で Oracle を冠して困るようなことはなかろうとやや大きめの名前だが RuboCop Oracle にした。 また、RuboCop Rails に含めた cop にすることも少しだけ考えたが、Oracle adapter 特化なので独自の gem にした。

そのほか、RuboCop Rails でもマイグレーションファイルへのルール検知をしたいという PR がいくつかあるが、マイグレーションファイルは適用済みかどうかの観点も重要なため取り込めていないものがある。今回の MigratedSchemaVersion はその課題に対するひとつの習作となっている。デフォルトで db/schema.rb のスキーマバージョンを活用するなど、もう少しリッチにするかもしれない (など、まだ改善の余地がある) 。

あとプロダクト自体のドキュメンテーションはもう少し整えておく予定。

Oracle x Rails でのサービス運用をしているプロジェクト向けですが、ご活用ください。