5.1さらうどん

@giginetの技術ブログ。ゲーム開発、iOS開発、その他いろいろ

Swift MacroをSwift PackageなしでXcodeで扱う

Swift MacroってXcodeから使えないの?

Swift 5.9からSwift Macroが実用段階になったが、WWDCの動画でも、公式ドキュメントでもSwift Packageから作成することが前提となっている。

targets: [
    // Macro implementation that performs the source transformations.
    .macro(
        name: "MyProjectMacros",
        dependencies: [
            .product(name: "SwiftSyntaxMacros", package: "swift-syntax"),
            .product(name: "SwiftCompilerPlugin", package: "swift-syntax")
        ]
    ),


    // Library that exposes a macro as part of its API.
    .target(name: "MyProject", dependencies: ["MyProjectMacros"]),
]

Xcodeで作成したtargetに組み込むときもパッケージの依存を組み込み、マクロフレームワークをimportするだけで利用可能になるようだ。

しかしXcodeGUIではMacroを含むモジュールに依存関係を設定する方法はない。通常の依存関係と異なり、Macroはビルドdestinationが特殊なので、これを内部的にどうやって設定しているのか気になった。 (例えばiOSアプリにMacroを組み込むとき、アプリケーション自体はiOS向けにビルドするが、Macroは常にmacOSで実行可能な形でビルドされなくてはならない)

XcodeやxcodebuildのレイヤーではMacroを依存として指定する方法がないのだが、swiftcのレイヤーでは何らかの方法でmacroへの依存関係を指定しているはずだ。

-load-plugin-executable

調べてみたところ、どうやら -load-plugin-executable というオプションがswiftcに生えていた。

この辺の記事にほとんど書いていた。

$ swiftc --help
  -load-plugin-executable <path>#<module-names>
                          Path to an executable compiler plugins and providing module names such as macros

この -load-plugin-executable でmacroターゲットのバイナリを指定すると良いらしい。Xcodeでは OTHER_SWIFT_FLAGS にこれを指定する。

実際に、適当なMacroを含むパッケージをXcodeプロジェクトに追加し、利用してみたときのログを見ていると、同じフラグを渡していることが確認できる。

Special Thanks : mtj0928/userinfo-representable

Swift MacroをSwift PackageなしでXcodeだけで作る

そして、調べてみると、SwiftPMにおける.macro ターゲットは、実は単なるmacOS向けの executableTarget とほぼ同等なものであることがわかった。

-load-plugin-executable で要求されるバイナリは、実は単に CompilerPlugin に適合した型をエントリーポイントとしたexecutableを要求しているだけのようだ。 あとでswiftc側でどういうバイナリを想定しているかの内部実装も読んでみたい。

ここまでわかると、Swift Packageを使わずとも、Xcodeだけでマクロを捏造できるのでは?と思って試してみた。

Macroターゲット側 (MyMacro)

  1. XcodemacOSのCommand Line Toolターゲットを作る
  2. swift-syntaxをSwift Packageとして追加して依存関係にする
  3. 普通にmacroを書く

ここで実装するマクロはなんでもよいので、公式ドキュメントのサンプルにある fourCharacterCode の実装を使うことにした。

重要なのは、executableのエントリーポイントとして、CompilerPluginを指定することだ。

import SwiftCompilerPlugin

@main
struct MyMacro: CompilerPlugin {
    var providingMacros: [Macro.Type] = [FourCharacterCode.self]
}

アプリターゲット側 (MyApp)

  1. Build Phaseのdependenciesに MyMacro を追加する
    • 単にビルド前にexecutableを作っておきたいだけ
  2. OTHER_SWIFT_FLAGS-load-plugin-executable $BUILT_PRODUCTS_DIR/../$CONFIGURATION/MyMacro#MyMacroを指定
    • これは BUILT_PRODUCTS_DIR に入っている MyMacro の成果物を指定している
    • 単に $BUILT_PRODUCTS_DIR だとアプリ側のdestinationになってしまうので ../$CONFIGURATIONmacOS側のdestinationにする
    • この指定は特殊で、 swiftc --helpによると、<executable_file_path>#<target_name> らしい
  3. シンボルの解決のために#externalMacroを仮宣言する
    • これをすることで、依存解決時はMacroが存在する体で扱い、実際にビルドするときに2で指定したバイナリを実行する

