OSSのソースコードを読む時に意識していること
こんにちは!サーバーサイドエンジニアの越川です。
今回は、先日のiCARE Dev Meetup#31 で登壇した内容を加筆修正してブログに書き起こしてみました。
お時間ある時に読んでいただければ幸いです。
OSS のソースコードを読むときに意識していること
先日iCARE Dev チームで出版させていただいた CarelyTechZine では、『2要素認証の仕組みを提供するGem「rotp」のソースコードを追ってみた』と題しまして、rotpのソースコードを追って挙動の理解を試みる記事を書かせていただいたのですが、この記事では、「rotp」をはじめとした、OSS(オープンソースソフトウェア) のソースコードを読むときに意識していることを列挙したいと思います。
批判的に読む
筆者は OSS のソースコードを読むまで、
『著名な OSS はたくさんメンテナーがいて、ベストプラクティスとされるコードが書かれている。』
と思っていたのですが、ここ最近 OSS 活動を行ううちに、「どうやらそうでもなさそうだ」と認識を改めるようになり、「今書かれているコードが正しい」という思い込みは捨てて、批判的に読むことを意識するようにしています。
ここで、そう思うに至ったいくつかの事例を紹介します。
Rails7のHTTP Request Headerの中にRails7からは不要になると思われるHeaderが含まれていた
Internet Explorer 11(以下IE)のサポートが2022年の6月で終了する予定になっていますが、Rails7 には IE を使わない前提の変更が組み込まれています。
Rails にはデフォルトでいくつかの Http Request Header が含まれるようになっているのですが、その中に IE での仕様を想定した Request Header が組み込まれたままになっていたため、「このHeaderは不要なのではないか?」という旨の issue を立てさせて頂きました。
https://github.com/rails/rails/issues/43948
結果的に他の方にPRを提出していただき、Rails 7.1で世に出るようなので、 issue を立ててよかったと考えています。(PR を私もよりも先に出されてしまったのは悔しい限りです。)
Rails 5.1 以降では非推奨のメソッドが devise で使われている
認証機能を提供する Gem 「devise」 で、モジュールの一部に changed? という Rails5.1 以降では非推奨になっているメソッドが使われているという事例です。
https://github.com/heartcombo/devise/issues/5421
こちらも変更点としては軽微なものにはなりますが、非推奨のメソッドの修正というのはどの OSS でも発生しうる問題のため、OSS への貢献チャンスなのではないかと考えています。
ワクチン接種証明のQRコードの発行/読み取り ができるGemの使い方の説明ファイルが間違っていた
health_cards というワクチン接種証明の QRコード の発行/読み取り ができる Gem があるのですが、USAGE.md というファイルの内容に誤りがあったため、issue を立てさせていただいたというものになります。
https://github.com/dvci/health_cards/issues/101
こちらも中の人から返事があり、現在は修正されています。
なぜ変更が必要だったのかを追う
なぜ変更が必要だったのかを追うようにすると、「そういうケースがあるのか」という知見が溜まるようになるのが大きなメリットかなと考えています。
いわゆる「できるエンジニア」は経験知が非常に深く、いろいろなケースに遭遇しているから問題解決が早い、という肌感を持っているので、「いろいろなケース」をたくさん経験するには、なぜ変更が必要だったのかを追うのが最適ではないかと考えています。
こちらもいくつか事例を紹介します。
ASCII-8BIT ではない文字列が含まれている場合、JSON.generateに失敗することがある
Sentry というエラートラッキングのツールがあるのですが、Ruby 向けの SDK である sentry-ruby 内で、「ASCII-8BIT ではない文字列が含まれている場合、JSON.generate に失敗することがある」という事象が発生していたようです。
https://github.com/getsentry/sentry-ruby/issues/1475
この事象を受け、修正された内容が以下になります。
https://github.com/getsentry/sentry-ruby/pull/1484/files
この事例からわかるのは、「ASCII-8BIT ではない文字列が含まれている場合、JSON.generate に失敗することがある」ので、「もしASCII-8BIT ではない文字列を JSON として parse する際には、parse 対象の文字列のエンコーディングに注意」という知見を得ることができます。
当該 issue は問題の再現手順や、なぜこの問題が発生するのか、他のライブラリはどう対処しているのか、等が記載されており、非常にわかりやすい内容になっていました。これだけ書いてくれると、事情をよく知らない人も助かりますね。
ruby-samlでDos攻撃の可能性のあるコードが含まれていた
ruby-saml というSAMLによる SSO(シングルサインオン) のロジックを提供する Gem があるのですが、内部で Dos攻撃 に対し脆弱なコードが含まれていた(現在は修正済み)ため、issue が立てられていました。
https://github.com/onelogin/ruby-saml/pull/383
それに対しての修正内容が以下のスクショです。
https://github.com/onelogin/ruby-saml/commit/533c84ebfc40f8cbac645b6c76ce4949f95d27d6
25万バイト以上のXMLファイルだった場合は例外をthrowするように修正されていました。
ファイルのparseを扱う処理では、常に想定よりも大きいサイズのファイルが渡されないかに気をつけながらコーディングする必要があるという知見が得られますね。
また、後続のPRでは、「25万バイト以上の問題のないファイルでもエラーにならないように、config で外部からバリデーションに使う値を設定できるようにした方がいい」という issue が立てられ、修正が入っていました。
ここでも、「config で設定できるような値は切り出すようにする」という知見が得られました。
読んでもわからない時は実際に動かす
なんの捻りもない話ですが、結局読んでもよくわからなくなってしまったら、実際に動かしてしまうのが一番早い気がしています。
私は主に以下のやり方で動かしています。
- サンプルアプリを作って適当な箇所に binding.pry を書く
- REPL が起動したら、step するとメソッドの内部に移動できるので、next 交えつつ適宜実行する
- 挙動は理解できるが意図までわからない場合はコミットメッセージを読んだり PR や issue も確認する
- それでもわからない場合はコード書いた人に意図を聞いてみる
大体のケースでコミットメッセージを読んだり PR や issue も確認すれば意図は理解できるんですが、それでもわからない場合はコード書いた人に意図を聞いてみるのが一番かと思います。
まとめ
- 「今書かれているコードが正しい」という思い込みは捨てて、批判的に読む
- なぜ変更が必要だったのかを追うことで、コードを読んで挙動を把握するだけよりもかなり知見が溜まる
- 読んでもわからない時は実際に動かすことで、挙動の理解を深める
上記のことはOSSのソースコードを読むときでも、普段の業務でのコーディングでも意識すべきことなのではないかと思っています。
また、技術力を向上させるには、結局は「場数」を踏む必要があると考えており、その「場数」に OSS のコードリーディングは最適なのではないかとも考えています。
OSSのコードリーディングをすることで技術力の向上に繋がり、あわよくば不具合を見つけて修正PRを出せば、OSS界隈にも貢献できるので一石二鳥ですね。
では、皆さんも素敵なOSS活動ライフを!