スライドづくりをはじめた

今週木曜日の Ruby Business Users Conference 2017 の LT 向けスライドを作りはじめた。

Ruby Business Users Conference 2017

Rabbit でサクッと作ろうと思っていたところ、タイトルが長過ぎて詰んでいた。

長いタイトルでも大丈夫なテーマを探す or 作るという手もあるが、スライドづくりそっちのけで本末転倒になりそうなので、久しぶりに Keynote 使うかーという気持ち。

Rails (OSS) パッチ会

ざっくりトピックに上がったことなどのサマリ。

  • Unicode まわりのはなし (後の mtsmfm の PR に繋がる)
  • ImageMagick 6 から 7 で動きが変わっていて RMagick は大変そうらしい (後でみたら MiniMagick はその辺り対応したテストが落ちているっぽい)
  • ファイル名変更などを追う際には git log –follow
  • GitHub 上で特定のコード位置を示した URL で master だとパーマメントな内容にならないので、その時点のコミットの URL をサクッと出したいのであれば “y” ショートカットを使うと良い (自分も OSS Gate でビギナーの人に伝えていた。便利なのでオススメのショートカット)
  • PR を出したものの GitHub 上でオーナーの動きがなさそうで、GitHub 上で連絡先も分からない場合は、git log で宛先を見てみると良い (昔はメールでパッチを送っていたのでなるほど)

懇親会は、インターネットで見つけた『郷味』という居酒屋。🍶も肴もなかなか美味しかったのでオススメ。

OSSにPull Requestを出すパターン

表題について、OSS Gate やその他での FAQ っぽくなってきたので記しておく。

travis の設定がある時点の Travis CI と合っていない

GitHub 上の対象リポジトリの CI が壊れているのを見つけるのが基点になる。対象の Travis CI のエラーログを見て失敗の原因を見てみるのが初手。最近だと .travis.yml の設定がある時点の Travis CI と合っていない現象としてこういったものがあったりするので、調査をして .travis.yml を変更した PR を出す。CI をパスしなければ継続調査となる。

このケースはだいたいテストの実行以前の bundle install 周辺で落ちていることが多い。

既存のテストが落ちている

達人プログラマーにも書かれているいわゆる割れ窓理論。CI でのテストが落ちているようであれば、手元に持って来たコードで同様にテストが落ちることを確認して、テストをパスさせて PR を出す。

依存ミドルウェアとのバージョンが噛み合ずに CI のテストが落ちている

依存ミドルウェアのある Gem で CI が落ちていて、手元でのテストがパスする場合は Travis CI 上で使っているミドルウェアのバージョンを見てみて、バージョン齟齬があるようであれば .travis の before_script あたりを変更することになる。

RailsRuby のバージョンが合わない

Rails 5 では Ruby 2.2.2 以降のみサポートしているため、その要件を満たさずにエラーになっている場合がある。.travis.yml の matrix にある allow_failures をメンテナンスして PR を出す。

Travis CI の Ruby のバージョンがメンテナンスされていない

いまだと Ruby 2.4.0 対応していない .travis.yml のプロダクトがそれなりにあると思うので、README.md にサポートしている Ruby バージョンが示されているようであればそれも合わせて変更した PR を出す。もちろん手元で対象の Ruby バージョンで動くことを見てから PR を出すのは大前提で、もし動かなければその修正も行なった PR にする。

EOL の Ruby が落ちている

EOL の Ruby をパスさせるのが大変そうであれば、メンテナンスコストと秤にかけてドロップすることを提案した PR を出す。EOL の Ruby をどう扱うかはオーナー次第なので回答にあわせてどうするか検討を進めていくことになる。

Rails のアップグレードで動かない

Rails アプリケーションで Rails のバージョンを上げたら動かないといった際に、Gem が対象の Rails のバージョンに対応していないようであれば対応して PR を出す。

テストを実行すると警告が発生する

テスト実行辞意 Ruby 本体、RSpec あるいは MiniTest が出力する警告があれば消す。特に Ruby 本体が出す警告は、その Gem なりを使う側のアプリケーションでも出力されている可能性があるため有用な PR になると思う。

Edge Ruby でテストが落ちる

