特定のリポジトリに対して機能追加・変更やバグ修正などを行う場合、エンジニアはPull Requestを発行します。プログラミングを続ける過程で数えきれないほど発行されるPull Requestは「エンジニアが歩んできた道のりそのもの」と言っても過言ではありません。
ならば、オープンソースコミュニティで活躍する方々が「特に印象に残っているPull Request」には、その人のOSS活動への思いや日々の研鑽が結実しているのではないでしょうか。今回は8名の著名エンジニアの方々に回答していただきました。
※人名の50音順に掲載。回答者は敬称略。
伊藤浩一が紹介『Change the max line length of Layout/LineLength to 120』
OSSでの確実なマージを狙うには、時に戦略を練ってから送ります。
その一例として、Rubyのリンター/コードフォーマッターであるRuboCopが検査するコード1行のデフォルト最大長80文字を120文字に変更した際の戦略の裏側を、3つのステップで紹介します。
1つ目は、とにかくパッチを送ることでした。まだ信頼がない地点から提案をするための戦略の初手です。私が見始めた当時は多くのイシューやバグがあったため、ひたすらパッチを送りました。パッチを送ることでまずコードと発言への信頼を築きました。
2つ目は、Metrics/LineLengthという名前を、Layout/LineLengthに変えることでした。コードの複雑性の検出が焦点だと、その指標値の根拠を示すのが難しいです。一方でレイアウトであれば、その不利益の根拠を伝えることができます。LineLengthの解決方法は、行の折り返しや本意でない短い名前への変更といったケースがほとんどですが、これはコードの複雑性に対する解決ではありません。
3つ目が本丸です。コードの複雑性という問題でなくなった以上、現代的なコード1行の最大長の値は何かというレイアウトに問題点を絞り込めます。ここではヘッドメンテナーが調査フォームを作るなどして、それらしき値をデフォルト値とするメンテナーの合意形成を取りました。
足掛け3年半での実現という思い出深いPull Requestになりました。確実にマージされたいPull Requestは、時に戦略を練った伏線手順で送っていくことを念頭に置いてみるのもひとつかもしれません。
【プロフィール】
株式会社永和システムマネジメントのエンジニアリングマネージャー。アジャイルソフトウェア開発手法を背景にRuby on Railsを用いたWebアプリケーションの開発ならびにプロジェクト運営に多く携わってきており、実践と理論に基づいた開発組織のエンジニアリングマネジメントを行っている。Rubyの静的解析ツールであるRuboCopコアチームの開発者として、オープンソースソフトウェアの開発も活発に行っている。
遠藤侑介が紹介『addr2line.c: Support DWARF 5』
Rubyの異常終了時のログを見たことはあるでしょうか?たとえばこのissueにあるようなログです。C level backtrace informationのところがとても重要で、どのC関数の実行中に異常が起きたかを示しています。
地味ですが、このバックトレース表示機能はRubyの安定性・信頼性にとても貢献してきました。バグ報告にこの情報があると、トリアージ・分析・修正が大幅に容易になります。この表示がなかった時代は、「Rubyが異常終了しました」「デバッガ(gdb)でバックトレースは取れますか?」「gdbってどう使うんですか?」みたいなやりとりの末、結局原因不明ということも多かったのです。
この表示は、Cコンパイラが出力するデバッグ情報(DWARFといいます)を、Rubyが自力で処理して出しています。この初期の実装をしたのは私ではないのですが、自力実装の何が大変かと言うと、メンテナンスが必要ということです。
背景説明が長くなりました。今回取り上げた私のPull Requestは、Rubyのバックトレース表示機能をDWARFの最新バージョン5に対応させるというものです。新しいCコンパイラがDWARF 5を使い出したため、このログがうまく出力されないことが増えていたのでした。500ページほどもあるDWARFの仕様書と格闘しながらサポートしたことを覚えています。Rubyの安定性・信頼性は、このような地味な努力に支えられています。
なお、Cレベルトレースを取得するには、libbacktraceというライブラリもあります。Rubyがそれを使っていないのは、libbacktraceの登場(2016年)より前の2010年に実装したからという歴史的経緯なのですが、libbacktraceは一部の環境で異常終了のシグナルハンドラからトレースが取れない(?)という話も聞いたことがあります。腕に覚えがある人は、libbacktraceにも手を入れるつもりでチャレンジしてみるといいかもしれません。
【プロフィール】
STORES株式会社で働くフルタイムRubyコミッター。OSSであるプログラミング言語Rubyの開発運営に業務として取り組んでいる。これまでの主な貢献は、キーワード引数の設計と実装(Ruby 2.0、Ruby 3.0)、コードカバレッジ測定機能(Ruby 1.9)、型推論器TypeProf(Ruby 3.0)など。
笹田耕一が紹介『M:N thread scheduler for Ractors』
このPull Requestはスレッド管理を軽量にするためのM:NスレッドスケジューラをRubyに導入するものです(詳細はM:Nスレッドによる軽量な並行処理への挑戦 | gihyo.jpなど)。このチケットは、マルチスレッドプログラミングをいい感じにしなければならず、それはそれで苦労したのですが、本稿では別の話を。
このチケットはスレッド周りの処理をまるっと換骨奪胎するというもので、そこそこ大きな変更になっています。これに限らずRubyへVMを導入したり、GCを変更したりと、大きめの変更をときどき入れてしまうのですが、それを受け入れてくださるコミュニティにいつも感謝しています(受け入れるには勇気が要りますよね)。受け入れてもらいやすくするために、根回ししたり、テストをがんばったり(詳細はRubyインタプリタの品質向上のために個人的にやっていること - クックパッド開発者ブログ など)しています。
大変なことも多いですが、自分の目指すソフトウェアのために大きく前進させるというのは、なかなか気分が良いです。でも、自分がレビューする側になるとウッとなるので(因果応報)、受け入れる側としても自分の懐を深くしないといけないですね。
【プロフィール】
大学在学時からRuby向け仮想マシンYARVを開発し、2007年に「Ruby 1.9」に採用される。以降、Rubyコミッターとして、言語処理系の高速化に従事。STORES株式会社所属。Rubyアソシエーション理事(2012年~現任)。博士(情報理工学)。
清水川貴之が紹介『support multibyte filename handling.』
※BitBucketからGitHubに移行してPull Requestはなくなってしまったため、コミットURLを記載
このPull Requestは、Sphinx(Pythonドキュメントジェネレータ)で日本語ファイル名を扱えるようにする修正です。このPull Requestが取り込まれた後にSphinxの多言語サポート強化のPull Requestをいくつも出して、その半年後にSphinxのコミッターとして活動し始める流れの最初の一歩だったと思います。
Sphinxを日本語で普通に使えるようにと、2012年頃からバグ修正や機能改善のPull Requestを出していました。当時はPython3.2がリリースされていましたがまだまだPython2を使うのが一般的で、Python2では日本語などのマルチバイト文字列を扱うには一工夫必要な時代でした。このため、英語圏で書かれたソフトウェアでは日本語が上手く扱えないのが当然、という状況でした。
このPull Requestも一度リジェクトされてしまいました。その頃は私自身OSSへのコントリビューション経験がほとんどなく、英語も不慣れだったため、この修正がなぜ必要なのかを説明できていなかったり、レビューコメントでの会話でも意図の読み違えなどがあったりしたんじゃないかと思います。
指摘を踏まえてPull Requestを出し直し、最終的にはマージしてもらえました。今見るとコード差分はそれほど大きくありませんが、当時はとても苦労して達成したPull Requestです。
【プロフィール】
株式会社ビープラウド所属。一般社団法人PyCon JP Association会計理事。2003年からPythonを使い始めて今年で21年目。Python関連イベント運営や、カンファレンス参加、書籍執筆、OSS開発を通じて技術情報を発信している。著書/訳書に『エキスパートPythonプログラミング 改訂4版』(2023年 アスキードワンゴ)、『独学コンピューターサイエンティスト』(2022年 日経BP社)、『自走プログラマー』(2020年 技術評論社)等。
Shougoが紹介『feat: Getregion function』
このPull Requestは新機能の追加で、選択範囲をVim scriptから取得できるようにするためのものである。これには元々ベースとなるコードがあり、ユーザーからの強い要望もあったのですんなりマージされると考えていた。しかし、ユーザーからの要望が幅広かった上にneovimの既存機能との互換性も考慮してどのような仕様にするかをかなり揉めることになった。私が出したPull Requestのなかでも一番時間がかかったのではないだろうか。
最終的には機能の名前も変更して、ユーザーから要望されたことを全て実現できるようにし、neovim側の機能でできることも全てできるようになり完成した。これから学んだことは、新機能の仕様を決めるのはとても時間がかかり大変だということである。
仕様を一度決めると互換性の問題もあり簡単には変えられない。実装の容易さで適当に仕様を決めると後悔することになる。自分の場合はプラグイン側の事情も本体側の事情もわかるので対応しやすかったはずなのだが、それでも苦労した。
【プロフィール】
長年Vim/neovimのプラグイン開発、本体の機能開発やバグ修正を行っている。独自の哲学を持っており、テキストエディタの設定が大好きである。ユーザーは皆テキストエディタを自分で設定するべきで、デフォルトマッピングやデフォルト設定は悪であると考えている。
Sosuke Suzukiが紹介『Keep a trailing comma in tsx type parameter』
このPull Requestは、現在私がメンテナーを務めているPrettierに最初に出したもので、すぐマージされて1.18.0としてリリースされました。
しかし実は、このPull Requestには影響範囲がとても大きいバグが含まれていたのです!具体的には、TypeScriptのコードで単一の型引数を受け取る関数やインターフェースなどがあったとき、末尾カンマを付けてしまうというバグがありました。
// Input function func\<T\>() {} // Ouput function func\<T,\>() {}
1.18.0がリリースされた日の朝、私は大学の1限の授業を受けるために朝8時くらいに起きて、やたらとメンションが来ていることに気がつきました。
1限の授業ではパソコンを開くことができなかったため、頭のなかで修正パッチを書いて、休み時間にPull Requestを作りました。すぐマージされて、修正版の1.18.1がリリースされ、事態は収束しました。
この経験によって、OSSが良くも悪くも多くの人々に影響を与えるということ、そして、やらかしても意外となんとかなることを学びました。結果的には、良い失敗だったと思っています。
【プロフィール】
筑波大学情報学群の学生で、Ubie株式会社のソフトウェアエンジニア。「テクノロジーで人々を適切な医療に案内する」ことを目指して、症状検索エンジン「ユビー」の開発に尽力している。また、JavaScriptのコードフォーマッターであるPrettierのメンテナーや、ブラウザエンジンであるWebKitのコミッターとしても活動中。
Toru Kobayashiが紹介『[Fiber] Fix to call deferred callbackQueue even if updates are aborted』
このPull Requestは、私にとって最も印象に残っているもののひとつです。実装についてはたった1行のコード変更に見えますが、実際にはその背景に多くの時間と労力が詰まっています。バグを認識してから修正に至るまで、何日も試行錯誤を重ねたことを今でも鮮明に覚えています。
このPull RequestはReactが内部アーキテクチャの完全な置き換えを行っている活動に対してのものです。当時、Reactは既存の「Stack」から、新しい「Fiber」アーキテクチャへの移行を進めていました。Fiberは、再帰的なレンダリングを中断可能なレンダリングに変更することで、より柔軟で効率的なUI更新を可能にするもので、SuspenseやTransitionなど現在のReactの基盤となっています。
私自身、この新しいアーキテクチャにとても興味があったため毎日コードを読み、多くはないですがバグ修正や未実装の機能の実装を行っていました。最初はただ画面がレンダリングできるところから、どんどん更新などもできるようになっていくのはとてもエキサイティングでした。
当然、既存の挙動を大きく変えることなく内部のアーキテクチャを完全に刷新することは容易なものではありません。Reactチームが採ったアプローチからは、実装だけではなく、どのように内部実装の刷新を通常の機能開発と並行して行うのかなど多くのことを学びました。
たとえば、Pull RequestのDiffに含まれている「text-passing.txt」は新しい実装に対して既存のテストと同等のものを実装し、テストがパスしたことを記録していくファイルです。これにより、どのテストが新しい実装でもパスしているのかわかります。
当時はこのデータを用いて「Is Fiber Ready Yet」というサイトで進捗が確認できるようになっていました。このアプローチは最近ではNext.jsがTurbopackへの移行に採用していました。
また実装面でも、適切なデータ構造の扱い方や最適化、プログラミングテクニックなど多くのことを学びました。これらは実際にコントリビュートすることで得られた経験だと感じています。
StackとFiberの実装の違いや内部で使われている仕組み(注: 現在は変わっているものもあります)に興味があれば、筆者が2018年にカンファレンスで登壇したときの資料をご覧ください。
【プロフィール】
2024年よりメルカリでフロントエンドエンジニアとして働いている。同時にSmartHRにてフロントエンドの技術顧問として関わっている。また、React関連のOSSのメンテナーやReact公式サイトの翻訳のメンテナンスをしている。
mattnが紹介『Add japanese translation files』
Jupyter NotebookのUIメッセージ表示を日本語化する翻訳Pull Requestです。翻訳は単調なようで、そこそこパワーが必要な作業です。それ故に誰もやりたがらない作業です。実際にこの翻訳をするのに、半日以上の作業が必要でした。
しかし翻訳はそれ以上に得られるものが大きい作業です。UIのメッセージを翻訳することで、それまで知らなかったJupyter Notebookの機能を知ることができます。それだけではありません。翻訳Pull Requestは英語が得意ではない多くの人たちが持っている、そのソフトウェアに対するUI障壁を低くするため、その効果は個人に享受される範囲に留まりません。
このPull Requestにより翻訳されたファイルは現在JupyterLabへと引き継がれ、Jupyter NotebookだけでなくJupyterLabからも日本語UI表示として利用することができます。
【プロフィール】
OSSプログラマー。VimやGo言語などの開発・コミュニティ運営に参加し、2019年からGoogle Developer Expert。2021〜2023年 GitHub Stars。著書に『みんなのGo言語』、単著に『Go言語プログラミングエッセンス』がある。