Ansible の新モジュールをプルリクしたらマージまで半年以上かかった話

この記事は [Ansible Advent Calendar 2018](https://qiita.com/advent-calendar/2018/ansible) の 17 日目の記事です！（遅刻しました）


# 経緯

今年 2 〜 3 月にかけて参加したとあるインターンシップで，Ansible を用いて [RabbitMQ](https://www.rabbitmq.com/)[^1] の設定を行う機会がありました。

[^1]: AMQP プロトコルを実装したメッセージキューサーバの一つ。サーバ内であるプログラムから別のプログラムを非同期に呼び出し，処理を行いたい際などに重宝します。

RabbitMQ 関連の Ansible モジュールは [Messaging modules](https://docs.ansible.com/ansible/latest/modules/list_of_messaging_modules.html) カテゴリに含まれます。
しかし，既存モジュールでは期待している設定を行えなかっため，これを可能にする新しいモジュールを作成することになりました。
また，メンターさんの提案でプルリクエストを出してみたところ，先日めでたくマージされました。

この記事では，マージされるまでのやり取りや得た知見などを共有できればと思っています。
Ansible モジュールを作成する際の参考になれば幸いです。

なお，12 日目の @morin_river さんも [Ansibleモジュールをコントリビュートしてみた話](https://qiita.com/morin_river/items/40abd1baab4c588deafd) という記事を投稿されています。
そちらの記事は OSS へ PR を立てる際のお手本となるようなもので，PR も 1 日でマージされたとのことでした。

しかし，私の場合は**マージまで半年もの時間がかかりました**。
マージに時間がかかってしまった原因と思われる点も記事の最後に書いていますので，反面教師としても読んでいただければと思います。


# モジュールの内容

RabbitMQ  で設定可能なパラメータの一つに [Virtual Host Limits](https://www.rabbitmq.com/rabbitmqctl.8.html#Virtual_Host_Limits) が存在します。
RabbitMQ には vhost という名前空間があり，各 vhost に対してコネクション数やキュー数を制限するための設定になります。

作成したモジュールは [rabbitmq_vhost_limits](https://docs.ansible.com/ansible/devel/modules/rabbitmq_vhost_limits_module.html) で，Ansible 2.8 に含まれる予定です。
以下のように使えます：

```yml
# コネクション数とキュー数をそれぞれ制限する
- rabbitmq_vhost_limits:
    vhost: /
    max_connections: 64
    max_queues: 256
    state: present
```


# コントリビュートの流れ

PR を作成してからマージされるまでの流れを追ってみます。


## Developer Guide の確認

何と言ってもまずはドキュメントの確認が必要でしょう。

大抵の OSS ではプロジェクト毎に開発フローや各種規約を定めています。
これに則らないと，たとえ機能に問題がなくてもマージしてもらえません。

Ansible はドキュメントも巨大なためどこを読むのか迷いますが，今回のようなモジュール開発の場合，まずは以下から読み始めれば良いと思います：

- [Contributing your module to Ansible](https://docs.ansible.com/ansible/latest/dev_guide/developing_modules_checklist.html)
- [Ansible module development: getting started](https://docs.ansible.com/ansible/latest/dev_guide/developing_modules_general.html)

開発環境の構築方法やモジュールのサンプルコードなどが記載されており，とりあえず開発を始めることができます。


## モジュールの作成

環境が構築できたら，モジュールの実装に移ります。
上記ドキュメントの他，既存の様々なモジュールのコードが参考になります。
Ansible の特徴である<ruby>冪<rp>（</rp><rt>べき</rt><rp>）</rp></ruby>等性を満たすよう意識しながらコーディングしていきます。

コード自体はシンプルな Python プログラムですので，説明は割愛します。
このときのコミットは以下です。
https://github.com/ansible/ansible/pull/37821/files/a0b9831274d94252f493b0b44d67e6aa0bafb9cd


## ドキュメントの作成

第三者が使用するため，ドキュメントはしっかりと書いておく必要があります。

ドキュメントはモジュールのソースコード中に記述します。
以下のエントリが参考になります：

- [Module format and documentation](https://docs.ansible.com/ansible/latest/dev_guide/developing_modules_documenting.html)

なお，書いたドキュメントはローカルでビルドし確認することができます。
以下のコマンドを実行することで，`_build/html/modules/` に `<モジュール名>_module.html` が生成されます：

```sh
$ pip install -U Sphinx
$ cd docs/docsite/
$ MODULES=<モジュール名> make webdocs
```


## 3 月 23 日：プルリクエスト作成

作成したモジュールをコミットし，PR を作成します。

[Add rabbitmq_vhost_limits module by h-matsuo · Pull Request #37821 · ansible/ansible](https://github.com/ansible/ansible/pull/37821)
![pr_1.jpg](https://qiita-image-store.s3.amazonaws.com/0/126427/ffc4c26d-5b21-dfc4-a3ae-8c8a73834c41.jpeg)

このように，作成した PR には「RabbitMQ の Virtual Host Limits を設定する新しいモジュールを追加したよ」としか書いていませんでした。

今思えば，非常に無愛想な PR だったと思います。
これでは，なぜそのモジュールが必要なのかさっぱり分かりません。

そのせいかどうかは分かりませんが，この PR は約半年間，レビューされることなく放置されることになります……。


## 10 月 8 日：レビュアーからの反応

約半年後，私自身 PR を出したことを忘れていた頃，待ち望んでいたレビュアーからの反応がありました。
![pr_4.jpg](https://qiita-image-store.s3.amazonaws.com/0/126427/e22ba802-2a71-3332-1e9f-70a48f26706e.jpeg)
「テストコードを追加してね」と言われます。

モジュールのテストについてはすっかり抜けていました。
確かにモジュールにもテストが必要です。


## テストコードの追加

有難いことに，コメントで「[rabbitmq_lookup モジュールのテストコード](https://github.com/ansible/ansible/tree/devel/test/integration/targets/rabbitmq_lookup) を参考にしてね」と教えてくれていたので，その通りにテストコードを書きます。

このときの変更が以下になります。
https://github.com/ansible/ansible/pull/37821/files/80a4cd6d33689a775f1b1f4a6f7a03b637069db3..69fdfa3938a9e266d8b757905a8102ac8139b6a6


### ローカルでのテスト実行

[公式ドキュメント](https://docs.ansible.com/ansible/latest/dev_guide/testing_integration.html#destructive-tests) によると，Docker を用いてテストを実行することが推奨されています。
コンテナ内でテストを行うことで，開発用 PC の環境が汚れることなく，またテスト対象のミドルウェア（今回は RabbitMQ）を用意することなく，簡単に何度もテストを実行できます。

例えば，Ubuntu 16.04 のイメージで統合テストを行うには，以下のコマンドを実行します：

```sh
$ test/runner/ansible-test integration --docker ubuntu1604 -v <モジュール名>
```


## レビュアーからの指摘

テストコードをコミットした段階で，以下のようなコメントがありました。
![pr_5.jpg](https://qiita-image-store.s3.amazonaws.com/0/126427/88c7c9cb-bccd-724d-501a-2e377c40d22e.jpeg)
新モジュールとして公開するのではなく，既存のモジュールにこの機能を追加するのはどうかという内容です。

私はこの意見には反対でしたが，面と向かって「反対」というのも恐かったので，顔色を伺いながら自分の意見を主張しました。
![pr_6.jpg](https://qiita-image-store.s3.amazonaws.com/0/126427/587a1a9e-7767-6eed-f335-a3717e5ebc50.jpeg)


## 11 月 15 日：無事マージされる

結局，最初に PR を出してから約 7 ヶ月もの月日が経ち，やっとマージされました。

最終的にマージされた段階でのコードは以下です。
https://github.com/ansible/ansible/pull/37821/files


# なぜマージまで半年以上もかかってしまったのか

以降は，この PR がマージされるまでになぜこれほど時間がかかってしまったのかを自分なりに考えてみようと思います。


## 説明不足

PR がとにかく説明不足でした。

[前述したように](#3-%E6%9C%88-23-%E6%97%A5%E3%83%97%E3%83%AB%E3%83%AA%E3%82%AF%E3%82%A8%E3%82%B9%E3%83%88%E4%BD%9C%E6%88%90)，私の PR には単に「新しいモジュールを追加した」としか書いていませんでした。
これではレビューを後回しにされても文句は言えないと思います。

例えば以下のような説明をしっかりと書いておくことで，第三者やレビュアーに PR の重要性を理解して貰いやすくなります：

- 現状の問題点
    - いつ問題が発生するのか
    - なぜそれが問題なのか
    - 問題の再現手順
- 解決策
    - どのように解決したのか
    - なぜ他の解決策ではなくその方法を選んだのか

また今回のように新モジュール追加の PR なら，以下の説明も有用だと思います：

- なぜそのモジュールが必要なのか
- そのモジュールがあると他のユーザがどう喜ぶのか

また，これらの説明が非常に長くなるのなら，それ用の issue を立てるのもアリだと思います。
実際，@morin_river さんの記事では，まず最初に issue を立てられていました。


## レビュープロセスの理解不足

Ansible のように巨大な OSS だと，レビュープロセスも独自にしっかりと決められていることが多いです。

Ansible の場合，[ansibullbot](https://github.com/ansible/ansibullbot) というボットが GitHub 上でのプロセスを管理しており，せっせとタグの付け外しやテスト結果のコメントなどを行ってくれます。
私は「お助けロボットが動いているなぁ」ぐらいにしか思っていませんでした。

しかし，実際には **ansibullbot が付け外ししていたタグはレビューの状態遷移を管理** しており，適切なタグが付いていないとレビューしてもらえないことがあるのです。

具体的には，レビューしてもらえる状況が整ったら GitHub に `ready_for_review` とコメントします。
すると ansibullbot が `community_review` というタグを付けれくれ，このタグが付いているものをレビュアーはレビューしていきます。

この辺りはドキュメントの [The Ansible Development Process](https://docs.ansible.com/ansible/latest/community/development_process.html) に書いてあったのですが，Ansible はドキュメントも巨大なため見落としていました。

自分の PR になかなか反応がない場合は，レビュープロセスに違反していないかどうかドキュメントを見直すことも必要かもしれません。


## プロジェクトの巨大さ

これはコントリビュートする立場としてはどうしようもないのですが，

- Ansible プロジェクトが非常に巨大なこと
- Ansible コミュニティ全体の中では，RabbitMQ に関する活動をしている人が非常に少ないこと

も原因だったのではないかなと思っています。

Ansible には，常に 5,000 前後のオープンな issue や PR が存在します。
これまでにクローズされたものも含めると，その数は 50,000 を超えます。

しかし[「rabbitmq」で検索してみる](https://github.com/ansible/ansible/issues?utf8=%E2%9C%93&q=rabbitmq) と，これまでに RabbitMQ 関連の issue や PR は僅か 220 程度しか存在していないことが分かります。
割合にしてたった 0.44 % です。

あまりアクティヴではないコミュニティでの PR が埋もれてしまいがちになるのも無理はなかったのかなと思います。
ただし，定期的に状況を確認してみるなど，埋もれないような努力はできます。
もっとアピールをしていれば変わっていたかもしれません。


# 反省を活かして次のコントリビュートへ

非常に時間がかかった PR となりましたが，これが人生初の OSS へのコントリビュートだったため，それがマージされたことは非常に大きなモチベーションとなりました。

Ansible とは関係なくなってしまいますが，[CircleCI](https://circleci.com/) の [CLI ツール](https://github.com/CircleCI-Public/circleci-cli) にバグを発見した際は，今回の反省を活かして [issue を立てて問題点を説明](https://github.com/CircleCI-Public/circleci-cli/issues/213) してから [PR を投げた](https://github.com/CircleCI-Public/circleci-cli/pull/214) ところ，1 日でマージしてもらえました[^2] 。

やはり自分のコントリビュートが誰かに使ってもらえるというのは非常に嬉しいです。
来年も時間を見つけて OSS に貢献できればと思っています。

[^2]: 差分も非常に小さく規模もそこまで大きくないため，単純な比較はできませんが……。