@freestanding(expression)
macro fourCharacterCode<T>(for value: T) -> UInt32? = #externalMacro(module: "MyMacro", type: "FourCharacterCode")

こうすることで、自作のMacroをXcodeターゲットだけで実装することができた 🎉

Swift Macroのビルドキャッシュ

では、このような複雑な構造を取って一体どんなメリットがあるかというと、ビルドキャッシュの利用という面でXcodeターゲットで管理していた方が扱いやすい面があるのではないかなと思う。

現状、Swift Macroはswift-syntaxへの依存が必須で、どの方法で作ってもswift-syntaxを依存として持つ必要がある。swift-syntaxはデカいので、単純なマクロを1つ作っただけで、ビルド時間が激増してしまうという問題があった。

僕の開発しているScipioなどで、swift-syntaxをprebuiltなXCFrameworkとして維持しておくことができるので、Xcodeで作成したMacroターゲットがprebuilt版のswift-syntaxに依存するようにしておけば、ビルド時間を大きく改善できそう。

また、Xcodeを使わないにしても、swift buildで作成したexecutableをキャッシュしておいて、-load-plugin-executableで利用することで、毎回swift-syntaxやmacroをビルドする必要がなくなる(アーキテクチャの問題はあるが)

ScipioはSwift PackageからXCFrameworkを生成するためのビルドツールだが、現在、macroを使ったターゲットからフレームワークを作ることができないという問題がある。理論的には今回紹介した方法で対応できそう。(先にmacroターゲットをexecutableとしてビルドして、framework側からビルドフラグを立てる)

いかがでしたか

業務上で調査して面白かったのでちょっと記事を書いてみた。ここ数年全く技術記事を書いていないという危機感があり今年はこれぐらいの技術記事を定期的に書いていきたいと思っていたのでちょうど良い。 気合入れると続かないので30分以内でガッと書けるやつを目指していきたい。

純粋な技術記事としては8年ぶりの投稿かも・・・・・・

ポケモンガチ対戦用パーティー管理アプリ『PokeBox』をリリースしました

まもなく『ポケットモンスター スカーレット・バイオレット』が発売しますが、先日、iPhone/iPad/Mac向けのポケモンパーティー構築管理アプリ、『PokeBox』をリリースしました。

PokeBox - 構築管理ソード・シールド

PokeBox - 構築管理ソード・シールド

  • gigi-net.net
  • ユーティリティ
  • 無料

ポケモン剣盾』以来、ランクマッチなど、いわゆるポケモンガチ対戦にハマり、自分の需要から開発したアプリです。

『剣盾』環境では、100体近いポケモンを育成し、努力値振りや構築意図などを、秘伝のスプレッドシートで管理していましたが、あまりにも煩雑なので、ちゃんと管理できるアプリを作ろうと思いつつ、この度ようやっと開発できました。

ひでんのExcel

今のところ『剣盾』での利用を想定しています。今更『剣盾』を遊んでいる人は面構えが違う廃人ばかりだと思いますが『SV』のリリース後も末永く使っていただけると幸いです。(SVでシステムが大きく変わらないことを願うばかり!)

ご意見、ご感想、機能要望はTwitterにてお待ちしてます。

特に耐久調整などあまり考えて構築できてないので、本当のガチ勢の方のユースケースなどぜひ聞きたいです。

主な機能

ポケモンエディタ

  • ゲームの表示に近いレーダーチャート
  • わざ、とくせいを管理、フレーバーテキストの閲覧
  • きそポイント(努力値)振り、せいかく補正エディタ
  • ASぶっぱ、CSぶっぱなどよく使う調整の入力支援
  • メモ

パーティーエディタ

  • 作成したポケモンをパーティーに登録
  • もちもの管理
  • 1匹ごとに個別メモが可能

OS標準の機能

  • iPad対応(要iPadOS 16以上)
  • Mac対応(要macOS Ventura以上とM1 Mac)
  • 日本語、英語サポート
  • ダークモードサポート
  • Dynamic Typeサポート
  • iCloudサポート
    • お手持ちの全てのiPhone, iPad, Macでデータを同期できます

今後の機能追加予定

技術的な話

このプロジェクト自体、技術的なキャッチアップの目的も大きかったため、語りたいこともたくさんあるのですが、この記事はリリース告知に留め、技術的な注目トピックをざっくりと紹介。

詳しい話はまた他所の勉強会やカンファレンスでできればなと思っています。

ポケモンデータの構造化

