Timee Product Team Blog

タイミー開発者ブログ

【iOSDC Japan 2025レポート】タイミーエンジニアが注目した最新技術とリアルな開発事例

こんにちは、iOSエンジニアの大塚、山崎、早川(@hykwtmyk)、前田(@naoya_maeda) です。

2025年9月19-21日に有明セントラルタワーホール&カンファレンスで開催されたiOSDC Japan 2025に、タイミーもゴールドスポンサーとして協賛させていただきました。 イベントは以下のように、3日間連続で行われました。

9月19日(木):day0(前夜祭)

9月20日(金):day1(本編1日目)

9月21日(土):day2(本編2日目)

私たちもイベントに参加したので、メンバーそれぞれが気になったセッションや感想をご紹介します。

大塚 編

先日、iOSDC Japan 2025に参加しました。今年は会場が例年とは異なり、カンファレンス全体の雰囲気にいつもと違った新鮮な印象を受けました。私は毎年iOSDCに参加していますが、日々の業務や自己学習だけでは触れる機会の少ない、高度でニッチな領域の知識を集中的に得られる点が、本カンファレンスの最大の魅力だと感じています。本レポートでは、その中でも特に印象に残った「金融サービスの成長を支える "本人確認フロー" の改善と取り巻く環境の変化」のセッションについてご報告いたします。

概要

セッションは、1. 本人確認フローの改善と2. 法令改正など取り巻く環境の変化についての発表でした。

1. 本人確認フローの改善

前半は、JPKI方式を用いた本人確認の実装戦略についての解説でした。リードタイムを短縮するため、マイナンバーカードの読み取りおよび電子証明書の検証といった機能は、外部ベンダーが提供する SDK を用いて実装しているそうです。一方で、ユーザーが直接触れるUI部分はあえて自社で開発するという戦略を採っています。UIを自社で開発することで、離脱率を改善するための様々な実験的な施策をスピーディーに導入し、その最適化のメリットを享受されているそうです。

2. 法令改正など取り巻く環境の変化

後半は、金融サービスを取り巻く犯収法などの法令改正がいかにアプリ開発に影響するかについてです。特にJPKIの署名用電子証明書を用いる方式やカード代替電磁的記録を用いる方式など、外部環境の変化にエンジニアがどう対応すべきかに焦点を当て解説されていました。

感想

私が所属するチームで担当している本人確認フローに関する発表だったため、特に強い関心を持って拝見しました。他社ではどのようにJPKI方式を実装し、離脱率の改善という難しい課題に対し、どのような観点で技術やプロダクト設計の選択を行っているのかを具体的に知ることができ、大変勉強になりました。

山崎 編

iOSDCは今回初めて参加させていただきました!

初参加だからこそ感じた現地の熱気やセッションの感想などをレポートします。ちなみに、私はday0とday2の2日間参加しました。

day0:カンファレンスの熱気に触れる

day0ではまず、プレオープニングセッションに参加し、iOSDCの歴史やコミュニティの成り立ちについて知ることができました。多くの開発者の情熱によってこの素晴らしい場が作られていることを知り、参加できることへの感謝の気持ちで胸がいっぱいになりました。

その後は、弊社の岐部さん(@beryu)の発表を応援しに行ったり、興味のあるセッションをいくつか拝見しました。どれもレベルが高く、知的好奇心を強く刺激される内容ばかりでした。

day2:ブースでの交流

day2では、弊社のブースに立ち、たくさんの参加者の方々とコミュニケーションを取らせていただきました。

私たちのブースでは、「最近うまくいったこと」をテーマに付箋を書いてもらう、という企画を実施していました。これをきっかけに会話が弾み、「最近、SwiftUI化がうまくいったんです」「AIをこう活用して業務改善しました」といった具体的なお話をたくさん伺うことができました。特にAI活用のトピックは多くの方の関心事のようで、他社さんのユニークな取り組みを聞けたのは大きな収穫でした。

心に残ったセッション

業務で直接関わる機会の少ない領域でのセッションを機会が多かったのですが、どれも新鮮で非常に面白かったです。

  • 手話ジェスチャーの検知と翻訳~ハンドトラッキングの可能性と限界~ fortee.jp

  • Apple Vision Proでの立体動画アプリの実装と40の工夫 fortee.jp

  • プログラマのための作曲入門 fortee.jp

  • 「iPhoneのマイナンバーカード」のすべて fortee.jp

特に、Apple Vision Pro関連のセッションは、従来のアプリ開発とは異なり、3D空間上でUIやUXをいかに自然に見せるかという点に多くの工夫が凝らされており、大変興味深かったです。オブジェクトを空間に違和感なく配置することの難しさを改めて感じました。

マイナンバーカードの話は、実際にどのようなAPIが使われているのかという技術的な解説が非常にためになりました。アプリ内、対面、ブラウザの3種類のVerifier APIの具体的な使い方やユースケース、さらにはmdocのデータ構造や日本のために作られたAPIの紹介など、普段は知ることのできない実装の詳細に触れることができ、とても貴重な体験でした。

SwiftコードバトルとLT大会の熱気

Swiftコードバトルは、制限時間内に要件を満たすプログラムを、Swiftでいかに短く書くかという競技で、緊張感のある中、参加者の方々のコーディングスピードと発想力に圧倒されました。

LT大会は、参加者がサイリウムを振って会場全体が一体となる、ライブのような賑やかな雰囲気でした!特に印象的だったのは、課金周りのLTが続いた時間帯です。各社それぞれの知見や工夫が凝縮されており、とても勉強になりました。

初めてのiOSDCは、技術的な学びはもちろん、何よりもコミュニティの温かさと熱量を肌で感じられる最高の体験でした。ブースでの交流、刺激的なセッション、そしてユニークな企画までとても熱狂感のある素晴らしいイベントでした!

早川 編

タイミーでiOSエンジニアをしている早川です。 一昨年ぶりにiOSDC Japan 2025にオフライン参加してきました!今年から会場が変わり、またいつもと違う雰囲気でしたね(個人的には、自宅から近くなったので嬉しいです)。

さて、いくつかのセッションを聴講した中で、特に学びが多かったのが、デスクスさんが発表された「5000万ダウンロードを超える漫画サービスを支えるログ基盤の設計開発の全て」です。

speakerdeck.com

大規模サービスにおけるログ基盤という、普段なかなか知ることのできない領域について、詳細なコードベースでの解説や実践的な知見が共有されており、多くの学びがありました。本記事では、発表内容の要点と特に印象に残った点についてまとめていきます。

発表の要点

1. 新ログ基盤「Tracker」の設計思想と特徴

パフォーマンスと柔軟性の向上を目的とし、モダンな技術スタックを全面的に採用。Swift 6のSendableに準拠した設計をベースに、並行処理による高いパフォーマンス、gzip/deflateによるデータ圧縮、そしてモバイル環境の不安定なネットワークを考慮したExponential Backoffによる堅牢なリトライ戦略が主な特徴として挙げられていました。

2. Clean Architectureによる責務の分離

アーキテクチャにはClean Architectureを採用。Entity、Use Case、Data Layer、Public Interfaceを明確に分離することで、各コンポーネントが独立して機能し、テスト容易性や変更容易性が格段に向上したとのことでした。これにより、全体で80%以上という高いテストカバレッジも実現していました。

3. Firebase Remote Configを活用した安全な移行戦略

Firebase Remote Configをフラグとして利用し、旧基盤と新基盤を並行稼働させ、いつでも切り戻しが可能な状態で段階的に移行を進めるという、非常に現実的でリスク管理に優れたアプローチが紹介されました。

特に印象に残った点・感想

この発表では、ログ基盤というテーマに留まらず、大規模なモバイルアプリ開発全般に役立つ知見が随所に見られました。

ログの送信自体はユーザーの目に見えない部分ですが、メインスレッドをブロックしない、メモリを圧迫しないといったユーザーファーストな視点と、テスト容易性を高めるアーキテクチャ設計や高いテストカバレッジといった開発者としてのこだわりが見事に両立されており、まさにユーザーと開発者の双方にとって「Win-Win」な内容だと感じました。

また、Firebase Remote Configの活用法も非常に印象的でした。特に「将来的に全体公開する前提のConfigは、デフォルト値をtrueにしておくことで、移行完了後にConfigを削除できる」という知見は、私自身も過去に逆の設計で失敗した経験があるからこそ、大変共感しました。

このように、自身の業務でもぜひ参考にさせていただきたい学びの多い、素晴らしい発表でした。

前田 編

僕は今年が二回目のiOSDCへの参加でした。今回も幅広いジャンルで興味深いトークがたくさんありました。その中で、僕が最も面白いと感じたセッションは、かっくんさんの「独自UIで実現する外部ストレージデバイスの読み書き」でした。

fortee.jp

