ヌーラボでScalaを書くRubyistの谷本です。
数年ぶりに開発環境をWindowsにしたら、JRubyのバグっぽい振る舞いを見つけたので、原因を探してPRを送るまでの自分のやり方について書きます。(ちなみに、仕事では全くJRubyを使っていません。)
目次
経緯
去年、2年間使っていたMacbook Proの調子が悪くなったで、PCの買い替えタイミングで数年ぶりに開発環境をWindowsにしました。
そこで、仕事ではJVM言語(Scala)を使っていることや数年前はJRubyを使っていたこと、インストールが簡単なことなどから、JRubyを使うことにしました。
しかし、いざ使ってみるとREPLモードであるirb
で矢印キーを使ったカーソル移動や入力の履歴をさかのぼることができませんでした。macOSで使っていた時や数年前にWindowsで使っていた時は問題なく動いていた記憶があったので、Windows固有の問題でデグレして使えなくなっているのではないかと考え、デグレなら古いコードを参考にすれば直せるかもと予測し、どこが問題かを探してPull Request(以下、PR)を送って見ることにしました。
既知の問題ではないか、すでに修正済みではないかを確認
OSSのメンテナに負担をかけないためや、自身の二度手間にならないようにするため、ほかの人と報告や修正が重複しないか調べます。
既知の問題か検索する
活発なOSSはIssueやPRがGitHubなどでしっかりと管理されているので検索をすれば大体既知の問題かがわかります。JRubyはWindows固有のIssueやPRをwindows
というタグを振って管理してくれているのでより検索しやすいです。このように検索をしやすく管理してくれているとIssueを立てたりPRを送ったりしたい人にとってはうれしいと思うので、日頃の仕事でも参考にしたいところです。
すでに修正済みか確認する
検索で同一の報告が見つからなかったら、最新のリリースバージョンと未リリースの最新コードでも修正がされていないか確認します。
JRubyの場合、最新リリースはJRubyのDownloadページからダウンロードできるのでそれを使って確認できます。
未リリースの最新コードの確認にはビルドが必要なので、ビルド環境を作ります。Dockerを使って環境をリセットしやすくしておくと便利です。もし、最新コードでビルドが成功しない場合、環境がよくないのか、最新コードがビルドできないものなのかを切り分けるため、リリースされたコミットでビルドします。JRubyの場合はビルド方法がBUILDING.md
というファイルにまとまっていて、それによればJDKが入っていれば./mvnw
を実行すればビルドできます。シンプルに作られていてとても簡単です。
なぜ振る舞いが変わったかを調べる
ビルドが成功して、無事に(?)修正が入っていないことが確認できたら、なぜそのような動きをしているかに着目してみます。単に考慮されていなかっただけなのか、意図したものなのか、他のバグ修正で顕在化したのかなどを切り分けることでIssue/PR内で論理的に説明するために役に立ちます。
どのバージョンで振る舞いが変わったのかを確認する
毎回ビルドして確認していては時間がかかるので、まずはリリース済みのものを使ってどのバージョンとどのバージョンの間で振る舞いが変わったのかを確認します。
確認した結果、今回は矢印キーの振る舞いは二度変わっていることがわかりました。
一つは、1.7.1と1.7.5の間のどこかで矢印キーがコマンドプロンプトと同じ動作をしていたものが矢印キーをタイプすると潭潯潼澑
と入力されるように変わりました。(1.7.2と1.7.3、1.7.4はリンク切れでダウンロードできなくなっていたため確認できず)
もう一つは9.1.2.0と9.1.3.0の間で、潭潯潼澑
と入力されていたものが、現在の最新と同じように矢印キーの反応がなくなるというように変わりました。
どのコミットで振る舞いが変わったのかを確認する
ビルドしながらどのコミットで振る舞いが変わったかを確認していきます。ある程度の前提知識があると予測しやすく絞り込みが早く終わります。例えば、今回はREPLモードで起こっている問題なので、GNU Readlineという名前に聞き覚えがあったりRubyでreadlineという名前のライブラリがあることを知っていたりとかです。これらを知っていればgit grep
やgit log -S"readline"
、git ls-files
とかを駆使して絞り込みやすくなります。
前提知識があまりないものの場合は地道に2分探索して探すとかくらいでしょう。
なぜその振る舞いになっているのか理解する
コミットが特定出来たら、コミットコメントを読んだり、コミット前後の動きを実際に確認したり、コードを変更したりして、なぜそのコミットがpushがされたのかや振る舞いが変わったのは意図したものなのかを理解します。
今回の場合だと、1.7.1から1.7.5の間で振る舞いが変わったのはjruby/jruby/commit/48c21267b1あたりのコミットでJLineの読み込みが変わったもしくは正しく読み込めていなかったものが読み込めるようになったようです。9.1.3.0で振る舞いが変わったのはjruby/jruby-readline/commit/36c4315167で、JLineのデフォルトのIOであるSystem.in
とSystem.out
を使うのではなくJRubyが持つIOの方が自然だと判断し変更されたようです。
Issueを報告する or PRを作る
何が問題なのか、いつからどういう振る舞いをしているのか、その原因や起点になっているコミットは何なのか、どうしたら期待する振る舞いになるのかを整理してIssue or PRを作ります。
いろいろ試したら1.7.5からの振る舞いはJLineの2.12以上を使うと解決したので、JLineのバージョンを上げる必要があることを書き、9.1.3.0からの振る舞いはIOまわりで詳細を追うのが自分にとって難しかったのと、それほどJRubyのIOオブジェクトを使う必要も高くなさそうに思ったので変更を戻すPRにしました。
調査とPRを振り返って
仕事で書いているコード以外を読むのは、違う知識が必要になったりして勉強になって面白かったです。
ただ、IOまわりの詳細まで追うだけの気力や能力が足りず完璧な修正ができませんでした。(PR内でもあまりよくないよねという話をしています。)PRにせずIssueくらいでもよかったかもなぁと思いつつ、もう少しIO周りまで追った方がよかったなぁと思っているので、時間を作ってIO周りまで追ってみたいです。