![見出し画像](https://assets.st-note.com/production/uploads/images/24595211/rectangle_large_type_2_4fdac008b0adc301f109dcfc4bf3ce2f.jpg?width=1200)
フルリモート新卒研修での短期チーム開発を振り返る
こんにちは!
iOS エンジニアの pihero です。
私ごとですが、この度 20 卒エンジニアとして CyberAgent に入社しました🙇♂️
今年はコロナウイルスの影響で、各方面、例年とは大きく異なる新年度になったかと思います。
残念ながら「コロナ世代」となってしまった私たちですが、CA では人事や先輩社員方の迅速な対応により、なんとか新卒研修をフルリモートで実施することができ、そして無事に終えられたので振り返り記事を残そうと思います。
「CyberAgent の新卒研修では何をやっているのか?」
「新卒研修の中でどのようなチャレンジがあるのか?」
僕が体験した範囲で書いていくので興味があれば一読してみてください📖
自己紹介
簡単にします。
「RICH MAN, POOR WOMAN」の日向徹に憧れ、高校 3 年生の冬にプログラミングを始めました。
HTML / CSS を学び幾つか企業の LP を製作したのち、大学 2 年生のときにお世話になったインターン先でサーバサイドの開発にも参加することになり、しばらくは Node.js で API 開発をしてました。
大学ではデータセンターの管理を任され、配線作業など土方も経験したのですが、最終的にはクライアントが自分に合っていたので今は iOS エンジニアとして頑張っています。
その他では、大学 4 年間はサッカーチームの監督をしていたのでサッカー観戦や色んなスポーツを観ながら戦術を考察することが好きです。
アニメも大好きです😆
新卒研修の内容
新卒研修は 4 月からの約 1 ヶ月間、完全フルリモートで行われました。
大まかな流れは以下の通りです。
- 顔合わせ / 自己紹介
- 会社説明(制度や社内コミュニティなど)
- 座学(セキュリティ研修など)
- ワークショップ(AWS)
- チーム開発
チーム開発が始まったのが 4 月 6 日だったので、所謂多くの人がイメージされる研修は第 1 週のみで完結しました。
お辞儀の角度や名詞の渡し方は…ありませんでしたね💦
個人的には、やりたかったんですが(GIYF)。
さて、新卒研修のメインは 5, 6 人に分かれてのチーム開発でした!
各グループに、サーバサイド / クライアント / データサイエンティスト / ゲームエンジニアが振り分けられ、協力してひとつのアプリを開発するという内容です。
与えられたお題は、 SNS !
- ログイン
- サインアップ
- 投稿
- いいね
- リツイート
以上の必要要件を満たしていれば、何を作っても OK 💪
僕が所属する "チーム K" では、Saketter というアプリを開発しました。
自分が飲んだお酒をログとして投稿できたり、他のユーザと共有することができます。
正直なところ、Twitter のような既存サービスをそのままコピーするだけでも難易度は高かったと思います。加えてフルリモートという慣れない環境🤔
ですが、チーム K では「新しいものを作りたい!」という気持ちが強く、コンセプトから考え新規サービスを開発することにしました。
3 週間という短い期間の中で、コンセプトを含めアプリをゼロから実装するのは正直高い壁でした。(コンセプトが決まらなければ機能や画面構成も決まらず、実装期間も少しずつ減っていきますからね😅)
僕 & チーム K がその高い壁を越えるため、どのような挑戦をしたのか。
ここからは具体的にお話していこうと思います。
フルリモート短期間チーム開発でのチャレンジ × 3
1. テックリードとしてのチャレンジ
2. 技術的なチャレンジ
3. チーム開発におけるチャレンジ
💡テックリードとしてのチャレンジ
チーム開発では、クライアントのテックリーダーをさせて頂きました!
今年は各チームで役割を設け、各々役に沿ってミッションを掲げそれらを達成するためのアクションを起こすことが求められました。
以下、役割の一覧です。
- チームマネジメント
- テックリード(サーバサイド)
- テックリード(クライアント)
- プロジェクト管理
- 仕様管理
テックリードとして僕が立てた目標は、こちらです。
「終わらせることを第一に、新しい技術にチャレンジする」
折角自由にゼロからアプリを開発できるので、今まで触ったことのない技術にチャレンジしたい気持ちが強くありました。
ですが、僕はついつい深堀しすぎて進みが遅くなる悪い癖があるため、必ず終わらせるという意識も持ってこの目標にしました。
加えて、終わらせるために積極的に周りのサポートをしていこうと考えていました。
iOS アプリの開発は 3 人で行ったのですが、他ふたりは iOS アプリ開発が未経験だったのでテックリードとしてチームを上手くまとめ上げるリーダーシップも求められたためです。
では、実際にテックリードとして行ったチャレンジについてお話していきます。
-- PR テンプレート --
ひとつ目は、PR テンプレートの導入です。
GitHub ではレポジトリ配下に .github/pull_request_template.md を配置することで、PR 作成時にテンプレートを使用できます。
テンプレートには、以下の項目を設けました。
- チケット / 仕様書へのリンク
- 変更内容
- 変更理由
- やらないこと
- 動作確認
- レビュー観点
- スクリーンショット
- 関連リンク
- その他
短期間の開発では PR が雑になってしまいがちですが、期間や環境に関わらず PR は丁寧に書くべきだと個人的に思っています。
テンプレートを設けることによって以下の効果が得られます。
- レビュワーが PR の全体像を把握しやすくなる
- 記載する項目を考える時間がなくなる
- スクリーンショットからデザインを確認できる
- 実装の意図を明記することで無駄な確認作業が減り、レビュー時間を短縮できる
- 初めて PR を書く人への大きなサポートになる
結果的に、レビューの質が向上しチームの開発速度も早まります!
実際に用意した PR テンプレートは以下になります。
そして、開発中に作成された PR がこちらです!
チームメンバーが、これ以上ないほど綺麗な PR を出してくれて本当に驚きました🙄
予想ですが、こんなにも丁寧に PR を作っているのはチーム K だけだったと思います。
個人的には、やらないこと という項目を設けたのは正解だったと感じています。
この PR ではロジックは実装しているけれどレイアウトは仮置きしている、などレビューにおいて注力すべきところが一瞬で把握できたからです。
PR テンプレートを用意することで、結果的に各メンバーが対応している機能の把握もしやすくなり、開発を円滑に進める手助けになっていたのではないかと思っています。
-- 環境構築 --
次はチーム開発における環境構築についてです。
尚、ここでの環境構築とはチーム開発の生産性を向上させることを目的としたものです。
先に結論を述べると、今回は環境構築に大失敗しました。
簡潔に言うと…
はじめに XcodeGen と SwiftLint を導入するべきでした。
~ XcodeGen ~
XcodeGen はディレクトリ構造と設定値を元に xcodeproj ファイルを生成するコマンドラインツールです。
XcodeGen is a command line tool written in Swift that generates your Xcode project using your folder structure and a project spec.
設定ファイルは YAML または JSON フォーマットで作成します。
今回は YAML ファイルを用意しました。
iOS アプリ開発では、xcodeproj ファイルというプロジェクトファイルが生成されます。
このファイルはディレクトリ構造やファイル情報を保持するため、開発中は度々変更されることになります。
そのため、複数人でのアプリ開発では xcodeproj ファイルのコンフリクトが多発します😓
今回のような 0 → 1 開発では、常に新規ファイルが生成されるためコンフリクトが頻繁に起こります。
そして、コンフリクトは開発の速度を下げると共に開発ストレスに繋がります。
先ほども説明した通り、XcodeGen はディレクトリ構造と設定値を元に xcodeproj ファイルを生成するツールです。
つまり、XcodeGen を導入することで xcodeproj ファイルを Git 管理から外すことができます!
ファイルのみ共有しておけば各々のローカル環境でプロジェクトファイルを生成することができるためです。
これによりプロジェクトファイルのコンフリクトは無くなります。
最終的に、僕が XcodeGen を導入したのは 3 週目の入りかけだったかと思います。
遅れた原因としては、XcodeGen の導入に伴う CI のメンテナンスが間に合っていなかったためです。(ちなみに、今回仕様した CI / CD ツールの Bitrise では XcodeGen 用のフローが既存で用意されているためワンクリックで対応することができます。今回は他のフローとの関係で簡単には出来なかったので先送りにしてしまいました。。)
多発するコンフリクトの苦痛を味わった後だったので、XcodeGen の導入後はその恩恵を最大限受けられたのですが笑、もっと早くに入れておけば良かった…
~ SwiftLint ~
SwiftLint では、ルールベースで Swift の記法を矯正することができる静的解析ツールです。スペースの有無や変数の文字数などチーム内でルールを共有することが可能です。
細かい設定は .swiftlint.yml にて行えます。
XcodeGen 同様、こちらも導入が遅れてしまいました。
当初、コードの質は CI で担保しようと考えていましたが CI だけでは以下の問題が発生しました。
- ビルド可能なコードを保証することは出来るが、Swift の記法などコード自体の質を担保することは出来ない
- スペースの有無やインデントのミスはレビューでは気づかないことが多い
結果的に、本来であれば相応しくない以下のようなコードが master ブランチへマージされてしまっていたのです。
× if (flag) { ... }
○ if flag { ... }
早々に SwiftLint を入れておけば、これらの問題は対処できていました。
チームメンバーには本当に申し訳なかったです…
ちなみに以下のコマンドを使用すれば、フォーマットも自動で修正してくれます🎉
swiftlint autocorrect --format
以上、反省は多いけれど大変実りのあった環境構築についてでした。
-- Clean Master Code --
Git の Master ブランチは常にビルド可能な健全なコードであることを保証したかったため、GitHub の Branch Protection Rule を活用しました。
Branch Protection Rule では、ブランチに対してマージ条件を設定することができます。条件を達成するまで、開発者はマージをすることができません。
リポジトリの「Settings」->「Branches」->「Branch Protection Rules」->「Add Rule」から設定可能です。
指定した条件は以下の 3 つです。
- Require pull request reviews before merging
- 1 人以上の approve が必要(人数は変更可能)
- Require status checks to pass before merging
- CI が Success 状態であること (対象は変更可能)
- Include administrators
- 管理者にもルールを適用
CI のステータスチェックには少々時間が掛かるため、当然マージまでの速度は落ちます。
そのため、 3 週間という短い開発期間を考慮してルールを撤回することも可能でしたが、マスターに不健全なコードが混入した際の修正や人的ミスによる誤ったマージを防ぎたかったため明確なルールを設けることにしました。
結果的に、Master ブランチのコードを常に綺麗な状態に保つことができたと共に、時間短縮のためのセルフマージも防ぐことができました!
💡技術的なチャレンジ
技術的なチャレンジとしては、 CI / CD の環境構築とアーキテクチャとして採用した BLoC についてお話します。
-- CI / CD --
研修で 1 番楽しみにしていたのは、CI / CD への挑戦です。
これまで自分で構築する経験はなかったので、是非この機会に試してみたいと思いチーム開発が始まって早々に着手しました。
CI / CD について簡単に説明します。
CI(Continuous Integration / 継続的インテグレーション)は開発中のコードを継続的にビルド / テストするための仕組みです。
CD(Continuous Delivery / 継続的デリバリ)はアプリを継続的にリリースするための仕組みです。iOS アプリであれば、作成した ipa ファイルを App Store Connect までアップロードすることがこれにあたるため、今回は厳密には CD ではないのですが、Continuous Distribution(継続的配布) として App Center へテスト用アプリの配布を行ったので CI / CD と呼ばせてください🙇♂️
CI / CD ツールとしては Bitrise を採用しました。
GitHub へのアクションをトリガーに、Bitrise のワークフローを走らせアプリのビルドとテストを行います。
テストが成功すると ipa ファイルを作成し、自動的に生成物が App Center へアップロードされます。この時点で、チームメンバーは手元の端末にテスト用アプリをダウンロードすることが可能です。いつでも最新のアプリ状態を確認できる環境の出来上がりです!
ワークフロー終了時には Slack へ通知を送り、チーム内で常にビルドの状態を確認できるようにしました。ちなみに、通知は頻繁に来るので普段の会話の邪魔にならないよう #teamK_bitrise 専用チャンネルを配置してました。
何も分からない😑状態からのスタートでしたので、まずは動くワークフローを構築できてホッとしました。
テストカバレッジ率が低かったので、精神的安全性という意味では効果が薄かったかもしれませんが、Success と表示されると嬉しかったです。
最終的に…
Bitrise のビルド数が 235
AppCenter へのアップロード数が 69
頑張りましたね💦
-- BLoC --
アーキテクチャには BLoC(Business Logic Component)を採用しました。
BLoC は名前の通りビジネスロジックのみを担当するコンポーネントです。
BLoC の定義は以下のようになります。
(AbemaTV iOS TECH BOOK 技術書典 6 版 v1.0.0 より引用)
- BLoC の入力・出力インターフェースはすべて Sink / Stream となる
- BLoC の依存は注入可能で、環境に依存しない
- BLoC 内に環境ごとの条件分岐は持たない
- 以上のルールに従う限り実装は自由
今回は BLoC として View Controller に 1 対 1 で紐づく View Stream を用意し、その中にビジネスロジックを記述する形を採用しました。
View Stream は内部にロジックを保持しており、与えられた入力をロジックに従って出力に変換します。
この形の利点としては、以下の点が挙げられます。
- 処理の流れを追いやすい
- テストがしやすい(与えられた入力に対して期待する出力が返されるか)
逆に、欠点としては
- Sink / Stream の実現に RxSwift 等を用いると学習コストが高い
- View Stream が肥大化する可能性がある
などがあると考えています。
実際、今回のように Swift 初挑戦のメンバーがいる中では間違った選択だったかもしれません。ただ、MVP でも MVVM でも結局難易度としては変わらなかったのでは?とも思っています💦
レイアウトとユーザーインタラクションは View Controller、ロジックは ViewStream と各々の役割を明確にすることでディレクトリ構造も簡潔になり、実装の際に着手すべき場所が明確になるのではないかと考えました。
実装に関しては以下を参考にしています。
もし興味があれば、時間があるときに見てみてください!
ちなみに、ABEMA iOS チュートリアルの初体験者は僕だったりします。
💡チーム開発におけるチャレンジ
ここからはチーム全体でのチャレンジについてです。
-- フルリモートを支えるコミュニケーションツール --
コミュニケーションツールとしては、Slack / Zoom / Discord の 3 つを使い分けていました。
テキスト → Slack
音声 → Discord
ビデオ通話 → Zoom
実のところ、Slack ひとつで全て出来るのですが。
「iOS チームだけで話がしたい」
「 〇〇君に質問があるんだけど…」
という場合に新しく別のルームを作成するのに少し手間が掛かります。
そこで採用したのが Discord です!
Discord は初めて使ったのですが、とても便利なツールでしたので紹介させて頂きます。
Discord ではボイスチャンネルを作成することができ、同じチャンネルに入っているユーザと会話をすることが可能です。
別のチャンネルのユーザへは話し掛けられず、相手の声も聞こえません。
何が良いかと言うと、ワンクリックでチャンネルを移動できることです🏃♂️
事前に用途別のチャンネルを作成しておくことで瞬時にグループを限定できるのは、無駄な手作業を省けて便利でした。
チーム K では、ご飯チャンネルや精神とテクの部屋チャンネルを作成して各メンバーの状態管理をしていました🙆♂️
Tandem でも同じ様なことが出来るので、興味がある方はそちらも試してみてください!
-- 朝会 --
毎朝 10 時は、チーム全員で集まって朝会をしていました!
- タスク共有
- 開発での懸念点の洗い出し(実装順序の相談など)
- 今日も 1 日頑張ろー!
上のような理由が主でしたが、1 日の初めにチームで集まることで開発のメリハリがついていた気がします。
フルリモートで直接会えない状況でも、チームで開発をしている感覚は大事にしていきたいですね!
-- 夕会での小話 --
チーム K では、独自の取り組みとして小話タイムを設けていました!
小話タイムとは…
夕会の時間に各メンバーが自由なテーマで行う LT のことです。
実際に各メンバーが話したテーマがこちら👇
- チーム K のシステムの裏側
- 仮想化技術
- 3D モデリングの裏側
- 大学 4 年間の苦悩と成長
- メカニズムデザイン/オークション理論
- 自然言語処理のタスクと現状
突然始まった小話タイムですが、どの話もとても面白く小話中は全員聞き入ってました。終わった後もほぼ全員が質問するという盛り上がりっぷり🤣
メンターさんも参戦するという予想外の展開にも大変驚かされました笑
小話タイムを楽しみにするあまり独自のスタンプまで作られていた。
「開発!開発!」となりがちな環境でしたが、上手く休憩時間を作ることでチームの雰囲気を和やかにしたり、一緒に開発をしているメンバーのことを知ることができる有意義な時間になりました!
まとめ
チーム K では新卒研修の成果として Saketter というお酒を軸とした SNS を開発しました。
残念ながら、求められた必要機能に対して Plus α の実装は出来ませんでしたが、厳しい環境の中でも与えられた開発期間の中で動くものを作れたことは評価できることなのではないかと思います。
個人の目標であった「終わらせることを第一に、新しい技術に挑戦する」に対しては、最大限コミットできたと感じています。
この記事でも取り上げた CI / CD や BLoC の他にも、
- 新規登録フローにおける 2 段階認証の実装
- ライブラリに頼らない APIClient の実装
- タイムラインでの無限スクロールの実装
- CI / CD での秘匿情報の注入(Git 管理はしない)
- テスタブルな DI 設計
などを完遂することができました🎉
ただ、反省点が多かったのは事実です。
反省は活かし、今後の糧にしていきます。
少し長くなりましたが、以上で新卒研修の振り返りまとめとさせて頂きます。
iOS エンジニアとして今後も精進して参りますので、どうぞ宜しくお願いします🙇♂️
CyberAgent ではインターンシップを随時募集しています。
興味のある学生さんは是非確認してみてください!