偶然なのですが、ちょうどこのトークの前日に、僕が個人的に調査を始めたトピックでした。

僕にとってはすごくホットなトピックだったこと、デモを交えた聴講者を惹きつけるトークが魅力的に感じたのでこちらのトークを選びました。

このトークは、iPhoneで撮影した写真や・ビデオデータを外部ストレージに直接保存する方法を紹介する内容です。まだ情報自体が少ないこともあり、Appleのエヴァンジェリストの方と一緒に調査を進めて、実装を実現したエピソードを交えたトークになります。

iPhoneのカメラで撮影した写真や・ビデオデータを保存する場所や方法は、大きく2パターンが用意されています。

一つ目の方法は、iPhoneのストレージに保存する方法ですね。こちらの方法は最もよく知られており、サンプルコードも豊富で難易度はそこまで高くありません。PhotoKitフレームワークを使用することで、10行程度のコードで実現することができます。

zenn.dev

二つ目の方法は、iPhoneに接続している外部ストレージに保存する方法です。こちらの方法は、さらに2パターンに分かれています。 一つ目の方法は、UIDocumentPickerViewController または、.fileExporter モディファイアを使用する方法です。これらのAPIを使用することで、データを外部ストレージに保存することができます。しかし、これらの方法では、ユーザーにデータの保存先を選んでもらう必要があります。ユーザーは、データの保存先を選択することができるメリットがある一方、ユーザーの操作数を増やしてしまうことになります。 そこで今回のトークで登場したAPIが、AVExternalStorageDevice です。iOS 17から使用可能な比較的新しいAPIです。このAPIと関連APIを使用することで、iPhoneに接続している外部ストレージに、データを直接保存できます。実装コストも高くなく、数十行程度のコードで本機能を実現できることを知れて、僕にとっては学びが多いトークでした。

本トークでは、実際に会場で撮影した写真を、iPhoneに接続されている外部ストレージに直接保存し、保存したデータ一覧を表示するといったデモもあり、楽しくトークを聴くことができました。

最近では、高ストレージ端末を除いては、ProRes Logデータを撮影する時に外部ストレージとの接続が必須になってきています。今後、外部ストレージ接続が必須になる機能が増えるかもしれない状況になる可能性もあるので、さらに深掘りを進めてみたいと思います。

最後に

この3日間を通して技術的な知見を深めたり、久しい友人に会って話をすることができ、すごく有意義な時間を過ごせました。この場を用意してくださったiOSDCスタッフの方々、参加者のみなさん本当にありがとうございました!

上記で紹介したセッション以外にも非常に興味深いセッションが多くありました。 記事にある内容や、その他の内容についても、もしタイミーのエンジニアと話したいという方がいらっしゃればぜひお気軽にお話ししましょう!

Kaigi on Rails 2025 に参加しました

タイミーの江田、徳富、神山、亀井、桑原、志賀です。 KaigiPass という制度を利用して Kaigi on Rails 2025 に参加してきました。タイミーは昨年に引き続きスポンサーをさせていただき、今年はなんと幸いなことにブースも出させていただきました。今回はそんな Kaigi on Rails 2025 の参加レポートを KaigiPass を利用したメンバーで記述していこうと思います。

2分台で1500 examples 完走!爆速 CI を支える環境構築術

Hiroshi Tokudomi

https://kaigionrails.org/2025/talks/falcon8823/#day1

「2分台で1500 examples 完走!爆速 CI を支える環境構築術」というタイトル通り、CI をどのように高速化していくかについての発表でした。

弊社でも現在 self-host runner を使って GitHub Actions 上で CI を回しており、2 万 2 千件のテストを平均 9〜10 分程度で実行しています。CI は短ければ短いほどいいものなので、このセッションタイトルを見たときに「これは絶対に見に行こう」と思ったのですが、まさに期待通り参考になる内容でした。

テストを並列に分割して実行する方法として Knapsack Pro が紹介されており、自分たちが使っている split-test と比較しながら聞くことができました。Knapsack Pro は実行時間の履歴をもとに分割を最適化できるとのことで、今後検討してみたいと思います。

また、EBS の I/O がボトルネックになることで CI が遅くなる話も印象的でした。弊社でも CI 実行が重なると I/O 使用率がギリギリまで上がることがあり、tmpfs を使うことで改善できる可能性があるのでは、とワクワクしながら聞いていました。

ちょうど最近 CI 基盤を self-host runner に移行したばかり(参考)ということもあり、「次はどこをチューニングできるか」と考えていたタイミングでのセッションだったので、個人的にはかなり刺さりました。CI をどう速くするかは日々の開発体験に直結するテーマなので、今回の学びを持ち帰って改善につなげていきたいです。

https://speakerdeck.com/falcon8823/2fen-tai-de1500exampleswan-zou-bao-su-ciwozhi-eruhuan-jing-gou-zhu-shu-kaigi-on-rails-2025

dynamic!

Keisuke Kuwahara

https://kaigionrails.org/2025/talks/moro/#day1

https://speakerdeck.com/moro/dynamic

1日目のキーノート「dynamic!」は、静的なアプローチとは対照的に、最初から完璧なゴールを目指すのではなく、継続的に変化していくプロセスを重視するテーマでした。

セッションでは、開発を細かく進めるための第一歩として、「ハッピーパス」の実装が重要だと強調されていました。ハッピーパスとは、ユーザーが使える「最小限かつ最もシンプルな機能」のことであり、これをまず実装することで、早い段階でフィードバックを得て、改善サイクルを回すことが可能になります。

特に印象的だったのは、開発者だけでなく、チーム全体で変化を起こしていくという考え方です。私自身、複雑な機能を実装する際、最初からすべてを網羅しようと時間をかけた結果、いざデモをしてみると多くのフィードバックをもらった、という経験があります。その時はできるだけ指摘をもらわないように実装しよう、という気持ちになっていましたが、今回の話を聞いて、動くものをいち早くチームメンバーやステークホルダーに確認してもらい、早くフィードバックを得ることの重要性を再認識しました。

またこれまでは、優秀なエンジニアほど、一発で完璧なプロダクトを作るものだ、と漠然と思っていましたが、実際は逆でした。経験豊富なエンジニアほど、最小限の開発から始め、段階的な改善を積み重ねていくのだと気づきました。

アジャイル開発は今のチームでは当たり前になっていますが、「動的に変化し続けること」の重要性を改めて深く感じました。完璧主義にとらわれて最初の実装に時間をかけるのではなく、変化を恐れずに、その時々で最もシンプルな方法を実践していきたいと思います。

「技術負債にならない・間違えない」 権限管理の設計と実装

Akitoshi Shiga

https://kaigionrails.org/2025/talks/naro143/#day2

https://speakerdeck.com/naro143/ji-shu-fu-zhai-ninaranaijian-wei-enai-quan-xian-guan-li-noshe-ji-toshi-zhuang

Webサービスにおいて頻出の課題である権限管理に対して、自社のプロダクトで行った取り組みを発表されていました。

権限管理のありがちなアンチパターンとして、権限の判定が必要な場所で操作者の役割を判定するような実装についてあげられていました。

例: あるControllerのcreateアクション内でif admin?

役割を判定する場合は、判定する箇所が役割ごとに何ができるかを把握する必要があります。

役割ごとの権限は、サービス内容や事業環境の変化が激しい状況においてはすぐに複雑化します。

その上、この実装では権限を変更するたびに、すべての判定箇所に手を加えなければいけません。

その結果としてすぐに保守が困難になります。

そこで、役割=何者であるかではなく権限=何ができるか に依存すること、その上で、権限管理に必要な要素である「対象」「操作」「役割」「条件」に対する記述を分離・明文化した設計を発表されていました。

具体的には、module分けした「対象」ごとに「役割」のクラスを作り、「操作」に紐づいたメソッド内で「条件」を判定する実装を行っていました。

これによって、対象ごとに役割が操作を行うための条件が非常にシンプルになりました。

https://speakerdeck.com/naro143/ji-shu-fu-zhai-ninaranaijian-wei-enai-quan-xian-guan-li-noshe-ji-toshi-zhuang?slide=64

その結果、カスタマーサポートやプロダクトマネージャーがGitHubでコードを読んで理解できるようになり、社内からのエンジニアへの権限に関する問い合わせが0になったそうです。

所感として、操作する対象が増えるたびにすべての役割のクラスを作成する必要があるものの、条件というコアなロジックは一箇所に集中されるので保守しやすそうだと感じました。

また、権限という複雑なビジネスロジックを非エンジニアが理解できるほどシンプルにコードで表現されていることに感銘を受けました。

複雑なビジネスロジックにちゃんと向き合ってシンプルな表現を目指すことの効果と大切さを今一度実感しました。

Railsによる人工的「設計」入門

Yutaka Kamei

https://kaigionrails.org/2025/talks/nay/#day1

