2週間でできる設計・集団開発の特訓法を考え、実践してもらってみた

## はじめに
[集団開発の王、集団開発キング](https://qiita.com/uts1_6/items/11e348ead4bae71571b8)、なりたいですよね。

しかし、集団開発というのは単に初心者ないしソロプレイヤーを複数人集めて同じプロジェクトを作らせようとしても、大学でランダムに組まされるグループワーク並みに地獄になりますね。

集団開発を上手にこなすには、下記が出来る事が必要であると考えています。
* **適切なドキュメンテーション**
　コードの説明のみならず、そのように書いた意図やシステムの全体像を明確にし、他人に理解してもらい、参入しやすくする
* **独立性・拡張性のあるアーキテクチャ設計**
　責務ごとにパーツを分離し、分担可能性、検索性、保守性を向上させる
* **可読性のあるコード記述**
　保守しやすくする

そこで、これらの重要性を **短期間で** 、 **苦しみながら覚え** 、その手法を **気づく** 訓練方法を考案し、この記事で提案します。

## 提案手法：Adaptive Challenge
### ざっくり言うと
参加者にこのフローを体験してもらいます
* ゲームマスターが **初期** 要件定義を発表
* 参加者は各々その要件を満たすソフトウェアを実装
* 自分は他参加者を、他参加者は自分にコードレビュー
* ゲームマスターから **追加** 要件定義が発表される
* 自分がコードレビューした **他人の** コードをもとに、追加要件について追加実装
* 最後に、コードレビューした人同士で元コード・ドキュメンテーションの扱いづらかった点を批判しあう

すなわち、 **他人に読まれる前提で** コードを書き、 **他人が書いたコードで** 追加実装する、という流れを体験できます。

### 詳しく
:::note
ルール説明(英語)レポジトリはこちら: https://github.com/konbraphat51/AdaptiveChallenge_Chat
:::

#### 1.初期要件定義発表
> ゲームマスターから参加者に下記事項が発表されます:
> * システム要件
> * テストケース
>
> 要件についての質問OK、その返答は全参加者に共有。
> 
> 参加者は[このレポジトリ]をフォークすること。

#### 2.実装
> 3.コードレビューまでに初期要件を実装する。
この際、`main`ブランチではなく`dev_base`ブランチで作業すること
>
> コードを理解しやすくするために、ドキュメントを書くことはOK

ここで、参加者たちは、
* コードレビューで指摘される
* 追加要件が待ち構えている

ことを念頭に実装に臨みます。

#### 3.コードレビュー
> 参加者は他の参加者の **後継者** となります。
> 誰の後継者になるかはこのとき判明します。
> `dev_base` -> `main` のプルリクエストを作り、後継者はコードレビューをしてください。
> 元コード作成者は、後継者の指摘に対応しコードを改善させます。
> 後継者が`approve`するまでこれを繰り返してください
>
> 後継者はそのコードを完全に扱えるようになるまでコードレビューをしてください。次はそのコードをもとに追加実装をします。

ここで、相手のコードの
* 意味が分からない記述
* 独立性・拡張性のない記述や設計

をコードレビューを通じて潰します。

元コード作成者はここで** 自分のコードを読んでもらい、指摘されるという体験** を受け、
後継者は **他人のコードを読む気持ちになり、拡張性を意識して調整する体験** を受けます。

#### 4.追加実装
>　コードレビュー後、 **ここで初めて** ゲームマスターが **追加実装要件** を発表します。
> **後継者**は、自分がコードレビューをしたコード **を** 拡張し、追加要件を満たすように追加実装します。
>
> 自分の元コードからコピペはしないように。
> 元コード作成者へのコードに関する連絡は禁止。全てコードレビューで済ませましょう。

ここで初めて追加実装要件が発表されます。

追加実装要件として最適なのは、「その機能の対象がa限定だと思ったらaもbも対応するようになったんだ」という、対象を広げる要件です。
例えば一人プレイのゲームを、いきなり協力プレイ可能にしろ、のような。この場合プレイヤーをカプセル化して抽象化しないといけませんね。

要件によっては、人によれば初期コードがドンピシャで嬉しいという場合もあれば、ほぼ書き直しで青ざめる場合もあるかと思いますが、コードレビューしたからには後継者の責任になるのです。

ここで、急な追加要件が下ってきてコードを拡張することで、
* **逆に拡張しにくいコードの特徴を知り、**
* **他人のコードの扱いやすい点、扱いにくい点を知り、**

アンチパターンを知ることで、逆に自分ならどうするかのヒントが得られます

#### 5.文句言い合い
> 追加実装の完了を確認したら、後継者は元コード作成者に
> * 追加実装にあたって苦しんだ点
> * コードレビュー後も元コードを理解できなかったところ
> 
> を批判しあいます。しかし、もちろん人格否定はせず、コードとドキュメンテーション **のみ** を、敬意を持って批判しましょう

簡単に言うと反省会ですね。
**各々が自分のコードを他人に使ってもらった気持ちを実際に聞くことができます。**

本当は差分行数などでスコア化できれば面白そうなのですが、初期コードの時点であらゆる機能を盛り込んでおくなどスコアハックされそうな気もするので、もし格付けするとしてもゲームマスターの主観がいいんではないですかね。

もし、初心者同士だと指摘も初心者目線になるので、ある程度の **経験者が最終結果を確認し、ざっとフィードバックする** ともっと勉強になるのではないかなと思いますね。

## 実践していただいた
:::note alert
もしChat課題に取り組んでいる当事者が見ているのであれば、ここで引き返してください。
**ネタバレになります。**
:::

### 参加者
[東大GDSC](https://qiita.com/organizations/gdsc_ut)（他大含めて誰でも入れますよ！）から、東大EEIC学科（電子情報学科&電気電子学科を指すが、2学科はほぼ同一のカリキュラム・連携のためEEICと呼ばれる）の3回生2人に集まっていただきました。

* @SuperHotDogCat 
    現在電子情報学科主席。1回生からデータ系のプログラミングを始め、数か月前までPytorchにつきっきりであったが、ふと「機械学習モデルを組めてもアプリ化せねば意味はない」と謎の覚醒を果たし、ソフトウェアエンジニアリングを頑張り始める
    実は筆者と共にOSS書いている途中で、ちょっと叩き込んだつもりではある。
    
* @lab-sprout 
 電気電子学科の者
 筆者とは本サークルで知り合ったばかりなのであまり紹介できない。プログラミングは高校ぐらいから5年間、初めての言語はJava。サークルではWeb/スマホフロントエンド担当として活躍。

二人ともプログラミングが大好きですが、ちゃんとした集団開発経験はないそうです。
どうなるでしょうか。

### 初期実装要件発表、実装
EEIC学科がお忙しいとのことなので（筆者はシステム創成学科）、小規模めな要件を発表します。

[こちらのチャットアプリ要件](https://github.com/konbraphat51/AdaptiveChallenge_Chat/blob/main/Docs/Requirements/Task.md)を渡しました。

詳細は上記リンクを見ていただければいいのですが、簡単にいうと、
* ユーザー登録機能
 ```
 input: add_user adam
OUTPUT: adam registered!
input: add_user adam
OUTPUT: ERROR: ID already used!
```

* 2人同士の会話
```
input: talk adam eve hi
input: talk eve adam I hate you
input: talk adam gogami nyugaku
OUTPUT: Error: no user ID
```

* ログ表示
```
input: show_log adam eve
OUTPUT: adam -> eve: hi
eve -> adam: I hate you
input: show_log adam gogami
OUTPUT: ERROR: no user ID
```

の3点を作るPythonアプリ（標準入力、標準出力を使用）を作らせる。

実はこの時点で追加実装要件は固まっていましたが、もちろん発表せず。

2人には、「拡張性」と「可読性」が大事やと強調しつつ、実装してもらいました。

1週間。

### コードレビュー
二人は追加要件を知らないまま、コードレビューを通じて不安点を潰しあってもらいました。

@SuperHotDogCatはコードレビュー経験者であり（筆者との戦いを通じて）、
@lab-sprout　はコードレビュー未経験
であるとのことなので、@SuperHotDogCatに先にコードレビューをしてもらい、お手本になってもらうことに。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2602537/d887ee07-9960-20e6-dfe1-197c93af4255.png)

> ここのrstripのお気持ちを教えてください

↑こっわ。

こちらはマージ完了。

次に@lab-sproutからのコードレビュー
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2602537/50d14e43-1c7e-ec22-c523-b945ffdacbe3.png)
とても良い指摘が降ってきますね。

### 追加要件発表、追加実装
二人ともコードレビュー完了を受け、[追加実装を発表](https://gist.github.com/konbraphat51/187b99eb9a1abec3dfc030abaeddc8c1)

ネタバレ回避ようにGistとして分離しておきました。

ここでは
1. `<br>`タグで改行
2. NGワードをマスキング
3. **2人チャットのみならず、n人（`n >= 1`)チャットへ対応**
4. **ユーザーに属性** を持たせ、
    * 一方はクレジットを消費しないとメッセージを送れない
    * もう一方はメッセージが送られるほどクレジットが溜まる

の4点を
最後の二つが阿鼻叫喚ポイントだろうなと期待して出題しました。

1., 2. はコードの単純な保守性を、
3.はメッセージ機能の設計の拡張性、
4.はあらかじめユーザーをクラスを作っていてカプセル化できているか

を試したつもりでした。

### Blame会

まずは　@lab-sprout から @SuperHotDogCatへ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2602537/4b165c8f-1b46-3295-3f1e-91dc0d22793d.png)

