NotionでOKR（目標）管理してる話

## はじめに
はじめまして株式会社トラストバンクでCTO室のチームリーダーをしております、礒部です。
社内で非公式ですが勝手にNotionエバンジェリストとしても立ち回っています。

弊社ではNotionをドキュメントや議事録の管理に使用しているため、多くのメンバーが毎日のように触れるツールになっています。
アドベントカレンダー2日目のこの記事ではそんなNotionを使ってOKRを効率的に管理できるようにした話を書いていきたいと思います。

## なぜNotionでOKRを管理するのか
![スクリーンショット 2021-11-30 15.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502978/009dd9bb-c859-c585-fedd-8119c2ef4410.png)


多分スプレッドシートや他のタスク管理ツールでも管理できると思います。が、あえてNotionでやったのは、Notionでどこまで効率的に管理できるのか試してみたかったというところと、エバンジェリストとして「Notionってこんな風にも使えるんだ」という事例を作りたかったのが理由です。

## NotionでどのようにOKR管理するか
![モザイクOKR.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502978/5887f5b3-379a-65be-ee98-39126d89477c.png)


Notionにはデータベースの概念があります。RDBのように複数のテーブルを組み合わせて情報が管理できるようになっています。このデータベースの機能をフル活用してOKRの管理を実現しています。
### 用意したデータベース
<dl>
  <dt>ObjectiveDB</dt>
  <dd>OKRのObjectiveを管理</dd>
  <dt>Key&ResultDB</dt>
  <dd>Objectiveに紐づくKey&Resultを管理</dd>
  <dt>KRマイルストーンDB</dt>
  <dd>Key&Resultに紐づくマイルストーンを管理</dd>
  <dt>ステータスDB</dt>
  <dd>各DBで管理しているものの進捗具合や状況を表すステータスを管理</dd>
</dl>
では、それぞれのDBの設計を細かく書いていきたいと思います。

#### ObjectiveDB
| プロパティ名 | タイプ | 内容・用途 |
|:-|:-|:-|
| Objective | Title | Objectiveのタイトル |
| Key&Result | Relation | Key&ResultDBとのリレーション |
| 実行期間 | Multi-select | スコープとなる期間を設定（例：2021Q1など） |
| ステータス | Relation | ステータスDBとのリレーション |
| チーム | Relation | チームDB[^1]とのリレーション |
| ユニット | Relation | ユニットDB[^2]とのリレーション |
| 達成率 | Rollup | Key&ResultDBのKR達成率（Rollup用）から平均値を計算したもの |
RollupのCalculateでKR達成率の平均値を設定しているところがポイントです。
![スクリーンショット 2021-11-30 21.49.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502978/f3856157-ca03-13e0-fad3-ce693d31bd42.png)

RollupはRelation先のプロパティを参照できる機能なので、Relation先のDBで表示させたい情報をFormulaなどで加工したりするといろんな情報が取れます。
あとはどこのチーム・ユニットのOKRなのかといった組織的な管理もできるようにそれ用のRelationを設定しました。
[^1]: 組織を構成するチームを管理するデータベース
[^2]: 組織を構成するユニットを管理するデータベース
[^3]: 組織を構成する担当を管理するデータベース

#### Key&ResultDB
| プロパティ名 | タイプ | 内容・用途 |
|:-|:-|:-|
| Key&Result | Title | Key&Resultのタイトル |
| 関連Objective | Relation | ObjectiveDBとのリレーション、紐づくObjectiveを設定 |
| 実行期間 | Multi-select | スコープとなる期間を設定（例：2021Q1など） |
| ステータス | Relation | ステータスDBとのリレーション |
| チーム | Relation | チームDB[^1]とのリレーション |
| 担当 | Relation | 担当DB[^3]とのリレーション |
| マイルストーン | Relation | KRマイルストーンDBとのリレーション |
| マイルストーン数 | Rollup | Key&Resultに紐づくマイルストーンの数を取得し設定 |
| マイルストーン完了数 | Rollup | Key&Resultに紐づくマイルストーンのうち完了状態になっているものの数を取得し設定 |
| マイルストーン更新日 | Rollup | Key&Resultに紐づくマイルストーンのうち更新状態が最新のものの更新日を取得し設定 |
| KR達成率 | Formula | マイルストーン完了数÷マイルストーン数で達成率を算出。 |
| KR達成率（Rollup用） | Formula | KR達成率を%なしの数値でObjectiveDBに渡すためのFormula。式は「KR達成率」からconcatとformatを取ったもの。 |
| コメント | Text | メモや進捗状況の詳細などを記載 |
ここのポイントはマイルストーン数、マイルストーン完了数をRollupで取得して、その結果をFormulaで加工して達成率を算出しているところですね。
達成率を２つ用意しているのは、%をつけて見栄えを整えるために計算結果を文字列に変換して結合しなければいけなかったのと、ObjectiveDBのRollupでAverageを算出するために数値型のものも用意する必要があったのが理由です。
KR達成率とRollup用に設定しているFormulaは以下

KR達成率

```
concat(format(round(divide(prop("マイルストーン完了数"), prop("マイルストーン数")) * 100)), "%")
```
KR達成率（Rollup用）

