【iOSアプリ】VIPERアーキテクチャのプロダクトで配属されて3週間の新卒社員のOJTをした話。

Advent Calendar 2021, iOS, Swift, 新卒教育

この記事は最終更新日から1年以上が経過しています。

この記事はレコチョク Advent Calendar 2021の最終日の記事となります。

はじめに

はじめまして。レコチョクの河野です。19年4月に新卒入社し、現在はiOSアプリエンジニアとして、Eggs・新規プロダクトのiOSアプリの開発・運用などを担当しています。また、21年度は新卒エンジニア研修全体の主担当としてカリキュラム策定から新卒メンバーへのフォローなど研修期間を通じて様々な業務を担当しました。音楽の専門領域はアイドルまわりで、個人的今年の1曲は日向坂46 「どうする?どうする?どうする?」です。よろしくお願いします。

レコチョクでは例年、エンジニアとして新卒入社したメンバーが新卒研修を終えた後に各部署に配属されてからOJT期間を経て、段階的に実務的な開発・運用業務に参画する仕組みがあります。そして、今年度iOSチームでは21年入社の後藤深山の2名を仲間として迎え入れました。

今回の記事ではメンター役として実プロダクトを題材にしながら、研修を終えた後のOJT期間の中で2人をどのように受け入れたのかを紹介しようと思います。

レコチョクの新卒エンジニア研修について

レコチョクでは例年、4月〜5月のビジネス研修の後、6月〜9月の4ヶ月間で新卒エンジニア研修を実施します。入社までにプログラミングの経験が無い未経験者でもついてこられるように、基礎的なUNIXコマンドの使い方から始まり、AWS・データ分析・ネイティブアプリなど専門的な内容まで網羅的に学習するカリキュラムが用意されています。詳細についてはここでは割愛しますが、弊社の塚本が研修を受けた側の視点での記事をアップしていますので、あわせてこちらもご覧ください。

レコチョク iOSチームのOJT

レコチョクのiOSチームでは例年、OJT期間中にこなすような決まったカリキュラムはありません。(マネジメント側と調整した上で、)新規で開発が始まるプロジェクトに開発メンバーとして参加する年度もあれば、すでにリリースされている社内のプロダクトのクローンアプリを作り、その画面を実際に作った先輩にレビューをしてもらいアプリ開発に必要な知識を習得する年度もあります。受け入れ時のプロダクトの開発状況や、指導に当たる先輩社員(以下、メンター)のリソース、新卒メンバーのタイプなど、状況に応じて臨機応変にテーマや進め方を決めています。

ただし、年度ごとに方針が違っていても「可能な限り実プロダクトに近いところで開発を体験してもらう」というコンセプトは共通しています。実際に世に出る(出ている)画面を実装してもらうことで、自分たちが学んでいる事柄の必要性をより理解してもらえると考えているからです。そして、何よりも自分たちが頑張って作った機能や処理が実際にアプリとして世に出るんだ、ということは何より指導を受ける新卒たちのモチベーションにつながるからです。

今年度は絶賛開発中の新規プロダクトの開発のなかでOJTの課題を設定し、アプリ開発に必要な知識を習得してもらう方針に決めました。

プロダクトのアーキテクチャ

レコチョクのiOSアプリの開発では、汎用的で堅牢な内部設計を意識した開発を推進しています。

とりわけ、OJTの題材となる新規プロダクトでは、VIPERアーキテクチャをベースに開発を進めています。詳細は割愛しますが、VIPERの構成要素(以下、コンポーネント)となるView・Interactor・Presenter・Entity・Routerを基本とし、さらに画面(View)の描画等の責務を持つPresentation層、Viewに表示するデータの取得処理のビジネスロジックを責務とするDomain層・各データソースからのデータ取得/更新を責務とするDataStore層の3つのレイヤーをベースとしたマルチモジュール構成も導入しています。

20211214_001.png