@SuperHotDogCatは初期段階で各概念をクラス化すること（本人はオブジェクト指向のつもり）で、仕様4はそれに追加するだけで済んだそう。
@lab-sproutからは「 **クラス化されていてやりやすかった**」という。

ここで面白かったのが
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2602537/e8343de7-b6e9-9e7e-f78f-564be34f0a88.png)
元コードの`ChatRoom`が`ChatManager`に改名され、`ChatRoom`が新規に実装されたところ。
名が体を表してなかったようですね。

次に @SuperHotDogCatから @lab-sprout  へ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2602537/f968a24a-ccc0-909d-1afa-cb200c4f1472.png)
なんと元コードがユーザーをクラスではなく、ただの文字列で管理していたため、 @SuperHotDogCat はその実装方針を変更せずに、ユーザー名→属性 の辞書を作ることで力技で各ユーザーのデータを管理。マジかよ

@lab-sproutは、クラスをあまり作成せず、全体的に関数的に記述していますね。（筆者は扱いやすければオブジェクト指向でもそうでなくともどちらでもいいというスタンスです）

それと各関数は出力するログを返す仕様に
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2602537/22e2f8ad-2628-436e-be06-b976b9f3c30a.png)
僕から「`add_user()`は『userをaddするだけ』の責務にとどめ、ログの機能を分離することで部品としての使いやすさが向上するのではないか」と言ってみたりしました。

