この記事の要点
- 開発者向けのプライバシー重視アプリ解析サービス TelemetryDeck が、バックエンドを Swift と Vapor で構築してきた経験をまとめた事例です。匿名化された解析データを扱い、毎月1,600万人以上のデータを処理しています。
- iOS のフロントエンドに加え、サーバーでも Swift を選んだことで、コンパイル時に多くのエラーを検出できる堅牢で高性能なサービスを、Python・Node・Ruby と変わらない手軽さで実現できたと述べられています。
Codableによる型安全な JSON 処理、クライアントとサーバーでの構造体の共有、Xcode を使った快適な開発体験、そして Vapor のキューやマイグレーションといった成熟した機能が、開発の生産性と信頼性を支えています。- 本番サービスの運用を通じて得られた、API のバージョニングやキャッシュ、エラー監視などの実践的な教訓も共有されています。
Swift を選んだ理由
TelemetryDeck は、Swift 製の Web フレームワークである Vapor の上に構築されています。アーキテクチャは、Things Cloud のような他の Vapor 製プロジェクトと同様に、Kubernetes 上のコンテナで動作します。メタデータは Postgres に、解析データは Apache Druid に保存し、これらのサービスへは Swift 製のコネクタでアクセスしています。コネクタの一部は Swift コミュニティ製で、一部は自分たちで書いてオープンソースとして公開しているものです。
当初は単に「Swift が好きで、得意だったから」という理由で、ホビープロジェクトとしてサーバーサイド Swift を試し始めました。結果として、この判断は、高性能で安定し、素早く開発・改善できる無駄のないアーキテクチャにつながったといいます。
特にマルチスレッド処理での性能は際立っており、Python の Global Interpreter Lock(GIL)のような並列性の制約が Swift にはないため、他のアーキテクチャでは破綻しかねない規模のトラフィックを少ないリソースで処理できています。この効率は、インフラコストの低減とユーザー体験の向上に直結していると述べられています。
開発を支える Swift の特徴
記事では、実際の開発で効果が大きかった Swift の特徴がコード例とともに紹介されています。
-
Codableによる型安全な JSON 処理。 API 主体のアプリケーションでは、JSON のエンコード・デコードに膨大な時間を費やします。Codableは、従来はエラーの温床だったボイラープレートを、型安全で素直な処理に変えてくれます。不正なデータを含むリクエストは、手動の検証なしに型システムが即座に弾くため、これは利便性であると同時に、まるごと一群の脆弱性を防ぐセキュリティ機能でもあります。struct Notebook: Codable, Content { let appID: UUID var snapshots: [NotebookSnapshot] let createdAt: Date let title: String }このわずかな記述だけで、パース・検証・型安全性が得られ、型や追加プロパティ、JSON としての妥当性を自分でチェックする必要がなくなります。
-
Data Transfer Object(DTO)はコントローラの近くに置く。 以前は、サーバーとクライアントで同じ構造体を共有するために、専用パッケージ「SwiftDTOs」を両者で共有していました。しかし、API のバージョンごとに入出力が微妙に異なるようになると、あるバージョン向けに構造体を変更すると別のバージョンが壊れる、という問題に直面しました。そこで最新の API バージョンではこの方式をやめ、DTO を各コントローラ内のインラインな構造体として定義するようにしています。
extension V3QueryController { struct QueryRequest: Codable { let query: QueryDefinition let timeRange: TimeRange } struct QueryResponse: Codable { let results: [QueryResult] let metadata: ResponseMetadata } }DTO をコントローラの近くに置くことで、シンプルで保守しやすく、変更も容易になったといいます。
-
Xcode を使った快適な開発体験。 Vapor プロジェクトの実体は、いくつかの依存関係を持つただの Swift パッケージです。Xcode(あるいは VS Code、Cursor、LSP 対応エディタ)で開いてテストを実行し、ブレークポイントを置いてスタックを追える、完全なデバッグ環境が得られます。開発時は、PostgreSQL をローカルで動かすか、Vapor のデータベース層である Fluent にローカルの SQLite ファイルを使わせることもでき、コンテナを立ち上げなくても済みます。フロントエンドと同じ慣れたツールで開発できるため、新しい開発者のオンボーディングも素早く行えます。
-
Vapor の組み込み機能の活用。 キューとジョブ、マイグレーション、ミドルウェアなど、よくあるパターンに対する成熟した解決策が Vapor に揃っています。TelemetryDeck では生の SQL ではなく Fluent をほぼ全面的に使い、Vapor のキューシステムでデータ処理から課金処理までをこなしています。
エコシステムも活用しており、Single Sign-On 向けの Imperial や、標準準拠の暗号処理を提供する Swift Crypto などのパッケージを利用しています。足りないものがあれば、StripeKit への機能追加や、独自 SDK である BrevoKit の公開といった形で、エコシステムに還元しているとのことです。
本番運用から得られた教訓
本番サービスの構築を通じて得られた、チュートリアルでは学べない実践的な教訓が共有されています。
- Swift パッケージのシステムを使う。 パッケージはコードを構造化し分離する優れた手段です。サービス自体がパッケージなので、意味のある単位でさらに細分化するのも自然です。
- Vapor サービスがボトルネックになることはほぼない。 Web サービスの遅延の多くは、データベース・ストレージ・トラフィック負荷の組み合わせから生じます。データの保存・アクセス方法は、経験を積むにつれて頻繁に作り変えることになります。
- API の URL は初日からバージョニングする。 既存クライアントを壊さずに API を進化させる必要が出たとき、自分自身に感謝することになります。
- キャッシュには必ず有効期限を設定する。 「決して大きくならない」と思っていた Redis キャッシュは、必ず肥大化します。キャッシュするすべてのものに妥当な TTL を設定すべきです。
- エラーと性能を監視する。 iPhone アプリと違い、サーバーではクラッシュログを自分で集める必要があります。これを始める前は顧客の方が先に問題に気づいてしまっていました。現在は Swift Distributed Tracing と独自の解析ベースのミドルウェアを組み合わせ、サービスの不調を顧客が気づく前に修正できるようにしています。
TelemetryDeck は、Swift がアプリだけでなく、スケーラブルで高性能なバックエンドサービスを構築するうえでも正当な選択肢であることを示しています。型安全性は動的型付け言語が追加コードで防ぐ必要のあるバグをまるごと未然に防ぎ、開発速度と性能の両面で恩恵が得られたと総括されています。サーバーサイドのプロジェクトで Swift を検討している人に向けて、安全・高速・表現力豊かというコードの約束を、iPhone 上でもデータセンターの中でも果たしてくれる、と勧める内容です。