iOSDC Japan 2022 ありがとうございました!#iwillblog

クックパッドでモバイルエンジニアをしているあつや(@n_atmark)です!iOSDCに参加されたみなさまお疲れ様でした!

さて、クックパッドは先日の iOSDC Japan 2022 でプラチナスポンサー & スポンサーブースを務めました。 スポンサー特典の一つにオープニングでの社名読み上げがあるのですが、今年もミサトさん(三石 琴乃さん)に社名を読み上げていただいて「これこれ〜!」とテンションが上がってしまいました。

会期中には、クックパッドに所属する あつや(@n_atmark)、アイカワ(@kalupas226)、ainame(@ainame)、あおい(@aomathwift)、yujif(@yujif_)がスピーカーとして登壇しました。

イベント参加のご報告として、当社所属メンバーの発表やブースの紹介をいたします!

発表

施策基盤としてのディープリンク 〜なめらかにアプリが開く体験のために〜 / あつや

https://fortee.jp/iosdc-japan-2022/proposal/6c4615f5-b471-4f78-9044-4ae3f8dd75d4

あつや(@n_atmark)からはディープリンクに関する発表を行いました!間違えやすいディープリンク用語の整理や施策の効果を発揮するために活用できる仕組みを紹介しています。

speakerdeck.com

個人ブログでウラ話も紹介しているのでよければご覧ください!

SwiftUI Navigation のすべて / アイカワ

https://fortee.jp/iosdc-japan-2022/proposal/0b6f453a-68f0-4300-9ab2-cb1e3457eb53

アイカワ(@kalupas226)からは”SwiftUI Navigationのすべて” という題で発表がありました!SwiftUIのNavigation APIを俯瞰した説明や、既存のNavigation APIの課題と課題に対するアプローチを紹介しています。

speakerdeck.com

9/28に開催されるAfter Party iOSDC Japan 2022では本編トークに入り切らなかった話もされるそうですよ!

cookpad.connpass.com

Swift 5.7で変わる正規表現を試してみよう / ainame

https://fortee.jp/iosdc-japan-2022/proposal/6ce89b3f-8f08-47ba-a78d-deaee335c215

Swift5.7で強力になった正規表現周りのアップデートに関してainameから発表がありました!これまでのSwiftの正規表現と比較して、どのようなアップデートがあったのかを紹介しています。

speakerdeck.com

Swift5.7でのRegexの実装についてさらに理解を深めたい方は、ainameがわいわいswiftcで発表した内容もぜひご覧ください!

www.youtube.com

即時通知を導入する際に考えるべきこと / あおい

https://fortee.jp/iosdc-japan-2022/proposal/dc963bce-52bd-429c-86ed-9a7b314063ce

あおいからは即時通知に関する発表が行われました!即時通知の紹介と、どの通知を即時通知にすべきかの判断をチーム内でどのように運用していくのかプラクティスを踏まえて紹介しています。

speakerdeck.com

即時通知の機能紹介をあおいがWEB+DB Pressに寄稿しています!バックナンバーになりますが、こちらもよろしければご覧ください。

aomathwift.hatenablog.com

モバイルアプリの行動ログの「仕込み」を快適にする / Yuji Fujisaka

https://fortee.jp/iosdc-japan-2022/proposal/ad544d2d-0e37-48f7-836a-3d46abe4ad2f

yujifからは”モバイルアプリの行動ログの「仕込み」を快適にする”という発表が行われました!ログ収集における悩みの種のうちログ実装の「仕込み」に対して、仕組み化によって解決を図っている事例を紹介しています。

speakerdeck.com

「Markdown定義からログの実装コードを自動生成する仕組み」に関してはクックパッド開発者ブログに載っています。

ブースや企画の様子

Cookpad TechConf 2019で元クックパッドのgiginetさんが発表したマルチモジュール図(通称: 親の顔より見た図)のパネルと、2022年現在のマルチモジュール図をパネルにして用意しました。

