Cookpad Summer Internship 2022 を開催しました!

こんにちは、ボイスサービス部の ymd (@y_am_a_da) です。今年は新卒採用エンジニアリーダーもやっています。

さて、 https://techlife.cookpad.com/entry/2022/02/25/100000 でも告知させていただいた通り、今年の夏は 15-day Tech Course と 3-day Tech Course の 2 種類のエンジニア向けインターンシップを開催しました。この記事ではその内容を紹介します。

15-day Tech Course

15-day Tech Course は前半 5 日間が講義形式、後半 10 日間が実戦形式でした。また、今年も前半の講義パートはオンラインのみ、後半の実践パートではオフィスに来訪されることを希望した方にはオフィスで、それ以外の方々は前半から引き続きオンラインで参加する形式を取りました。また、昨年と違う点として今年のオンライン講義は Gather を利用しました。

講義の際には右側に集まり、サービス開発講義などでグループワークをする際には左の小部屋に集まり作業をしました。参加者全員にビルダー権限を付与したおかげで日々画面が賑やかになっていく様が見ていて楽しかったです。 Gather 跡地

1日目: オンボーディング & Git/GitHub 講義

初日はまず午前中にイントロダクションとしてクックパッドの取り組みの紹介や自己紹介などを行いました。 また、例年と違い今年は全ての参加者が後半の 10 日間では OJT に取り組むため、それに必要なセットアップなどもこの時間にやりました。

イントロダクションを終えランチをした後、 Git/GitHub 講義から技術講義がスタートしました。

講義の後は、引き続き OJT を進める上での各種説明や、 CTO の成田による技術組織の紹介などがありました。

2 日目: iOS 講義

2 日目の iOS 講義では、簡易なレシピサービスを SwiftUI で実装するという内容でした。この時点ではまだモックですが、 API 通信をしてデータを取得したものを表示させるところまできちんと網羅しています。 Swift を書いたことが無い人も多かったため、独自の記法に慣れない場面も見受けられましたが、ほとんどの人が無事にハンズオンパートを完了させることができていました。

https://github.com/cookpad/cookpad-internship-2022-summer-ios

3 日目: サーバーサイド講義

3 日目はサーバーサイド講義でした。今回は Backend For Frontend (BFF) を題材に、複数のリソースサーバーを操作してデータのやりとりをする単一の GraphQL API サーバーを実装しました。 BFF という概念自体一定の規模の大きいサービスでないとあまり見かけないため、初見の方も多く見受けられましたが、最終的にはきちんと使いこなして実装を進められているようでした。

また、最終的には何名かが iOS アプリケーションとの繋ぎ込みまで完成させることができ、フロントエンドでデータが表示できている様子に喜んでいる姿も見受けられました。

https://github.com/cookpad/cookpad-internship-2022-summer-serverside

4日目 ~ 5 日目: サービス開発講義

講義の後半パートでは、サービス開発講義を実施しました。今回の内容は、ユーザーインタビューからそのユーザーが抱いている課題を見つけ出し、プロトタイプを作成してユーザーテストを実施して最終的なフィードバックを受ける。というものでした。

まず最初に、クックパッドのサービス開発に対する考え方や開発プロセスを座学形式で学びました。ここでユーザーインタビューのコツやその後のアイディア出しのためのテクニックについて、クックパッドで実際にやっている手法についても学びました。

その後は、グループごとに別れてユーザーインタビューをし、価値仮説から始めてアイディア出しをしました。参加者同士がガッツリコミュニケーションを取るタイミングはここが初めてだったので不安もありましたが、 Gather のワイワイ感もあったのか議論は盛り上がっているように見えました。アイディア出しのパートでは講師や TA に壁当てをすることが出来るのですが、講師も TA もかなり忙しそうに色々なグループを回っている姿が見えました。

5 日目は、まず前日に引き続き価値仮説やユーザーストーリー、プロトタイプの作成を引き続き行い、午後からユーザーインタビューの時と同じユーザーを対象にユーザーテストを行いました。 あまりこういったユーザーインタビューやユーザーテストの経験が無い方も多かったため苦戦している様子もありましたが、普段個人サービスを出しているもののこういったことが出来る機会は無いというフィードバックもあり好評でした。

6~15 日目 OJT