この手のアプリで一番頭を悩ますのが、ゲーム内のデータをどのように構造化するかという点です。

既存の構造化されたポケモンデータとして、PokéAPIというデータソースがあります。これは、ポケモンの様々な情報を取得できるWebAPIです。GraphQLなどにも対応しています。

このPokéAPIオープンソースで開発されていて、実はデータソースもGitHubにあります。

このリポジトリには、大量のCSVと、それらをSQLiteにdumpするPythonスクリプトがあるのですが、長らくメンテされていなかったため、いろいろPRを投げて修正しました。 SQLAlchemyのバージョンを上げたりDocker上でのdumpをGitHub Action対応したりなどです。

ここまで来ると、あとは全データをRDBとして扱えます。

PokeBoxでは、ここから生成したSQLiteをアプリ内に保持し、SQLを投げています。アプリ容量が大きめなのはそのためです。

クソデカSQL。開発にはJetBrains DataGripが役立ちました。

『SV』発売後に、この情報ソースが迅速に新仕様に対応できるかは懸念があります。この辺を自給自足できれば良いのですが、現状難しいため、発売後は別のソースも検討しないとならないかもしれません。

また、わざの習得テーブルなど、一部怪しいデータも散見されました。どうぐの細かなパラメータなども、6世代付近の情報で止まっていそうです。

SwiftUI on iOS 16

今回の裏テーマとして「SwiftUIを使って、Appleの推奨するモダンアプリケーションを正しく作る」というところを目指しました。 全てがSwiftUIでできていますし、UIは標準のメールやメモアプリを参考にしています。

業務ではあまりアプリケーションレイヤーを触らないため、長年、SwiftUIについてしっかりキャッチアップできていないという課題感を感じていました。(エアプ)

今回、1本ちゃんと作って、さまざまなハマりを経験したことで、かなり知識のアップデートができたと考えています。 この手のアプリの中では、かなり使い勝手の良いものが作れたのではと。

PokeBoxは、7月頃に開発を始めたため、WWDC 2022で登場した、iOS 16/iPad OS 16の新機能をふんだんに使っています。

What's new in SwiftUI - WWDC22 - Videos - Apple Developer

Layout

エディタ画面のレーダーチャートの実現のため、新しいCompositional Layoutの仕組みを使っています。

Compose custom layouts with SwiftUI - WWDC22 - Videos - Apple Developer

Pathレンダリングしたグラフに、ZStack で文字を重ね、Layout でグラフ上に配置しています。 おかげで任意のサイズで描画できるレーダーチャートが実装できました。

当初はSwift Chartsの採用も考えましたが、試してみたところ、時系列グラフを前提として設計されていて、レーダーチャートの描画には向かなかったので早々に諦めました。

ViewThatFits

ViewThatFitsiOS 16から登場した新しいViewで、複数の候補のうち、収まりが良いものを自動的に採用してくれる仕組みです。PokeBoxでは、わざの表示に採用しています。

文字数が少ない場合はグリッド表示、多い場合はリスト表示に自動的に切り替わります。これによりiPadで表示しても収まりが良いものとなりました。

Grid/GridRow

Grid は、表組みのようなものを作る際に、最長の要素の幅に合わせて、自動的にレイアウトしてくれる仕組みです。

PokeBoxでは努力値エディタなどに利用しています。各パラメータについて、ラベルやスライダーの開始位置が揃っていることがわかるかと思います。

NavigationSplitView は新しいNavigationStackの一種で、これ1つで全プラットフォームに適したナビゲーションを構築できます。

iPadではSplitViewとなり、iPhoneやwatchOSでは、自動的に NavigationStack のような挙動をします。

これのおかげでワンコードでサイドバー付きのiPad対応が実現しています。

素晴らしい仕組みのように見えて、iPhoneで正しく動かすには、バグが多く悩まされました・・・・・・。β版どころか、16.0になってもバグってるので注意です。

navigationDestination modifierを使うことで、NavigationLink の遷移先を従来より管理しやすくなりました。

PokeBoxではほとんどの画面遷移に用いています。

The SwiftUI cookbook for navigation - WWDC22 - Videos - Apple Developer

Variants Preview

Xcode 14から、Xcode PreviewをダークモードやDynamic Typeを適応した状態でまとめて閲覧できるようになりました。(なぜ今までなかった)

PokeBoxでは、随所でPreviewを活用してUIを作成していました。またタイプ表示といった、小さなコンポーネントもSwiftUI化できました。

