「2days ONE CAREER Tech Internship」に参加してきた話

ワンキャリアの「[2days ONE CAREER Tech Internship](https://www.onecareer.jp/events/internship/35554)」に参加してきました！

インターンの内容を振り返りつつ、学んだことや感想などを書いていこうと思います！

# インターンシップ内容

主なコンテンツとしては2つあり、1日目の午前中は**システムデザインインタビュー**、その後はECサイトの**パフォーマンスチューニング**という流れでした。

両方とも基本的に二人一組チームで行い、最後にパフォーマンスチューニングの成果発表を行いました。

メンターの方々から開発における考え方のアドバイスをいただくことができ、
またCTOの方と1on1面談もさせていただくことができ、技術力以外にも学びのあるインターンシップとなりました！

# システムデザインインタビュー

インターンのオープニングや自己紹介・アイスブレイクが終わった後に、システムデザインインタビューが始まりました。

システムデザインインタビューはソフトウェアのシステム設計能力を評価するための面接です。

外資系IT企業の採用面接では割と行われているようですが、日本企業の面接ではあまり行われておらず、私自身も今回のインターンシップで初めての体験しました。

出されたお題に対して要件をドキュメントにまとめ、その要件をもとにシステム構成図を作成しました。

具体的には、
機能要件 → 非機能要件 → リソース見積もり → High Level Design → Detail Design
という流れで設計を行いました。

## 1. 機能要件

何を解決したいのか、どのような機能が必要かを考えます。

ここでは考えつくものであればどんな小さなことでも書き出し、後から重要な要件だけに絞っていきます。

面接なので、設計に慣れている人は細かいことを気にせずに重要な部分だけを最初から考え、すぐに次のステップに移行しても良いかもしれません。

## 2. 非機能要件

機能要件ではない品質などに関係するものを考えます。
今回のインターンでは例として以下の4つが挙げられていました。

- 高可用性
    システムが常時利用可能である状態を維持しているか。

- スケーラビリティ
    ユーザー数の増加など処理が大幅に増えた場合に問題が生じないか。

- ハイパフォーマンス
    遅延が起こらずスムーズな機能提供ができるか。

- 信頼性
    災害や障害など不測の事態に陥いり機能が停止したとしてもユーザデータが紛失・破損せず信じて使用できるか。

他にも様々な非機能要件があったので、調べてみると面白いかもしれません。

## 3. リソース見積もり
    
サーバー台数やストレージサイズ、要求帯域などを見積もります。

例としてサーバー台数の見積もりを行います。

:::note warn
定義している数値は全て適当です。
:::

まずは1ヶ月あたりのアクティブユーザー数を決めます。
    
MAU: 15億人

次に1日あたりのアクティブユーザー数を求めます。
 
DAU: 15億人 / 30日 = 5億人

そして1秒あたり、どの程度リクエストが来るのかを求めます。
    
秒間リクエスト: 5億人 / 24h / 60m / 60s = 約6000人 / sec

1秒間にだいたい6000リクエストくることが求められました。
    
ここで1台のサーバが1秒あたり、1000リクエスト捌けるとします。
    
6000人 / 1000リクエスト = 6台
    
サーバーの台数はだいたい6台程度と見積もることができます。

実際は他にも考慮すべき点がありますが、面接では時間の関係もあるので大まかで大丈夫のようです。

## 4. High-level design

High-level designでは要件を満たせる機能を優先して、全体像を設計していきます。

クライアント、サーバー、ロードバランサー、データベース、ストレージや機能を満たすためのコンポーネントなど、全体像のフローをdrow.ioなど図面作成ツールを使用して設計します。

## 5. Detailed design

Detailed designではHigh-level designの詳細を詰めていきます。

例えば

- サーバーとは具体的にどんなサーバーなのか(ウェブサーバーやアプリケーションサーバー)
- データベースとは具体的にどんな情報を扱うためのデータベースか
- データベース・ストレージでは、どのようにデータを保持するのか
- High-level designで機能を満たすためのコンポーネントに不明瞭な部分はないか

などを考えて、最終的にシステム構成図を完成させました。

# パフォーマンスチューニング

Goで書かれたヘッドレスECサイトのパフォーマンスを最大化できるように改善を行いました。

### 環境構築

出だしのDockerによる環境構築で、DBの初期化がうまくいきませんでした。

原因を調べたところ、自分のPCの容量不足でした。特にDockerに容量を食われていました。

Dockerをあまり勉強せずに使用していたのでコンテンとイメージを削除すれば全て削除されていると思っていましたが、実際はボリュームとネットワークが残っていることに気づきませんでした。

本当に全て削除したい場合は`docker system prune --volumes`コマンドを使用する必要があることを学びました。
結果的に20GB以上の無駄なデータを消すことができ、環境構築が終わりました。

特定と解決に時間がかかりスタートしてから1時間を環境構築に使ってしまいました...

(チームメンバーには多大なご迷惑をおかけしました:bow_tone1:)

### 計測

環境構築も終わりやっとパフォーマンスチューニング開始です！
ですが、私の実力としてはパフォーマンスチューニングの始め方すらよくわかりませんでした。

最初からコードを読んでおかしいところをチューニングしていこうと最初は考えていましたが、
メンターの方からまずは計測してボトルネックを見つけた方が良いということを教えていただきました。

そこで、ECサイトのエンドポイント毎に計測し、優先順位を決め、次に優先順位の高い順番にpprofを使用して関数単位での詳細な計測を行い、ボトルネックを特定していきました。

pprofとはGo言語のプロファイリングツールで、関数実行時間などを計測し、グラフなどで可視化することができます。
フレームワークにGinを使っていたので`gin-contrib/pprof`を導入して計測を行いました。

実はpprofが使用するのに、コードに数行記述するだけで簡単に使用可能なのですが、かなり時間がかかってしまいました。

原因はdockerのリビルド忘れでした...

今考えればなぜそれを考えつかなかったんだ！となりますが時間が限られている中で焦っていたのか全く思いつきませんでした。

今回の失敗で完全に記憶に残ったので今後はリビルド忘れはしないはずです！！

「推測するな、計測せよ」というGoの作者の一人でもある、 Rob Pike 氏の言葉通り、
パフォーマンスチューニングでは、アプリケーションのどの部分がどの程度時間がかかるかを計測してから手を動かすべきということを学びました。

### チューニング

pprofで計測し、ボトルネックになっていたところはデータベース操作の部分でした。

原因のコードを見たところ、最初はループで何回もSQL実行してるから遅いんだな〜としか思わなかったのですが、
これが噂のN+1問題か！ と気付き、テンションが上がりました。

N+1問題の解決策としてはjoinを使用して一回のクエリでデータを取得できるようにしました。
ですが、無闇矢鱈にjoinしてしまうと、`out of memory`になってしまうため、注意が必要ということも学びました。

他にも外部コマンドを実行している部分があったのでGoのライブラリに置き換えたりしてチューニングを行っていきました。

またテストの重要性も学びました。
パフォーマンスチューニングする時は、テストで機能性を担保してからチューニングをしていかないと、挙動に問題があった時にどのチューニングによって不具合が生じたのか特定することが大変だったので、テストの大切さを学ぶことができました。

## 改善点

NGINXログの内容を正しく読めていませんでした。
コンテナが落ちる原因を勘違いしたことで作業時間を取られてしまったのでログをしっかりと深く理解することが重要だと学びました。

また工数の見立てを行えませんでした。
実務では期限を設けなければいけないのでそのために工数の見立てを行いますが、今回は見切り発車でパフォーマンスチューニングを行ってしまったので今後は工数の見立てを行いながらチューニングに取り組みたいです。

# 面談やフィードバックで学んだこと

CTOの方やメンターの方と、面談やフィードバックで様々なことを学ばせていただきました。
特に成長するための要素について以下のようなことを教えていただきました。

- 学生の時にOSなどの低レイヤー周辺やCSの知識を学ぶと良い

これに関しては業務となると納期や信頼性のためにフレームワークを使うことになりますが、
エラーに陥った時に根本部分を理解していれば修正力が高まるからだと思います。
またフレームワークや言語などは新しいものがどんどん出てきて進化が激しいですが、低レイヤーやCSなどの根本の知識にはあまり変更がないので、将来も半永久的に活躍してくれる知識だから重要なんだと思います。

- 車輪の再発明が大事

ネガティブな意味で使用されがちですが、やはり根本を理解するために一番確実なのは、それ自体を実装してしまうことです。
確かに実務で車輪の再発明をしてしまうとコスパが悪く生産性の面で注意されるかもしれません。
ですがつよつよエンジニアさんはフレームワークやライブラリに頼らず1から実装できる人が多いイメージなので学習においては車輪の再発明を積極的に行っていくことが重要だと思います。

# 感想

システムデザインインタビューとパフォーマンスチューニングに経験のない自分でも楽しむことができました！

チームで一丸となって課題に向かう体験は社会人になってからも活きると思うので貴重な経験を積ませていただき感謝しています。

また手厚いフィードバックがあり、今後エンジニアになるためにどのように学習していけばいいのか指針を得ることができ、参加して良かったと心から思いました！

2日間ありがとうございました！！