
Treasure2023 参加体験記
お疲れ様です。よしPです。
今回は、株式会社CARTA HOLDINGS(旧voyage group / CCI)が毎年夏に開催しているサマーインターン「Treasure」に参加した時の体験記をここに残そうと思います。
Treasureって何やるの?
2023年度のTreasureは、3週間という短期インターンにしてはちょっと長い期間を使って、前半の約1週間でバックエンド+フロントエンドやDB講義に取り組み、後半の約2週間でアイデア講義やハッカソン形式のチーム開発に取り組むといった流れでした。
2023年度のTreaureの技術スタックは、バックエンドがGo (GraphQL) / フロントエンドがReactでUIコンポーネントライブラリがMUIでした。
技術選定は、『今後、将来性がありそうな技術スタック / 色々と学びを最大化できそうなものにしたい』という方針があるらしく、毎年変わる場合も全然あるそうです。ちなみに、GraphQLは今年度が初だったらしいです。
この体験記を読んでる26卒以降の学生さんで、もしかしたら「夏になるべく多くの企業のサマーインターンに参加したいから3週間はちょっと長いなぁ…」と感じてる方も少なくないかもしれません。実際に私がそうでした。ただ、バイアスがかかっているかもしれませんが、最終的にTreasureを選んで本当によかったと今では思っています。
そう感じた理由を後に記していきます。
実際の講義
講義日程は以下の通りでした。
Day1:講義導入+初日懇親会
Day2:バックエンド講義(Go / GraphQL)
Day3:フロントエンド講義(React / TypeScript)
Day4:講義振り返り+前半講義打ち上げ
Day5:DBモデリング講義(@t_wadaさんが講師)
Day6:アイデア講義+チームキックオフ
Day7〜13:チーム開発
Day14:最終発表+打ち上げ
バックエンド講義とフロントエンド講義に関して
講義フェーズは、CARTAの現役エンジニアの方が講義スライドを作成し、それに沿って進行していきました。Treasure期間中は、主にSlackを活用して社員さんや同期のTreasure生とコミュニケーションを取っていたので、分からない箇所や疑問に思ったことは適宜質問できる環境が整っていました。
講義の後半では、課題が用意されており、それに取り組みながら学んでいきました。フロントエンド講義では、チームに分かれて実装するものもあり、TAの方(24卒の内定者)が各チームに配属されていたのでコミュニケーションに困ることは全くなかったです。
私はGraphQLの経験がなかったのでバックエンド講義で苦戦しました…笑
ただ、resolverやusecase、repositoryのレイヤーに分けて依存関係を分離したりなど、クリーンアーキテクチャを意識して実装してみることができたので勉強になりました。
DBモデリング講義に関して
DBモデリング講義では、テスト駆動開発の第一人者で有名な和田卓人(@t_wada)さんが講師を勤めました。

買い物レシートをERDにモデリングしてみるというお題で、講義の後半では、チームごとで自分たちが考えたDBモデリングをぶち壊す買い物を実際にしてみて、それをモデリングに反映させるところまでやりました。

コンビニによっては、「対象の商品○点セットで〇〇円引き」「○○%OFFセール」「お支払い割引」「税率」などモデリングする上で考えるべき事象が多く、かなり大変でした…
また、この講義を通して、リソース系エンティティとイベント系エンティティの存在や交差エンティティなどの概念についても認識することができ、勉強になりました。
その中でも、ナチュラルキーを主キーにすることのリスクの一例として、以下の事例が取り上げられ、エンジニアからしたらかなり恐ろしく感じました()
追記【2023/9/1】
CARTA TECH BLOGにて、DBモデリング講義の記事がでたので貼っておきます。
アイデア講義に関して
UNS(User Needs Solution)というプロダクト案の構成要素を活用して、アイデア考案をしました。
「そもそも、価値のあるプロダクトとは何なのか?」という導入から始まり、社会を流れゆくもの「時流」と捉え、社会の揺らぎ(新たに生まれてきた課題や欲求 / 技術の進歩で解決できるようになった課題)に着目する中で、自分たちのアイデアを考案していきました。
久しぶりにアイデアワークショップをやったので、最近の社会の動向を掴むのが個人的に楽しかったです。普通に生きてて何も感じてなかったけど、よくよく目を向けたら変わったこと多いなぁ…と感じました。
チーム開発
アイデア講義が終わった後は、チームのMeetupでした。
そして、4人の同期のTreaure生と4人のサポーターの計8人で私たちのチームが構成されました!チーム名は『おまっちゃ』🍵
協調性が高すぎるチームで、誰もが発言しやすく、心理的安全性が常に保たれてた良いチームでした。

