ZenHubを使ったIssueベースの開発

# ZenHubについて

## ZenHubについて
ZenHubはアジャイル開発を行うための、GitHubの拡張機能です。
GitHubのリポジトリをベースにしており、GitHubのIssueをタスク、チケットとして扱うことができます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/47327/c5e2865e-2fd1-97ab-5f8f-944be03a3adc.png)


具体的には下記のような機能があります。

- [かんばん](https://ja.wikipedia.org/wiki/%E3%82%AB%E3%83%B3%E3%83%90%E3%83%B3)（タスクボード）
- ストーリーポイントの割り振り
- マイルストーンの終了日
- ベロシティの計測

## ZenHubの登録とOrganizationへのライセンス依頼

チームでZenHubで始める際の、チームメンバー追加の手順についてです。
メンバー側がZenHubのアカウントを登録し、ライセンス割当を要請します。

1. https://app.zenhub.com を開きます
2. GitHub で認証（Sign Up）します
3. 利用規約に同意します
4. Organizationを選択します

<img width="969" alt="Screen Shot 2019-10-01 at 16.23.48.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/47327/ae7c44ce-d6b2-6eb2-d79e-92334be43b72.png">

5. 左側に出てきているワークスペース一覧から、どれかのワークスペースを選択します
6. 「Request Lisence」をクリックします
<img width="631" alt="Screen Shot 2019-10-01 at 16.25.54.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/47327/4d346655-b437-238d-33ae-f3d3510c0be0.png">

7. 管理者にSlackで「リクエストの承認をお願いします」という依頼をしてください。

## ZenHubとGitHubプロジェクト
GitHubにはかんばん機能として「プロジェクト」という機能があります。
ZenHubの方が先にかんばん機能を提供しており、GitHub本家でも遅れてかんばん機能をリリースした、という経緯のようです。

## ワークスペースとリポジトリ
ZenHubにはワークスペースという概念があります。
複数のリポジトリを一つのワークスペースにまとめて扱います。

1つのプロジェクトでサーバサイド、フロント、アプリなどのリポジトリが分かれている場合でも、それを一つのまとまりとして扱うためにワークスペースという単位で扱います。

注意点として、1つのリポジトリは1つのワークスペースにしか属することができません。
1つのリポジトリを複数のワークスペースに属させることはできません。

## Issueとタスクボード
GitHubのIssue（とPullRequest）をチケット（札）として扱います。
このチケットにタスクを書き、タスクボードに配置します。

デフォルトのタスクボードは下記の通りです。

名前 | 意味
----|----
New Issue | 振り分け前タスク
Icebox | 手を付けないタスク（凍ったタスク）
Backlog | 手を付けるタスク
In Progress | 着手中
Review/QA | 検証中
Done | 終了
Closed | 終了（IssueとしてClosed）

タスクボードは変更することもできますが、チーム内でZenHub運用に慣れるまではデフォルトのもので運用すると良いです。

特になれるまでの間、デフォルトのタスクボードのうち「New Issue」「In Progress」「Closed」の三つで運用するとみんながわかりやすいためおすすめです。

## Issueの作成
Issueの作成についてです。

タイトルは簡潔かつわかりやすく書きます。言い切り型で書くと良いです。

修正での良い例)
1. ○○を○○する
2. ○○を○○に変更すると○○が発生するので、○○では○○のバリデーションを入れる

バグの場合には不具合を簡潔に述べます
1. ○○が表示されない
2. ○○で○○するとエラーになる 

議論をIssueに書くと閉じるタイミングが不明になることがあるため注意が必要です
1. ○○の仕様について
2. ○○は○○なので○○ですか？

議論、質問をIssueで行う場合には `question` タグを利用するなどのルールを作りましょう。

## Issueの本文について
マークダウンを利用して書くことがおすすめです。
仕様であれば期待する結果、背景、行うことをリストにすると良いです。


![image.png](https://qiita-image-store.s3.amazonaws.com/0/47327/c74202f4-7507-34d9-3918-ae7c14f79e38.png)

表記上の修正リストの場合にはチェックボックスを使うと良いです。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/47327/de59535e-d680-bfc0-b5e1-cd40f3647ff9.png)

## Estimate
タスクに対する作業量の見積もりです。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/47327/0998629f-b48f-8a76-524f-fb7b7fed3e3f.png)

アジャイルでは「ストーリーポイント」という名称で呼ばれています。
このストーリーポイントは、スクラム開発では相対見積もりで行います。
[ストーリーポイントに関する15個のよくある質問と答え](https://www.ryuzee.com/contents/blog/3716)

基準となるタスクを元に作業の重さを見積もります。

ただスクラムに慣れていないチームの場合、「○時間」という絶対見積もりでの運用も良いです。
その上でいくつかスクラムのプロジェクトをこなしてストリーポイントによる相対見積もりに移行すると良いでしょう。

# IssueとPRの紐付けについて
ZenHubのタスクボードではIssue（Epicを含む）とPullRequstの両方が一覧で表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/47327/08e483bf-b0b1-b567-ffdc-405491c5f3b5.png)

この状態だとPRとIssueが増えてくるため、ボードの見通しが悪くなります。

## IssueとPRの紐付け

見やすくするためにPRとIssueを紐付けします。
PRの下の方にある「Connect this pull request with an existing issue」から、関連するIssueを選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/47327/53252ada-2980-046a-b0dd-6903c47ee7c8.png)

そうすることでZenHubのボードでIssueとRPがセットで見えるようになります。スイムレーンの移動も一緒に行われるようになり、見通しがかなりよくなります。

またIssue本文に「Fixes #123」や「Refs #123」といった、PRと関連するIssue番号を記載しておくと良いです。
`Fixes`の場合にはPRがマージされるとIssueが自動的にクローズされます。[^zenhub1]
またPRからIssue、IssueからPRへの関連を見ることができるようになります。
他にも閉じる下記のキーワードを利用することができます。こちらはZenHub固有の機能ではなくGitHubの機能なので積極的に使っていきましょう。

- close
- closes
- closed
- fix
- fixes
- fixed
- resolve
- resolves
- resolved

https://help.github.com/en/github/managing-your-work-on-github/closing-issues-using-keywords

余談ですがこのIssueを閉じる予約後はGitHub登場前から使われていました。[^trac]
ですのでGitHubに限らず他のGitサービス、今後他のVCSなどでも採用されていくのではないか思います。

[^trac]: https://trac-hacks.org/wiki/TracTicketReferencePlugin

[^zenhub1]: ただしIssueがCloseされるとZenHubの関連は解除されるため注意が必要です。