新旧見比べることで2019年からモジュール構成に差分があったり、モジュール分離が進んでいる様子を知ることができ参加者の方からも好評でした!

また、9/11(日) day1ではクックパッドアプリの開発の様子を体験できるデモをブースで実施しました。 「テンプレートを用いたVIPERシーンの自動生成を行い、シーンに対してサンドボックスビルドを生成するデモ」と、「ログ定義Markdownからログ実装用コードを自動生成し、仕込まれたログを疎通確認ツールで検証するようなデモ」の2つを実施しました。

デモが成功すると「おおー!」と歓声があがって盛り上がりました!

9/12(月) day2にはアンカンファレンスブースを利用して、CTO座談会とios-cookpadのコード見せる会を実施しました!

CTO座談会では、あつや(@n_atmark)[クックパッド事業本部 買物サービス開発部所属 *1 ]・あおい(@aomathwift)[買物事業本部 買物プロダクト開発部所属 *2 ]・CTOの成田(@mirakui)の3人で"買い物領域"について話しました! クックパッドはレシピサービスをずっとやっている印象をもたれることも多いのですが、クックパッドが力を入れている “買い物領域” について知ってもらえるきっかけになりました。

ios-cookpadのコード見せる会では、2019年に盛況だったios-cookpadのコード見せる会からのアップデート部分を主に、クックパッドエンジニアが順番に実装コードの紹介を行いました!多くの方にアンカンファレンスブースを覗きに来ていただけました。「クックパッドアプリで使われているカスタムナビゲーションの実装*3を見せて欲しい」とリクエストをいただけたりしました。

おわりに

改めて、iOSDC Japan 2022ありがとうございました!

次は10月5日から開催される DroidKaigi 2022 に参加する予定です。みなさまにお会いできることを楽しみにしています🤗

droidkaigi.jp

宣伝

まだまだiOSDC熱が収まらない皆さま!9/28(水) 19:00よりYouTube Liveにてクックパッド主催のiOSDCアフターイベント「After Party iOSDC Japan 2022」を実施します!

cookpad.connpass.com

  • enum で Key Paths のような機能を実現する Case Paths / アイカワ(@kalupas226)
  • Maintainability Indexを計測することでiOSプロジェクトのコードの保守性を改善した話 / toya108(@tk108gabalian)
  • DocC Documentation Archiveをアプリ開発で活用してみよう / あおい(@aomathwift)
  • OpenAPIのクライアント自動生成を現場に導入していくためのノウハウ / imajin(@mrimjn)

4つのトークタイトルを発表予定です。ぜひお越しください!

*1:クックパッド事業本部 買物サービス開発部: レシピサービスクックパッドに買い物体験を取り入れることで、食卓におけるレシピ決定をより豊かにすることを目標としている部署

*2:買物事業本部 買物プロダクト開発部: クックパッドマートにおける注文、出品、マーケグロース等、作り手と買い手のための仕組みづくりの設計開発を行う部署

*3:UINavigationControllerをカスタマイズ 〜OSの影響を受けづらいカスタムナビゲーションの実装〜

新卒向け社内研修制度Horizonを利用してイギリスに出向してきました

こんにちは。エンジニアの河邉です。

クックパッドにはHorizonという新卒3年目までの若手エンジニア・デザイナーにグローバルな環境で働く機会を与えて成長の後押しをしてくれる海外出向研修プログラムがあります。

詳細は英国派遣プログラム「Horizon」 責任者に聞く制度への思い(前編)を御覧ください。

2021年4月にクックパッドに新卒入社した私は、この制度を利用して2021年末にイギリスに渡航し、2022年1月から6月までの半年間ロンドンから電車で2時間ほどのブリストルにあるグローバル本社でiOSエンジニアとして働きました。

今回はその体験談をお届けします。

グローバルクックパッドについて

クックパッドは現在74の国や地域に32言語でレシピサービスを提供しています。 日本以外の地域で提供しているサービスはイギリスのブリストルにあるオフィスで開発されています。

Horizon参加の流れ