このアーキテクチャを採用している実プロダクトにコミットをするには、VIPERの各コンポーネント毎の責務を理解した上でコードを書いていく必要があります。しかし、いきなり全ての理解を要求するのはOJTの難易度設定として無理があります。そこで、今回はマルチモジュールの各レイヤー(層)に対応する形で課題を設定し、段階的にコミットしてもらうことで徐々にアプリのアーキテクチャの全貌を理解してもらえるようにOJTを進めていくことにしました。

どう進めたか

Swiftの基礎を学習する

まず、10月1日に配属されてから実プロダクトのコードを読み書きするために必要最低限のSwiftの知識を学習する期間としました。前述したように参加してもらう予定のプロジェクトがUIKitで開発されているため、Swift × UIKitで基礎的な項目を解説しているカリキュラムを最初から順にこなしていくドリル形式で学習を進めてもらいました。

今年度のOJTでは株式会社ゆめみさん、株式会社ミクシィさんがそれぞれ公開されている資料をSwift5の仕様に合わせてメンター側でフォローを入れつつ、Swiftの基礎を学習してもらいました。

2週間ほどでカリキュラムベースでの学習は一旦区切りとし、実プロダクトのコードを使用した実践形式の演習へと進めていきました。

実プロダクト上でコミットする

アーキテクチャという概念を導入する

まず初めにメンバー全員がオフィスに集合し、3時間くらいのまとまった時間でアプリ内部の設計やSwiftにおけるプロトコルの概念について一通り話をする解説会を開きました。

解説会ではいきなり理論を説明するのではなく、メンターと新卒たち全員でグループディスカッションのような形式で会話をしていく中でアプリ内部の処理にまつわる「ロジック」の概念を明らかにしていくところからはじめて行きました。

会話の中で、アプリ内部の処理にまつわる「ロジック」が

  • 画面の描画・更新にまつわるロジック(プレゼンテーションロジック)
  • 要件を実現するためのデータ自体の取得や更新などにまつわるロジック(ビジネスロジック)
  • 遷移処理などにまつわるロジック(ルーティングロジック)

などに大別できるよねという共通認識が持てるようになった段階で、VIPERの基本的な構成と実プロダクトでの構成について解説をしました。

VIPERの概念を導入した後、手元のMacと検証端末で実際にアプリをビルドしながら操作してもらい、Xcode上でブレイクポイントを貼りながら、挙動を追いかけて確認をしてもらいました。この段階では主に画面描画・更新に関係するView(ViewController) → Presenterへの処理の流れや、遷移処理のView(ViewController) → Presenter → Routerと処理が進んでいく一連の動きを中心に見てもらい、アプリの画面上で起きていることとコード上での処理の対応関係を明確に持ってもらうようにしました。

Presentation層ではじめてのコミットをしてもらう

初日の導入を終えた後、デビュー戦として最初に任せたのは当時開発を進めていた、ある機能についてのViewController・Presenterの実装でした。この機能は「設定画面 > 画面A > 画面B」というプッシュ遷移での導線が用意されていて、新卒2人には画面A・画面Bそれぞれを並行して担当してもらいました。

20211214_002.png

この時点では、1機能にまつわる全てのロジックの実装を丸投げせず、プレゼンテーションロジックについての実装に範囲を限定して作業を進めてもらいました。具体的には、本来UseCaseから取得するプロパティ・データをPresenterの内部で静的に保持させた状態で、View・Presenterの2つの実装に集中してもらうという形式です。
作業を進めてもらうときにメンター側から、
「Presenterがどこからかデータを取得した前提でそのデータをView上で表示するようにイメージして、View側の実装を進めてみてね」
「設定値を変更するUIイベントを検知して、Presenterに通知して、Presenterの内部で自身が持つプロパティを書き換えるところまで実装してみてね。実際はUseCaseのメソッドに値を渡して、メソッドを通して値の更新をするんだけどね。」
と適宜フォローして、全体処理の完成形をイメージしてもらいながら進めていきました。ある程度実装が形になった段階で、通常の開発フロー同様にプルリクを出してもらい、コードレビューを経てマージされる流れでコミットしてもらいました。

