フロントエンドエンジニアとしてRECRUIT Job for Student 2021 Summerに参加しました!

はじめまして!早稲田大学基幹理工学部4年の矢田宙生(yada yuki) です。
普段は研究のために機械学習系の基礎勉強をしたり、スタートアップでアルバイトをしたりしています。
今回私はRECRUIT Job for Student 2021 Summerのエンジニアコースに参加しました。
2021年9月から約1ヶ月間、スタディサプリ ENGLISHのWebフロントエンドエンジニアとして業務に参加しましたので、その体験記を本記事にまとめたいと思います!

はじめに

本記事は今回参加したリクルートのアルバイトにおける選考過程、期間中に取り組んだタスクの内容や感想をまとめてみました。
普段小規模な開発が多い私にとって、フロントエンドのプロ集団の中での大規模開発は非常に良い経験になりました

RECRUIT Job for Studentに参加するまで

まずはRECRUIT Job for Studentへ参加するまでの経緯についてです。
実はリクルートのアルバイトに応募するのは今回が初めてではなく、今回のアルバイト以前にも数回受けたことがありました。
ですが、実力不足や案件のミスマッチ等が起因してこれまで参加には至らず、今年においては「今年は就活の年ではない。研究もあるし、受けないでいいかな...。」という想いもあり、一度は受けることを諦めかけそうになりました。

しかし、やはり自分の中で

  • 大規模なフロントエンド開発が経験したい
  • プロのエンジニア集団の中で自分の実力がどの程度通用するかを試したい。

という思いが徐々に強くなり、さらには研究室の先輩が昨年同じアルバイトに参加していたため宣伝や後押しを頂き、不安はありましたがエントリーすることにしました。
今回私が参加したアルバイトの選考では最初に事前の技術テストがあり、次に技術的な内容を含む面接が数回ありました。

面接の内容や回数は毎年変化があるようですが、今回私が受けた技術面接ではスタディサプリ ENGLISHのフロントエンジニアの方が面接官でした。
面接では架空のWebサービスの仕様書をもとにフロントエンドのコンポーネントや状態管理の設計が問われ、手元に用意した紙とペンで回答を行いました。(課題の内容も毎年同じとは限りません)

作成したアウトプットをもとに、「なぜそのような設計をしたのか?」「どのような技術を選定する想定であるか?」といった点について細かく問答を受けました。
私はこれまでも様々な技術面接を受けてきましたが、その中でもリクルートの面接は特に実践的なものだと思います「この人はしっかりプロダクトを作り切るスキルがあるのか」という点を誤魔化しの効かない質問によって見極めているように感じました。1)実際には"作り切るスキル"というよりは、問題を解くプロセスや考え方などを主に見ていたとのことでした。

技術面接には回答に不安な面も多くあったため結果が少し怖かったのですが、無事合格することができました。

期間中に取り組んだこと

今回のアルバイトでは「大規模プロダクトへの機能追加」や「技術基盤や既存機能の改善」といった、普段個人の開発では取り組むことができないようなことを経験してみたいという想いがありました。そのため事前にアルバイト担当の人事の方へ「既に一定以上のユーザーを抱えている大規模なフロントエンド領域の開発に携わりたいです。」というお願いをしており、結果としてスタディサプリ ENGLISHのWebフロントエンドチームに配属されました。

スタディサプリ ENGLISHといえば会員数が数十万人にも上る大規模サービス!
念願が叶ってそのようなサービスを作るチームの一員として働ける機会が得られたことは非常に嬉しかったです。

技術・アーキテクチャ

スタディサプリ ENGLISHのWebフロントエンド開発における技術スタックは、ReactとTypescriptによるSPAが採用されており、状態管理にはMobX というライブラリが用いられています。私が普段行っているアルバイト先や個人開発ではReduxを使用することが多かったため、MobXのキャッチアップは若干大変でしたがメンターやチームメンバーのサポートもあり、それほど詰まることなく実装を進めることができました。