亀井です。万葉の大場さんのこちらのセッションが素敵だなと思ったので、このセクションを書かせていただいています。私なりにこの発表を解釈すると、設計がうまくなる方法について深掘りした内容だったのかなと思います。この AI 時代にコーディングを AI に任せることは増えてきた中で、人間が設計をできることの重要性がとても高まっています。そんな中で、どのようにしてもっとうまく設計ができるようになるのか?というのをご自身の偶然の経験から形式知にしてまとめてくださった内容でした。

完成したシステムを思い浮かべてそこから「逆算」して考えていくとよいのではないか?というのが重要そうでした。私の経験でも、ゴールを思い浮かべてそこに至るまでのマイルストーンを描きステップを重ねるというやり方がよいのではないか?ということを思っていたので非常に納得感があります。まさに全体から部分へ、という思考を行うことによってうまく設計ができる、という考え方ですね。たしかに、 Ruby on Rails が MVC をベースにしたフレームワークだからといって、モデル→コントローラー→ビューという順番に書く必要もないですし、むしろその順番で書くと全体が見えない状態で開発をすることになるので、次第につぎはぎだらけのコードが生成されてしまいます。その場しのぎのコードになってしまうと、やはりそれはそれで今後のメンテナンス性に影響してくるわけです。あるべき状態、あるいは本質的なゴールを描いてそこから「逆算」する、という考え方の言語化がとても素敵でした。

また、名付けの重要性について語っておられたのもよかったですね。 Ruby 界隈では「名前重要」というのはよく知られていると思いますが、設計の上でなぜ名付けが重要なのか?ということについての言語化もクリアでわかりやすかったです。たしか、コードのレベルではなく、抽象度の高いレベルで短い名前をつけながら考えを進めて「デザインパーツ」を取捨選択し「仮置き」することが重要というようなこともおっしゃっていたと思います。「仮置き」というワーディングがよいですね。たしかに、「決定」というと後戻りができない感じがしますが、「仮置き」というのは「変更の余地があること」を示唆する感じがして、日本人としてこういう日本語表現を利用できるのはとてもラッキーだなと思います。そういえば、「仮置き」で思い出しましたし、このセッションで参照されたキーノートの dynamic! にもあったように、オプショナリティーについて言及が最近増えましたね。「仮置き」という用語にもオプションというニュアンスを感じます。『Tidy First?』を読んで私なりにオプションについて理解をしているつもりでしたが、こうしていろいろな登壇を聞いて私なりの解釈もそこそこあってそうな予感がしてうれしさを感じています。みんな Kent Beck が好きですよね。私もです。

今改めてServiceクラスについて考える 〜あるRails開発者の10年〜

Yuki Eda (edy)

https://kaigionrails.org/2025/talks/joker1007/#day1

Ruby on Railsでアプリケーション開発に従事しているエンジニアであれば一度は通るであろうServiceクラス。2025年のこのタイミングでjokerさんがこのタイミングで発表を行う理由も気になり視聴しました。