初手でPresentation層のみの実装に集中してもらうことで、自分たちの実装範囲外の要因で作業が止まってしまうということを最小限に抑え、開発とOJTを並行させることができました。また、手元でデバッグビルドして直感的にできた/できないがわかりやすいView側の実装に範囲を限定することで、実装がうまくいかなかった時に自分たちで調べて、実装を試してみて解決するというサイクルを自律的に回しやすくなったというというメリットもありました。

そして、2人が担当するそれぞれの画面が両方ともができたタイミングで画面A > 画面Bの遷移処理をモブプロ形式で実装してもらい、本来の遷移導線を完成させるドッキング作業までを体験してもらいました。初日の解説会だけではRouterとDI(依存性注入)の概念を掴み取るのは難しかったようですが、自分たちがここまで実装してきたコードに追加する形でRouterやDIの処理について実装を進めていくことで、より理解が深まった体験ができたようです。

Domain層・DataStore層でのコミットにトライしてもらう

プレゼンテーションロジックについての実装を体験してもらった次に、Domain層・DataStore層で実装するミッションにトライしてもらいました。ここでは、

  • 画面上でユーザーが設定した設定値をUserDefaultsに保存・読み取りができるようにするI/Fを提供するDataStoreの作成
  • 楽曲をダウンロードする際の音質(128kbps/320kbps)の設定値を読み取り・保存するロジックを持つUseCaseの作成

の2つのタスクにトライしてもらいました。

このタスクでは、処理のフローを意識してもらうことに集中してもらうため、フローで受け渡す値の型がシンプルなUserDefaultsにまつわるDataStoreを題材として選択しました。また、最初にTyporaで使えるSequence記法でフロー図を書いてもらってから実装を進めてもらいました。

image-20211214213250320.png

(Typoraで使えるSequence記法について詳しくはこちら)

このフロー図を書く習慣をつけることで、DataStore・Repository・UseCaseと複数のコンポーネントを横断する複雑な処理フローでも見通しを持って実装を進めてもらえるようになりました。また、Slack上で質問・相談をする際、テキストで全ての内容を説明しなくても図を交えて、コミュニケーションを取ることもできるのだということを認識してもらうことができました。

DataStore・UseCaseを作成してもらったあとは、ダウンロード音質の設定値を使うアプリ内の各画面のPresenterでUseCaseのメソッドで設定値を取得し、後続の処理に使用したり、設定画面上で設定値を変えるUIイベントを受け取った後にUseCaseを介して、設定値を更新(保存)したりする処理の実装まで進めてもらいました。複数のPresenterから共通のUseCaseを参照する実装をしてもらうことで、共通の機能(ここではダウンロード音質設定)に関するビジネスロジックを共通化して実装するという概念・メリットを理解してもらうことができたと思います。

ここまでの流れで、全てのレイヤーでのタスクを一通り体験することができたので、これ以降の期間は開発の状況に応じて発生した細かめのタスクを都度こなしてもらいました。この際、〇〇の実装について片方しか経験できないという状況を避けるように配慮しながら、タスクを振っていきました。

メンターとして気をつけたこと

この方式でOJTを進めるのにあたって、課題設定以外にもメンターとして以下の点を意識しました。

  • Twitter感覚でSlack上で報告・相談ができる雰囲気を作る
    質問したいと思ったタイミングで遠慮なく質問してもらえるように、いい時も悪い時も逐一、Slack上で分報をあげてもらうように周知しました。綺麗な文章じゃなくてもOK(箇条書きでもOK)、違和感を感じたらアプリ画面のスクショだけ貼ってくれるだけでOK、テキストにすることが難しかったら、すぐにハドルで呼んでね、と「先輩は忙しいから、質問するのはやめよう」と質問しなくなってしまう状況を無くすような雰囲気作りを意識しました。
  • 各タスク着手前に見積もりを事前に宣言してもらってから実装に取り組んでもらう
    見積もりが外れた場合にペナルティを与えるなどは一切せず、この機能を実装するならおおよそ◯時間くらいでいけるかな…というあたりをつけてもらう習慣をつけてもらいました。
  • その場で全て教え切ろうとしない
    新卒からの質問に回答できるものは全て回答しますが、完全な回答をするために新しくもう1段階インプットが必要だという質問に対しては、その場で全てを教え切ることを敢えてせずに進みました。その際は「この部分は必ず後でもう一回戻ってくるから、今は〇〇の部分まで理解できていればOK」と伝えて、理解すべき事柄の線引きをこちらから明確に提示して新卒側にも納得してもらうように意識しました。