二人に共通として、全てのコードを一つのファイルに書き下していて、検索性に欠ける点が見られたので、プログラムを責務で分けるという観点をお伝えしました。[SOLID則の記事](https://qiita.com/baby-degu/items/d058a62f145235a0f007)とともに。

### 参加者からの感想
@SuperHotDogCat
> 相手と"対話"することの大切さを学べた。よくレビューするプログラマーは「なんで君さあ〜〜〜(無限問い詰め)」をするが、あれは本当に善意で、必要な問い詰めであることを学べた。 

コード記述の観点からなんか言って

> **コメントはかけ**

設計の観点からなんか言って

> Userクラスは拡張性のことを懸念して追加したけど良かったのでしっかり意識したコードを今後は考えます。

@lab-sprout 
> ただ動けばいいだけではなく、追加の機能が来たときのことを想定したり、他の人が読んだときに理解できるようにしたりするのは、慣れていないとどこまでやればいいか加減がわからず難しかった。

二人とも感謝です

## 今後の展望
まずは試しというところで、中級～上級者の二名に試してもらいました

二人とも大満足のようでしたので、この特訓法Adaptive Challengeをサークル内で拡大していこうと思います。

皆様も、もし良いなと思ったらぜひやってみてください。

ゲームマスター一人 + 参加者2名以上から可能です。
もし偶数なら2人組でコードを交換し合う、基数なら3人組でサイクル状にコードを渡す、という方法で運営できるはずです。

:::note
各レポジトリです（スター頂けると嬉しいです）

ルール説明: 
https://github.com/konbraphat51/AdaptiveChallenge_Chat

Chat課題初期要件定義：
https://github.com/konbraphat51/AdaptiveChallenge_Chat/blob/main/Docs/Requirements/Task.md

Chat課題追加要件定義：
https://gist.github.com/konbraphat51/187b99eb9a1abec3dfc030abaeddc8c1
:::

もちろんChatアプリのみではなく、初級として読書管理、上級として銀行口座の課題の追加も企んでいます

:::note warn
いいね頂けると泣きながら喜びます ><

この記事を読んでいる人は、次の記事も読んでいるのかもしれません：
* [初心者だらけでもとりあえず共同開発ができる手引き](https://qiita.com/konbraphat51/items/8793f03807c39573fac2)
* [王とキング](https://qiita.com/uts1_6/items/11e348ead4bae71571b8)
:::