3行まとめ
- データエンジニアの界隈で日本からもっとOSSに貢献する人が増えるといいなと思ったので、自分が気を付けていることを事例多めでまとめました
- データエンジニアの界隈以外でも通じる内容が多いですが、データエンジニアリング文脈多めです
- 偉そうに書いてますが、自分もまだひよっこ卒業レベルです
- 3行まとめ
- 背景: データエンジニアリングの仕事にOSSは欠かせないが、継続的なメンテナンスは簡単ではない
- Pull Requestを送る前に気を付けていること
- Pull Requestを送る際に気を付けていること
- 脱線: なぜOSSにPull Requestを送るか
- 謝辞: OSS活動を背中で見せてくれていた方々
背景: データエンジニアリングの仕事にOSSは欠かせないが、継続的なメンテナンスは簡単ではない
私は最近データエンジニアリング関連のOSSにPull Requestをそれなりの頻度で送っています。2024年は約45個送っていて、送っている対象としてはdbt-osmosis / datacontract-cli / dbt-bigquery / dbterdなどでした。
- https://github.com/pulls?q=author%3Asyou6162+-user%3Asyou6162+is%3Apublic
- このURL、自分がOSSに対してどれくらい貢献しているか分かるので、user_nameのところを自分のGitHubのアカウント名にしてみると面白いと思います
こうした活動を行なっているのは「楽しいから」というのもありますが、どちらかというと「業務や事業に必要だから」という側面が大きいです。データエンジニアリングに関わる業務は、最近では少なくとも自分の回りだとOSSなしで回すのは難しい状況になってきています。例えば、私が所属している株式会社10Xにおいて、OSSであるdbt-osmosisやdatacontract-cliはメタデータ管理やData Contractの文脈において、重要な役割を果たしています。もちろん、こういったツールを自作することもできますが、これらのOSSのおかげで事業ドメインに深く関わる時間をより確保できている、という側面は見逃せません。
しかし、こういったツールのメンテナが十分に足りているかと言われれば、YESと言えるケースのほうが珍しいと思います。例えば、2024/12/09にdbt 1.9がリリースされました。しかし、周辺のエコシステムであるdbt-osmosisがdbt 1.9対応するには少し時間がかかりました。
また、Data Contractの文脈でも同じような状況があります。datacontract-cliは
- 様々な種類のデータ仕様書からのdatacontract-speficiationへの変換
- datacontract-speficiationから様々な種類のデータ仕様書への変換
をサポートしており、その中の一つにdbtへのサポートが挙げられます。しかし、一ヶ月ほど前はdbtへのサポートはかなり貧弱であり、primaryKey
/ not_null
/ unique
の記述がサポートされていませんでした。そのため、production環境で使うには機能不足でしたし、そもそもBigQueryが対象だとそもそもエラーで動かない、といった状況でした。
事業を下支えしてくれているOSSですが、基本的にはリポジトリオーナーのボランティアで成立していることが多いです。もちろん、dbt Labsのように事業会社がOSSをホストしている場合もありますが、OSSに対して潤沢に時間をかけているという会社はかなり稀でしょう。
データエンジニアリングに関わるOSSはこうした状況に置かれている場合が多いですが、日本のデータエンジニアでOSSの改善に関わる人は(Web開発界隈のSWEと比較すると)まだまだ多くはないと思っています。このエントリでは、これまでデータエンジニアリングのOSSにcontributeしたことがあまりない人の背中を押せるように、自分が最近Pull Requestを送っている際にどういったことに気を付けているのか、具体例を交えながら紹介しようと思います。
Pull Requestを送る前に気を付けていること
類似のissueがないか検索する
改善や修正のPull Requestを送る前に、類似のissueがないか検索しておきましょう。検索してみると、割と情報を得られることがあります。
- 以前に誰かが取り組んでみているが、ボトルネックや事前に解消すべき点が存在しており、思ったより混み入った問題である
- 解決方法の選択肢がいくつかあるが、どれがよいかコミュニティ内でまだ議論中である
- issueは存在するが、誰からの返信もなくそもそも継続的にメンテナンスされているか怪しい...
GitHubはissueに紐付くPull Requestなどもリンクで簡単に辿ることができるので、関連するPull Requestにも目を通しておくとよいでしょう。一発で解決することが難しいので、step by stepで解決に向けて動いている、ということはよくあります。進展が気になるissueやPull Requestがあれば、GitHubのsubscibeの機能を使うのもオススメです。半年くらい動きがなかったけど、急に進み始める、なんてことはよくあります。
issueやPull Requestでよく目にするアイコンは覚えておくとよいでしょう。そのリポジトリの勘所を知っている人だったり、自分がこれから出すPull Requestのレビュアーであることが多いからです。そういった人たちがどういった観点を気にしているかは重要な情報になります。
こういった調査は一文一文丁寧に全て読む必要はありません。私の場合は初手ではDeepLに翻訳してもらったり、意図がよく掴めないときに英語を精読し、それでも分からないときはChatGPTに英語のニュアンスなどを聞いてみたり、といった形で調査をしています。そもそも意図が不明瞭にしか書かれていない、という場合もあるので、そのケースでは意図を確認するなどのコメントをしてみるとよいでしょう。
dbtやdatacontractなど、ある程度ユーザー数が多いコミュニティの場合、Slackなどチャットでやり取りされているケースもあります。余裕があったり、深く調査したい場合はチャットツールについても検索するとよいでしょう。
issueで解決策の頭出しをしてみる
タイポなどの簡単な修正であれば不要なことも多いですが、新規の機能追加や多数の個所に関わるリファクタリングなどであれば、いきなりPull Requestを出さずにissueで頭出しをするのがよいでしょう。手がかかる修正だと思っていたケースがリポジトリに対して深い知識がある人がいいポインタを教えてくれることもありますし、簡単だと思った修正に意外と難色を示されることもあります。
以下のissueは具体例で、datacontract-cliのimportとexportの情報が不足しているので追加したい、というものです。様子を聞いてみた上で、ヘルプを求めていそうな雰囲気だったので、後続でPull Requestをいくつか送った、という形です。
また、以下はdbt-osmosisでの具体例です。dbt-osmosisは複数のサブコマンドやオプションなどがある割に、テストがほとんど存在しておらず、デグレしていても気付きにくい状態でした。また、既存のテストが若干存在はしているものの、メンテナンスが非常にしにくい状態となっていました。
このissueではテストの方針についてリポジトリオーナーと議論し
- 既存のテストを一旦全て削除する
- 既存のコードをテストしやすく改善する
- 実際に新規のテストコードを追加する
というPull Requestを後段で提出して進めていきました。リポジトリオーナーとしても大きな修正がいきなりくるのは認知負荷が高いですし、Pull Requestを出す側としても大量の修正をした上でrejectを食らうとダメージが大きいので、事前に擦り合せておくことが重要です。ここはチーム開発でも一緒ですね。
課題が再現する状況をissueに記述する
これもよく言われることですが、課題を再現する最小のケースをissueで提示するようにしましょう。再現する最小のケースを用意できたら課題は半分くらい解けたようなものですし、用意するのが実は簡単ではなかったりします。再現する最小のケースを用意する中で、そもそも課題が何だったのかを言語化する助けになることもあるので、丁寧に考えてみるのがよいでしょう。
仮に課題自体を解決するpull requestの作成まで行き付けなかったとしても、再現ケースが記述されていることは他の人が課題を解決するための近道になるので、issue raise自体が素晴しい貢献です。
以下のケースはterraform-provider-googleのバグを修正したもので、どういったケースで問題が起きるか最小ケースを例示した上で、そのケースをテストケースでも追加し解決するpull requestを送ったものになっています。
Pull Requestを送る際に気を付けていること
実際にコードを書いてpull requestを送る際は、pull requestのスコープを特定の話題に絞り、レビューの際にレビュアーが気になりそうなところを先回ししてケアする、という気持ちが大事になります。具体例を見ていきましょう。
手元でコードを動かす
コードの修正や機能の追加をするには、手元でコードを動かす必要があります。そして、意外とここははまりどころが多いです。
- 依存関係にあるツールのインストールができない
- テストコードの動かし方が分からない
- CIでは通っているテストがローカルだと落ちる
などなどはよくあるハマりどころでしょうか。
まず、開発者に向けたドキュメントが用意されていないか確認しましょう。dbtなどcontributorも多いリポジトリでは比較的用意されていることが多いです。
- https://github.com/dbt-labs/dbt-bigquery/blob/main/CONTRIBUTING.md#running-dbt-bigquery-in-development
- 環境構築|dbt-coreのOSS活動ことはじめ
- https://github.com/datacontract/datacontract-cli?tab=readme-ov-file#development-setup
手元で動かしてみるのが大変な場合、Dockerfileが用意されていることも多いので、それを手掛りにしてみるのもよいでしょう。対象の機能やテストが手元で動けば、ようやく開発に取り掛かれます。
ドキュメントやテストコードを改善する
また、手元で開発してみようとした時に動かないのであれば、それはちょっとしたcontributionチャンスです。特にコードベースにリファクタがあった後などはドキュメントが古くなっていて最新に追従できていないケースやdead codeになったものが存在するケースも珍しくありません。こういった改善は是非Pull Requestとして出していきましょう、あなた以降の開発者が迷わずに済みます。
数行程度のpull requestですが、以下はドキュメントやdead codeの改善の例です。
リポジトリの流儀や方針に従う
リポジトリ内で開発をしていると、微妙に気になることが出てくることもあると思います。
- パッケージマネージャーにxxxを使っているのか、今どきならuvを使えばいいのに...
- 型アノテーションがあったりなかったりして、気になる...
- このフォーマット強制されるの、ちょっと嫌だな...
などなどです。しかし、最初は「郷に入れば郷に従え」でリポジトリの既存の流儀に従いましょう。本来Pull Requestで行ないたい修正内容とは別の修正内容があると、レビュアーとしては考えるべきポイントが多くなってしまうので、簡単にはapproveしにくくなってしまいます。もし、どうしても修正したいというのであれば別のPull Requestとして出したり、issueとして方針をリポジトリオーナーに聞いてみる形を取るのがいいでしょう。「リポジトリの流離などがよく分からない」という場合はmerge済みのpull requestの一覧などを眺めてみるとよいでしょう。リポジトリのオーナーがコメントしている個所があれば、そこは気にしやすいポイントであることが多いので、自分がpull requestを送る際はそういった点をケアしましょう。
このpull requestでは、dbterdのようなthird partyのツールがdbt-artifacts-parserの型を利用しやすいようにexportする、という修正を送りました。しかし
- 修正で用いた
TypeAlias
はpython 3.8 / 3.9では使えない - dbt-artifacts-parserとしてはend-of-lifeになっていないバージョンはサポートできるようにしたい
ということが分かり、pull requestを閉じる形になりました。python 3.9は今年の10月にend-of-lifeになるため、その時に再度pull requestを送ろうかなと思っています*1。
Pull Requestには経緯やWhyを書く
コードはAIが補助 / 生成してくれる時代になってきています。その中でまだ人間がやるべき役割と思っているのが経緯やWhyに関する部分です。レビュアーの立場になってみると、既存のコードが実は間違っていてその修正がきた場合、レビュアーは例えば以下のようなことを頭の中で考えるでしょう。
- いつからその間違いが取り込まれていた(起きていたのか)のか
- ずっと前から起きていたのであれば、もはや仕様として扱ったほうがよい場合もある
- ユーザーへのアナウンス(例: migration guide)をどうする考える必要がある
- 既存のコードが問題があることは前から分かっていて、制約などがありToBeの形でコードを書けない事情があった
- その制約を考慮できているのか、回避できているのか
- どの修正(例: 依存しているライブラリのcommitやissueでの議論)を元にそれが正しいと判断できるか
- 送られてきたpull requestは解法の一つに過ぎず、他にどういう選択肢がありえるのか
- どういった評価軸で考慮した末にこのpull requestがbest(or better)だと判断できるのか
- 松竹梅のプランなどが提示されていると、目線も合いやすく議論もしやすい
- この修正に依存しているコードはテストあったかな? テストがない場合は問題ないかの判断が難しいな...
- テストコードも一緒に書いてくれてるとありがたいな...
こういった労力をレビュアーにぶん投げるのをやめましょう。レビューで支配的な要因はこういったことが多いので、pull requestを出す側がケアするとレビューしてもらえるまでの時間も短かくなるし、コメントでのやり取りも少なく済ませることができるでしょう。
以下の例はdbt-osmosisでdbt-core 1.9の対応するときに送ったpull requestです。1.9に上がる際に依存元であるprotobuf
のバージョン範囲が大きく変わる関係で、1.7以前など古いバージョンのdbt-coreの扱いをどうするべきかをオーナーに向けてメッセージを書いています。
- dbt-coreのリリースサイクルが公式から発表されており、dbt-core 1.7は2024年の11月にEnd of Lifeになっていること
- dbt-osmosisはsemantic versioningされており、仮にdbt-core 1.7以前のバージョンでdbt-osmosisを使いたい場合でも手段は担保されていること
- その他、1.9対応の際にCIで落ちるようになったケースは1.9のどの修正によるものかを説明する
など、オーナーがレビューする際に必要となる情報をdescriptionやコメントなどで補足した上でpull requestを作成し、無事にmergeされました。
Embulkのメンテナをされているdmikurubeさんも同じようなことを言われているので、レビュアーの気持ちになって意思決定をしやすくなるようにpull requestを構成するのは大事だと思います。
コードベースのリポジトリ全体、関連チケット、メーリングリストやチャットを含む会話、それらすべてを「時間軸込み」でコードベースごとに学習していただけたら、コードリーディングとコードレビュー、コードのオーナーとしての意思決定に役立つえーあい様になるとは思うんですけどね…、っていう
— Dai MIKURUBE (@dmikurube) 2024年12月29日
結局「ここなんでこうなってるんだっけ?」「ここを変えるとどういう影響が想定される?」の調査が時間と労力の支配要因なので、そこに貢献してくれないことには…、ってなるんですよねえ。それができるやつが出てきたら起こして
— Dai MIKURUBE (@dmikurube) 2024年12月29日
リポジトリオーナーがPull Requestを取り込むインセンティブを説明する
一つ前の項目とも重複しますが、リポジトリのオーナーがあなたのpull requestを取り込むメリットを説明できるようにしましょう。あなたはpull requestを送ってそれが取り込まれれば自分の機能が使えるようになってハッピーかもしれません。しかし、リポジトリオーナーは仮に取り込むのであればしばらくそれをメンテナンスし続けなければなりません。該当の機能だけでなく、それが依存するコードもメンテナンスしなければなりませんし、該当機能のコードを既存のコードが利用する個所があれば、その影響も考慮する必要があります。
このように、リポジトリのオーナーは広いスコープを長い期間に渡ってメンテナンスする必要が出てきます。そのため
- 機能としては魅力的かもしれないが、実装がかなり複雑でメンテナンスしきれるかな...
- このリポジトリの本来やりたいことに対して、too muchだな...
- その機能、そもそもどういう時に役に立つのかイメージが全然湧かない...
などの理由によって、pull requestがcloseされてしまうことは普通にあります。
こういったことと回避するためには、リポジトリのオーナーに対して「このpull requestを取り込むといいことがありそうだ」というインセンティブがある状態にするのがよいでしょう。例えば
- 機能が取り込まれた場合の具体的なユースケースをissueで示す
- 取り込まれた場合に同様に嬉しい人がいればissueでreactionしてくれるようにコミュニティ内で募る
- 複雑なことをやっているのであれば、コーナーケースなども含めてテストケースを厚めに実装する
- 加えて、ドキュメントなども加筆
などが挙げられるかと思います。
以下はdbt-osmosisに新機能を取り込んでもらうpull requestの例です。osmosisはメタデータ(description)を伝播してくれる便利なツールですが
- メタデータが人間が書いたものなのか、osmosisで伝播されたものなのか
- 伝播されたとすれば、どこから伝播されたものなのか
- 記述を変えたい場合はどこが大本であるか知りたい
といったことを具体的なyamlで例示し、無事mergeされました。
脱線: なぜOSSにPull Requestを送るか
仕事で自分や顧客が普通に困るから
冒頭にも書きましたが、OSSは自分の欲しい機能が足りなかったり、デグレしてコードが動かなくなるときがあります。そういった場合、仕事に普通に影響が出るので、何とかできる力は持っておくのがよいでしょう(ない場合は本当に祈るだけになってしまいます)。
また、特にデグレして動かなくなるケースを避けるために外部のライブラリをなるべく利用しない、という戦略ももちろんあると思います。
できるだけ依存ライブラリを少なくするという方針で製品を開発してるんだけど、あまり理解して貰えない戦略なのかもしれない。
— V (@voluntas) 2024年9月19日
主力製品は外部ライブラリ 11 個しか依存してない。https://t.co/RpLYO9eQO7
自分のエンジニアリングスキルを見直すきっかけになるから
今の会社に数年所属していると、自分が触る部分のコードは大体把握している、という状態になることは珍しくないと思います。そういった場合に「自分のエンジニアリングとしてのスキルは最近向上しているんだろうか?ここにただ長くいるからうまくやれているだけでは?」と思って、転職活動を始めるという方もいるかと思います。
OSSのコードにcommitする際は会社のコンテキストを切り離した上でコードやpull requestを書くことになるため、自分のスキルを客観的に見る機会にもなると思います。また、OSSに貢献するようになってから、会社で書くコードの質も多少上がったのではないかなーという感覚が自分としてもあります。
書くだけでなく、コードや過去のpull requestを読む機会も当然増えるので、自社の文脈を外した上で自分のコードリーディングのスキルはどれくらいのものか、というのが身を持って分かってくると思います。
「コード」をしっかり書く機会になるから
これは自分も悩んでいるのですが、最近のデータエンジニアリングはSaaSによって楽をできる部分が増えています。そのため、それらを繋ぐパーツを配管工のごとくデータエンジニアの仕事(例: k8sのyamlを書く、CI/CDのbashを書く)、となる場合も珍しくありません。それもそれで重要ではありますが、SWEとしては「もっとコード書きたい!」となることもあるでしょう。というより、私はこういう状態によくなります。
OSSではコードをゴリゴリを書く機会も多いので、自分のSWEとしてのスキルを落とさず保つ(あるいは向上)ことに寄与できると思います。また、普段の仕事でやっていることがOSSのCI/CDなどで役に立つことも多いので、仕事とOSSでポジティブなループが回せるようになると強いと思います。
コミュニティと関わるきっかけになるから
登壇はエンジニアのアウトプットとして分かりやすい例でしょう。それよりも目立たないかもしれませんが、OSSにpull requestを送るのも立派なアウトプットです。勉強会での懇親会などでもOSSの話になることは多いですし、ある程度pull requestを送る程度の経験があれば深い話で盛り上がることも多いですし、それは非常に楽しい時間です。
dbt-osmosisは自分の好きなOSSの一つですが、好きだったのでpull requestを送りまくり、コミュニティ内で色々話したいと思い、昨年パネルディスカッションを行ないました。これをきっかけにdbt界隈で知り合いも増えましたし、dbt Community spotlightやGoogle Cloud Champion Innovatorに選ばれたりもしました*2。OSSがきっかけとなって、自分が楽しめる場所が広がっていくのはとてもよい経験になると思います。
謝辞: OSS活動を背中で見せてくれていた方々
ここまで偉そう(?)に色々書いてきましたが、私が自分の意思でOSSにpull requestを送り始めたのはこの2~3年のことです。こういった活動を始めることには少なからずハードルが自分の中にあったのは事実で、こうした活動が特別なものではないと感じることができたきっかけははてなのMackerelチームに所属していたことでした。MackerelではagentなどをOSSとして公開しているため、ユーザーさんからのpull requestを受けることもありました。また、AWSやAzureなどOSSとして公開されているSaaSのSDKなどにpull requestを送る経験もありました。
所属していた初期の頃はこうした活動にめちゃくちゃ高いハードルを感じており、OSSの当番の週が回ってくると無力感から若干テンションが落ちていたこともありました(苦笑)。しかし、Mackerelチームのエンジニアは非常に優秀で、GitHub上でどういったコミュニケーションをしたり、時には力で解決していったりなど、背中で「こうしていくといい」というのを学ぶことができました。
また、はてなではid:taraoさんを中心に#oss-guild
という活動が社内で可視化されていたことも大きかったです。
はてなに在籍していた頃はこの経験はあまり生かせなかったですが、データエンジニアになってからはこの経験がすごく生きていますし、このエントリを通じて他のデータエンジニアの方にも少しでも伝わるといいなと思って、このエントリを書きました。