こういったものを作るには非常に向いていますね。

最新の開発機能の活用

iCloudサポート

複数のiOS端末を日常から使っているため、個人的な要求として、デバイス間のデータの同期は外せない仕様でした。

今回はシンプルにデータストレージにはCoreDataを採用。CoreDataは NSPersistentCloudKitContainer を使うだけで、簡単にマルチデバイス対応することができました。

Using Core Data With CloudKit - WWDC19 - Videos - Apple Developer

CoreDataやNSManagedObjectAPIは、今の時代には辛かったので、なんとかして欲しいところ・・・・・・。

ローカライズ

i18nも対応しています。実は開発言語は英語で、あとから日本語ローカライズを追加しています。

先ほど紹介したデータベースでは、ポケモンの名前やフレーバーテキストは言語毎に格納されているため、発行するSQLで言語IDを変更することで、簡単にローカライズが実現できました。

英語設定だとこの通り。

StoreKit 2

有料機能のアンロックにはStoreKit 2を利用しています。StoreKit 1は業務で利用していたのですが、2は今回初。あまりの簡単さに涙が止まらなかった・・・・・・。

Meet StoreKit 2 - WWDC21 - Videos - Apple Developer

StoreKit ConfigurationやStoreKit Testingは今回利用していませんが、そのうち試してみたい。

Xcode Cloud

先日からXcode Cloudが利用可能になったので、ユニットテストの実行や、TestFlightの配信に取り込んでみました。

今回のような、プライベートリポジトリでの小規模個人開発にはまさにこれしかないソリューションに感じました。この規模のアプリであれば、pushごとに毎回ユニットテストを回しても無料枠で使えています。

ダンプしたSQLiteの置き場所にGit LFSが必要になり、GitHubへの課金が発生したのはまた別の話。

サブミット自動化

一方で、ストア提出に関してはまだまだfastlaneなど、旧来の手法に分があるように感じました。

metadataの提出が現状、Xcode Cloudだけではできないので、この辺を解決する需要はありそう。

今回はお家芸のdeliverを用いたサブミット自動化*1のほか、snapshotを使ったスクリーンショット撮影自動化にも挑戦しています。

iPadOS/iOS両対応、日英二カ国語対応程度の規模でも、40枚(4枚 * 5機種 * 2カ国語)の撮影が要求されるので、自動化しないとやってられません。

この辺の基盤作りをしっかりしたので、今後の柔軟なバージョンアップにも耐えうると思います。

ちなみに、このアプリ開発のために、iPhone 14 Proサポートを取り込むコミッター業もしました。個人アプリ開発のためにOSSの開発も進むのは良い相乗効果だなと思います。

ぜひダウンロードしてね

手短に書こうと思いつつ、長くなりましたが、良い感じのアプリが作れて大変勉強になりました。 普段UI層をあまり書かないアプリエンジニアなので、「UI作れる人すげーな」という気分。

ポケモンプレイヤーはもちろん、そうじゃない人が触っても楽しいアプリになったと思います。

どうぞご利用ください。

PokeBox - 構築管理ソード・シールド

PokeBox - 構築管理ソード・シールド

  • gigi-net.net
  • ユーティリティ
  • 無料

*1:筆者はfastlaneコミッターです

クックパッド株式会社を退職して、LINE株式会社に入社しました

こんにちは、@giginetです。 先日、新卒以来7年3ヶ月勤続したクックパッド株式会社を退職しました。

このエントリは5年半振りの当ブログの更新になるのですが、いわゆる退職エントリというやつです🇨🇳👨‍🍳🍗

でっ誰?

クックパッドでやったこと

クックパッドでは、新卒入社後、最初1年はプレミアムサービスのグロースを行う事業を経験した後、その後丸6年は、モバイル基盤部という、全社のモバイルアプリの開発環境改善や、組織開発を行うチームで、全社横断的なiOSアプリの基盤開発をしてきました。

例えば、認証、決済、ロギング、A/Bテスト基盤といった、アプリ開発の基幹となるOSS・社内ライブラリ開発のほか、継続的デリバリー実現のためのCIやテスト、リリースフローの構築といった役割です。 その他、社内iOSエンジニアのメンタリングや、面接や書類選考など、モバイルエンジニアの採用にも携わっていました。