手元で ruby 2.5.0dev を使って、テストがとおらない Gem があれば調査をする。Edge Ruby が原因で動かないといったことは (経験上) 滅多になく、単体の Gem 基点ではなかなか見つかるものではないので、使っている Rails アプリケーションで Edge Ruby を使った際に何らかの不具合があれば対応するといった流れ。必要に応じて、bugs.ruby-lang.org への ISSUE なども検討することになる。

typo の修正

SSIA.

機能提案をする

自分が欲しい機能がないのであれば、その機能があると良い背景を説明した PR を出す。機能提案は上記のような expected に actual を合わせに行くといったものとは違い、as-is より to-be の方が優れているなぜならばといった話の流れになるため、やや上級者向きだと思っている。余談だが、Rails のように多数のコンポーネント間での相互作用が多い Gem よりも、RuboCop のように新たな Cop を add-on できるような Gem の方が機能提案はしやすいように感じているが、このあたりは個人差がありそう。


ぱっと思い当たるあたりだとこのあたりになる。自分が PR を出している経験則を元にしているので、これ意外にも多くのパターンがあると思う。

おまけ

使っているアプリケーションの Gemfile.lock に書かれている (gem でインストールする) プロダクトについて、対象を手元でパッと探索、確認、変更できるように ghq + gem-src の環境を作っておと PR が捗るのでオススメ。

ghq と gem-src については過去のエントリ参照。

koic.hatenablog.com

非トランザクショナルリソースを含むトランザクション

たぶん5年以上に渡って、何度かコードレビューで話している気がするのでポインタを作っておく。

TL; DR

RDBMS の恩恵を受けられるトランザクショナルリソースと、ひとつの非トランザクショナルリソースでトランザクションを括る場合は、例外発生時にロールバック可能な RDBMS のリソース方を先に操作する。

もう少し書く

以下は雑に書いたサンプルコード。この foo メソッドは、トランザクション境界となるコントローラやバッチにあるメソッドを想定している。Alternative Rails な考えを持った設計の場合はサービスレイヤーに置かれるメソッドとなる。

def foo
  ActiveRecord::Base.transaction do
    current_user.update!(foo: params[:foo])

    Model.create!(bar: params[:bar])

    API.delete!(current_user.an_attribute)
  end
end

上記サンプルコードの current_userModelActiveRecord のモデル、つまり RDBMSトランザクションロールバックできるものとする。一方で API はここではロールバックできない API の呼び出しとする (ロールバック API を用意していればまた別の巻き戻し実装を考えられる) 。API に関してはロールバックできないファイルシステムなんかに置き換えて考えても良いかもしれない。

これら3つのメソッドを呼んだ際に例外が発生した際に、データをロールバックすることを期待したものとなる (実際に API での通信での例外の場合は、起きた例外によって処理を振り分ける必要があると思うのがここでは簡略化している) 。

(常にこの設計が正しいわけではなく、コンテキストにより設計が変わる例として、例外を発生させない非トランザクショナルリソースへの操作について、RDBMS リソースのコミットが成功した場合は常に後続の処理を行なうとして AR::Base.transaction の外に置くというアプローチもある。)

ポイントとしては3つ。

  1. AR::Base.transaction で囲む (基本)
  2. transaction 内のリソース更新では、失敗時に例外を起こす破壊的メソッドを (用意して) 呼び出す
  3. 先にロールバック可能な RDBMS のトランザクショナルリソースへの操作をしておいて、最後に失敗したら巻き戻しのできない非トランザクショナルリソースを操作する

順番を変えて current_user.update!API.delete!Mode.create! のの流れで考えると、最後の Model.create! の際に例外が起きたときに非トランザクショナルリソースの API.delete! に対してロールバックできないという問題が起きる。

補足の Pro tip としては、必要に応じた rescue による例外処理を入れるなどある。

自分が出しているFixnum警告のPRで未マージのもの

Ruby 2.4.0 以降の Fixnum 警告に関連して、自分が出していた PR のうち、この日記の日付で未マージのもの。意外と残り少なかった。

去年、ローカルの ghq 管理リポジトリを ag で雑に串刺し検索して対応していたものもある中で、実際のところマージされていなくても困っていないものもあるが、そうでないのもある。Gemfile 指定は最後の武器にしておきたいので、そうでないものはどうするかなといったところ。