次にWebフロントエンドのアーキテクチャ周りについてです。
スタディサプリ ENGLISHのWebフロントエンドは、一つのリポジトリの中に「一般ユーザーが使用するアプリケーション」や「学校の先生やパーソナルコーチの方が使用する管理画面」といった関連するサービスのコードが全てまとまっており、いわゆるモノレポ形式が採用されていました。一つ一つのサービスがパッケージという単位で分割されており、パッケージがデプロイ単位となります。
以下にディレクトリ構造の簡略版を示します。

└── packages
├── es-web-api // 全てのパッケージで使用するAPIリクエストモデルの定義
│   ├── node_modules
│   ├── scripts
│   └── src
├── es-web-catalog // storybook用
│   │   ├── coach
│   │   ├── library
│   │   ├── main
│   │   └── organization
│   ├── node_modules
│   ├── public
│   ├── scripts
│   └── static
├── es-web-coach // パーソナルコーチ専用アプリを管理
│   ├── node_modules
│   ├── public
│   └── src
├── es-web-library // 全てのパッケージで共通して使用するコンポーネントや定数などを定義
│   ├── node_modules
│   └── src
│   ├── components
│   ├── constants
│   ├── hooks
│   ├── stores
│   ├── styles
│   └── utils
├── es-web-main // エンドユーザが使用する学習アプリを管理
│   ├── node_modules
│   ├── public
│   ├── scripts
│   ├── src
│   └── static
└── es-web-organization // 学校の先生や企業の管理者が使用する管理画面アプリを管理
├── node_modules
├── public
├── src
└── static

またスタイル周りの技術選定ではCSS-in-JSとしてEmotionが採用されており、Reactのコンポーネントは基本的にFunctional Componentがベースになっています。今回触れたコードの中には一部、過去に採用されていたSUSS (CSS Modules)やClass Componentが残っているなど技術的負債もありましたが、5年を超える長い期間運用されているプロダクトの割には負債となっている箇所が思っていた以上に少なく、個人的に驚きを感じました。

英検試験スコアの一覧画面・入力画面の実装

私がアルバイト期間で取り組んだのは「英検試験スコアの一覧画面・入力画面の実装」というタスクです。
現在、スタディサプリ ENGLISHの使用層は「TOEIC等のスコアアップを目的とする社会人ユーザ」に限らず、「学校やクラス単位でスタディサプリ ENGLISHを使用している中学生・高校生のユーザ」も多く存在しています。
そして学生の多くは英検をはじめとする検定試験を受験していますが、団体受験ではなく学生が自主的に受験した英検やTOEICのスコアについては先生側が知る機会がありません
そこで、生徒側が先生に個人の検定試験結果の報告ができるように、試験スコアの入力フォーム・一覧画面の実装に取り組みました。

実装物

今回のアルバイトを通して実際に実装した「英検試験スコアの一覧画面・入力画面」の完成形は以下のものになります!

動的に変化するフォーム

今回実装した機能の中で一番複雑だったのはバリデーションや入力項目が動的に変化するフォームの実装だったと思います。

上記の動画を見ていただくと分かるとおり、TOEICの場合は「スコア入力項目が2つ、最高得点が495点」である一方で、英検3級の場合は「スコア入力項目が4つ、最高得点は550点」であるといったように、入力項目やバリデーションに用いている最高得点が「検定種別」項目に応じて変化していることがわかります。

このような動的なフォームを実装する上で必要な「検定種別」に応じた最高得点や入力項目等の情報は以下のようなフォーマットでバックエンドから取得しています。

{
"items": [
{
"examinationName": "TOEIC® L & R",
"examinationScoreTypes": [
{ "scoreType": 1, "scoreName": "リスニング", "maxScore": 495 },
{ "scoreType": 2, "scoreName": "リーディング", "maxScore": 495 }
]
...
},
{
"examinationName": "英検 3級",
"examinationScoreTypes": [
{ "scoreType": 1, "scoreName": "リスニング", "maxScore": 550 },
{ "scoreType": 2, "scoreName": "リーディング", "maxScore": 550 },
{ "scoreType": 3, "scoreName": "ライティング", "maxScore": 550 },
{ "scoreType": 4, "scoreName": "スピーキング", "maxScore": 550 }
]
...
}
...
]
}