長いこといたので、全て書くとキリがないのですが、大きな仕事としては以下のようなものが挙げられます。

  • レシピ検索の『クックパッド』アプリの開発環境改善とビルド高速化
    • 6年間継続してメンテしていた
    • 後半はモジュール分離やビルド環境改善にフォーカスした、通称「霞が関」プロジェクトを主導(後述)
  • 記述しやすい行動ログ基盤の導入と汎化
  • クックパッドマート』や『cookpadLive』といった、新規サービスの開発支援や、社内ライブラリ、開発基盤の整備
  • 全アプリのサブミット自動化と、毎週のアプリリリースフロー自動化
  • オンプレのmacOS CIクラスタをフルPaaS(Bitrise)化
  • 登壇、執筆、面接官、メンタリングなど組織開発と採用

やりきった!もうゴールしてもいいよね

アーキテクチャとモジュール分離

霞が関」プロジェクト。社内の政治的問題も解決していくぞ、とアイロニカルな意図を込めた名称でした

特にその中でも、後半の2~3年間は、事業の柱となっているレシピアプリである、クックパッドアプリの大規模なリアーキテクチャと、ビルド時間高速化を主導しました。

2019年当初のクックパッドアプリは、旧来から続く負債や、依然まだ25%残るObjective-C、計24万行に達するコードベースから来るビルド時間が事業上の大きな問題になっていました。当時の様子は、以下の講演記事をご覧ください。

そこで様々な問題を改善するため、「霞が関プロジェクト*1を立ち上げ、ObjCの撲滅や、クリーンアーキテクチャの整備、ビルド待ち時間の削減に着手しました。

ビルド時間の改善のアプローチとして、Appleの主導するSwiftコンパイラの性能が支配的な要因であるフルビルドを効率化するのは早々に諦め、大きなアプリを複数のモジュールに分割し、Sandboxアプリと呼ばれるミニアプリのみを使って開発可能にするマルチモジュール化を推進しました。

すなわち、開発時に一部だけ簡単にビルドして起動できるようにするということです。

中層にあるFeature Moduleの1つだけしかビルドしなきゃ早くなるんじゃね?という考えで生み出されたアーキテクチャ。通称「親の顔より見た図」。

詳しいアーキテクチャの説明は、過去の講演資料や、ブログ記事に譲りますが、 今では*2、アプリ全体が30個程度のモジュールに分かれ、ほとんどの機能開発がミニアプリのみを使って開発できるようになりました 🎉

アプリ全体のビルドには、一部のデザインを調整した程度の修正で、差分ビルドに十数秒を要していましたが、ミニアプリを使った開発では、ほんの3秒程度で起動できるようになります。

Sandboxアプリの実行の様子。機能毎にアプリが分かれているため、ビルドが爆速になり、画面の頭出しも容易になった

また、モジュール化により、一部の画面だけSwiftUIを取り入れたり、Xcode Previewを使うなど、Appleが提唱する標準のワークフローに乗ることができるようになりましたし、モジュール間の依存関係が整理され、機能間を疎結合に保ち、開発することができるようになりました。

この取り組みは、iOS開発界隈にも影響を与えられたと思います。近年のカンファレンスでは、多くの組織によるアプリのアーキテクチャや、マルチモジュール化の話題が多く取り沙汰されるようになり、クックパッドの取り組みを先進的だと評価してもらえたり、メルカリさんのイベントなど、様々な場所で発信の機会をいただきました。ありがたいことです。 前掲のモジュール分離図は、界隈では「親の顔より見た図」と親しまれるようになり、自身の仕事によりプレゼンスを確立できたのが何より嬉しかった!もっと親の顔見て。

「モバイルファースト」の達成

僕が新卒で入社した2015年は、まだまだモバイルアプリの黎明期。 当時から社内では「時代はモバイルファーストだ!」と言われてはいたけれど、アプリ版の開発は注力事業ではなかったし、まだまだWebフロントの開発が主流でした。

そこから7年、業界の様子はすっかりと様変わりしました。 今やクックパッドではほとんどの新機能がモバイルアプリに優先的に投入されています。 開発のスケジュールはアプリ版のリリーススケジュールに沿って組まれ、バックエンドの開発課題も、BFF*3化やOpenAPIの導入など、モバイル開発を意識したものに変化しました。

退職時に、「そういえば昔はモバイルファーストとか言ってたなあ」と思い出したけど、いつのまにか当たり前になり、言われることはなくなったとしみじみしております。