後半は OJT として実際にチームに配属されての実践パートでした。 事前に参加者からヒアリングした部署や技術領域などの希望をもとに配属され、実際にチームの一員としてメンターと共に 2 週間の間いくつかのタスクをこなしていただきました。

最終日には各自やったことをまとめてもらい、成果発表会をやりました。配属先のチームが多種多様だったこともあってか、発表内容も非常にユニークなものに仕上がってました。 最終日の成果発表

CTO も全ての発表に目を通し、最終的に CTO 賞の決定をしました。加えて今回は、最優秀賞を参加者含むオーディエンスの方々による投票で決定しました。それぞれ特別な商品を贈呈しました。

発表会に参加している CTO の様子

成果発表会終了後には、それぞれのメンターから修了証書を渡しつつ、最後のフィードバックをしました。 メンターからのフィードバックの様子

3-day Tech Course

15-day Tech Course が終わった後、少し日をあけて 3-day Tech Course を開催しました。 https://internship.cookpad.jp/ でも触れているように、今年のサマーインターンシップは開発者として働いている「未来の自分」に出逢うことがテーマとなっています。しかしながら 15-day Tech Course と違いこちらのコースは期間が 3 日間しかなく、 OJT で現場の仕事を体験するには短すぎます。 それ以外で可能な限り実際の現場に近い体験ができるよう、クックパッドと実際に関わりのあるクリエイターさんを相手にユーザーインタビューや壁当てをしながらお題に沿ったサービスを実装してもらう、というプログラムを用意しました。クックパッドでのサービス開発の一部を体験してもらえるような内容にしています。

まず、午前中はクックパッドのサービス開発に対する考え方やユーザーインタビューのテクニックなどを座学形式で学びました。この後にクリエイターさんへのユーザーインタビューとなるため、とても重要な講義です。

サービス開発講義の様子

お昼休憩を挟んで講義を終えたところでクリエイターさん方が到着しました。弊社が提供している生鮮 EC プラットフォームのクックパッドマートに出品されている方など、様々な場面でご協力を頂いている方々です。

クックパッドで活躍されているクリエイターさん達

参加者はそれぞれのクリエイターさんごとにグループに分かれ、ユーザーインタビューをしました。個人開発やアルバイトをしていても実際にユーザーインタビューをする機会が無い方も多く、新鮮な経験ができているみたいでとても盛り上がっていました。 クリエイターさんにインタビューをしている様子

インタビューが終わった後はまた個人ワークに戻り、話の内容から価値仮説を組み立てていきました。この間も必要に応じてクリエイターさんやメンターに壁当てをしたり、社内のスタッフから条件に当てはまりそうな人に声をかけて別途インタビューをしている方もいらっしゃいました。

2 日目からはひたすら価値仮設をもとにサービスを実装していき、 3 日目に成果発表を行いました。同じクリエイターさんをインタビューしたグループ内で見てもそれぞれが個性的なサービスを考えて実装しており、きちんと動くものを組み立てられていました。それぞれの発表にたいしてクリエイターさんとメンターからフィードバックをしました。 また、こちらも 15-day Tech Course と同様に CTO による賞と、各グループのクリエイターさんとメンターによる賞を決定しました。こちらもそれぞれ特別な商品を贈呈しました。 最終日の成果発表

ノベルティ

今年のノベルティ

写真のノベルティセットを当日は用意しました。特にネックストラップやタンブラーなどはオフィスに出社する時などに活用されていました。

まとめ

以上が今年のサマーインターンシップの開催報告です。ご参加頂いた皆さま、本当にありがとうございました! 今年は 15-day Tech Course でのオンライン講義に Gather を利用するなど初めての試みもいくつかありましたが、無事盛況に終わることができました。 加えて、昨年と比べてほとんどオフラインでの開催となりましたが、学生同士で横の繋がりを作って盛り上がっていたり、社員と共にオフィスでパフェを作るなど様々な現地でのイベントに参加したりと活発な交流が行われているようでした。 このサマーインターンシップが参加者の皆さまにとってひと夏の思い出になってくれていることを願っています。

さて、今年のサマーインターンシップは終わってしまいましたが、クックパッドでは就業形インターンシップを通年で募集しています。ぜひご応募ください!

internship.cookpad.jp

Amazon ECS と AWS Lambda で汎用 self-hosted runner を提供する基盤

技術部 SRE グループの @s4ichi です。ここ最近は本業に加えて Overwatch2 のヒーローとして戦いに明け暮れています。救わなければならないレートがある。

