サーバーサイドエンジニアとしてRECRUIT Job for Student 2021 Summerに参加しました!

TanjiHaruto
5

はじめまして!RECRUIT Job for Student 2021 Summerのエンジニアコースに参加しました丹治(@ntk_ta01)と申します。

参加したアルバイト

今回私はRECRUIT Job for Student 2021 Summerのエンジニアコースに参加しました。このコースでは実際のプロダクトメンバーとしてチームにジョインし、1ヶ月間業務に携わりました。アルバイトの基本情報は以下の通りです。

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

アルバイトの募集ページはこちらからご覧ください!

アルバイト参加まで

参加経緯

半年前まで私は大学での研究や競技プログラミングに力を入れており、Webアプリケーション開発の経験がありませんでした。しかし大学院に進学して就職を意識し始め、「夏は企業のインターンシップに参加しよう!」という考えが生まれました。そしてとある逆求人イベントでリクルートの人事の人と話す機会があり、「実際のプロダクト開発を経験したらめちゃくちゃ成長できそう!」と感じたので今回のアルバイトに応募しました。

選考過程

募集ページにも書いてある通り、書類選考とwebテスト、それから面接が行われました。webテストは競技プログラミングのような問題とSQLの問題がありました。前者はスラスラ解けたのですが、後者は自分のSQLの経験が少なかったために解けない問題も複数ありました。とはいえ教科書に載っているようなレベルでしたので、似たようなwebテストを受けるときは事前に普段書いていない分野の復習をお勧めします。

私の場合、面接は複数回ありました。印象的だったのはエンジニアとその場で架空のサービスについてAPI設計をする形式があったことでした。(あくまで私が受けた面接の話で、毎回同じとは限りません。)「紙とペンを用意してください」と事前の連絡にはあったのですが、API設計をするとは思ってなかった上にそれまで取り組んだこともなかったのでかなり焦った覚えがあります。

正直に「API設計をやったことがないので相談しながら取り組んでいいですか?」と聞いて、わからないながらも取り組みました。二次面接が終わった直後は「これは落ちたな〜」と思っていたのですが、8月になって合格の連絡が来たのでめちゃくちゃびっくりしました。嬉しかったです。

事前面談

人事と配属先のチーム、メンターになる人との面談がそれぞれありました。アルバイト参加の目的を事前にすり合わせたり、配属先のプロダクトについて説明がありました。このアルバイトでは 学生が何を経験したいか? をめちゃくちゃ尊重してもらえます。私の希望は「バックエンドエンジニアとして成長したい」「業務におけるチーム開発を経験したい」などとあまり具体的ではなかったのですが、人事やメンターの人には上手く課題を設定してもらいました。アルバイトの内容の中で詳しく書きます。

アルバイトの内容

業務内容

スタディサプリENGLISHには事業案件を開発するスクラムのチームがいくつかあります。私はそのうちの一つに1ヶ月ジョインしました。チームからは二人の社員にメンターとしてついてもらい、案件に取り組みました。

担当案件詳細

スタディサプリENGLISHでは次のような画面からスタディサプリ内やスタディサプリ外の学習記録を見ることができます。

この機能のために日別に学習の時間や内容を取得する学習報告APIが存在します。スタディサプリENGLISHのサーバサイドは機能分割とマイクロサービス化がされているため、一つのマイクロサービスがこの機能を担当することになります。しかし、初めはこの学習報告ではスタディサプリ外の記録のみを持つとして開発されていました。スタディサプリ内の学習記録は別の機能を担当する学習マイクロサービスが保持しており、スタディサプリ外の学習記録を担当する学習報告マイクロサービスがデータをコピーして使用しています。

これをサプリ外の学習記録を扱うマイクロサービスとサプリ内の学習記録を扱うマイクロサービスとして将来的には分けたいです。

しかし一気にAPIを切り替えるのは危険があります。よって、まずは学習報告マイクロサービスからコピーデータを取得することは変更しません。取得したデータをgRPCの内部通信でやり取りし、学習マイクロサービスにAPIを移し替えることから始め、私はこの案件を担当しました。次の図の左から右のようにAPIを移し替えます。

担当案件実装

実装の流れは次のように設定してもらいました。

  1. 学習報告マイクロサービスにgRPCメソッドを作成
  2. 学習マイクロサービスにgRPCの呼び出しを行うようなメソッドを作成
  3. 学習マイクロサービスに2.のメソッドから得られるデータを加工し、そのデータを返すメソッドを作成
  4. 学習マイクロサービスにJSONを返すAPIを作成

最終的に1.のコードがマージされるところまで行けばよい、というのがメンター側の想定だったらしいのですが、実際は3のコードまでがマージされてかつ4.のコードも実装することができました。これはメンターからのかなり手厚いサポートを受けられ、かつ既存APIを参考に実装が上手く進んだからだと考えています。

実装について全てを書くことはできないのですが、面白かった点や苦労した点をいくつか挙げます。