結成ホヤホヤなのに、びっくりするくらいみんな笑顔w
(実は昔から知り合い…??笑)
おまっちゃは協調性が高いメンバーで、最初から最後までHRTが完璧なチームだったなぁと思います。
HRTに関しては、前回書いた記事を読んでみてください。
チーム開発で取り組んだアプリ
おまっちゃは、グッズを交換したい人同士が、交換条件に合致した人をスムーズに探すために、自分が求める交換条件を指定して相手を検索できるサービス『ヲタトレ』を開発しました。


開発背景
おまっちゃは、複数のテーマ(領域)において、社会の揺るぎに着目して未だ解決できていないものを洗い出し、その中から実装コストや需要の面において、実現可能性を視野にアイデアを削っていきました。
最後は「聖地巡礼のお助けアプリ」か「グッズ交換のお助けアプリ」まで絞り込みました。
また、サポーターの方の知り合いの社員さんがアニメファンと聞き、実際にユーザーインタビュー(PoC)を行い、第三者目線からの意見も伺いました。他にインタビューをやってたチームはそこまでいなさそうだったので、良い経験ができました!
最終的に『自分たちが熱意をもって開発に取り組めるのか』という視点を重視し、ヲタトレを開発することに決めました。
開発の技術スタック
前半の講義フェーズでも使用していた技術スタックと同様に、フロントエンドをReact(TypeScript)/ バックエンドをGo/GraphQL / DBはPostgreSQLの構成で、インフラはAWSのECSを選定しました。
前半の講義フェーズは講師陣が用意していたベースアプリを使って作業していましたが、そのまま拡張する形にしました。Makefileがかなり充実していた点と、一から自分たちで構築する手間を省きたかったからです。
(じゃないと、期間内に終わらない…)
ベースアプリのインフラ構成図は以下の通りです。


開発フェーズ
おまっちゃは、まずコア機能の洗い出しを行い、DB設計から始めてそこからユーザーストーリーごとに機能を分割して役割分担をしました。

コア機能の洗い出しでは、『いち早くユーザーに価値を提供するには何が必要最低限なのか』をチームで目標にして取り組みました。
そのため、開発もMVP開発を意識して、ミニマムスタートを心がけました。

DBモデリング講義で学んだことを生かして、イベント系エンティティとリソース系エンティティの関係やテーブル同士の依存関係をなるべく避けるためにusersテーブル周りに新たにテーブルを切り出しました。また、exhibiting(出品)のステータスをstatus_changingの交差エンティティを挟んで切り出したことで、いつ更新されたのかを保つ設計にしました。