2021年の夏、Horizonの実施が社内ブログで告知されました。 私が参加を決めた理由は大きく分けて2つあります。

1つめは、グローバルクックパッドのサービス自体に興味があったからです。 私はクックパッドに入社する前からコミュニティサービスの開発に興味を持っていました。 もちろん日本のクックパッドや私がプログラム参加前まで開発を担当していたcookpadLiveにもユーザー同士のコミュニケーションは存在するのですが、グローバルクックパッドは現状いわゆるSNSチックなサービスの設計がされていて、ユーザーのコミュニケーションがより重視されたサービスだなと思っていたので、開発に携わってみたいと思いました。

2つめは、異なる文化や言語を持った多様なメンバーと一緒に働いてみたかったからです。これまでグローバルな組織でエンジニアとして働いた経験がなかったので人生経験として一度は挑戦したいと思っていました。

仕事内容

クックパッドグローバルのエンジニア組織は機能開発をする「プロダクト」、基盤の開発をする「プラットフォーム」と大きく2つに分かれています。

私はまずアプリの全体像を把握するためにグローバルモバイルプラットフォームチームという基盤の開発をするチームに入りました。 そこで最初に拾ったタスクがiOSプロジェクトへのOpenAPIの導入でした。

具体的な業務内容は別ブログでご紹介していますのでよかったらご覧ください。

techlife.cookpad.com

当初の予定では初めの3か月プラットフォームチームで働いてその後プロダクトチームで働きたいとバディ*と話していたのですが、結局このプロジェクトが楽しくなってしまい5か月以上プラットフォームチームで働いていました。

*入社してから数か月は同じ領域のエンジニアがバディとして付いてくれる。

6か月目にプロダクトチームのiOSエンジニアの退職に伴い、まだまだプラットフォームでやりたいこともありましたが、良いタイミングだったのでプロダクトチームに異動させてもらいました。

プロダクトチームはタイムラインを担当するチームや検索を担当するチームなど、基本的に機能ごとに1つのチームが編成されています。 私は検索機能の開発を担当するチームでiOSアプリの実装を担当することになりました。 私のチームでは週に1度イテレーションプランニングというミーティングがあり、ここで1週間のチームのタスクを決め、毎朝軽い進捗共有のミーティングをしています。

プロダクトチームに移ってから面白いなと感じているのは、主に2つあります。

1つは、ある機能のA/Bテストを行う場合にどの地域で実施するのかという議論があることです。この国では、〇〇な使われ方をしているから、〇〇のデータを持っているから、既に〇〇をリリースしているからなど、それぞれの国でのサービスのステージの違いや宗教的な行事の有無などによって機能の出しわけをするのは、多様な地域にサービスを提供している実感を持てて興奮します。

2つめはチームに専属のデータエンジニアがいることです。これは日本とグローバルの違いというよりは組織の違いでしかないのですが、グローバルクックパッドでは基本的に1つのプロダクトチームに1人のデータエンジニアがいて、A/Bテストをはじめとしたさまざまな施策の進捗を客観的な数値として報告してくれます。

日本にいたときは数値の測定も自分でする場合が多く、調べきれない部分もあったのですが、データエンジニアが付いてくれていることで自分達がやっていることに対する納得感が数値としてより正確に得られるのは、異なる母国語や文化を持つメンバーで構成されているチームでは特に重要なのではないかと感じています。

成長

まず技術面では、私は基盤的な開発をした経験がこれまでになかったので、長期間に渡って1つの大きな改善に取り組めたのは自信に繋がりました。 その過程でCreateAPIというOSSの改善に初めて加わることもできました。 プロダクトチームに異動してからはチームのiOSエンジニアとして工数見積もりの精度や実装スピードを週を追うごとに少しずつ向上できている実感があります。

これらの成長実感は日本とグローバルでの違いではなく仕事内容の変化によるものですが、6か月という限られた期間を別の組織に出向して、それまでと異なる働き方やプロダクトの開発に関わることのできるのはHorizonの魅力と言えると思います。新卒で入社してからの1年間で、複数の組織で複数のプロダクト開発に関われたことはとてもありがたいことでした。