Effによって抽象化されるコード

スタディサプリENGLISHのサーバーサイドではEffが多く使われています。Effについてはこちらの記事をご覧ください。

私の理解はまだまだ浅いのですが、EffはOptionやEither、FutureなどをEffの中に押し込める便利な存在という認識です。例えば今回以下のようなコードを一度書きました。ユーザの報告に含まれるIDから名前を取得し、取得した名前を含むような報告を返す処理です。

userReportsWithNames <- Eff.traverseA(userReports) { userReport =>
  for {
    hogeOpt <- hogeRepository.resolveEff(userReport.hogeId)
    fugaOptOpt <- Eff.traverseA(userReport.fugaId) {
      fugaRepository.resolveEff
    } 
  } yield UserReportWithNames( 
    userReport = userReport,
    hogeName = hogeOpt.map(_.name),
    fugaName = fugaOptOpt match { 
      case Some(fugaOpt) => fugaOpt.map(_.name)
      case None => None
    }
  )
}

このコードではfugaOptOptOption[Option]型であるためにmatch式を用いなければいけなくなっています。これは以下のように書き直すことができます。

userReportsWithNames <- Eff.traverseA(userReports) { userReport =>
  for {
    hogeOpt <- hogeRepository.resolveEff(userReport.hogeId)
    fugaOpt <- Eff.flatTraverseA(userReport.fugaId) {
      fugaRepository.resolveEff
    }
  } yield UserReportWithNames(
    userReport = userReport,
    hogeName = hogeOpt.map(_.name),
    fugaName = fugaOpt.map(_.name)
  )
}

この書き換えによってmatch式を使わずに済むようになりました。これはEff自体が便利というよりはflatTraverseAが便利だった例になってしまっている気がします。しますが、私はこのコードを書いていてEffがコードを抽象化して読みやすくしていることを実感しました。

Clean Architectureを意識したコード

スタディサプリENGLISHのサーバーサイドではClean Architectureが採用されています。私はClean Architectureに初めて触れましたが、案件で触るAPIの流れを追ったり他のAPIを参考にしながらコードを書いて慣れていきました。アルバイト終盤はドメインモデルやデータモデルの影響を受ける部分を意識しながらコードを書いていました。しかしまだまだ理解は浅いですので、アルバイトの書籍購入支援制度を用いて購入したドメイン駆動設計の本などをアルバイト後も勉強しようと思います。アルバイトの書籍購入支援制度については後述します。

めちゃくちゃ良かったサポート体制

今回の案件によってメンターに設定してもらったゴールは次の通りです。

  • 思想・知識面
  • マイクロサービスによる境界わけとドメイン・ビジネスロジック、永続的データ(データベース)の関係について理解が深まる
  • 技術面
  • RPCとプロトコルバッファーについての理解、JSONなどの他のシリアライゼーションとの比較など

  • Scala言語に関する程々の理解

初めはマイクロサービスもgRPCもわかっていなかったので、こんなゴール達成できるのか、という気持ちでしたがメンターの方の手厚いサポートのおかげで達成できたと思っています。事前面談の経験したかったことも叶いました。

わからないことはslackでかなり気軽に質問することができて、チャットでもhuddle(slackの通話機能)でもたくさんのことを教えてもらいました。本当に大量の質問(Effのこと、gRPCのこと、GitやGitHubのことなど)をしていたのですが、二人のメンターの人はいつでも快く応えてくれ、そのおかげで案件も早く進めることができました。

案件以外の内容

他にも案件以外であったイベントなどを以下にまとめます。

  • ご飯がたくさん届きました!しかし例年はランチによく行っていたらしいので、今回のアルバイトで唯一残念に感じています。
  • メンターからAmong Usに誘ってもらって社員の方々と遊びました!チーム以外の人と交流する機会を増やしてもらえて嬉しかったです!!
  • 組織長講演や技術交流会など、興味があれば社員の人から組織や技術の話を聞ける機会が多かったです!組織長講演では別参加コースのデータスペシャリストコースの講演も聞けましたし、技術交流会では乱数予測や量子コンピュータ入門の話からMarkov Algorithm Onlineの話、イベント運営に関するお話などたくさんのお話を聞けて面白かったです!!
  • 「よもやま」という社員の人と雑談する機会が多くあり、様々な社員の人と多く話しました!就活のことを相談したり、競プロや研究の話をしたりと楽しかったです。
  • 技術書の購入費のサポートがありました!嬉しかったです!僕は実践ドメイン駆動設計とコップ本を買ってもらいました。

まとめ

スタディサプリENGLISHという実際のプロダクトの開発チームメンバーとしてジョインし、大規模なサービスの開発を経験できました。多くの知識を習得し、とても成長できた楽しい1ヶ月でした。

これを読んでいる学生の皆さんは興味があればぜひ次のアルバイトやインターンに応募してみてください。

https://engineers.recruit-jinji.jp/event/