```
round(divide(prop("マイルストーン完了数"), prop("マイルストーン数")) * 100)
```
#### KRマイルストーンDB
| プロパティ名 | タイプ | 内容・用途 |
|:-|:-|:-|
| マイルストーン | Title | マイルストーンのタイトル |
| Key&Result | Relation | Key&ResultDBとのリレーション、紐づくKey&Resultを設定 |
| 完了 | Checkbox | 対応が完了したらチェックをつける、対応状況を管理 |
| ステータス | Relation | ステータスDBとのリレーション |
| 更新日時 | Last editted time | マイルストーンに何か動きがあった時の更新日時を管理 |
| 開始日 | Date | 着手する日を設定 |
| 終了予定日 | Date | 完了を予定している日を設定 |
| 進捗メモ | Text | 進捗状況のメモ |
| 完了日 | Formula | 「完了」のチェックボックスをつけた日時が自動的に設定される |
| 空日付（Formula用） | Date | 「完了日」のFormulaで条件がfalseだった時用の空日付 |
完了のチェックボックスを付けるとそのタイミングで自動的に完了日に入るようにしているのがこのDBのポイントです。
ifで完了にチェックが入っていたら更新日時を設定するといったロジックですが、Trueの場合もFalseの場合も同じ型を入れないといけないので、空の日付を入れるためだけのプロパティを用意しなくてはいけませんでした。なのでそのための「空日付（Formula用）」です。
完了日に設定しているFormulaは以下、

```
if(prop("完了"), prop("更新日時"), prop("空日付（Formula用）"))
```


#### ステータスDB
| プロパティ名 | タイプ | 内容・用途 |
|:-|:-|:-|
| ステータス | Title | ステータスの名称 |
| アイコン | Files & media | ステータスのアイコン（パワプロ的なやつ） |
| ObjectiveDB | Relation | ObjectiveDBとのリレーション |
| Key&ResultDB | Relation | Key&ResultDBとのリレーション |
| KRマイルストーンDB | Relation | KRマイルストーンDBとのリレーション |

ステータスはわざわざデータベースにしなくてもSelectでタグ的なものを作成すれば機能的には満たせていたんですが、賑やかし要素が少し欲しかったのでデータベースとして切り分けて、それぞれステータスのページのアイコンにGIFアニメ（パワプロのステータスアイコン的なやつ）を設定しました。
![画面収録 2021-11-30 16.48.22.mov.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502978/a62281b9-8eeb-1322-2580-e330ebc90798.gif)


## 具体的な使い方
上記のデータベースを使いたいページでcreate linked databaseの機能を使って呼び出します。
![howto.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502978/1662c339-315e-34da-8cf8-51ea952dca78.png)
ステータスDBを直接呼ぶシーンはないと思うので、基本的にはObjectiveDB、Key&ResultDB、KRマイルストーンDBが対象になると思います。
推奨する使い方としてはKey&ResultDBで作成したKRのページの中でKRマイルストーンDBを呼び出してKRのプロパティでFilter設定してマイルストーンを管理する方法です。
![スクリーンショット 2021-11-30 17.05.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502978/ac980a19-c6ad-183e-1675-3659fe34072f.png)

Key&ResultDBに登録した各KRのページの中でマイルストーンを管理するといったイメージです。

データベースの設計的にKRに紐づくマイルストーンが一つも存在しない場合、Key&ResultもObjectiveも達成率が0になってしまうので、マイルストーンを設定してKey&Resultに紐づける作業は必須です。
そういう意味でもKey&ResultのページにFilter設定した状態でマイルストーンのDBを呼んでおけば、後からマイルストーンを追加する必要があった場合もKey&Resultのページから新規作成すればKey&Resultに紐づいた状態でマイルストーンが登録されるようになるので、この使い方がベターです。

### 進捗報告の場などでのDBのFilter設定について
弊社ではOKRの進捗管理のためのミーティングが１週間に一度のペースで行われています。
そのミーティングで進捗を報告する際、OKRの進捗状況をまとめる必要があるのですが、そこで私がDBに設定しているFilterについて書きます。
ObjectiveDBはチームのプロパティで自チームにFilterして置いておけばいいのでシンプルです。
Key&ResultDBの方は、関連ObjectiveでFilterさせればいいのでこれもシンプルです。
KRマイルストーンDBは次のように設定しています。
![スクリーンショット 2021-11-30 17.34.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502978/a9c5628e-a4a5-28f7-9df6-e43504c8265d.png)

まず、進捗を報告する対象のKey&Resultで絞り込みます。
あと、１週間の進捗を報告するので、終了予定日がその週の終わりよりも前のもの、かつ完了していないものか完了日が週の初めより後のものという条件になります。

こうすることで１週間で完了したものしてないものが一覧でピンポイントで見えるようになります。

こういった進捗報告のミーティングは組織や会社によって様々だと思いますが、終了と完了の日付の部分の設定をいじるだけで応用できると思うので、使えると思います。

## 終わりに
いかがだったでしょうか。
Notionってこんな風に使えるんだ！うちの組織でもやってみたい！そんな感想を持ってもらえたら嬉しいです。
今回はOKRの管理の話を書きましたが、その他にもTODO管理だったり、社員のコミュニケーションのきっかけを作る仕掛けだったりと、アイデア次第でいろんなことができるのがNotionの魅力なので、これからもNotionの可能性を探っていきたいと思います。