グローバルで働くということならではの成長としては、日本にいるときよりもより簡潔に議論を展開できるようになったことだと思っています。もともと喋りながら考えてしまうタイプでまとまりのない主張をしてしまいがちだったのですが、英語力の問題もあり、より結論ベースで簡潔な主張をするようになりました。

また今回1歩海外へ踏み出したことによって将来の自分のキャリアへの展望が大きく広がったと強く実感します。海外で英語を使って働くことができるという自信と、同僚の多種多様な来歴を聞いて、今後も海外で働くなど、日本にいたときには考えられないような将来の選択肢を考え始めるようになりました。

私はHorizonプログラムの終了後、グローバルクックパッドの選考を受け、転籍することにしました。クックパッドをもっとたくさんの人に世界中で使われるサービスにしていきたいですし、個人としても今後も日本だけじゃなくていろんな国で活躍できるようになっていきたいです。

生活

まとめの前に生活面の経験についても少しご紹介させていただきます。

現地に到着してまず取り組んだのは友達づくりでした。思い切って参加した家の近くにあるダンス教室で友達をつくることができました。これまでダンスをしたことはなかったし、かなり勇気のいることでしたが飛び込んでみてよかったと思います。会社外でも友達をつくることで仕事から完全に離れてリフレッシュする時間を楽しめました。

ブリストルでは美味しいクラフトビールが楽しめます

またイギリスからヨーロッパへは飛行機で安く行けるので、スイス、フランス、オーストリア、スロヴァキア、スペインに週末や有給をつかって観光に行きました。あまり遠く離れていないにも関わらず、それぞれの地域で言語や食などの文化の違いを大きく感じられるのは、ヨーロッパに住む大きなメリットだと感じました。

フランスのモンブラン近くでスノーボードをしました

まとめ

グローバルクックパッドを開発したい、海外で働いてみたいという2つの思いを持って参加したプログラムでしたが、1つめのサービス開発という面では挑戦しきれなかったというのが正直なところです。ほとんどの時間を基盤系の仕事に使ったことも理由ですが、プロダクトチームに移ってからもまだ毎週のリリースサイクルに付いていくのが精一杯です。これからもっとスピードをあげてiOSエンジニア領域外の仕事にも手を出して行きたいと思っています。

次に2つめの目的だった海外でグローバルな組織で働くということについては、本当に経験してよかったと思っています。同僚との何気ない会話の中からカルチャーショックをもらったり、仕事終わりのパブでいろいろな人生観を知ったり、そういった刺激がとても心地よくて同僚と会話することを楽しみに会社に行っています。

ただ「毎日の料理を楽しみにする」という共通の目標を持っている人間同士、同じである部分も多く感じられました。 日本にいてメディアなどを通じて伝わってくる「違い」だけではなく、「同じ」であることも多く実感できたことは、これから先グローバルに働いて生きていく上でとても重要な感覚を得られたなと思っています。

Horizonプログラムはクックパッドに新卒で入社する最大の魅力の1つだと思います。また中途入社でイギリスで活躍している方もいらっしゃいます。ご興味があればぜひご連絡ください。

最後までご覧いただきありがとうございました。

OpenAPI SpecificationsからiOSプロジェクトのネットワーク層を自動生成する

こんにちは。iOSエンジニアの河邉です。 今回は海外出向研修プログラムで出向した海外版Cookpadを開発するブリストルオフィスで取り組んだ、OpenAPI SpecificationsからiOSプロジェクトのネットワーク層を自動生成する話をしたいと思います。

海外出向研修プログラムについての体験談はこちらをご覧ください。

techlife.cookpad.com

本題に入る前にまず海外版Cookpadについて簡単に紹介します。 海外版Cookpadは、日本のクックパッドレシピサービスとはコードベースも開発チームも会社も分かれていて、イギリスのブリストルという都市にあるオフィスをベースとするチームによって開発されています。 現在は世界74の国や地域で、32言語をサポートし、各地域のコミュニティチームと連携しながら世界中の毎日の料理を楽しみにするためにレシピサービスを展開しています。