そして、せっかくのオフライン開発だから、GitHubのProjectやJiraとかのタスク管理ツールを使用せず、付箋で管理しよう!というノリで、おまっちゃは付箋駆動開発を行うことにしました笑
タスク管理において意識した点は、技術領域ごとで達成すべきタスクを設定するのではなく、ユーザーストーリーを意識して、『ユーザーが〇〇できるようになる』という視点でタスクを切り分けたことです。
こうすることで、ユーザーにいち早く価値を提供するMVP開発に則したタスク管理を行えるようになりました。
しかし、後の振り返りで気づいたデメリットとしては、ユーザーストーリーを意識してタスクを切り分けることで、一つ一つのタスクの粒度が大きくなり、フロントエンドとバックエンドも兼ねて実装する必要があることです。圧倒的な実装力があれば別ですが、必然的にPRの粒度も大きくなり、コードレビューが大変になったり、mainブランチへのマージでコンフリクトが起きやすくなるというデメリットがありました。
ハッカソン形式ということもあり、タスクの見直し作業の時間がなかなか確保できなかったのですが、タスクの粒度を一度見直す作業を途中で入れたことで、実装の負担が少し軽減された気がします。見直し大事!
開発中に起きた困ったこと
実際の開発期間はアイデア出しも込みで4日半ありました。
その中で起きた困ったことについて振り返ります。
サポーターの方がコロナ陽性になり、おまっちゃチームは急遽4日間オンラインに移行。
PRが肥大化しすぎて、mainブランチに反映しづらい。
無意識のうちにベースアプリの技術スペックに無理に合わせようとしすぎてた。
自分がMVPのどこを実装していて、どのタスクを優先的に処理すべきかを見失う時があった。
焦りから、コードレビューの質が落ちてしまっていた。
慣れないGraphQLで一から認証処理を作り直そうとし、かなりの時間を割いてしまい実装が終わらなかった。
付箋駆動開発で始めようとした矢先、急遽オンラインのリモートに切り替えることになり、やむなくGitHubのProjectにタスク管理を移行しました。
前述したようにユーザーストーリーに沿ってタスクを切り分けた影響で、PRが肥大化してしまい、コードフリーズの直前にmainにマージできなかったPRが複数ありました。そのため、タスクチケットの振り分けをフロントエンドとバックエンドでより細分化すべきだったと感じました。
また、私たちのプロダクトでは、グッズの画像もAWSのS3のストレージ上で管理する予定でしたが、ローカル上でコンテナ環境を用意して、本番環境での動作確認がコードフリーズ直前になってしまい、結局mainにマージすることを諦めました。(アト10秒アレバイケタ)
ただ、よくよく考えればわざわざS3を使わなくても、ベースアプリが認証をFirebaseで処理してるので、FirebaseのCloud Storageで画像を管理すれば良かったなと…ECSでデプロイしているからと脳死でAWSのPaaSを使おうとしていたのは要注意でした。
調べてみたら、ローカルにS3完全互換のストレージ環境を構築できるツールがあるらしい。
さらに、『常に自分がMVPのどこを今実装しているのか』の視点が開発フェーズの後半は見えてないケースがありました。特に、開発後半は時間が本当になく、MVPを意識して機能の取捨選択をし、残りのタスクの優先順位を見直すことが重要だと感じました。
どうしてもコードフリーズまでの時間の焦りから、最後の方はコードレビューがかなり雑になっていました。当然、実際のプロダクト開発では、コードフリーズの概念がないので、一晩寝かせてからmainに反映させるのが安全ですが、ハッカソンだと厳しいので焦る必要のない先を見越したタスク管理が理想ですね。。。
また、ベースアプリで既にFirebaseを使ったGoogle認証基盤が構築されていたのですが、グッズ交換のためのTwitterID(今はXIDの方が適切?)と名前をusersの情報と一緒にアプリ側のDBで保持しようと認証基盤をいじってしまったため、かなりの時間を要してしまいました。ここは自分の技術力を過信せず、ベースアプリの認証基盤のまま進めるべきだったと反省しました。
開発終了後の講師陣からのFBにて、usersテーブル周りについて色々と聞かれたので、おまっちゃが想定してた設計に近い記事を載せておきます。
また、一時期臨時でサポーターに入っていただいたZucks CTOの@河村さんから、Zucksのエンジニア組織における日々の営み、大事にしているバリューやプラクティスを言語化した「The Zen of Zucks」を読むことをオススメされたので、ぜひ目を通して自分なりに色々と解釈したいと思います。
開発したアプリ 『ヲタトレ』
最終発表プレゼン資料のURLを置いておきます↓
https://www.canva.com/design/DAFscZvo63w/UNcCwDRaIIeREfGh3hFDBg/edit?utm_content=DAFscZvo63w&utm_campaign=designshare&utm_medium=link2&utm_source=sharebutton
今後の課題
デプロイ環境の移行(Treasure期間中のリソースが削除される関係)
ログイン機能の改良
ストレージ機能の実装(Firebase Cloud Storage等)
リクエスト送信のフロントエンド側の画面実装
コードのリファクタリング
主に、時間内に実装し終えられなかった箇所を重点的に実装し直したいなと考えています。継続開発に関しては、他のインターンに参加するメンバーもいたため、任意でフォークして継続開発をする形をとりました。
Treasureを通して学んだこと
3週間を通して学んだことは数多くありますが、主に挙げるとすると、以下の5点です。
短い周期でPDCAサイクルを回すことの重要性
PRは肥大化させない
心理的安全性や軸は良いチームを構築する
状況を伝える言語化能力
コンフォートゾーンを抜け出すことの重要性
おまっちゃは開発期間中、60~90分周期でPDCAサイクルを回していました。そのおかげで、お互いの状況整理やタスクの粒度の見直しが取りやすかったと感じています。また、おまっちゃはチーム結成時に『自分たちの軸』を決めました。

今までのチーム活動では、課題を解決するための目標は掲げていましたが、自分たちが成長するための軸を定めた経験はありませんでした。今回のおまっちゃはこの軸を定めたおかげで、自然と全員が当事者意識を持って、全員がチャレンジできる環境を意識し、最後までコンフォートゾーンを抜け出すことができたと実感しています。
また、雑談を積極的に取り入れることを意識したことで心理的安全性の構築や、ユーザーインタビューの時も情報の削ぎ落としを防げたと感じています。この話については、@ミノ駆動さんの記事をぜひ読んでみてください。
Treasureが始まってから、おそらくTreasure生全員が意識していたことの一つに『コンフォートゾーンの少し外側に身を置く』があると思います。これに関しては、CARTAのテックブログにバックエンド講師の@yanyanさんが良い記事を書いているので、こちらもぜひ読んでみてください。
さいごに
始まる前は長いと感じていた3週間のTreasureもあっという間に終わり、技術面でもパーソナル面でも新たな学びが本当に多かったです。逆に3週間という期間があったからこそ、中途半端なところで終わらず、学びを最大化できたと感じています。
Treasureの運営の方々および、講師陣、サポーター、TA、同期のTreasure生、そして、おまっちゃチームのみんなに心から感謝したいです。
もし、Treasureに参加することを迷っている26卒以降の学生さんがいたら、ぜひチャレンジしてみてください。きっと良い学びがあると思います。
最後にTreasure期間中の思い出として、おやつタイムや懇親会の様子をここに残しておきます^^