自分だけの力と言うつもりはなく、メンバーの協力や、業界の変化といった要因も大きいけれど、ここに至るまでにわりと寄与できたのではないでしょうか。

なんでやめたの?

やりきったから!」というのは大きかったです。 仕事がなくなったかと言えば、他にもSwift ConcurrencyやSwiftUIなどの新しい開発手法の推進、既存ツールの更なる汎化や、通信のGraphQL化、その他無数に積み残した細かなissueの改善など、まだまだやらないとならない課題は無数に残っています。

とはいえ、個人的にはすでに大きい仕事をやりきった気持ちがしており、ここ1年ほどは正直結構ダレていたという感覚は否めません。

働き方の変化もありました。コロナ禍はもちろん、昨年、職場が横浜に移転したことで、チームメンバーが集まりにくくなったり、移転や経営の注力事項の変化などによる社内メンバーの入れ替わりで、空気感の変化も感じました。

長く所属した組織なので、離れがたい気持ちはあるけれど、変化の激しいこの業界、定年まであと30年居続けるということはありえないだろうし、まあここらが潮時なのかなと。

これから何をやるの?

LINE株式会社のディベロッパーエクスペリエンス(DX)開発室でLINEアプリの開発基盤の改善をしていきます。 ObjCの撲滅など、クックパッドではすでに達成できたことをもう一度やっていく必要がある部分もありますが、前職では取り組みきれなかった、ビルドパイプラインの改善や、リモートキャッシュ化など、世界有数の大きなアプリ向けのスケールの大きい問題をなんとかしていければなと思っています。

前職と比べ、開発人員もコードベースの規模も数倍に。 今までは全ての開発者の顔が見えていたけれど、今度は韓国のチームを含め、世界中で1つのアプリを開発しています。 新しい環境でもやっていけるか、それともあまりのデカさに尻尾を巻いて逃げ出すことになるのか、今から楽しみにしています。

新しい職場の感想

まだ入社して1週間ほどですが、早くも小さなことから改善に着手することができて、これからの仕事にわくわくしています。

新しい職場で何より最高なのが裁量労働制になったことです。これは本当に良い。マジで良い。僕の中では、労働の仕方が大きく変わり、パラダイムシフトとも言える変化でした。本当に帰りたいときに帰って良いのか?って心配になって未だに慣れない。

今までは、1日8時間の刑期を全うするために、どうやって乗り越えるかと、グダグダ働くことに無駄なリソースを割いていたけれど、時間を気にしなくて良くなったおかげで、とても集中して働くことができています。やる気が出ない日はさっさと上がってしまえばいいわけだし。

今までのフルフレックス制では、月にあと何時間働かないとと意識するのが何よりも辛かった。 入社前は、裁量労働でちゃんと成果を出せるのか?と懐疑的だったけど、今のところは自分のペースで働けそうで、とても良い変化となっています。

反面、細かなツールの使い勝手や、業務フローに慣れなかったり、前職の方がより洗練されていたなと感じることはもちろんあります。 大きな組織で、多数の人を巻き込んで業務環境を改善していく難しさはとても理解できるので、当事者意識を持っていきたい気持ちはある。

また、今までは裁量があり、わりと自由に業務上の意思決定をできていたけど、新しい職場では、どこに話を通せば良いかわからなかったり、業務把握のためにまだまだ難しいという、転職後特有のもどかしさを早くも感じています。 そもそも、新卒以来初めての転職なので、これはどこに行っても起きていそうな問題だけど・・・・・・。

転職先で前職の不満を言い続けているのも、逆に「前職ではこうだったのに」とか言い続けてるのも、両方ともダサいなあという気持ちがあるので、「まあ両方いいところも悪いところもあるよね」以上では無いかなと思いますし、どちらの会社も「最高!!!」と言えるようになっていきたい。

おわりに

以上、初めての転職エントリでした。

僕が今までやってきたことは、社内では退職時にアウトプットしてきたのですが、社外の人向けにまとめて書いたことがなかったので、この機会にブログにまとめられて良かったです。 1エントリでは収まらないほど、やってきたこと、語りたいことがあるけれど、そろそろ筆を置こうと思います。

クックパッドには7年もいて、愛着もあるので、今後とも影ながら応援していきたいと思っています。

今後の活躍にご期待ください。やっていくぞ!!!

*1:クックパッドでは、プロジェクト名に都内の地名を付けるのが流行っていた

*2:退職時

*3:Backend for Frontend