冒頭で歴史的な経緯を含めて日本国内で布教した背景の考察や、『パーフェクトRuby on Rails』にてServiceクラスを題材に執筆された当時の意図、執筆後数年経ってからの[Qiitaでのエントリ](https://qiita.com/joker1007/items/25de535cd8bb2857a685)などに触れられつつ、Serviceクラスに対しては出来る限り使わない方が良いと結論づけられていました。理由は「開発統制の困難さを上回るメリットが得られない」とのこと。

この点、私も思い当たる節はあり、例えばFat Modelを解消する手段としてServiceクラスを選択していた過去があります。適切な命名付けをしたとしても、アプリケーションの成長や数年間の運用の過程で特定のドメインだけの処理で留まらずに肥大化したトランザクションスクリプトになる傾向があると思います。これはjokerさんも言及されていた「基準の作りにくさ」から来る部分や、適切なドメインモデリングを怠った結果の2つが大きな原因だと、発表を聞きながら改めて考えさせられました。

結局のところ、ビジネスにおける関心事を顧客やチームメンバーを交えながらシステム内でうまい具合に表現できるするか、その丁寧な抽象化と具体化の繰り返し作業が大事で、Serviceクラスもそうですし対抗馬として挙げられることの多いFormクラスも含めて、デザイン方法は表現技法の一つに過ぎないということですね。

発表の末尾のスライドの「正解はない、一緒に考え続けましょう」「ソフトウェア設計は継続的な営み」が非常に印象的で心に留めておきたいと思いました。

履歴 on Rails : Bitemporal Data Modelで実現する履歴管理

Daichi Kamiyama - dak2

https://kaigionrails.org/2025/talks/hypermkt/#day2

https://speakerdeck.com/hypermkt/history-on-rails-with-bitemporal-data-model

直近で履歴を残すかどうかの設計に頭を悩ませたことがあり、Bitemporal Data Model での履歴管理の良し悪しが気になったので、拝見させてもらいました。

履歴テーブルのパターンとして参考になるのは、一休さんの https://user-first.ikyu.co.jp/entry/history-table このスライドが非常に参考になると思っています。普通に“履歴”という概念を表現するのであれば、このスライドの内容に沿って場合分けしていけば多くの場合は網羅できるんじゃないかと思っています。

ただ、SmartHR さんが扱うドメインとして “従業員を起点とした変化” に向き合っていく場合、「あとから分かった出来事も正しい日付で反映したい」というニーズがあるようです。確かに言われてみればそうですよね。

レコードとして有効な期間(ex. 2025/09/26 までに役職が部長だった)と、操作時間の2つの時間軸で履歴を管理するコンセプトが Bitemporal Data Model です。有効な期間だけだと、そのレコードがいつ登録/無効になったかの事実が抜け落ちるので、2つの時間軸で管理しようという話のようです。

パッと直感的に思ったのは2つの時間軸を考慮しないといけないので、考えることが掛け算で増えてしまう懸念を持ちました。SQL も複雑になりそうですしね。後から有効な期間を追加したい場合に、有効期間が重複してはいけないと思うので、そこの制約を Model のバリデーション、Database の制約ともに考慮する必要はあるんだろうなとか。

スライドでも想定外の履歴データが作られていることがあり、原因調査に丸一日かかったという言及がされていました。基本的に INSERT されるはずなので、そこから問題となっているデータを特定するのに時間がかかるというのはあるんだろうなと。activerecord-bitemporal gem では visualizer 機能があり、レコードの履歴を可視化してくれるそうです。

有効期間の日付管理が timestamp だと時分秒の管理があるから、date 型に変更して運用容易性を担保したという話も興味深かったです。この部分で意図しないレコードが生まれるケースはありそうだなと思っていたところ、https://tech.smarthr.jp/entry/2025/09/12/115617 も拝見し、まさにその問題があったようですね。“履歴の一括出力後、Excelで適用日を編集するとExcelの仕様で時分秒の情報が「00:00:00」に丸められてしまう”、“例えば部署マスターの更新、並べ替え、削除、従業員部署の登録、更新などでは多数のモデルが同一トランザクションで更新されます。 このとき、適用日の時刻を固定して揃えないと、処理タイミングの僅かなズレによって適用日が秒未満の精度で異なった履歴が作成されてしまう” 、“同一適用日の更新において、社員番号と適用日の組み合わせでレコードを特定する際、ユーザーから秒未満を切り上げた日時を受け取り、秒未満を考慮して対象の履歴を探す” などなど、かなり負の側面を抱えていたようです。大変な移行だったようですが、とても意味のある移行だなと思いながら拝見しました。date 型だと unique 制約によって重複を弾きやすくなりますしね。

“履歴” を表現する1つの手段として Bitemporal Data Model を使ったリアルな声が公開されているのは、本当に嬉しいですね。とても参考になる話を聞けました。今後モデリングする際は、1つの手段として頭の片隅にインデックスを貼っておこうと思いました。

Kaigi on Rails 2025 に参加したタイミーのメンバー

「問い」を「分析」に変える思考プロセス

こんにちは! タイミーでデータアナリストをしているtakahideです。

突然ですが、「この事業を成功させるにはどうすれば?」といった、ふんわりと大きなテーマを渡されて、「さて、どこから手をつけようか...」 と悩んだ経験はありませんか?

タイミーでも、今後より会社の重要課題に関わる分析プロジェクトが増える中で、こうした上流の課題を見つけ、精度の高い仮説を立てる力、いわゆる「課題発見・仮説思考力」の重要性が高まると考えています。



本記事では、「仮説向上プロジェクト」での取り組みを元に、複雑な課題を構造化し、具体的なアクションに繋げるための思考整理術をご紹介します。
この記事が、同じように課題発見に悩む方々の助けに少しでもなれば幸いです。

「知っている」と「できる」の壁

これまでもデータアナリティクス部では、事業部のメンバー向けに仮説構築の勉強会を開いてきました。1回目は仮説のタネから仮説の木を育てる「仮説構築」の全体像を、2回目では論理を整理するための「便利な道具 (フレームワーク)」について行いました。



おかげで、チーム内で「仮説」という言葉の目線は一定揃ったのかな、と思っています。一方、知識として「知っている」ことと、実践で「使いこなせる」ことの間には、思った以上に大きな隔たりがありました(当たり前ではありますが、、)。

思考のプロセスを可視化する「仮説向上プロジェクト」

そこで、この壁を乗り越えるために、実験的な「仮説向上プロジェクト」を立ち上げました。
このプロジェクトの目的は、とてもシンプルです。

「問いを立てる力を引き上げること」。

分析の精度は、最初の「問い」の質でそのほとんどが決まってしまいます。MECE (モレなく、ダブりなく) やロジックツリーといったフレームワークといった調理器具を使う前に、「そもそもどの食材をどう料理するべきか?」 という「見立てる力 (素材の目利き)」を鍛えることにフォーカスしてみました。

具体的には、会社としての重要テーマを題材に、メンバーと1on1形式でディスカッションを重ねました。この抽象的なお題を、どう整理し、具体的な分析テーマに落とし込んでいくか。その思考プロセスを繰り返しました。

思考整理の「3つのステップ」

この実験的な取り組みを数回繰り返す中で、手応えのある思考整理のプロセスが見えてきました。

1. 「問い」から「5W1H」への整理

すべては、一つの大きな「問い」から始まります。特に会社の重要課題につながるような抽象的な問いの場合、そのままでは、どこから手をつければ良いか判断がしづらいです。
そこで、まずは問いを具体的な要素に分解することで、その後のプロセスがスムーズに進むことが分かりました。

特に、5W1Hは問いを具体化する初期段階において、シンプルですが便利なフレームでした。

  • Who (誰が)
    まず、「誰にとっての成功なのか?」を定義します。特に私たちのようなプラットフォーム事業では、関わるプレイヤーが複数存在します。例えば、「ワーカー」と「事業者」です。
  • What (何を)
    次に、この新しい事業が「具体的に何を価値として提供するのか」を、それぞれのプレイヤーの目線で定義します。
  • Why (なぜ)
    そして、それぞれのプレイヤーが「なぜ、提供された価値に関心を持って、関わりうるか?」という動機を深掘りします。提供者が抱える「不安定さへの不満」や、利用者が感じる「既存サービスへのコストや品質面の課題」など。

一つの問いを様々な視点から分解していくことで、漠然としていたテーマの輪郭が見えてきます。チーム全員の目線を合わせ、分析のブレをなくすための最も重要な土台作りと考えています。



2. 「5W1H」から「Flywheel」への落とし込み

5W1Hで事業の構成要素を洗い出したら、次に行うのがFlywheel (はずみ車)への落とし込みです。

Flywheelとは、事業を「一度回れば自律的に成長していくサイクル」として捉えるための思考ツールです。「何がどう作用して、次のどんな結果に繋がるのか?」 という一連の因果関係のループとして可視化することで、事業成長のエンジンがどこにあるのかを特定しやすくなります。

私たちのようなプラットフォーム事業を例に考えてみます。

1. まず、事業の成長を促すためのアクションがあります。例えば、マーケティング施策や営業活動によって、ワーカーの集客を強化したとします。
2. プラットフォーム上のワーカーが増えると、人材を探している事業者にとっての魅力が増し、「ここなら良い人が見つかりそうだ」と事業者の利用が増加します。
3. 事業者の利用が増えれば、仕事の募集件数も増えます。
4. 仕事が増えることで、ワーカーはより多くの就業機会を得ることができ、満足度が高まります。
5. 満足したワーカーがリピートすると、事業者の満足度にも繋がります。満足した事業者は継続的に利用し、さらに多くの仕事を募集してくれます。



このように、「ワーカーの増加 → 事業者の増加 → 仕事の増加 → ワーカーの満足度向上 → 事業者の満足度向上 → さらなるワーカーと事業者の増加...」 というように、片方の満足がもう片方の満足を呼び、雪だるま式に事業が成長していく好循環が生まれます。

この図を描いて共通認識を得ることで、「このサイクルのどこにエネルギーを注げば、最も効率的に全体を加速させられるのか?」 という、事業戦略の勘所が見えてきます。

3. 「Flywheel」から「定義」の再整理へ

最後のステップは、Flywheelで事業全体のサイクルを俯瞰しながら、もう一度最初の問いに立ち返る、「定義の再整理」です。

5W1Hで各要素を分解し(点の理解)、Flywheelでそれらの因果関係を繋ぎ合わせる(線の理解) ことで、事業を一つの動的なシステムとして捉えられるようになります。この視点を持つと、当初ぼんやりと設定していた言葉の定義が、より解像度の高い、具体的なものに変化していることに気づきます。

特に、求められている「成功」が「Flywheelのどの部分を、どのように回すことなのか?」という問いに変わります。

  • 「短期的な売上」を成功とすれば、新規獲得やマッチング率といった回転数を上げるための分析に集中します。
  • 一方、「長期的な成長」が成功であれば、リピート率や評価といった質を高め、遠心力を強めるための分析に注力します。

このように、抽象的な言葉が、具体的な指標やアクションと結びつきやすくなります。
このステップを行うことで、分析が向かうべきゴールが明確になり、その精度が高まると思います。

今後の展望:思考プロセスをAIを用いてスケールさせる

今後は、本プロジェクトで得られた知見を基に、AIとの対話を通じて同様のワークが誰でも実現できる仕組みを作りたいと考えています(例えば以下のようなものを想定しています)。

1. 分析したい「問い」をAIに入力する


2. AIが対話形式で分析テーマをサポートする


3. 仮説を選択・編集する


4. 最終的な分析プランが提案される


私たちの挑戦はまだ始まったばかりです。データから価値を生み出すために、これからもアナリスト自身の「考える力」を磨き続けていきたいと思います。

We’re Hiring!

タイミーのデータアナリティクス部では、ともに働くメンバーを募集しています!!

カジュアル面談も行っていますので、少しでも興味がありましたら、気軽にご連絡ください。

DroidKaigi 2025 参加レポート〜Part 2〜

はじめに

タイミーでAndroidエンジニアをしているふなちです。

本記事は、「DroidKaigi 2025 参加レポート〜Part 1〜」の記事の続きになります!

まだPart 1を読んでないよ!と言う方は、ぜひPart 1も読んでいただけると嬉しいです。

本記事(Part 2)では、Part 1から続いてエンジニアメンバーによるセッションレポートと、タイミーのブース出展の様子をお届けします 📣

エンジニアによるセッションレポート

nakagawa

紹介するセッション:Gemini エージェントで Android Studio 開発を高速化

タイミーではdroidkaigiでブースを出しており、多く方に足を止めていただくことができました。

ブースに立っている中で初日にどこか見覚えのある方がいらっしゃり、「お会いしたことありましたっけ?」と聞いてみたら、特に面識はないとのこと… 翌日に聴講したセッションでその方が登壇しており、その時に気づきました。

「あの人、YouTubeのGeminiでE2Eテストの動画に出てた人だ!!」

www.youtube.com

セッションではYouTubeで見て未来に思いを馳せていたGeminiが自然言語で記述されたテストを実行するJourneyのライブデモを見ることができ、ちょうど当日にAndroid Studio Canaryでリリースされたばかりとのことでした。

デモでは日本語で記述して実行結果のスクリーンショットとその結果とその根拠をテキストで出力しており、メンテナンスコストが低いE2Eテストの実装ができそうだと感じました。

後にAsk the speakerに質問をしにいき、見覚えがあった理由の話もしたのですが、「彼はYouTube Famousだからね」と一緒に登壇されていたMandaさんも笑っていました。

「CIで動くようになるのはいつですか?」と伺ったところ、絶賛開発中とのことでした、期待です。

DroidKaigiから帰ってさっそくタイミーのプロジェクトで試してみましたが、まだ動かなそう…?Build Logic使っているせいか、まだうまく読めてないような気がしていますが、まだしっかりとは見れていません。安定的に使えるようになったら実際の運用で使えるか試してみたいと思いました。

murata(@murata

紹介するセッション:Cache Me If You Can

RyuNen344さんによる「Cache Me If You Can」は、多くのAndroid開発者が"何となく"で使ってしまいがちなGradleのキャッシュ機構に深く迫るセッションでした。

私自身、Gradleはブラックボックス同然で、ビルドエラーが起きるたびにStack Overflowを彷徨う…そんな場当たり的な対応を繰り返していました。このセッションは、そんな私のGradleに対する苦手意識を打ち破る、まさに目から鱗の内容でした!

セッションで得た知識を元にさっそくプロジェクトのGradle設定を見直したところ、ビルドパフォーマンスにつながる以下の改善を実現できました。

  • Configuration Cacheと並列実行の有効化org.gradle.configuration-cache.parallel=true
  • 環境変数を参照していた System.env()Provider API に置き換え
  • 通常のビルドでは不要なタスクを提供するプラグインの適用方法を最適化

これまではConfiguration Cacheが効かずに頭を悩ませることも多々ありましたが、今ではこのセッションで学んだ知識を武器に、自信を持って原因を調査できる気がしています👍

「Gradleのビルド遅いな…でもよくらからないから後回し!」となっている、そこのあなた! ぜひ本セッションのアーカイブ動画を視聴して、一緒にGradleの世界を切り拓いてみませんか?😊

スポンサーブースも大盛況でした🎉

DevRelのみーた(@earlgrayMK)です。

今回タイミーではゴールドスポンサーとしてブースを出展しました。

多くの方にお立ち寄りいただき、ありがとうございます!

スキマバイトとしてアンケートのお仕事をみなさんにお願いし、たくさんの回答をいただいたのでご紹介します。

みなさんのご投票の結果、Android開発において最も困難だと感じられているのは、「既存コードベースの保守・改善」と「OSバージョン・デバイスの多様性」であることが明らかになりました。

この根深い課題に対して、タイミーのAndroidエンジニアがどのように向き合っているのか、具体的な取り組みをまとめました。

1. OSバージョン・デバイスの多様性への対応

  • 自動テストの活用
    • テスト自動化ツール「MagicPod」を導入し、サポート対象OSの上下限バージョンで毎日テストを実行。広範囲の環境を効率的にカバーしています。
  • 多様な物理デバイスでの検証
    • 外部のQAチームや、クラウド型検証サービス「RemoteTestKit」を活用。さらに、社内Slackで特定端末を持つメンバーに協力を仰ぐなど、物理デバイスでの実機検証を徹底しています。個人的に折りたたみスマホを購入し、検証に活かす開発者もいます。

2. 既存コードベースの保守・改善

  • 進捗の「見える化」と「仕組み化」
    • リファクタリングの進捗をLinterのwarning数やモジュールの分割状況などで定量的に可視化し、チーム全体で課題意識を共有する仕組みを重視しています。デザインシステムの構築やEdge-to-Edge対応もその一環です。
  • プロダクトオーナー(PO)との共通理解
    • 技術的負債の解消がプロダクトの価値向上に不可欠であるという点をPOと共有。これにより、計画的なリファクタリングを実現しています。
  • 適切なエンジニアリソースの確保
    • リソース不足が負債の蓄積と開発の悪循環を招かないよう、Androidエンジニアの適切なリソース確保に努めています。
  • バランスの取れた技術選定
    • 新技術の導入時は、必ずその妥当性をチームで議論し、合意形成を図ります。これにより、将来の負債化を防ぎ、技術的なバランスを保っています。(この領域では、特にエンジニアの村田が重要な役割を担っています。)
  • 高いサービスレベル目標(SLO)の維持
    • プロダクトの品質目標を高く設定し、それを維持する文化が、コードベースの健全性を保つ動機付けにもなっています。

両課題に共通する、タイミーの強み

  • 厚いチーム体制
    • チームメンバーが多いため、新規のプロダクト開発と並行しながら、検証やリファクタリングといった改善活動を分担して進められる体制が強みです。
  • 「地道な努力」の文化
    • メンバー全員が「地道に改善を続けるしかない」という共通認識を持っており、日々の継続的な取り組みを大切にしています。

Day2「開発している中でAIをどのように活用していますか?」

Day2では様々なご回答をいただいたので、特に多かったものや面白いと思ったものをまとめました。

おわりに

DroidKaigi 2025では、各セッションや参加者の方々との交流から、日々の開発の参考になる知見を得ることができました。ここで得た学びは、今後のプロダクト開発につなげていきたいと思います💪

また、10月21日(火)にココナラ社、アンドパッド社、令和トラベル社、そしてタイミーの4社共催で「After iOSDC & DroidKaigi 2025」を開催します。

当日は弊社からAndroidエンジニアのtick-takuが登壇します 🎉

ハイブリッド開催となっておりますので、ご興味のある方はぜひ気軽にご参加ください 🙌 

reiwatravel.connpass.com

最後に、本カンファレンスを支えた運営・登壇者のみなさん、ならびにタイミーブースにお越しいただいた方々、ありがとうございました!

DroidKaigi 2025 参加レポート〜Part 1〜

はじめに

タイミーでAndroidエンジニアをしているみかみです。

2025年9月10日から12日にかけて、Androidの技術カンファレンスである「DroidKaigi 2025」が開催されました。タイミーからはAndroidチームをはじめとする複数のメンバーが現地に参加し、今年も昨年に続いてゴールドスポンサーとしてブースを出展しました。

セッションでは最新の知見に触れる機会が多く、日々の業務にもつながる具体的な学びを得ることができました。また、会期を通しては立ち話や展示をきっかけに参加者同士が議論を深める場面も多くあり、交流の広がりも強く感じました。そのような様子は会場にとどまらず、XなどのSNSを通じて、オンラインでも盛り上がりをみせていたのが印象的です。

Part1、Part2の2記事に渡り、エンジニアメンバーによるセッションレポートと、ブース出展の様子をお届けします。

本記事(Part 1)では、エンジニアメンバーによるセッションレポートをご紹介します!

エンジニアによるセッションレポート

まずは、DroidKaigiに参加したエンジニアメンバーによるセッションレポートを紹介します。

Hunachi(@_hunachi

紹介するセッション:Androidライブラリアンの手引き:堅牢なライブラリとSDKの構築

私はライブラリを公開した経験はないのですが、このセッションはライブラリ開発者だけでなく、マルチモジュール構成で開発している人、そしてライブラリを利用する人にも多くの学びがある、非常に有益な内容でした。

このセッションで特に印象的だった、新しく学べた点をいくつかご紹介します。

  • 公開範囲の制御の重要性について

internalを正しく使うことはもちろん、Explicit API mode を有効にすることで、意図せずパブリックAPIが公開されてしまうのを防げると知りました。これによって、モジュールの責任範囲が明確になり、APIの健全性を保つことができます。

  • 親切なAPIの非推奨化ついて

クラスや関数を非推奨(Deprecated)にする際、@Deprecated アノテーションのmessagereplaceWith 引数に具体的な説明を記述することで、利用者がスムーズに新しい実装に移行できる配慮が大切だと学びました。

  • 破壊的変更の自動検知について

パブリックAPIを変更、特に削除する際には、binary-compatibility-validator を導入して自動的にチェックをかける手法が紹介されていました。うっかり互換性を壊してしまうミスを防ぐための仕組みは、特にライブラリのメンテナンスにおいて非常に重要だと感じました。ライブラリを作成する機会があったら利用するようにしたいです。


また、ライブラリとそれを利用するプロジェクト間でリソース名が衝突するという問題についても話がありました。マルチモジュールでの問題においては弊社でも対応は済んでいるものの、ライブラリ使用者として予期せぬ挙動に悩まされた経験が何度かあるので自分がライブラリを作る側になった時は気をつけようと思いました。

ライブラリの裏側で何が起きているのかを知ることで、利用者としてもより賢く付き合っていくことができると再認識しました。今後、マルチモジュールでの開発やライブラリを利用する際に、今回学んだ知識を活かしていきたいです。

tick-taku

紹介するセッション:EncryptedSharedPreferences が deprecated になっちゃった!どうしよう!

タイトルの通りで、なぜ deprecated になったかなどの背景を含め紹介し覚悟を決めさせてくれる素晴らしいセッションでした。

タイミーでは KeyStore + Cipher + DataStore を利用していましたが、別のブログで Tink を利用するといい感じに wrap されて、複雑な暗号化周りをライブラリに任せつつ実行速度が速くなると知りました。特定端末でのみクラッシュしてそうな気配を Crashlytics から観測しており、「もしや自前の実装が悪く Tink であれば Google 提供だしその辺も対処してくれているのでは…?」と思い移行しようとちょうど DroidKaigi 直前に Issue を作成して検討していたところ、このセッションの存在を知りました。

結論からですがやめた方がいいとのことです😇

どうやら観測していたクラッシュは OEM デバイスの KeyStore のバグでどうしようもないとバッサリでした。これは security-crypto が deprecated になった要因の1つらしく、Tink に移行したところで解決せず、むしろアプリ側でのハンドリングが難しくなるそうです。こうなったらどうしようもないのでデータは捨てましょうと割り切るしかないとのことでした…

また、クラッシュの要因としてもう1つバックアップ設定の話がありました。allowBackup=false に設定しているため大丈夫と考えていたのですが、Android 12 からメーカーによっては device-transfer によるバックアップは allowBackup の設定を無視するようになっているそうです。おかげでデータは移行されるのに key が異なるので復号に失敗するというものでした。

本当にちゃんと作ってくれメーカー…

また EncryptedSharedPreference が存在してしまうが故に我々はなんでもかんでもデバイスのストレージに保存してしまうという思想のもと deprecated にした背景もあるらしく、「そもそもそのデータをデバイスに保存する必要があるのか?」は設計時に常に意識したい事項だと感じました。

紹介するセッション:OAuthを正しく実装する:Androidアプリのためのセキュアな認証

OAuth を導入するための基礎知識や歴史が理解できる内容でした。

一度実装したり触れたりしたことがある人はそうだよねとなる内容も多く OAuth の入門として非常に勉強になると思います。

気になった点としては、多くのアプリでは access token をデバイス上に保存していると思いますが、その際は変に暗号化せずにシンプルに SharedPreference を使ってデバイスを信頼しましょうといった趣旨の内容が話されていて、Android は root 化したら引き抜けると思ったのですが大丈夫なんでしょうか…

また、PKCE がベストプラクティスらしいですが、そこまで実装しているアプリはどれだけあるのか気になります。

haru

紹介するセッション:スマホ新法って何?12月施行?アプリビジネスに影響あるの?

DroidKaigi初の公正取引委員会の人による発表で、主にこれから施行される新しい法律に関する話でした。

対象になるのは基本的にAppleやGoogleなどのプラットフォーム事業者で、In App Biilingなどの機能に対して影響があるようでした。

とはいえ、一般デベロッパーに開放していない機能を開放して欲しいなどのリクエストを送ることもできるようになるらしいので、今後どうなっていくか目が離せない法律の1つでもありますね。

みかみ

紹介するセッション:Be a Business-Driven Android Engineer

DroidKaigi 2025に参加して、特に印象に残ったセッションの1つが、ohzonoさんの「Be a Business-Driven Android Engineer」です。Androidエンジニアがどのようにビジネスの成長に貢献できるのかを解きほぐした内容で、今の自分が所属するストリームアラインドチーム(価値提供チーム)の状況とも重なり、とても心に残りました。

特に共感したのは「越境」という考え方です。現在所属するチームは少人数のため、エンジニアがデータ分析を担ったり、専門外の実装に挑戦したりと、役割の垣根を越えた働き方が自然に行われています。そのため、「越境」という言葉はもともとチーム内でもキーワードになっていました。今回のセッションは、そうした取り組みを価値あるものとして肯定してくれる内容であり、大きな励みになりました。AIの進化によって専門外の領域に踏み込みやすくなっている今、「越境」はこれからますます重要になると感じます。

また、開発チームが売上を直接的なKPIとして持つという話も新鮮でした。私はこれまで、パフォーマンス改善やエラー率の低減、ユーザー行動に基づく指標といったプロダクト内部の成果に注目することが多かったのですが、このセッションではそれに加えて、自分たちのアウトプットを事業全体の成果と結びつけて考える視点が提示されました。自分の仕事がどうビジネスインパクトにつながるのかを意識することで、エンジニアとしてもっと広い視野で取り組んでいきたいと感じました。

さらに、この考え方を技術面から支える手段として、Kotlin Multiplatform (KMP) の存在感も改めて実感しました。副業や別プロジェクトでKMPを利用してきた経験からも、その有効性を強く感じています。もちろん、ビルド速度やKMPそのものの複雑さ、iOSとAndroidエンジニア間の連携といった課題はまだあります。ドメインレイヤーの共通化によるメリットは大きく、KMPはAndroidエンジニアがiOS開発へと「越境」する後押しとなり、チーム全体の生産性を高める現実的な選択肢だと思います。今後も注目していきたい技術です。

syam

紹介するセッション:KotlinでのAI活用による開発

JetBrains の Sebastian Aigner さんと Márton Braun さんによる「KotlinでのAI活用による開発」というセッションが気になったので聴講しました!

Kotlin と AI の関わり方を「コード補完のような軽い支援」から「エージェントに任せる自動実装」まで段階的に紹介しており、JetBrains の AI エージェント Junie を使ったデモでは、新しい画面追加や UI の改良を自動で行っていて、既存コードのパターンも踏まえた修正が印象的でした。

また、Kotlin 製のフレームワーク Koog も紹介され、マルチプラットフォームで AI エージェントを組み込める仕組みとして活用できるとのことでした。

nshiba(@nshiba310

紹介するセッション:ユーザーも開発者も悩ませない TV アプリ開発 - Compose の内部実装から学ぶフォーカス制御

AndroidTVアプリを Compose を使って実装方法を紹介するセッションでした。

Compose 以前の時代に存在していた leanback library という Google 製のライブラリがありましたが、これは Compose には対応していません。

Compose で AndroidTV を実装しようと思ったら、どういったライブラリを使ったら良いかと行った基礎的なことから始まり、leanback library ではデフォルトでライブラリが対応してくれていた、フォーカス周りの制御やいまどのUIにフォーカスがあったているかがわかりやすくなるUIの制御などを Compose では自前で実装する必要がありどういった対応が必要かについても詳しく解説されていました。

また AndroidTV アプリでは、スクロールの制御についても通常のモバイルアプリとは異なる実装方法が必要になり、これについても詳しく解説されていました。

セッションタイトルの通りどのセクションでも Compose の内部実装までちゃんと処理を追って説明されていてとてもわかりやすく、これから Compose で AndroidTV アプリを作成する方にとって必見の内容がつまっていました!

続きはPart 2の記事で!

引き続き、Part 2の記事にて他のエンジニアメンバーによるセッションレポートと、ブース出展の様子をお届けします。

ぜひ読んでください!

tech.timee.co.jp

EKS × ARCでつくるGitHub Actions Self-hosted Runner基盤

こんにちは、タイミーでエンジニアをしている徳富です。

今回は、EKS上にGitHub Actions Self-hosted Runner基盤を構築した話をお届けします。

背景:GitHub Actionsへの移行と、新たに見えてきた課題

2024年10月に公開したCI基盤をGitHub Actionsへ移行した記事で紹介したとおり、

CircleCIからGitHub Actionsへの移行によって、私たちのCI体験は大きく改善しました。

しかし、開発者やテストケースが増え、時間が経つにつれて新たな課題も見えてきました。

  • 実行回数の急増によるコスト高騰
    • 2025年2月頃からDevinをはじめとしたAIエージェントの利用が進み、PRやpushの回数が一気に増加
    • 開発者数の増加も重なり、ワークフロー実行回数が比例して伸びていった
    • GitHub-hosted Runnerは料金や安定性の面である程度最適化されているため、Self-hostedに切り替えれば必ずしもコスト削減につながるとは限らない。しかし、割引オプションが少なく、コストコントロールが難しいという課題もある
    • 一方AWSならSavings PlansやSpotインスタンスなどの仕組みを活用でき、柔軟に最適化が可能。開発者やエージェントの利用増加で実行回数が急増するタイミーのユースケースにおいては、この「柔軟に最適化できる」という点が大きなメリットであることがわかってきました
  • テスト時間のじわじわとした増加
    • テストケース数の増加により、全体の実行時間も長くなってきている
    • apt install などのセットアップ処理にも時間がかかっている
    • 「ランナーイメージに事前インストールしておけばもっと速くできるのでは?」という声も出始めた

「コストをコントロールしながら、テストももっと速くしたい」

そんな思いから、私たちはSelf-hosted Runner基盤の構築を検討し始めました。

最初のアプローチ:ECS + Lambda構成

当初は ECS + Lambda + API Gateway を組み合わせて、ランナー基盤を構築しようとしました。

しかし実際に検証してみると、すぐにいくつかの課題に直面しました。

  • レートリミットの考慮

    1回のCI実行で最大35並列のランナーを起動してます。  日中は多いときで 1時間に60回以上 実行されることもあり、GitHub API の レートリミットを意識した設計が必要になります。

    → これを Lambda 側で考慮して実装するのはかなり複雑。

  • ランナーは30秒以内に立ち上がってほしい という要件がある。

  • Lambda のコードを継続的にメンテナンスするコストも無視できない。

「長期的に運用するには、この構成は少し複雑すぎるかもしれない」

そう判断し、よりシンプルに運用できる別のアプローチを探すことにしました。

選んだのは EKS(auto mode) × Actions Runner Controller

そこで目をつけたのが、GitHub公式が提供する **Actions Runner Controller(ARC)**。

ARCはGitHub ActionsとKubernetesをつなぎ、必要なときだけランナーPodを動的に起動してくれます。

さらにクラスタ基盤には EKS Auto Mode を採用しました。

ノード管理やスケーリング設定をほとんど自前で持たずに済むため、運用の手間を大幅に減らせるのが魅力です。

「EKS Auto Mode × ARC であれば、管理コストを抑えつつ柔軟なSelf-hosted Runnerが作れるのでは?」

そう考え、この構成で進めることにしました。

アーキテクチャ概要

ざっくりとした構成はこんなイメージです。

アーキテクチャー図

  • ARC: GitHub APIと連携し、ランナーPodを自動的に作成・削除
  • EKS Auto Mode: クラスタ管理を最小限に抑えつつ、柔軟なスケーリングが可能
  • Karpenter: Auto Modeの裏側で働くプロビジョナー。従来のCluster Autoscalerよりnode起動が速い

特にCIのように時間帯によって必要リソースが大きく変動するワークロードでは、

Auto Mode+Karpenterの組み合わせが非常に相性が良く、メンテナンス性・柔軟性の両立ができました。

導入時に直面した課題と解決策

ここからが本番です。

実際に導入を進めていくと、次々と問題が発生しました。

1. Spotインスタンスの安定性問題

当初はコスト削減を狙って、停止率の低いインスタンスタイプの Spotインスタンス を採用していました。

しかし、弊社のCIは 35並列で高頻度に実行されるため、必要なインスタンス数が多くなり、停止確率が低いタイプでも 1日あたり5〜10回ほどノードが落ちることがありました。

その結果、CIが途中で失敗するケースが頻発し、開発者体験を大きく損ねる要因となってしまいました。

対策

そこで思い切って オンデマンドインスタンスに切り替え、必要に応じて Savings Plans を適用する方針にしました。

  • オンデマンドにしたことで、ランナーが突然落ちるリスクがなくなり、安定してCIを回せるようになった
  • 安定性が向上したことで、CIだけでなく デプロイなど他のワークフローもSelf-hosted Runnerに寄せる ことが可能に
  • これによりEC2のアイドル時間を減らし、稼働率を高めることでコスト効率も改善できました

2. スケールインでランナーPodが強制終了する問題

次に直面したのは「EC2のスケールインによって、ランナーPodがCI実行中に突然落ちる」という問題です。

原因は、Karpenterの設定でした。

デフォルトでは disruption.consolidationPolicyWhenEmptyOrUnderutilized になっており、

ノードのリソース使用率が低いと、Podが稼働中でも容赦なくノードを落としてしまうのです。

(参考: https://karpenter.sh/docs/concepts/disruption/)

対策

  • consolidationPolicyWhenEmpty に変更
  • Podがないノードのみスケールイン対象とするよう設定
spec:
  disruption:
    consolidationPolicy: WhenEmpty

これでランナーPodが実行中に消える問題は解消しました。

3. ノードが全然スケールインしない問題

しかし、ここで別の問題が発生します。

「一度スケールアウトすると、ノードがほとんど減らない」という現象です。

原因は Kubernetes のスケジューリング。

Kubernetes のスケジューラには、Pod をできるだけ均等に配置しようとする仕組みがあります。

そのため Pod が複数のノードに分散して配置されやすく、ノード上の Pod が 0 になるケースが少ないため、スケールインがなかなか進まなくなります。

対策

  • Pod Affinityを利用し、ランナーPodはなるべく同じノードに詰めるよう設定
  • Pod配置の断片化を防ぎ、スケールインしやすくしました
affinity:
  podAffinity:
    preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 100
        podAffinityTerm:
          labelSelector:
            matchLabels:
              actions.github.com/scale-set-namespace: arc-runners
          topologyKey: kubernetes.io/hostname

これによりリソース効率が大きく改善されました。

4. 夜間にリソースを最適化する作戦

リソース効率をさらに高めるため、日中は安定性を優先し、夜間だけ段階的にノードを整理する仕組みを導入しました。

具体的には、disruption.consolidationPolicyWhenEmptyOrUnderutilized に設定したうえで、夜間に 一定間隔で15分だけpodが存在するノードのスケールインを許可 → その後は再び禁止 というサイクルを繰り返します。

これにより、ノード上にPodが残っていても一気に消されることはなく、「急にPodが落ちてCIが止まる」といったリスクを避けながら、少しずつリソースを最適化できるようになります。

spec:
  disruption:
    consolidationPolicy: WhenEmptyOrUnderutilized
    consolidateAfter: 5m
    budgets:
      - nodes: "0"
        reasons:
          - Underutilized
        schedule: "0 0 * * *"     # 0:00〜11:45 UTC 禁止 (JST 9:00〜20:45)
        duration: "11h45m"

      - nodes: "0"
        reasons:
          - Underutilized
        schedule: "0 12 * * *"    # 12:00〜15:00 UTC 禁止 (JST 21:00〜翌0:15)
        duration: "3h15m"

      - nodes: "0"
        reasons:
          - Underutilized
        schedule: "30 15 * * *"   # 15:30〜17:00 UTC 禁止 (JST 翌0:30〜翌2:15)
        duration: "1h45m"

      - nodes: "0"
        reasons:
          - Underutilized
        schedule: "30 17 * * *"   # 17:30〜20:00 UTC 禁止 (JST 翌2:30〜翌5:15)
        duration: "2h45m"

      - nodes: "0"
        reasons:
          - Underutilized
        schedule: "30 20 * * *"   # 20:30〜24:00 UTC 禁止 (JST 翌5:30〜翌9:00)
        duration: "3h30m"

この仕組みによって、日中は安定してCIを回しつつ、夜間は少しずつノードを整理してリソースを効率的に活用できるようになりました。

5. コールドスタート問題をランナープールで解消

弊社では35並列のランナーを利用しています。

そのため、完全なオンデマンド起動では間に合わず、

ランナー起動待ちが発生してしまうこともありました。

そこで、ARCの minRunners 設定を活用し、ランナープールを作成

あらかじめ一定数のランナーを起動しておくことで、

要求があればすぐに割り当てられるようになり、

GitHub-hosted runnerと同じ快適な使い心地を実現しました。

5 Runner PodでDockerを使う工夫

最後のハードルは「ランナーPodでDockerをどう使うか」です。

私たちのCIではMySQLやRedisなどのservice containerを多用しているため、RunnerコンテナからDockerを操作できる仕組みが必要でした。

選んだ方法

RunnerでDockerを扱う方法は大きく分けて DooD (Docker outside of Docker)DinD (Docker in Docker) の2種類があります。(参考:GitHub Actions の self-hosted runner で Docker を使う際のパターン整理)。

今回は DinD を採用しましたが、その中でもさらに実現方法が2パターン存在します。

  1. Runnerコンテナ内で直接Dockerデーモンを起動する方式
    • Runnerコンテナ自身が dockerd を立ち上げ、docker builddocker run を自己完結的に実行する。
    • シンプルですが、Runnerコンテナに 特権モードや大量の権限 を付与する必要があるため、セキュリティ面での懸念が残ります。
    • また、RunnerコンテナとDockerデーモンが同居することでリソース管理が複雑化しやすく、トラブルシュートもしづらいという課題があります。
  2. Dockerデーモンをサイドカーとして起動する方式
    • Pod内で Runner と dockerd を分離し、emptyDir などを介して ソケット通信 させる。
    • Dockerの実行環境はサイドカーに閉じるため、Runnerコンテナは通常権限で動かせる。
    • CIジョブ終了とともにPodごと削除されるため、イメージやボリュームなどの作業痕が自動的に掃除される点もメリットです。

私たちは Runnerコンテナに強い権限を持たせないことを重視し、後者の DinDサイドカー方式 を選択しました。

まとめと次回予告

今回、EKS × ARC を使ってGitHub Actions Self-hosted Runner基盤を構築し、

コスト・パフォーマンス・柔軟性のいいバランスで実現できました。

ただ、これで終わりではありません。

次回は、この基盤の上でテスト実行時間をさらに短縮するために行ったチューニングについて詳しく紹介する予定です。

「GitHub-hosted runnerで限界を感じている」

「EKSでSelf-hosted Runnerを検討している」

そんな方の参考になればうれしいです。

ながらRuby 会議01に行ってきました!

こんにちは!
タイミーでBackendEngineerをしている志賀(@akitoshiga)です!

2025年9月6(土)に開催された「ながらRuby会議01」に行ってきましたので、その様子を振り返りたいと思います!
ながらRuby会議には、「Kaigi Pass」という社内制度を利用して参加しました。

「Kaigi Pass」とは、世界中で開催されているすべての技術カンファレンスに無制限で参加できる制度です。

productpr.timee.co.jp

会場の様子

当日は長良川沿いにある「長良うかいミュージアム」というとても素敵な場所で開催されました。

会場内にはスポンサーノベルティや展示などもありました。

セッションの様子

refinementsのメソッド定義を4000倍速くした話

alpaca-tcさん

Ruby3.2以降、refinementsにおけるメソッド定義は約1万倍低速化していました。
社内サービスの開発でこの事態に直面した際に、原因の究明からRubyへのコントリビュートまでを行った過程をお話しされていました。
refinementsとはRuby2.0から導入された安全にRubyを拡張する仕組みのことで、モンキーパッチを当てたクラスのスコープを限定させることが可能です。
きっかけは、社内サービスのRubyのアップデートの際にRuby on Railsのアプリケーションの起動に数十秒かかるようになってしまったことでした。  
VernierとMiddlewareを利用して計測を行ったところ、ボトルネックとなっている処理が判明しました。
そこにrefinementsのメソッドModule#refineが存在していました。
Ruby3.3では、Module#refineを呼び出した際にrefineのcallcacheがクリアされる処理が追加されます。
このcallcacheが削除されたことが低速化の原因でした。 これをRuby Issue Tracking Systemで報告したところアドバイスをもらいました。
しかし、alpaca-tcさんはRubyの実装であるC言語には馴染みがありませんでした。
この問題に対してはChat-GPTやko1/rubyhackchallengeを活用したりコミュニティでアドバイスを得ることで解決していきました。
最終的にプルリクエストを作成してRuby本体へのマージが実現したそうです。
技術的なギャップを埋めるためにAIを活用したのは素晴らしい解決方法ですし、粘り強く取り組みRubyへのコントリビュートを実現する姿は素晴らしいと思いました!  

知っているようで知らないrails newの世界

luccafortさん

speakerdeck.com
  Ruby on Railsではプロジェクトの初期化の際にrails newというコマンドを実行します。
しかし、このコマンドの裏側でどのような処理が行われているかは多くは知られていません。
そこで、コマンドはどのような実行フローを行っているか、また使われている技術がどのような設計の組み合わせによって実現しているかについて深掘りしてお話しされていました。
luccafortさんの今回の発表の動機の一つには、オーガナイザーを務められた「関西Ruby会議08」での体験から、個人開発以外の成長の選択肢を模索したかったという想いがあったそうです。

rails newで実行される処理は以下の流れになっています。

  1. コマンド解析
  2. ジェネレータ初期化
  3. オプション処理
  4. ディレクトリ作成
  5. ファイル生成
  6. bundle install

これだけでも長大な処理なので、本発表ではコマンドの解析からジェネレータの初期化まで中心に説明していました。

rails newを実行するとRails::Commandによってargの解析やエラーチェックが行われます。
その後、Rails::Command.invokeによって入力したコマンドの内容からRails::Commandの適切なサブクラスが呼び出されます。
今回の場合はRails::Command::ApplicationCommandが読み込まれます。
Rails::Command::ApplicationCommand#performによって無効なコマンドチェックなどが行われた後、Rails::Generators::AppGenerator.startで定義された各種ファイルの生成タスクが実行されます。
その後、Rails::Generators::AppGenerator#bundle_commandによってbundle installが実行され最終的にコールバックが呼び出されます。
rails newに関する説明は以上です。
この取り組みを通してluccafortさんは仕組みを理解する重要性について気づきがあったそうです。
仕組みを理解していなくてもRuby on Railsは使えるものの、深く理解することで新しい発想や新たな気づきのきっかけになるとお話しされていました。

Ruby × iOSアプリ開発:共に歩んだエコシステムの物語

Tomoki Kobayashiさん

speakerdeck.com

Kobayashiさんは普段は主にモバイルエンジニアとして活動されています。
RubyはiOS開発の歴史において過去大きな役割を担っており、またiOS開発コミュニティもRubyに大きく貢献しています。
iOS開発とRubyが今までどう関わってきたかの歴史をお話しされていました。
2010年ごろのiOSアプリ開発はObjective-Cが使用されていましたが、サードパーティのライブラリのインストールが大変だったそうです。
ライブラリによってインストールの仕方が異なっており、Xcodeのビルド設定を行う際にもAppleの非公開の独自仕様のために保守性が非常に低いものでした。
この問題を解決するためにCocoaPodsというパッケージマネージャーが登場しました。
これによりライブラリの依存性解決・ダウンロード・Xcodeへのプロジェクト統合まで自動できるようになりました。
CocoaPodsはRubyでライブラリ管理に使用されるRubyGemsとBundlerを参考に作成されており、本体の実装もRubyで書かれています。
その他もnomad-clifastlaneといったRubyを参考にしたツールが登場してきました。
この背景はツールの作成者が元々RubyやRuby on Railsのエンジニアが多かったことにあるそうです。
そして、CocoaPodsの依存関係リゾルバーであるMolinillo(モリニージョ)はBundler1.9, RubyGems2.9に搭載されるようになりました。
しかしながら、iOS開発とRubyの関わりは薄れつつあるそうです。
2014年のSwiftの登場を機にSwiftが公式のパッケージマネージャーを発表したりBundler2.4でMolinilloが引退しています。

Ruby Mini Language作成記 〜ハンズオンで学ぶインタプリタの世界〜

haruguchiさん
Rubyを用いてインタプリタを作成した経験をもとに、字句解析、構文解析、評価とった処理の実装方法や設計上の注意点についてお話しされていました。
インタプリタを作ろうと思ったのはharuguchiさんがRubyKaigi2025に参加したことがきっかけだそうで、RubyKaigiでよく発表される言語処理の話の理解を深めたいと思った時にインタプリタの実装を思いついたそうです。
haruguchiさんが参加されている勉強会でこの話を持ち込み、他のメンバーと実装していくことになりました。
インタプリタはFizzBuzzが動くものをゴールとして、単純な2項演算の実装からはじめることにしました。
最初は単純なパーサーのみで実装することとし、インタプリタの機能を追加していくにつれてレキサーを実装したり構文解析方法を工夫したりと実装を進めていきました。
自身で実装することを面白くするポイントとしてif文の条件式の区切りを< >にしたりとオリジナルの要素を追加していったそうです。
5ヶ月ほどでFizz Buzzの実装まで完了して、途中デモで実践していました。

当初のゴールとしては達成したのですが、ここから配列やハッシュといったデータ構造も行ってみたいとのことでした。
言語処理の話題はRubyではよく出てくるのですが、その理解のためにインタプリタを自前で実践するところに尊敬しました。また、自分も挑戦してみたいと思いました。

💡Ruby(ひかるびー) 川辺で灯すPicoRubyからの光

bashさん

speakerdeck.com

PicoRubyという組み込み向けの軽量なRubyを使ってLEDを点灯させるところから、音声や加速度といったセンサーを追加して様々なことに挑戦することでRubyで組み込み開発をする楽しさについてお話しされていました。
最初の機材は「ATOM Matrix」という開発ボードで、内蔵のLEDを点灯させるところから始まりました。
また、基本的なアーキテクチャは「Super Loop Architecture」というものを用いていました。
Super Loop Architectureとは、初期化の後に発生させた無限ループの中でLEDに対しての操作を行うものです。
LEDの点灯に成功させたあとは、ランダムに点灯させたり自分の動きに合わせて点灯させたりといった試みを行っていきました。
最終的には棒状のLEDやMIDIシンセサイザーといった他の機材と連携させる試みを行っていました。

365日のOSS開発を続ける舞台裏

Koichi ITO(Koic)さん

speakerdeck.com
  RuboCopのコミッターであり、365日OSSにコントリビュートを行っているITOさんの普段の開発環境やOSSに対する心構えについてお話しされていました。
開発環境は業務のコードとOSSのコードを透過的に扱えるようにすることをテーマとしていました。
そのためのツールとしてghqgem-srcの使用を推奨されていました。
OSS活動をするとローカルリポジトリが大量に増えるのですが、その点についてはpecofzfを用いた対策を紹介されていました。 印象的だったのは、gitコマンドの扱い方でコミット権のないリポジトリとリポジトリでの振る舞いを合わせるためにFork先のリポジトリをoriginとして、upstreamをForkした方のリポジトリとすることを推奨されていた点です。
これによってどの環境にプッシュする際もgit push upstream headと同一のコマンドにできる利点について強調されていました。 心構えについては、コードの内容だけではなく発言やレビューについても恥ずかしくない振る舞いをしようという「ソーシャルコーディング」という考え方や、OSSを地球全体での非同期開発と捉えて自己完結したコードのみのPRを出さずにコンテキストを文章化して伝えることの重要性にも触れられていました。  

アフターイベント

懇親会の後にはアフターイベントとして鵜飼漁の観覧がありました!


残念ながら自分は参加できなかったのですが、大変盛り上がったみたいです。

まとめ

スポンサーLTも含めてどのセッションも大変面白かったです。
発表者の「これがやりたいからやる!」といった気持ちに基づいた発表が多かったのですが、その姿勢をとても尊敬しました。
また小規模の開催だったこともあり、アットホームで参加者間でのコミュニケーションもとりやすくたくさんの方と交流できました。
また、自身は今回初めて岐阜に行ったのですが、自然と人々の生活が調和したとても素晴らしい場所でした。
大変心に残る素晴らしい会だったので、次回開催される際はまたぜひ伺いたいなと思いました!