GitHub flow に従った開発では GitHub Actions が非常に便利です。特に最近では CI 用途だけでなく、ソフトウェアのデリバリーなども Actions で完結させる事例も見かけます。しかしながら、クックパッド社内では GitHub Enterprise Server を使っているため、GtiHub Actions の利用には self-hosted runnner の利用が不可欠になっています。

そこで、社内では Amazon ECS 上に ephemeral で汎用的な self-hosted runner を提供しています。実行する job の数に応じた autoscaling を備え、runner の起動を司る部分は AWS Lambda を用いたサーバーレスな構成です。今日はその基盤についての構成やチャレンジ、そして独自拡張の話をします。

クックパッドにおける GitHub Actions

社内では、ほとんどのチームの開発に GitHub Enterprise Server(以下、GHES)が使われています。GHES は EC2 上にデプロイされており、開発者に不自由が無いよう、利用規模や用途に合わせて調整する形で SRE チームが運用をしています。ただし、最新のバージョン 3.7.0 現在においても GHES には GitHub-hosted runner が提供されていないため、self-hosted runner を用意しないことには GitHub Actions を使えませんでした。

そんな中、昨年12月にリリースされた GHES のバージョン 3.3.0 にて、self-hosted runner を ephemeral に扱えて、かつ autoscale に用いることができる webhook が提供されるようになりました。依然として self-hosted runner 自体を用意することには変わりませんが、GHES でも比較的容易に GitHub Actions を運用するための機能が提供されました。世の中的にも GitHub Actions の機能が拡充されるに連れて利用の幅が大きくなっているのを感じていたのもあり、GitHub Actions を試してみようという動きが始まりました。

今回はこうした背景のもとで構築された GitHub Actions を提供する基盤の話になります。

ghe-actions: 汎用的な self-hosted runner を提供する基盤

ghe-actions は社内の GHES 上で GitHub Actions を提供する内製の仕組みです。汎用的な用途で使える self-hosted runner を ECS Task として提供します。runner は ephemeral な用途で使えるよう job ごとにクリーンな環境が用意され、同時実行する job の数に応じて必要な Container instance を調整する autoscaling の機能を備えています。

ghe-actions 概略

ghe-actions は GitHub Apps と AWS 上のいくつかのサービスを組み合わせて実現しています。

  • self-hosted runner 本体である Amazon ECS Task
  • GHES から webhook を受け取って runner を起動する AWS Lambda function
  • runner の ECS Task を起動するためのAmazon SQS queue

ghe-actions の構成は運用の手間が少なくなるよう、GHES 本体以外に状態を持たない設計にしました。状態遷移を保存するためのデータストアを持たないことで依存するコンポーネント管理の手間を削減するのが目的です。

利用の流れ

社内の GitHub Actions のユーザーは、まず ghe-actions のための GitHub App を自身のユーザーや organization にインストールします。GitHub App には workflow の job が起動した webhook(workflow_job)を Lambda の function URL へ送る設定がされており、インストールされた organization のリポジトリで workflow が起動すると、workflow_job の webhook から Lambda が起動します。

workflow_job の webhook を受け取った Lambda は、webhook の内容を解釈して必要なデータを抽出します。それらのデータは runner 起動のための SQS に SendMessage されます。SQS は別の Lambda から ReceiveMessage されたのち、GHES の API を使って runner 登録のための token を発行し、job を起動したリポジトリ専用の self-hosted runner を ECS Task として起動します。

runner は起動して job を実行したら Task を終了します。ephemeral な runner なので、同じ Task で複数回 job を実行することはありません。実行ごとに完全に削除されます。

構成要素の詳細

ユーザーがインストールする GitHub App は必要な permission を最低限要求し、以下の操作のために使われます。

  • 有効にしたリポジトリの workflow_job webhook の購読
  • リポジトリ向けの Registration Token の発行
    • self-hosted runner はこの token を利用して runner を GHES に登録する

2つの Lambda function はそれぞれ以下の役割を持ちます。

  • function URL から webhook を受け取る Lambda function
    • workflow_job の webhook の中でも Queued となるイベントにフィルターする他、payload を解釈して必要なデータだけを抽出して SQS に SendMessage する
  • SQS から ReceiveMessage してrunner を起動する Lambda function
    • SQS 経由で受け取った payload からリポジトリや labels を特定し、Registration Token の発行と labels に応じた適切な runner を決定・起動する