結果どうだったか

この形式で実プロダクトにコミットしてもらうことによって、メンター役の社員からのフォローを受けつつ開発が進められるようになりました。今回のプロダクトではスクラム開発の形式で開発を進めていますが、そのスクラム開発においてスプリントバックログに対応するプルリクエストを出すことができるまでになりました。

良かったところ

VIPERのプロジェクトを題材にOJTを進めたことで、前述したようにアプリ内部の設計に則して、段階的に課題の難易度を設定することができました。

メンター側の視点では、

  • 実際のプロダクトのコードで指導することで、新卒たちが触っている処理が「このアプリの〇〇の画面の□□の表示に使われてるんだよね」と必要性や関連性を具体的に説明することができた。
  • 教えるときに「今の時点でどこまで話をするべきか」という難易度の調整がしやすかった。
  • 実プロダクトのコードとOJTのカリキュラムの二重管理がなくなったので、効率よく指導そのものに力を注ぐことができた。

などのメリットがありました。

さらに新卒メンバーからも、

  • カリキュラムで単元・項目毎に学んでいた内容を実際の使い方を想像しながら試してアウトプットすることができた。
  • 実プロダクトにコミットしてることで成果を出していることが実感できたのでモチベーションになった。

という声も聞かれました。

これ以外にも、今回のOJT期間では週5日のうち1日をドキュメントデーと題して、自分がインプットした内容をまとめでドキュメントとして蓄積していく日として設定しました。ドキュメントデーの中で、学んだ内容を整理できたり自発的にプロジェクト内の他のコードを読んでみたりできたことも理解を深めるために良い作用をもたらしたようです。

改善できるところ

一方で、開発と並行して実施する形式ならではの課題もありました。とりわけ、メンター側が開発側のタスクで精一杯になっているときに、新卒側への指示出しが間に合わず手持ち無沙汰になる期間ができてしまったことは今後解決すべき課題です。これはメンター側の課題ではありますが、リポジトリのissueなどで緊急度が低いリファクタやViewの微調整などを集めたチャレンジ課題集のようなものを事前に用意して、非同期的にメンターと新卒が並行稼働できる仕組みを作る必要がありそうです。

また、リモートワーク中心の勤務体制だったので、オフィスのようにホワイトボードを使っての図解ができず苦労するシーンも多々ありました。特に、リモート環境下でも簡単にフリーハンドで図解できるようなコミュニケーション方法は積極的に模索すべきだと感じました。

今後は

新卒たちのOJTはこれからも年度内続きます。今後は、3つのレイヤーを横断したより複雑で分量の多い実装にトライしてもらう予定です。また、OJTという枠組みの中では与えられた設計を前提として処理を実装していくことを体験してもらいましたが、開発チームのメンバーとしてより深く関わっていくためにアーキテクチャ自体を振り返り、改善していくサイクルも回す必要があります。これは開発キャリア問わず、メンバー全員で対等に議論し、進めていくことが重要です。OJTの枠組みを超えて開発チームのカルチャー的な部分ではありますが、将来的にはこの部分まで各メンバーが考えていけるような開発サイクルを回せるところを目指せればと思います。

おわりに

レコチョクでは新卒・中途の採用フェーズを問わず、音楽愛に溢れ、共にものづくりに熱中できる素敵な仲間を募集しています。興味がある方はこちらの採用サイトをご覧ください。

最後まで今年のレコチョク Advent Calendar 2021をお読みいただきありがとうございました。今日はひなくり2021の最終日。自分は現場で今年のライブ納めをしてきます!

それでは皆様、メリークリスマス🎄

参考