そして、バックエンドから取得したデータをもとにMobX Storeのクラス内で以下のような関数を定義。

public isValidScore(scoreType: ScoreType): boolean {
....maxScoreを取得
return score >= 0 && score <= maxScore;
}

isValidScoreが返す値によって、入力されたスコアのバリデーションを実装しています。
このようにアプリケーションの状態に基づいた派生状態をクラス関数という形で柔軟に定義できる点はMobXの大きな利点の一つであると思いました。

案件を進めるにあたってのコミュニケーション

今回の案件は只々webフロントのコードを書いていれば良いというわけではなく、様々な役割の方とのコミュニケーションが必要になりました。
まずはAPI仕様をサーバ担当の方に細かく確認することから始まり、デザインについてもエラーメッセージの文言や画面遷移の挙動など細部まで密なやりとりを行いました。
時には「検定の種類によってはバリデーションが異なるのではないか」「そもそも入力項目が変化するのではないか」といった点をPMやデザイナの方に確認し、自分の提案や指摘が仕様に反映される経験を得ることができました。
PMやデザイナの方にうまく伝わるよう、なるべく技術的用語を使わないで現状の事態や方針を言語化するのは大変でしたが、これもまた大規模開発ならではの経験になったと思います。

アルバイトについて

最後に参加したアルバイトの待遇や働く環境について書いていきます。

待遇や勤務体形

  • 期間:2021年9月1日 (水) 〜 2021年9月29日(水)
  • 報酬:時間額2,500円
  • 週の勤務頻度:2日〜5日(土日祝日は休み)
  • 開催場所:参加時期の社会情勢を踏まえて、自宅からのリモート勤務2)最初からオンライン前提というわけでなく、開催時期の社会情勢踏まえて判断とのことでした。

勤務時間に関しては非常に自由でした。基本的には好きな時間に出勤してよく、学会や研究室の用事があるときはそちらを優先して良いことになっています。3)一方で働きたい時は週40時間の上限を超えない限りは好きなだけ働けます。

働く環境

社会情勢の影響で、初日から最後の懇親会まで全てオンラインでした。4)重ねてになりますが本来はオフィス勤務の予定でした。
そのためオフィスに出社することが一度もできなかったことが非常に残念です。
しかし私が参加したスタディサプリ ENGLISHの部署では、SlackやGithubのissueを活用したオープンなコミュニケーションが非常に活発でした。
業務中に私がSlackに投げた質問に対してWebフロントチームの方々のみならず、サーバサイドやモバイルチームの方までもが答えてくれることもありコミュニケーションという面では全体的に非常にスムーズであったという印象があります。

まとめ・全体を通しての感想

今回のアルバイトを通して技術的な面でも様々な学びがあったのですが、一番の収穫はエンジニアとして成長意欲がより高まったことだと感じています。

実際の業務を通じてプロのエンジニアとのコミュニケーションとその人たちが書いた妥協の無いコードに触れることを経験しました。
その経験から、自分は技術的難易度の高い課題にも対峙していけるような技術力の高いエンジニアになりたいとより強く思うようになりました。
今後も新たな領域に挑戦することをやめず、エンジニアとしての道を極めていきたいです。

一ヶ月という短い期間ではありましたが、貴重な体験をさせてもらい、本当にありがとうございました!

脚注

脚注
1 実際には"作り切るスキル"というよりは、問題を解くプロセスや考え方などを主に見ていたとのことでした。
2 最初からオンライン前提というわけでなく、開催時期の社会情勢踏まえて判断とのことでした。
3 一方で働きたい時は週40時間の上限を超えない限りは好きなだけ働けます。
4 重ねてになりますが本来はオフィス勤務の予定でした。