self-hosted runner 本体である ECS Task は次の特徴を持ちます。

  • マルチサイズ・アーキテクチャに対応
    • 最小 1 vcpu, 2 GiB RAM から最大 8 vcpu, 15 GiB RAM まで4種類のサイズを提供
    • アーキテクチャは amd64, arm64 環境を提供
  • Ubuntu ベースで基本的なパッケージは導入済み
    • 社内のユースケースに合わせつつ、GitHub-hosted runner に近い体験を提供
  • sidecar コンテナ内で dockerd を rootless で起動して利用
    • workflow 内の Docker コンテナの実行をセキュアに保つ

以上が汎用的な self-hosted runner を提供するための基盤である ghe-actions の概要です。ここからは ghe-actions の提供にあたって検討したチャレンジを紹介します。

汎用的な self-hosted runner を提供するために

GitHub-hosted runner では ubuntu-latest などの labels を指定すると、様々なパッケージが事前に用意されている汎用的な runner の環境が手に入ります。しかし、GHES の GitHub Actions には GitHub-hosted runner はありません。そのため ubuntu-latest で起動してくるような汎用的な self-hosted runner の提供が必要です。まったく同程度の汎用性までは求めずとも、社内の開発における不便さを解消できるところまでは提供する必要がありました。

self-hosted runner は https://github.com/actions/runner をインストールした計算機を repository や organization に登録することで runner として機能し、job を実行できるようになります。actions/runner 自体の requirements はそこまで大きくないため、いくつかのパッケージを入れるだけで満たせます。しかしながら、その状態の self-hosted runner は私たちが普段開発する上で必要な機能が不足しています。

ubuntu-latest などの labels で起動してくる GitHub-hosted runner は https://github.com/actions/runner-images から提供されているイメージです(着手当時は virtual-environments という名前だったんですが、変わってました)。例えばこれを Docker イメージ化することで同等の環境が提供できるのですが、イメージのサイズが数十 GiB とかなり大きくなってしまいます。AMI 化して EC2 で提供する方法も試しましたが、ephemeral な環境を提供するにあたって、毎度 EC2 の起動を待つことは実行時間の増加が見込まれるため諦めることにしました。

さて、管理や運用の楽さ、そして起動時間の観点から、やはりコンテナ化して提供することが好ましいです。しかし、コンテナ環境で self-hosted runner を提供するには課題があります。それはコンテナの中で Docker CLI を使えるようにしなければならないことです。workflow ではイメージのビルドはもちろん、MySQL などのミドルウェアの起動にも Docker を使います。

Docker コンテナ内で Docker CLI を使うためには、dockerd が必要です。コンテナ内で dockerd を提供する方法として、ホストで動いている dockerd のソケットをコンテナ内に共有する dood(docker-outside-of-docker)、もしくはコンテナ内でホストとは別な dockerd を立ち上げる dind(docker-in-docker)があります。前者はホストの dockerd を直接操作できるため、ホストで動いているコンテナを触ることができ、後者はコンテナごとに完全に独立した dockerd の環境が与えられます。

今回、リポジトリによっては秘匿値を扱ったり AssumeRole の操作を含むこともあり、汎用的な用途を目指すうえでセキュリティ面を重視する必要があります。そのため、dood のようにホストの dockerd が共有される環境は、簡単に他のコンテナへ侵入できるためセキュリティの観点から危うく、必然的に dind を選ばなければなりません。しかし dind でもコンテナ内で dockerd を実行するにはコンテナに特権を渡す必要があります。特権を持つコンテナは、ホスト環境を参照できてしまうので脆い状態には変わりません。そういった状況で、今回はコンテナに特権を与えつつ dind でセキュアな環境を提供するため rootless な dind の docker を利用しました。docker は公式で dind-rootless なイメージが配布されています。

そのイメージを ECS Task の sidecar コンテナとして起動する方針を取りました。dind の特権付与済みコンテナを runner のコンテナで dood した、というわけです。これで runner が参照する dockerd の環境は特権を持ちますが、root を持たないため、できることが限られます。以下に構成図を示します。

dind-rootless を sidecar として起動する ECS Task

図中では書いていませんが、sidecar に切り分けた dind-rootless コンテナ内の dockerd は、runner のコンテナと同じ network で動かし、localhost アドレスを共有するため、ECS Task を awsvpc network mode で起動しています。volume も共有して使うことで、基本的なユースケースでは runner と dockerd のコンテナが異なることを気にすることはほとんどありません。