海外版CookpadとOpenAPI

海外版Cookpadでは2019年頃からOpenAPIを用いたスキーマ駆動開発の導入を開始しました。 Androidプロジェクトではすでに2021年の段階でOpenAPIのスキーマからDTO(Data Transfer Object)と呼んでいるネットワーク層に用いるオブジェクトや、APIエンドポイントの定義の自動生成をしていました。

英語の記事ではあるのですが、iOSに先行して実施したAndroidプロジェクトへの導入について、以下の記事で紹介しています。 Let OpenAPI generate your Android network layer by leveraging Retrofit, Moshi, and Coroutines

しかし、iOSプロジェクトは2022年になってもOpenAPI SpecificationsからDTOやエンドポイントの定義を生成することができていませんでした。

Androidと比較してiOSのプロジェクトが遅れてしまっていたひとつの要因は、もちろんマンパワー的な問題もありますが、Androidプロジェクトには導入以前からすでに手書きのDTOが存在したためOpenAPIから生成するものと置き換えることができましたが、iOSプロジェクトにはDTOが存在しなかったため単に置き換えることができず、新しくDTO層を追加する必要があったからです。

DTO層が存在しなかったので、1つのオブジェクトをAPIレスポンスのデコードからUIロジックまで使っていて責務の切り分けができない・肥大化する・変更しづらいといった問題と、自動生成していないことによって単調なコードをAPIの変更のたびに手書きする必要がある・記述ミスのリスクが排除できないなどの問題を認識していました。

OpenAPIからiOSプロジェクトのネットワーク層を自動生成する

DTOの無かったiOSプロジェクトにOpenAPIから生成したDTOを導入した実際の手順について紹介します。

DTOを生成する

まず初めに取り組んだのはDTOの自動生成でした。自動生成に用いたライブラリはCreateAPI/CreateAPIという非常に新しいライブラリです。

// Generated by CreateAPI
public final class UserDTO: Codable, DTO {
    public let type: `Type`
    public let id: Int
    public let name: String
    public let avatarURL: URL
}

海外版Cookpadアプリはバイナリサイズにシビアな地域でも多くのユーザーに使われているので、アプリのバイナリサイズにはより細心の注意を払いました。 海外版Cookpadは既に400以上のComponentsが定義されていて、決して小さいアプリとは言えず、全てのComponentsをDTOとして一気に生成してしまうとバイナリサイズを不必要に大きくしてしまう懸念がありました。

今回のCreateAPIを使ったDTOの自動生成は当初は実験的に開始したため、CreateAPIの include というパラメータを用い、アプリのバイナリサイズを肥大化させないために少しずつDTOの生成を進めていきました。

また、CreateAPIにあるisGeneratingStructsというパラメータを用いて、DTOをStructではなくClassとして生成しました。我々のケースではStructで生成するのと比較して1.7MB縮小することができました。

Mapperを記述する

enum UserMapper {
    static func toEntity(from dto: UserDTO) -> User {
        User(
            id: dto.id,
            name: dto.name,
            avatarURL: dto.avatarURL
        )
    }
}

CreateAPIによって生成したDTOを既存のオブジェクトにマッピングする関数を記述しました。 これによって既存のオブジェクトには変更を加えずに、DTOとMapperを用いたネットワーク層を新しく追加することができます。

DTOとMapperのテスト

DTOとMapperが既存のオブジェクトと同じようにAPIのレスポンスをシリアライズしているかを確認するために、実際のレスポンスのJSONと同じ形式のダミーデータを用意し、DTOとMapperの組み合わせと既存のシリアライズ方法で全く同じ結果を得られるかを確かめるテストを用意しました。

