「asa1984 Advent Calendar 2024」8日目の記事です。
2024年9月、株式会社サイバーエージェントさんの次世代トップエンジニア創出インターンシップ ACEに参加しました。
初めてのインターンだった上、私にとって非常に大きな転換点となったので、本稿ではそこで得た学びとメンタルモデルの変化について記していきます。
ACEはハッカソン形式の2週間のインターンです。まず最初に開発のお題(今回は「架空の動画配信サービスの番組表」)とその仕様書・デザインが与えられ、ビジネスサイド(運営)とコミュニケーションをとりながら完成を目指します。
学生同士でチームを組むのが特徴で、今回はフロントエンド2人とバックエンド3人のチームが2つという構成でした。インターン生1人につき社員さん1人ついてくださるので、毎日1on1やチャットで質問しながら開発を進めていきます。
ただ完成物だけが評価されるわけではなく、技術戦略の妥当性や長期的な保守運用に耐えうるか否かなど、総合的な観点から評価されるのがポイントです。
詳しい様子は以下の公式のレポートを覗いてみてください。
【インターンレポート】次世代トップエンジニア創出インターンシップ ACE
私がこのインターンに参加できたのはほとんど偶然と言って差し支えなく、正直なんで自分が参加できたんだろうと疑問に思ったくらいです。ACEを紹介・案内してくださったことには感謝してもしきれません。
最初の数日と最後の数日は対面で、それ以外の日はリモートで開発を行います。
私は宮城県在住なので東北新幹線で前日入りしました。その日は渋谷のタワレコに行って、店デッケ〜という感想のもと特に何も購入せずにホテルに帰りました。
そして寝坊することもなく無事インターン初日を迎えたのですが、あまりの緊張で激しい胃痛に見舞われ山手線で車酔いしました。オフィスビルに入るのも初めてだったので、めちゃくちゃキョドりながらAbema Towersに入りました。あの日エントランスにいた不審者は私です。
会場(?)に着くと早速同じチームの方が話しかけてくれました。めちゃくちゃ強いインターン生にボコボコにされるんじゃないかと思っていたので、子供っぽいことを言いますがめちゃくちゃ安心しました。ありがとうございます。ちなみにチームメンバーは全員もれなくめちゃくちゃ強く、危機感を覚えましたがそれはまた別の話です。
その後顔合わせと自己紹介を行ったのですが、すぐに技術談義が始まりました。学校にWebフロントエンドの話をできる人なんていなかったのでめちゃくちゃ楽しかったです(そしてこれが2週間続く…)。社員さんからも言われたのですが、チームビルディングはとても上手くいったと思います。
自分以外のチームメンバーは自分のスーパーセットみたいな技術知識と経験を持っていて、当然ながら自分より遥かに強いのですが、それ以上に思慮深いなという印象を抱きました。軸となる考えがあり、キャリアについても具体的な展望を持っていて、開発者としてのステージが違うと感じました。チーム開発においてもチーム視点でのメタ認知のようなものを持っているのか、こちらが動きやすいようなやり方をしてくれてとてもやりやすかったです。
対面の時はメンターさんたちと食事をとります。技術の話、会社の話、雑談など色々話したのですが、一番面白かったのは技術よりも抽象的な領域の話、具体的にはビジネスやソフトスキルの話でした。
ACEでは最初に個々人で目標設定を行い、期間を通してその達成を目指すというサブテーマみたいなものがあります。私が設定した目標は以下の2つです。
- (開発について)一貫したワークフローを得る
- サービスの長期運用に耐えるテストを実装する
前者はソフトスキル的な目標、後者は技術的な目標として設定しました。これについて、メンターの社員さんから方向性はいいが定量化すべきという指摘を貰いました。
ここでの「定量化」は、自分がこうしたいと思っているものを他者が評価可能な状態にするという意味で、ある種恣意的なものです。そして、実際にBizと一緒に仕事をしていくには、このような「定量化」を、私たちDevが技術的理想として掲げているものに適用していかないといけない、というような話をされました。
「テストの実装」という目標についても、カバレッジ100%を目指さないフロントエンドにおいて、私が目標に挙げたテストの実装をどこまで行うのか、そもそもそういった非機能要件は何を目的としたものか、などなど…
エンジニアとして事業に参画していくためにはどう行動すればよいか、それを踏まえてどんな技術戦略を取っていくか(もしくはどうやって技術的理想をねじ込むか)という、まさしく私が一番知りたい部分について教えてくださり、非常に面白かったです。
リモートの期間は、SlackとMetalifeというツールで非同期にコミュニケーションを取りながら開発を進めていきます。チームビルディングが上手くいったのと、最初にコミュニケーションの取り方やタスク管理について決めていたのでスムーズに進みました。
タスク管理にはGitHub Projectを用いてIssue駆動で行いました。フロントエンドとバックエンドのIssueを同じProjectで管理することで、全員がチーム全体の進捗を常に把握できる状態だったのが後々大いに役に立ちました。
問題やタスクがある時は必ずIssueに書くことをチームメンバーに念押しされました。暗黙知を作らないように振る舞うべきで、そのためのコミュニケーションは惜しんではいけないという観念がこのインターンで身につきました。
フロントエンド側では具体的な技術方針の決定と技術選定を終えていたので早速実装に着手しました。相方が経験豊富な方だったので、ディレクトリ設計や主な実装方針を決めてもらい、私がそれに乗っかる形になりました。フロントエンドはとにかく実際に動かして試せる状態にするのが一番重要ということで、機能要件最優先でスピード重視で実装し、問題が起きたら作り直すという腕力方針になりました。
採用した技術はNext.js (App Router), Tailwind CSS, shadcn-ui, Storybookです。極力依存関係を追加せず、ReactあるいはNext.jsの機能をフル活用するという方針を取りました。当初はこれが最適だと思っていましたが、今思うと一考の余地がありました。
最初の数日は、APIの緩衝層を設けることを前提に、Storybookを利用しながらひたすらコンポーネントを書いていました。Contaner/Presenterパターンを徹底し、ボタンのhandlerなどはDIするようにしていたので、後で繋ぎこむ時もそんなに困らなかったと思います。
他人に自分の書いたコードをレビューされるという経験が初めてだったので、自分が作ったPRがマージされた時はとても興奮しました。
番組表は2次元的な広がりを持つ結構複雑なUIなので、中盤はCSSの悪魔と戦っていました。
- 条件が複雑なテキスト末尾の省略
- 縦横の
position: sticky
テキストの末尾省略の仕様は、
- テキスト表示スペースの高さが〇pxの時は1行
- テキストがスペースの高さから溢れる時は末尾を省略
- テキストがN行以上の時はN行で省略
という複雑な条件でした。複数行のテキストの末尾を省略する場合、textOverflow: ellipsis
は使えず、line-clamp
を使う必要がありますが、line-clamp
は静的に行数を指定しないといけないので、2の仕様を満たせません。
素朴に実装するならuseRefを使ってJSで高さ計算を行いますが、そんなことはしたくなかったので、コンテナクエリとline-clamp
を利用して、コンテナの高さが〇pxだったらline-clamp: 1
、〇pxだったらline-clamp: 2
…というCSSによる条件分岐を行いました。if文地獄みたいで気持ち悪いですが、最大N行ということがわかっているので問題ありません。
次に縦横のposition: sticky
は、番組表の上側のチャンネル名を表示するバーと左側の時刻を表示するバーを固定するために必要になりました。position: fixed
を使えば簡単に固定できるのですが、番組表には開閉するサイドバーがあるため、要素を画面全体の絶対位置に固定するfixedを使った場合、バーの位置をJSで計算する必要があります。それは嫌だったので、stickyを使うことにしたのですが、stickyは有効になる条件がかなりややこしく大変苦戦しました。これをささっと実装できたらCSSのプロだと思います。
いよいよ最後の大詰めになると24時間開発してるんじゃないかと思うくらい忙しくなりました。デッドラインに追われる開発ってこんな感じかァ〜と内心ちょっとテンションが上がっていました。
やらかしました。
Bizとの擦り合わせの結果、番組表のセルの高さを計算するロジックの変更が必要ということが分かり、私がそのタスクを担当していたのですが、当初の想定よりずっと重いタスクであることが後に判明し、これがフロントエンド全体の開発を滞らせるボトルネックになってしまいました。同時にフロントエンドの機能要件がかなり多く、工数的に厳しいということが判明したタイミングだったので、かなりクリティカルでした。
一応、タスクが思っていたより難しそうだという共有はしていたのですが、それは援護要請ではなく進捗共有という形だったので、問題が大きくなるまで私1人で抱えてしまいました。そこでバックエンド担当の2人にタスクの詳細を説明し、この大タスクをいくつかの小タスク切り分けて2人にやってもらうことになりました。この時、タスクができないからといって怒ったりする人は誰もいないので教えてほしいと言ってくれて本当に助かりました。
結局、私が切ったブランチは約40ものコミットを抱えてマージされました。
最終日前日、デプロイされたサイトを確認すると番組表のセルが部分的に欠落するという謎の不具合を発見しました。ローカルで起動した時は何も問題はなく、デプロイ先にログを仕込んでAPIレスポンスを確認しても問題は見られず、チームメンバーもメンターさんたちも頭に「?」を掲げている状態でした。
直前に大問題が発覚したため、全員で夜のファミレスに行き原因究明を試みていたところ、「LinuxでNext.jsをstandaloneモードでビルドした時だけ再現する」ということが判明しました。私のラップトップがNixOSだったことで奇跡的に判明しました。
ただ本当に原因不明なので、もしまた再現できたらNext.jsにIssueを建てます。
ギリギリながらもフロントエンドの機能要件を90%近く達成し、コードフリーズとなりました。機能要件最優先で実装するという方針が結果的に功を奏した形となりました。最後の3日間は全員フロントエンドを触っていました。私以外の全員がフルスタックな技術知識を持っていたからこそできた芸当です。
コードフリーズ後、社員の方々にプレゼンし、最終的にチームとして最優秀賞をいただきました。
- 自分にある程度実装力があることがわかった
- チーム開発で意識すべきことがわかった
- コミュニケーションのコストを惜しんではならない
- コミュニケーションコストを天秤にかけるより、すぐに共有してチームの利点を引き出すべき
- 技術戦略について、より深い検討と早期のトライアンドエラーが必要
- 状態管理設計の是非
- フロントエンドとバックエンドの繋ぎ込みの遅れ
- 結果的に想定より大きくパフォーマンスが劣化してしまった
私のやらかしだけでなく技術的な反省もたくさんあります。しかし、初めてのインターン・初めてのチーム開発1で学びもまだ書ききれていないくらい得られました。常に楽しいインターンで、これも全て関わってくれた社員の皆さんとチームメンバーあってこそだと思います。ありがとうございました!
後泊日、チームメンバーの1人と遊びに行きました。つよつよエンジニアと科学未来館のインターネット(物理)を見に行き、秋葉原でガイドしてもらうという夢が叶いました。
https://x.com/asa_high_ost/status/1838848506754404800
Footnotes
-
厳密には初ではないが、技術的に自分と同等かそれより強い人たちとのチーム開発は初 ↩