ここまで来たらあとは必要なパッケージを同梱するだけです。actions/runner のアプリケーションをベースに、よく使われるパッケージを事前に入れた Docker イメージを提供しました。イメージサイズは ubuntu をベースにした actions/runner で 1.47 GiB、sidecar の dind-rootless コンテナは 367 MiB です。

多様な self-hosted runner を提供する

今回提供している self-hosted runner は ECS Task として起動できる形式ならば様々な拡張が可能です。ghe-actions は社内のユースケースに合わせてマルチアーキテクチャに対応しており、用途に応じて runner サイズの選択もできるようにしています。

workflow_job の webhook から受け取れて、かつ input とみなせる情報として labels があります。この labels で表現できる範囲であれば容易に多様な runner を提供することが可能です。現状は前述したアーキテクチャとサイズのみを展開していますが、例えば特定の SecurityGroup を持つ runner を起動するなど、GitHub-hosted runner では難しい領域で拡張していく予定です。

AWS 利用料金の節約

self-hosted runner が提供できるようになったとはいえ、提供する ECS Task は無料ではありません。今回は継続的に基盤を提供し続けるためにも、できるだけ利用料金を節約する方向に ECS Cluster を構築しました。

ghe-actions の ECS Cluster に属する Container instance は全て Spot Instance で構成されています。Spot Instance の利用は、On-Demand Instance と比べてかなり利用料金を削減できるためです。Spot Instance interruptions により workflow が途中で終了してしまう可能性もありますが、capacity-optimized allocation strategy を用いることで頻度を抑えるようにしているため、今のところ困ることもほとんど無く済んでいます。

Container instance は job の実行数に応じて autoscaling する構成になっています。そのため、利用頻度の低いときは台数を減らして待機させることにしました。autoscaling を有効にすることで、一度に大量の job が起動する場合は Container instance の起動時間のペナルティがかかりますが、大量の job を一気に起動する用途は限られるため、通常の用途では困ることは少ないでしょう。

現行の制約

ghe-actions は社内のほとんどの用途で問題無く使えますが、本家の GitHub-hosted runner と比べればいくつか制約が残ります。

Service containers の機能が使えない

Service containers は GitHub Actions の workflow で記述できる Docker コンテナ起動のための記法です。actions/runner はまだコンテナ内での起動を公式にサポートしているわけではないため、 Service containers の機能を使う前の実行環境の validation を違反してしまう状態です。

GitHub Marketplace にある action が全て使える状態ではない

ほとんどのケースにおいて問題にはならないんですが、GitHub Marketplace にある action の一部は使えないことがあります。action の実装によっては ghe-actions の構成と非互換な使われ方をしていることがあるためです。都度回避策を用意するなどして回避していますが、稀に存在するため、GitHub-hosted runner と完全な互換だと想定することができない現状です。例えば、docker/build-push-actiondocker/setup-buildx-action は README にある通りの設定では ghe-actions の環境で動作しないため、事前に別途コマンドを実行した上での利用が必要です。

おわりに

本記事では社内の GHES に導入した ghe-actions の基盤についてその背景やチャレンジ、独自拡張について紹介しました。GitHub-hosted runner と比較して不足する部分もあるものの、self-hosted runner であるために細かな調整や独自拡張を入れやすい環境が提供できています。

運用の手間や起動時間を最小限にしつつ、現実的なコストで運用ができる程度の汎用的な runner を提供する基盤が整っています。今後は社内にある開発フローやシステムとの連携を進め、より使いやすい環境を提供していきます。

クックパッドでは、このような CI/CD 環境の構築を始めとした開発者向けの仕組みの基盤整備にも積極的に取り組んでいます。こうした分野の改善には幅広い領域への理解と深い専門性が必要になります。開発者向けの基盤、及びサービスの信頼性向上に興味のある方は、ぜひお気軽にご連絡ください。下記の採用ページからも申し込むことができます。

cookpad.careers cookpad.wd3.myworkdayjobs.com

Kaigi on Rails 2022 にて『森羅万象に「いいね」するためのデータ構造』の発表をしました

メディアプロダクト開発部で Rails を書いているなどやま ( @pndcat ) です。業務では、広告基盤の開発、運用から新規サービス開発など、マーケティングソリューション領域に関する開発をしています。趣味は、スプラトゥーンと推し活動をがんばっています。