final class UserMapperTest: XCTestCase {
    func test_user() throws {
        // Given User response json
        let response: Data = try Bundle.module.data(forResource: "User") // JSONファイルを読み込む関数を用意
    
        // when parse the response to User with legacy parser
        let legacyParser = DefaultModelParser<User>()
        let old = legacyParser.parse(response).value // 従来の方法でシリアライズ

        // and when parse and map the response to User with DTO parser
        let parser = DTOResponseParser<UserDTO>()
        let new = UserMapper.toEntity(from: parser.parser(response).get().result) // 新しい方法でシリアライズ

        // then
        XCTAssertEqual(new, old)
    }
}

この過程で既存の実装にAPIの定義とは異なる記述が見つかりましたが、ここではそれらのリファクタリングは後回しにして、とにかく現状の実装と一致する結果が得られるようにMapperやテストを記述しました。 タスクのスコープをネットワーク層の導入以外に広げないようにしたことが、導入をやり切る上でとても重要だったと思います。

これらのテストは移行期間中のみの一時的なもので移行が完了したら一緒に削除していきます。

DTOとエンドポイントはモジュールに分割して閉じ込める

DTOとエンドポイントはAPIKitという新しくつくったモジュール内に生成しています。 ApplicationモジュールはAppBaseモジュールを通じてのみAPIKitを参照するので、ApplicationモジュールはAPIKit内のネットワーク層の実装を意識しなくても良いようになっています。

便利にするための小技

今回ネットワーク層を自動生成する過程で用いた便利な小技をいくつかご紹介します。

Sourceryでpublic initを自動生成する

Mapperを記述する過程で既存のオブジェクトにpublicなinit関数が必要になりました。 これを毎度手書きしているとなかなか大きな手間になるので、Sourceryで自動生成する仕組みを導入しました。

// sourcery: autoPublicInit

StructやClassの定義の一行上に上記のように記述すると下記以下のようなpublic initを生成してくれます。これによって面倒な記述を減らすだけでなく、抜け漏れなども起きなくなりました。

// sourcery:inline:auto:Recipe.autoPublicInit
    public init(
        id: Int,
        title: String
    ) {
        self.id = id
        self.title = title
    }
// sourcery:end

GitHub ActionsでスキーマをWeb・Android・iOSにデプロイする

OpenAPIのスキーマは独立したレポジトリで管理されていて、これによって生成されたスキーマファイルはWeb・Android・iOSプロジェクトの各レポジトリ内でそれぞれに保持しています。 これらの同期を簡単にするため、OpenAPIスキーマのレポジトリからGitHub Actionsでそれぞれのレポジトリにデプロイし、プルリクエストを立てる仕組みを用意しました。

まとめと今後

今回ネットワーク層を自動生成したことによって、iOSプロジェクトもより確実に最新のAPIの最新の定義に追従できるようになりました。また、ネットワーク層を自動生成するようになったことで、よりアプリケーション層の実装に注力できるようになったと考えています。

さらにDTOをOpenAPIのスキーマから自動生成する過程で、より良いスキーマ定義について考える機会となったということも今回のプロジェクトの副産物でした。

現時点では全てのDTOとエンドポイントを利用できているわけではなく、一部APIのスキーマを改善しながら継続して既存の仕組みとの置き換えを進めてていく必要があります。 導入にあたっては私の所属していたGlobal Mobile Platform(モバイル基盤)チームで主導しましたが、現在ではProductチームのiOSエンジニアにもそれぞれの担当している機能に導入をお願いするなど、全iOSエンジニアで進めていけるように継続的にコミュニケーションを取っています。

海外版Cookpadを開発するブリストルオフィスのチームには機能の開発をするプロダクトチームと、今回のOpenAPI Specificationsのような基盤の改善をするプラットフォームチームに分かれています。 両チーム共にiOSエンジニアを募集しているので興味のあるかたはぜひご連絡ください。

今回私はHorizonという新卒向け研修プログラムでブリストルオフィスに出向しました。Horizonについての詳細は以下の記事をご覧いただければと思います。

英国派遣プログラム「Horizon」 責任者に聞く制度への思い(前編)

最後までご覧いただきありがとうございました。