Treasure2022体験記【Matchong】



### はじめに

こんにちは！神奈川県の大学に通っている mayukorin と申します．本日は，今年の夏に参加した Treasure というインターンのことについて書きたいと思います！Treasure については他にも様々な方が記事にしているのでぜひ見てみてください！

- [Treasure2022に参加してきた](https://rio-1.hatenablog.com/entry/2022/08/31/182334)
- [Treasure2022に参加](https://note.com/akira4649/n/nf5d8aff0ecec)
- [「Treasure2022」企画への意気込みと概要について](https://techblog.cartaholdings.co.jp/entry/treasure2022-planning)
- [過去最大規模のTreasureへ！インターン裏側奮闘記](https://techblog.cartaholdings.co.jp/entry/treasure2022-report)
- [Treasure 2022で学生にFBしたこと](https://note.com/ryosuke_kawamura/n/ne98d26002b75)
- [Treasure2022参加記](https://qiita.com/EbiTT/items/6775b85f6d555db21f58)
- [Treasure2022(CARTA HOLDINGSサマーインターン)に参加してきた](https://qiita.com/ktaroabobon/items/d293baacca64d96eb632#%E6%A6%82%E8%A6%81)

### この記事で伝えたいこと

この記事で私が伝えたいことは以下の通りです．

1. Treasure はどんなインターンなのか
1. Treasure で開発したアプリについて
1. Treasure 期間中どのように実装したか
1. その後の継続開発でどのように改善したか

### Treasure はどんなインターンなのか

株式会社 CARTA HOLDINGS さんが毎年夏に開催している，学生向けのインターンシップです．全部で3週間あり，最初の1週間ほどでバックエンド・フロントエンドなどの講義が行われます．そして残りの2週間ほどでチーム開発を行います．インターン全体の流れについては，[同じチームだったけいちゃんの記事](https://qiita.com/EbiTT/items/6775b85f6d555db21f58)で詳しく書かれているのでぜひ見てみてください！

#### 参加した感想
3週間全日程とても楽しかったです！大変なことも沢山あったのですが，とても充実していました！私はプログラミングを始めて2年半ほど経つのですが，私のプログラミング人生史上，ここまでの充実感を味わったのは Treasure 以外にありません！笑 それくらい自分の今ある力を全力で出せて楽しめたインターンだったなと思います！

##### なぜ楽しめたか
Treasure をなぜ楽しめたのか，要因は色々あると思うのですが，自分が思うに以下のような感じかなと思います！

- 開発するアプリをチームで一から決めるので，当事者意識をもって開発できる
- 前半の講義で学んだことを後半のチーム開発で活かすことができる
- サポートしてくださるメンターさんがとても頼りになり，挫折せず取り組むことができる
- 日報に対するコメントやTreasure期間中頻繁に行われる面談を通じて，自分自身のFBを沢山していただけるので，自分に今できていてこれからすべきことは何かなどが明確になりモチベーションが上がる
- Treasure 自体の雰囲気がとても明るく，開発で行き詰まっていても頑張ろうという前向きな気分になれる


これを見ていいなと思ってくださった学生さんは，是非来年の Treasure に応募してみてください！


### Treasure で開発したアプリについて

私たちのチームは，筋トレをしたい人同士がリアルタイムでマッチングして，オンラインで一緒に筋トレできるサービス『Matchong』を開発しました．

#### なぜこのアプリを作ろうと思ったか

チームでどんなアプリを作ろうか考えていたときに，コロナ渦で運動する機会が減ってしまったという人多いよね.. という話になりました．そのような人が抱える課題として，「筋トレしたいけどジムだと高い，ジムに行くのが面倒な時もある，そもそもコロナでジムに行くのが不安，でも家で一人で筋トレするのはモチベーションが続かない」ということがありそうだよねと推測しました．そこで，__自分の好きな時にオンラインで一緒に筋トレをする人がいれば__，家での筋トレのモチベーションも保てるのではないかという話になり，『Matchong』を開発することに決めました！

#### 『Matchong』の使い方
1. 筋トレのメニューを選択する
![s1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1840262/a965da21-4050-8351-7266-154dda59426a.png)
1. あとは待つだけ
![s1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1840262/a9fd6323-f96b-d098-5ad7-8fda923a484d.png)

1. マッチョングした人と楽しく筋トレをしましょう！！
![fun.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1840262/3c9c6023-bd90-8e5f-8f17-1d570ce54db5.png)


### Treasure 期間中どのように実装したか
インターン中の開発期間は約5日間でした．どのように実装していったか，私が担当したところを中心に説明していきたいと思います．ここら辺の話は，[同じチームだったえびくんの記事](https://qiita.com/EbiTT/items/6775b85f6d555db21f58)でも話しているので是非読んでみてください！なお，言語はGoとReactを使っています．

#### 1日目
1日目は，『Matchong』の要であるマッチング部分のフローを設計しました．紆余曲折あり，以下のような設計方針になりました．

![スクリーンショット 2022-11-29 13.01.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1840262/6f94e01a-3161-ce38-0c42-9ff106b1d36d.png)


設計を決めるにあたり一番考えたのは，__APIからフロントにマッチングしたことをどう伝えるか__ という部分です．チームで話し合った結果，以下3つの選択肢が出てきました．

1. マッチングリクエストのタイムアウト時間をとても長くし，マッチングしたらAPIからフロントにレスポンスで返す
1. フロントからAPIへ定期的にマッチングしたかどうかアクセスする
1. マッチングリクエストの直前に WebSocketを開通し，フロントとAPI間で双方向通信を可能とする．マッチングしたら，APIからフロントにWebSocketを介して送る．

それぞれのメリット・デメリットは以下のような感じでした．
|  実装方法 |  マッチングしたことを確実に伝えられるか  |同期性  |実装コスト  |
| ---- | ---- |---- |---- |
|  1  |  △  |○  |○  |
|  2  |  ○  |△  |△  |
|  3  |  ○  |○  |×  |

これらを考慮し，私たちは3番の WebSocket を使った方法に挑戦してみることにしました！

WebSocket はチームのメンバーの誰も使ったことがありませんでした．しかもあと4日間しか残されていません．本当にこれで大丈夫なのか...少し不安がよぎりましたが，サポーターの方の __後は実装するだけじゃん__ というお言葉に背中を押され，今できることを全て全力でやろう！と決めて取り掛かることにしました！まず最低限として，このフローに該当する， __筋トレメニューを推したらマッチングできてビデオ通話を開始できる__ というところまで実装しきることを目標としました．


#### 2日目

他のメンバーがAPI-Redis間のポーリング処理を実装してくれている間に，私は筋トレメニュー一覧を表示するエンドポイントの作成などを行っていました．

#### 3日目

3日目は，私は WebSocket 周りの実装に取り掛かりました．以下のフロー図で説明していきます．

![スクリーンショット 2022-12-06 22.52.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1840262/98d86afe-9e64-b79f-48e4-c05531fd97dc.png)



##### フロント側
1. 筋トレメニューをクリックします．
1. React の`useEffect` を用いて筋トレメニューがクリックされたら，webSocketのコネクション確立のためのリクエストを`webSocketEndpoint` に送ります．
1. webSocket のコネクションが確立されたら，マッチングリクエストを送ります．

##### バックエンド側
`webSocketEndpoint` では，リクエストしてきたユーザーの webSocket のコネクションを保持しておきます．
具体的には以下のように，ユーザーのIDをキーとした map （`webSocketClients`）に，コネクション情報(`conn`)を保持しておきます．
![スクリーンショット 2022-11-29 1.55.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1840262/383a8cf0-5196-ff6f-45a1-2d961120a5b2.png)


また，`webSocketClients`の一つ一つの要素には，コネクション情報(`conn`)の他に，チャネル（`Send`）も含まれています．このチャネルは何に使うかというと，Redis をポーリングしている Go ルーチン① から，マッチングしたことを`webSocketClients`に非同期で伝えるために利用します（以下図）．
![スクリーンショット 2022-11-29 13.03.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1840262/ed009668-156f-5eb9-02f2-739d6f98f24d.png)



`Send`からマッチングしたというメッセージを取り出したら，コネクション情報(`conn`)を使ってwebScketを介してフロントにマッチングしたことを知らせます．なお，このときに`roomID`も伝えます．`roomID`は，この後のSkyWay で同じ部屋でビデオ通話する人をまとめるための ID です．


##### WebSocket 周りの実装を行うにあたり工夫した点

今自分が知りたい情報を重点的に理解するようにすることです．参考になる記事はたくさんありました[^1]が，全て完璧に理解しようとすれば，4日間でサービスを完成させることはできないと思いました．そのため，実装するにはこの情報が絶対必要という部分だけ重点的に理解することを心がけました．例えば今回の場合，「webSocketのコネクション情報(`conn`)を使ってフロントにマッチングしたことを知らせる」という部分が重要かつ，どのように実装するか理解が足りていなかったため，その部分だけ様々な記事を読んだり，ライブラリのソースコードを見て使い方を理解しました[^2]．

そしてなんとか webSocket 周りの実装を完了させることができました！


#### 4日目
webSocket 周りの実装終わったし，後は本番環境で確認するだけだと思っていたのですが，なんとメンターさんから衝撃の一言が.. 

「__このままだと本番では動かないかも__ 」


本番環境では複数のAPIサーバーを使っていました．そのため，現状の実装方法だとマッチングしたという情報を複数のサーバー間で共有できないため，マッチングしたのにAPIから伝えられないユーザーが出てきてしまうということです．．

この問題を解決するために，__Redisのpub/subを使ってマッチングしたという情報を複数APIサーバー間で共有__ することにしました．

普段，複数サーバーが動いている環境で開発をしたことがないので，このような問題が起こるということに全く気づきませんでした．実際に起きる前からその可能性に気付かれていたメンターさんは本当に凄いなと思いました．

その後は，本番環境で動作確認をして終わりました！


#### 5日目
最終日は，Skyway を使った筋トレのビデオ通話の部分を担当していました．もともとメンバーがある程度は実装してくれていたのですが，レイアウトを整えたりなどしていました．

最後はなんとコードフリーズの2分前にデプロイをしました．なんとか，1日目に決めた最低限の目標である __筋トレメニューを押したらマッチングできてビデオ通話を開始できる__ というところまで実装し切りました！

#### 発表
最後に発表を行いました！発表資料は[こちら](https://docs.google.com/presentation/d/1jDio8GgOExHaZjJBW_g2_zCIrUYTqGIDUUmhM401g3s/edit)です！

#### 結果発表
私たちのチームは，この『Matchong』で __アイデア賞・チャレンジ賞__ をいただくことができました！とても嬉しかったです！チーム全員で喜びました！

##### アイデア賞をいただけた理由
「コロナ渦という現在の時流に合っていて，UNS [^3]に沿った開発をできていたから．その UNS が伝わったので，みんなに面白いと思ってもらえたのだと思う」というフィードバックを審査員の講師の方にいただけました！

##### チャレンジ賞をいただけた理由
「自分たちが知らない技術に対してやったほうが良いという強い気持ちでチャレンジして時間がない中実装しきったのが偉い」というフィードバックを審査員の講師の方にいただけました！

##### 今後の課題
一方で，いくつか課題点もいただきました．
1. ユーザー側の，『Matchong』を使い始める障壁が高い
筋トレメニューを押すといきなり知らない人とマッチングするので，使い始めるのには勇気がいるのではないかというご指摘をいただきました．その通りだなと感じました．自分たちのチームは，どちらかというとマッチョングした後にどのように筋トレをみんなで行うかという部分に注目していました．このご指摘から，__サービスを始める段階ではユーザーに使ってもらいたいと思ってもらうことに注力するべき__ であるということを学びました．
1. コードのリファクタリングが必要
WebSocketやRedisのポーリング部分のコードを全て同じファイルに書いてしまいました！これでは認知負荷が上がってしまうので良くないというご指摘をいただきました．おっしゃる通りだなと思います．

#### チーム内のFB
結果発表が終わった後は，チームでメンバーに対して FB を送り合いました！
下の写真は私に対して皆さんがしてくださったFBです．とても嬉しかったです！

![fbb.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1840262/5bc2aa3b-10a8-4c25-8492-ed4e1a30424f.png)


#### Treasure 終わってみての感想
チームみんなで未知の技術に挑戦して短期間で実装しきることができたので，大きな自信につながりました！また，私のことを信じて WebSocket を任せてくれたメンバーに本当に感謝しています。メンターの方々もつきっきりでサポートしてくださり，本当にありがたかったです．一人でも欠けてしまったら，『Matchong』を完成できなかったと思います．

##### なぜ未知の技術に挑戦できたか
「『Matchong』で届けたい価値は何か」という部分がチーム全員で一致していたからだと思います．時間を言い訳にして，より簡単な技術で届ける価値を妥協したくないという思いがありました．また，技術的にも精神的にも大いに頼れるメンターさんがいるという安心感が大きかったと思います．

##### 個人的な反省
__もっとメンバーにタスクの共有をするべきだった__ と思います．5日目にビデオ通話の画面のレイアウトを整えていました．しかし，タスクの共有が疎かになってしまっていたせいで，自分が今何をやっているのかメンバーにきちんと伝わっておらず，大きな混乱を招いてしまったということがありました．結果的にレイアウトは全部は完成せず中途半端な状態でコードフリーズになってしまいました．．最初からタスクの共有を細かくしておけば，メンバーも巻き込めてレイアウトを完成できたかもしれないと思っています．

#### その後の継続開発
その後の継続開発では，いただいた FB を元に改善していきました．主に以下の点に取り組みました．

1. 『Matchong』を使い始める障壁を低くするようにする
いただいた FB を参考にして，筋トレメニューの中で更に「ガチ」「ビギナー」というカテゴリで分けることにしました（以下写真）．このようにレベル別で分けることで，使い始める障壁を少しでも低くできたかなと思います．
1. コードのリファクタリング
WebSocketやRedisのポーリング部分のコードを全て同じファイルに書いてしまっていたので，どの関数にどの処理を書くべきか，この関数はどんな関心毎があるのかなどを意識して処理を分けて，コードのリファクタリングを行いました．
1. デプロイ環境を，AWSからVercel・Cloud Run に移す
Treasure 期間中にデプロイしていた AWS は使えなくなってしまったので，Vercel・Cloud Run に移しました．この作業は他のメンバーがほとんどやってくれました！

##### 継続開発で個人的に意識していた点

Treasure 期間中の反省点として，「タスクの共有をもっとメンバーにすればよかった」ということがあったので，継続開発中はIssueなどで自分のタスクの進捗状況を細かく共有することを心掛けていました．そのようにしていると，メンバーが助けてくれたりしました．

![fbb.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1840262/8492f9a6-9730-efde-5d89-cfae113c3b19.png)


また，コードのリファクタリングをどれにすればよいか，自分では決められないと思った時はその選択肢を図式化してどれが良いと思うか，メンバーに意見を求めるなどしました．

![fib3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1840262/e3a1ae5c-7c9e-a5d7-91e4-57b846395c8a.png)

##### 完成！！
完成版は[こちら](https://treasure-app-2022-g-frontend-dhpk.vercel.app/)からアクセスできます！ぜひ使ってみてください！！
最後になりますが，Treasure はとても楽しいです！青春です！学生の方はぜひ来年のTreasureに申し込んでみてください！




[^1]: 以下の記事を参考にさせていただきました．
https://selfnote.work/20210410/programming/websockets-chat-with-golang-2/
https://zenn.dev/tady/articles/adcdc65617ae57
[^2]: 以下の部分などです．
https://github.com/gorilla/websocket/blob/v1.5.0/json.go
[^3]: UNS とは，User・Needs・Solution の略です．アプリのアイデア出しの期間では，このUNSをフレームワークとして利用していました．