Kaigi on Rails 2022 にて、森羅万象に「いいね」するためのデータ構造 というタイトルで発表をしました。この記事では、Twitter などで寄せられた質問に回答したいと思います。発表中にあった「いいね」のリファクタリングについてのさらなる詳細については、後日公開する予定です。

After Kaigi on Rails イベントの開催のお知らせ

本日 (10/31) の19時から Cookpad Lounge #15 After Kaigi on Rails を開催します!イベントでは、Kaigi on Rails に登壇した3人の振り返りや、発表では話せなかったことにも触れます。また、惜しくもプロポーザルが落ちてしまった社員による発表もありますので、ぜひ遊びに来てください!(アーカイブもあるのでよろしくお願いします)

cookpad.connpass.com

資料

speakerdeck.com

動画

www.youtube.com

Q&A

以下、今回の発表に関して Twitter などで寄せられた質問への回答です。いろいろな感想や質問があり、とても嬉しかったです。ありがとうございました!

リファクタリングはどうやって進めたのか?リファクタリングの工数はどうしているのか?

メーカーズタウン(今回の発表の題材となったサービスです)の開発チームでは、週に1回、モブプロをする日を作っています。 モブプロには、開発メンバー4人に加え、えにしテック@darashi さんと、@cafedomancer さんにも参加していただき、6人で行っています。 モブプロでは、

  • リリース後に真の仕様がわかったため、より良いデータ構造に変更したい
  • リファクタリングをしたくても、コードが難しい上に、テストもないが、どうにかしたい
  • リリースが迫っているタスクをモブプロで行い、マージまでの時間を短くしたい

など、いろいろなテーマに取り組んでいます。
「いいね」テーブルの種類が増えていき、そろそろ実装が辛くなってきたという段階でリファクタリングのモブプロを行いました。

「いいね」のモブプロでは、現状の仕様や振る舞いの理解を深め、リファクタリングの戦略を検討し、実際に1種類の Like / AnonymousLike を移行しました。そこまでをモブプロで行い、その他の「いいね」は普段の開発をしながら移行していきました。

大規模なリファクタリングは、一人でコツコツ取り組むのは難しいものです(気持ち的にも、正しいリファクタリングができているのかという点においても)。モブプロにおいて議論しつつ移行戦略を確立させたことで普段の開発をしながら移行を進めることができたため、大きな問題もなく移行することができました。

匿名いいねの like_identifier ってなに?

like_identifier は、ログインをしていないユーザーに対して発行するランダムな文字列です。これを Cookie に保存して、匿名いいねに利用しています(文字通り、like をしたユーザーの識別のみが目的の値です)。

like_identifier はユーザーのブラウザのみにある情報であり、Cookie が有効な間は、そのユーザーの「いいね」の情報を取得することができます(Cookie が切れた場合は、「いいね」の取得ができないのですがそれを仕様としました)。

何で中間テーブルを使う方法がリファクタリングの候補になかったの?

今回は、「いいね」の対象が増えるたびにテーブルが増えて、開発やメンテナンスが難しくなっていたので、テーブル数やモデル数は減らしたいという方向に考えていました。また、今後も「各いいねの振る舞いを同じ」にするという制約をおいたため、ポリモーフィック関連か STI でのリファクタリングを検討しました。

「ポリモーフィック関連で if 文を書くと破綻する」の例は?

ポリモーフィック関連のモデルのタイプ別に、異なる振る舞いを持たせたくなった時が典型的な例でしょう。例えば、商品やトピックが「いいね」されたときだけ購入導線を出すとした場合、いいねメソッドを呼び出す側でその実装を意識する必要に迫られ、どんどん複雑になっていきます。ポリモーフィック関連のモデル、つまり、Like には if 文は絶対に書かない=異なる振る舞いはさせない、という強い意志を持ちリファクタリングを行いました。

おわりに

本記事では、森羅万象に「いいね」するためのデータ構造 の発表の Q&A の解説をしました。発表では話せなかったリファクタリングの詳細についても別途記事を書くので、次回作もお待ちください。

クックパッドでは、データの設計やリファクタリングについて熱く話し合う人を募集しています!もし少しでも興味があればカジュアル面談も実施していますので、ぜひご応募ください。

cookpad.jobs