TECH PLAY

タイミー

タイミー の技術ブログ

264

こんにちは、タイミーのプロダクトアナリティクスチームでプロダクトのデータ分析をしている松下です。 この記事は Timee Advent Calendar 2025 シリーズ 2 の22日目の記事です。 はじめに 私の趣味はランニングで、仕事はデータアナリストです。 ランニングウォッチをつけてランニングをしていると多くのデータが溜まっていきます。 GarminDB という、 Garmin Connectからデータをダウンロードしてパースするライブラリを見つけたので、データベースに入れて改めてデータ分析をしてみました。 すると仕事で大事にしていることが、そのままランニングにも当てはまることに気づきました。 見るべき指標を選ぶこと 平均ではなく分布を見ること データの向こう側にある情報を処理すること どれもデータ分析の鉄則です。やっぱりそうだよな、と思いながら分析を進めていきました。 この記事では、ランニングデータの分析を通じて改めて実感した、データ分析で大事にすべきことについて書きます。 いつものランニングコース。車が少ない川沿いを走るのが好きです。 ランニングデータを分析してみた 最近のランニングウォッチはデータの宝庫です。 私はGarminのランニングウォッチを使っていますが、走るたびに以下のようなデータが溜まります。 距離、ペース、タイム 心拍数(平均、最大、ゾーン別の時間) ケイデンス(ピッチ) 気温 標高差 トレーニング効果、負荷 etc... BigQueryに自動同期する仕組みを作った GarminのデータをBigQueryに入れるために、以下のライブラリを活用しました。 github.com AIの力を借りながらパイプラインを構築できました。データを集めるハードルは、AI時代にどんどん下がっています。 github.com データで見えること①:見るべき指標を選ぶ 心拍数ゾーンでトレーニングする方法 ランニングには「心拍数」でトレーニングする方法があります。 心拍数ゾーンとは 心拍数を最大心拍数に対する割合で5段階に分けたもの。 ゾーン1(50-60%):ウォーミングアップ、回復走 ゾーン2(60-70%):脂肪燃焼、持久力向上。会話できるペース ゾーン3(70-80%):有酸素能力向上 ゾーン4(80-90%):乳酸閾値付近、レースペースに近い ゾーン5(90-100%):最大努力、短時間のみ維持可能 「ゾーン2で長く走る」トレーニングは、体への負担を抑えながら持久力を高める方法として人気があります。Garminのウォッチも心拍数ゾーンをリアルタイムで表示してくれます。 でも、私はペースを見ることにしました。 心拍数トレーニングにしっくりこなかった理由はシンプルです。 レースで求めているのは「心拍数」ではなく「タイム」だから。 心拍数は体調、気温、睡眠、ストレスによって大きく変動します。同じゾーン2でも、調子が良い日は5:30/km、悪い日は6:30/kmになることがあります。これでは「今日どれくらい走れたか」がわかりません。 一方、ペース(タイム)は嘘をつきません。5:00/kmで10km走れたら、それは紛れもなく「5:00/kmで10km走れる体」ができているという証拠です。 これは仕事でも同じ 見るべきは「施策を打てる指標」であり、「結果に直結する指標」です。 DAU(デイリーアクティブユーザー)を追っていても、それだけでは何をすればいいかわかりません。一方で、「新規ユーザーの7日後継続率」なら、オンボーディング改善という施策につながります。 心拍数は「体の状態」を表すデータ。ペースは「結果」を表すデータ。アマチュアランナーの私にとって、追うべきは後者でした。 データで見えること②:平均の罠と比較の重要性 練習の平均ペースを比較してみた 「じゃあペースで何を見ればいいのか?」 まず、レース前3ヶ月の練習の平均ペースを比較してみました。 レース 練習の平均ペース レース結果 熊本城マラソン2024 5:19/km 3:17:50(4:38/km) さいたまマラソン2025 5:08/km 3:16:51(4:36/km)ベスト つくばマラソン2025 6:27/km 3:29:28(4:56/km) 速く練習したほうが速いタイムで走れそうですが、ここはアナリストなら平均の罠が隠れていることに気がつくと思います。 平均の中身を見る 練習のペースを「速い(5分/km未満)」「中程度(5-6分/km)」「遅い(6分/km以上)」に分類して、その割合を見てみました。 レース レースペース 速い練習(%) 遅い練習(%) 総距離 さいたまマラソン2025 4:36/km 38.6% 2.8% 598km 熊本城マラソン2024 4:38/km 30.8% 0% 844km つくばマラソン2025 4:56/km 26.2% 29.6% 906km 発見 ベストが出た時(さいたまマラソン、熊本城マラソン)は、速い練習の割合が30%以上、遅い練習は0-3% つくばマラソンは練習量906km(最大)だが、遅い練習が29.6%もあり、ベストは出なかった 平均だけ見ても「中身」がわからない 熊本城マラソン2024の練習平均ペースは5:19/km。一見、ゆっくり目に練習しているように見えます。 でも中身を見ると、 速い練習30.8%、遅い練習0% 。緩急をつけた質の高い練習をしていました。 つくばマラソン2025の平均ペースは6:27/km。こちらも「ゆっくり練習」に見えます。 でも中身は、 速い練習26.2%、遅い練習29.6% 。遅い練習が多すぎて、平均が下がっていただけでした。 平均だけ見ても「遅い練習が多いのか」「緩急をつけているのか」わからない。分布を見なければ意味がない。 これも仕事で経験済み CVRの平均が上がっても、新規ユーザーだけ上がって既存が下がっていたら? 売上の平均単価が上がっても、高単価商品だけ売れて低単価商品が売れなくなっていたら? 平均だけを追うと、重要な変化を見落とします。 データだけでは見えないもの 身体性の重要さ ランニングデータを分析して一番再確認したのは、 身体性の重要さ でした。 心拍数180の苦しさは、データで見る「180bpm」とは全く違う体験です。 データを見る人と、実際に経験している人では、同じ数字を見ても解釈が全く違う。 これは仕事のデータ分析でも同じです。 自社サービスを自分で使う  - ユーザー体験を肌で感じる 生ログを500件くらい見てみる  - データの「手触り」を知る ユーザーインタビューに同席する  - 数字の向こう側にいる人を想像する 商談・カスタマーサポートに同行する  - なぜ契約が決まる/決まらないかを体感する データに現れる「前の段階」の手触りを知ることが、良い分析の前提条件だと思っています。 これは頭ではわかっていたことです。でも、自分のランニングデータを分析して、改めて強く実感しました。 おわりに AIには難しいこと 身体性は今のところAIが持つのは難しい領域です。 AIはデータを高速に処理し、パターンを見つけ、予測モデルを構築できます。SQLも書けるし、可視化もできる。正直、データを見る作業の多くはAIに代替されつつあります。 しかし、AIは自社サービスを使ったことがありません。ユーザーの不満を直接聞いたことがありません。 データの「手触り」を知っているかどうか。これが、AIと人間のデータアナリストを分ける決定的な違いになると思います。 データの手触りを大事にしながら、プロダクトに向き合いたい方。 ご興味があればぜひお話ししましょう! プロダクト採用サイトTOP カジュアル面談申込はこちら
アバター
ogp こんにちは。データエンジニアリング部 DRE(Data Reliability Engineering)グループの つざき(tsu-san) です。 この記事は「 Timee Advent Calendar 2025 」シリーズ3の21日目の記事です。 今回はDREグループで導入したGoogle Cloudの PAM(Privileged Access Manager) についてご紹介します。 AIエージェントにGoogle Cloudの「権限」を預ける怖さ 最近DREグループ内では、開発効率を上げるために ローカル実行型 の AIコーディングエージェント(Claude Code / Cursorなど) を積極的に活用していこうという動きがあります。 ローカル実行型のAIコーディングエージェントは、実行ユーザーのローカル認証情報を使って自律的にコマンドを実行します。つまり、 ユーザーが持っている権限の範囲で、AIコーディングエージェントがGoogle Cloudのリソースにアクセスできてしまう 状態になります。 人間が毎回チェックすれば良いという話もありますが、AIが生成した複雑なコマンドを完璧にノータイムでチェックし続けるのは、精神的にもかなりの負担です。 「普段は閲覧のみ、必要なときだけ必要な権限を」へ タイミーのインフラ変更は Terraform + CI/CD が基本であるため、通常時は閲覧以外の権限は不要なはずです。しかし、現実には以下のような「編集権限が必要な瞬間」も存在します。 障害対応時の緊急オペレーション Terraform化されていないリソースの調査や一時的な変更 「AIを安全に使いたい」けれど、「いざという時は動きたい(=権限が必要)」。このニーズを解決するために導入したのが、Google Cloudの PAM(Privileged Access Manager) です。 Google CloudのPAM(Privileged Access Manager)とは PAMは、一言で言うと 「権限の時限付き貸し出し機能 」を実現する仕組みです。 特定の権限を、 「必要な時だけ」「承認を得て」「指定した時間だけ」 ユーザーに付与することができます。 PAMを導入して良かったこと 編集権限の完全廃止: 普段は閲覧権限のみにしておける。AIエージェントが万が一暴走しても、そもそも権限がないので被害が出ない。 監査ログの強化: 「誰が」「いつ」「何の目的で」権限を昇格させたかが明確にログに残る。 スムーズな承認フロー: チーム内での承認プロセスをGoogle Cloudの標準機能として組み込める。 導入後のフローと使用感 PAMのフロー図 導入後は、権限が必要になったらGoogle Cloudコンソールの「特権アクセス管理」画面から申請を出します。 申請: 理由を書いてリクエストを送信。 承認: チームメンバーに通知が届き、コンソール上で承認ボタンを押す。 作業: 承認された瞬間から権限が有効化される。 自動終了: 設定時間が過ぎれば、自動で権限が剥奪される。 このフローのおかげで、普段の作業でAIエージェントがうっかり破壊的な指示を出したとしても、物理的に権限がないのでエラーで止まってくれます。この「ガードレールがある安心感」は、開発スピードを落とさないためにも非常に重要だと感じています。 PAMで解決したこと PAMの導入により、DREグループでは以下の状態を作ることができました。 AIエージェントを安心して活用できる: 通常時は閲覧権限のみ、誤爆のリスクがなくて安心 運用の機動力は犠牲にしない: 緊急時はPAMで即座に権限を昇格できて安心 うっかりを仕組みで防ぐ: 人間もAIもミスをする前提で、システム側で安全性を担保できて安心 まとめ AIコーディングエージェントは非常に強力な武器ですが、編集権限を持った状態では安心して利用できません。 DREグループではPAMの利用により「緊急対応の迅速さ」と「最小権限」を両立することができ、AIと人間が安心して開発が可能な環境に近づくことができました。 「AIをフル活用したいけれど、編集権限を持っているのが不安」という方は、ぜひGoogle CloudのPAMを活用して、安全なAI開発環境を構築してみてはいかがでしょうか。 明日のアドベントカレンダーもお楽しみに! もし本記事やDREの取り組みにご興味があればぜひお話ししましょう! カジュアル面談申込はこちら プロダクト採用サイトTOP 付録:Terraformでの設定例 Terraformでの記述例を紹介します。 この例ではDREグループのメンバーが、必要に応じて「承認」を経てWriter権限をリクエストできるように構成しています。 # 1. PAMサービスエージェントへのIAMロール付与 resource "google_organization_iam_member" "pam_service_agent" { org_id = var.organization_id role = "roles/privilegedaccessmanager.serviceAgent" member = "serviceAccount:service-org-$ { var.organization_id } @gcp-sa-pam.iam.gserviceaccount.com" } # 2. 特権アクセスの設定(Entitlement) resource "google_privileged_access_manager_entitlement" "dre_admin" { entitlement_id = "dre-admin-entitlement" location = "global" max_request_duration = "3600s" # 最大1時間 parent = "organizations/$ { var.organization_id } " # 権限をリクエストできる対象(DREグループのアドレス) eligible_users { principals = [ "group:team-dre@example.com" , ] } # 一時的に付与する権限 privileged_access { gcp_iam_access { role_bindings { role = "roles/writer" } resource = "//cloudresourcemanager.googleapis.com/organizations/$ { var.organization_id } " resource_type = "cloudresourcemanager.googleapis.com/Organization" } } # 承認ワークフローの設定 approval_workflow { manual_approvals { require_approver_justification = true steps { approvals_needed = 1 approver_email_recipients = [ "user:data-dre-manager@example.com" , # 承認者 ] } } } # リクエスト時の理由入力を必須にする requester_justification_config { unstructured {} } depends_on = [ google_organization_iam_member.pam_service_agent ] } 実際に設定する際は、ユーザが作業に必要な最小の権限を付与するのが望ましいので、たとえば roles/bigquery.admin のようなサービスごとに権限を付与する特権アクセス設定を作成しましょう。
アバター
この記事は Timee Product Advent Calendar 2025 21日目の記事です。 データエンジニアリング部DSグループ所属の藤井と申します。現在タイミーで推薦エンジンの改善に取り組んでいます! この記事では、タイミーの推薦エンジンにおける候補生成で導入している ANN(Approximate Nearest Neighbor)と、その ANN用ベクトルを作る Two-Tower モデルを題材にします。そして、このドメインで重要なテーマのひとつである Negative Sampling 、特に In-Batch Negative Sampling を使ったモデル開発における課題と対策について議論していきます。 ANNはRAG(Retrieval-Augmented Generation)のバックエンドにおいても使用されることが多いので、ぜひ読んでいただけると嬉しいです! Two Towerモデル利用の背景 ここからは Two-Tower モデルの話に入っていきます。 推薦エンジンで推薦を行う際、推薦対象となる item v をすべての user u に対して brute force で厳密に計算すると、組合せ爆発により計算量が となってしまいます。そのため、件数が増えるにつれて、現実的なコストでは計算することが難しくなっていきます。 例として、日本の大学生300万人に対し、100万冊の本からベストな本を推薦する状況を考えましょう。この場合、「300万人×100万冊」で3兆通りもの組み合わせが生じてしまいます。推薦エンジンでの重たい計算や、LLM への API コールが必要なケースでは、このように全件をそのまま計算すると、非現実的なコストがかかる可能性が高いです。 ここで挙げた例のように、item数とuser数の組み合わせが多くなるケースでは、何らかの方法でうまく候補を抽出し、計算量を削減する必要があります。 この計算量の問題に対処するため、タイミーではANNおよびANNに使う推薦用のベクトル(埋め込み)を生成するために Two-Tower モデルを利用しています。 Two-Tower モデルと InfoNCE Loss のおさらい Two-Tower モデルでは、損失関数として InfoNCE Loss がよく使われます。 以下の InfoNCE Loss の式は、In-Batch Negative Sampling(「同じミニバッチ内の他アイテムをネガティブとして扱う」設定)を仮定した形になっています。 ここで、 : バッチ内 i 番目のユーザのベクトル : そのユーザに対する正例(ポジティブ)アイテムのベクトル : バッチ内に含まれる任意のアイテムのベクトル : コサイン類似度などの類似度関数 : 温度パラメータ : バッチサイズ 分子は「ユーザ と、そのユーザに対する正例アイテム との類似度」を、 分母は「同じバッチ内に存在するすべてのアイテム との類似度の総和」を表しています。 この式から分かるように、 どのサンプルをネガティブとして扱うか は InfoNCE の性能に直結する重要な設計要素であり、これまでに多くの研究が行われています。 本記事では、このうち Two-Tower モデル × In-Batch Negative Sampling という設定にフォーカスして話を進めます。 In-Batch Negative Sampling とは In-Batch Negative Sampling とは、あるユーザ に対して「 同じミニバッチ内の他ユーザの正例アイテム 」をネガティブサンプルとして兼用する手法です。 この方法では、ミニバッチ内で既に計算したアイテム埋め込みを負例として流用できるため、 負例のために追加でアイテムをサンプルして埋め込み計算(forward)するコストを抑えつつ 、多数のネガティブと比較できます。InfoNCEでは一度に複数のサンプルを比較するため、Negative Sampleの計算コストが無視できなくなる傾向にあります。 以下は具体的な手法です。 先ほどの InfoNCE の式の文脈でいうと、ユーザ ui に対して 正例(ポジティブ): ネガティブ: (同一バッチ内のその他のアイテム) という対応付けになります。(図1参照) 図1.In-Batch Negative Samplingイメージ図。 厳密には、バッチ内の他サンプルが「同一アイテム」または「同一ユーザのペア」である場合、False Negative となるのを避けるために、損失計算から除外(マスキング)する処理を行うのが望ましい ここからが本題です。 この In-Batch Negative Sampling + InfoNCE の構成は Two-Tower モデルの文脈において非常に一般的な構成ですが、実際のモデル開発においてはいくつか考慮すべき課題があります。 今日は、その課題の一部と対策例を議論していきましょう。 課題1: バッチサイズへの強い依存 InfoNCE Loss には、「相互情報量 I(X;Y) の下限を与える」というよく知られた評価式があります。[1] ここで N は「1 つの正例と一緒に比較されるサンプルの総数」です。 (* 厳密には独立負例を仮定して導かれる下界であり、in-batch negatives ではその仮定が必ずしも成り立たない点に留意されたい。) In-Batch Negative Sampling の設定では、1 ユーザあたりの比較対象はほぼ「バッチサイズ B 個」になるため、バッチサイズが小さいと、到達しうる相互情報量の下限も小さくなってしまいます。 その結果、モデルの性能がバッチサイズに強く依存するという問題が生じます。 対策例: 1. MoCo 型のメモリバンク / キュー この問題への対策一つが、MoCo に代表されるメモリバンク(キュー)方式です[2][3][4]*。 過去バッチのアイテム埋め込みをキューとして保持しておき、 現在バッチのユーザ埋め込みと比較するときに、そのキュー内の多数の埋め込みをネガティブとして利用する ことで、実効的なネガティブ数 Nを「バッチサイズ」ではなく「キュー長」まで拡張できます。 これにより、大きなミニバッチを組まなくても、多数のネガティブを確保しつつ学習できるようになります。 一方で、実装上のハードルは比較的高く、導入にあたっては慎重に検討する必要があります。 厳密には、最新の MoCo v3 [4] ではモデル構造の単純化(ViTへの適応)のためキュー(Memory Bank)は廃止され、SimCLRと同様の大規模バッチ学習に戻っていますが、同シリーズの重要な発展形として併記しています。 * 課題2: 出現頻度に由来するバイアス In-Batch Negative Sampling は「バッチに出てきたアイテム」をそのまま負例として使うため、バッチに登場しやすい=出現頻度の高いアイテムほどネガティブとして選ばれやすいというバイアスがあります。 その結果、人気アイテムは不当に類似度を押し下げられやすくなります。一方で、低頻度アイテムはそもそもネガティブとして登場しにくいため、学習で受けるノイズ(更新)が弱くなるという問題が生じます。 タイミーの文脈では、単なるアイテムの人気度だけでなく、エリア(地理)や職種によっても出現頻度が大きく異なるため、同様の構造のバイアスがより複雑な形で入り込みます。 対策例: 1. LogQ Correction In-Batch Negative Sampling では、popularity bias によりスコアがサンプリング確率 (学習時に負例としてサンプルされるアイテムvの周辺確率)に引きずられ、以下の形に収束してしまいます。 ここで r ( u , v ) は真の関連度を表します。 そこで、ロジットを としてあらかじめバイアス項を差し引くことで、人気度に依存しない本質的な関連度を学習させます[5]。 2. ランダムサンプリングによるネガティブ補完 In-Batch Negative Sampling だけに依存せず、別途ランダムサンプリングしたネガティブを足す/混ぜることで、人気アイテムだけにネガティブが偏らないようにする、というアプローチもあります。 この対策は比較的実装ハードルが低いです。 課題3: False Negative In-Batch Negative Sampling では、本来はポジティブであるべきアイテムがネガティブ側に紛れ込む(False Negative) ことが、かなりの確率で起こります。 有効バッチサイズやネガティブ数を増やしていくほどその発生頻度も上がるため、現実的には「避けきれないが、無視もできない」やっかいな問題です。 InfoNCE では、学習が進むと多数の easy negative はほとんど loss(=勾配)に寄与しなくます。そのため、性能を上げるには hard negative をしっかり集めることが重要になります。 しかし、良い hard negative ほどポジティブとの境界付近に位置するため、hard negative を攻めるほど False Negative を混入させやすくなるというトレードオフがあります。 False Negative が多いと、 本来近づけたいユーザ–アイテムのペアを、loss が「離せ」と強く押してしまう 結果として、似たアイテム同士が不自然に遠ざかり、リコールや一般化性能を削ってしまう といった形で、表現学習全体に悪影響が出ます。 筆者としては、False Negative の発生自体はある程度は仕方ない前提だと考えており、 「False Negative を完全に消しに行く」よりも、それによって勾配が暴れすぎないようにコントロールする仕組みを重視したいスタンスです。 図2. False Negative(=本来はPositiveとすべきSample)とHard Negative/Easy Negativeの位置関係のイメージ。一般的にFalse NegativeとHard Negativeは隣接しており、良質な境界ギリギリのHard Negative得ようとすると、同時にFalse Negativeを取得してしまうリスクが上昇する。 対策例: 1. Debiased InfoNCE (統計的な補正) 「ネガティブサンプルの中には一定確率 π でポジティブが混ざっている」という仮定を置き、Loss の分母からポジティブ成分の期待値を差し引くことでバイアスを除去する手法です [6]。 これにより、FN を無理やり遠ざけようとする誤った勾配の発生を統計的に抑制します。 2. False Negative Masking (高スコアの無視) 学習が進むと、モデルは FN(ラベルは負だが実は正例)に対して高い類似度スコアを出すようになります。 これを利用し、バッチ内のネガティブサンプルのうち、スコアが閾値を超えた(=モデルがポジティブだと確信している)ものを Loss 計算から除外(Masking)します [7]。 「怪しいものは学習に使わない」という割り切りにより、外れ値的な勾配によるモデル崩壊を防ぎます。 一方で、閾値が恣意的になりやすく、この閾値をどのように定義するかに難しさがあります。 おわりに ここまで、幾つかの課題とその課題に対する対策例を挙げてきましたが、モデルを学習する状況やデータによって、相応しい対策は異なります。手法をきちんと理解した上で運用することで、より良い候補生成用のベクトルを作っていきたいです。 We’re Hiring! タイミーではデータサイエンティストをはじめ、一緒に働くメンバーを募集しています! カジュアル面談 も行なっておりますので、興味のある方はぜひお気軽にお申し込みください! product-recruit.timee.co.jp 現在タイミーでは推薦エンジンを一緒に改善していくメンバーを募っております。 参考文献 [1] [1807.03748] Representation Learning with Contrastive Predictive Coding [2] [1911.05722] Momentum Contrast for Unsupervised Visual Representation Learning [3] [2003.04297] Improved Baselines with Momentum Contrastive Learning [4] [2104.02057] An Empirical Study of Training Self-Supervised Vision Transformers [5] Sampling-Bias-Corrected Neural Modeling for Large Corpus Item Recommendations [6] [2007.00224] Debiased Contrastive Learning [7] [2010.08191] RocketQA: An Optimized Training Approach to Dense Passage Retrieval for Open-Domain Question Answering
アバター
こんにちは!タイミーでバックエンドエンジニアをやっている福島です。この記事は Timee Product Advent Calendar 2025 の20日目の記事です。 みなさんは普段リファクタリングにどれくらい時間を割いていますか? 将来的な品質や開発スピードを担保するためには定期的なリファクタリングが必要ですが、普段の業務が忙しくてなかなか時間を割けない方も多いと思います。 そこで今回は、AIを活用して効率よくリファクタリングできないかを検証してみたので、その振り返りを兼ねてご紹介したいと思います。 リファクタリングの進め方 今回のリファクタリングは、直近取り組んでいた機能開発に関連するコードを対象にしています。 Cursorのチャットスペースを使い、以下の手順で進めました。 リファクタリング候補の洗い出し リファクタリング箇所の選定 実装方針を決定 実装 テストのカバレッジを確認 リファクタリング実装 テストの追加 リファクタリングの実践 先述した進め方に沿って、実行結果をまとめます。 1. リファクタリング候補の洗い出し AIに以下のプロンプトを投げて、リファクタリング候補を優先度順にまとめてもらいました。 機能Aの中でリファクタリングできそうな箇所、共通化できそうな箇所などを洗い出して、優先度順にまとめてください。 観点に以下を含めてください。 - 問題点 - 改善案 - 期待される効果 - 工数 優先度は以下の順で検討してください。 1. 保守性向上につながるか 2. 対応工数低めで対応できるか AIの回答(一部抜粋) ### 1. シリアライザー間のXXXロジックの共通化 - 対象ファイル: - … - 問題点: 同一ロジックが重複 - 対応案: ${クラスA}に${メソッドA}を追加し、シリアライザーから呼び出す - 効果: 変更箇所が1箇所に集約、保守性向上 - 工数: 1-2時間 ... ### 8. 有効期限計算ロジックの集約 - 対象ファイル: - … - 問題点: 有効期限計算が複数箇所に分散(TODOコメントあり) - 対応案: ${クラスA}を作成し、計算ロジックを集約 - 効果: 計算ロジックの一元化、テスト容易性向上 - 工数: 3-4時間 ... ## 推奨対応順序 1. 優先度:高の1-4を順次対応(合計5-8時間) 2. 優先度:中の5-7を対応(合計4-6時間) 3. 優先度:中-低の8-10は必要に応じて対応 特に優先度:高の1-4は対応工数が少なく、保守性向上の効果が大きいため、優先して対応することを推奨します。 トータルで12箇所ほど挙げてくれました。問題点と改善案も提示してくれたため、調査にかかるコストはかなり削減できたと思います。 2. リファクタリング箇所の選定 リファクタリングの優先度を検討した結果、「8. 有効期限計算ロジックの集約」を最初に着手することを決定しました。 主な観点は以下の通りです。 TODOコメントが残り(チーム内で既に問題意識がある) 設計の健全性を大きく損なっている 優先度に関しては、AIと人間の認識にズレが生じる結果になりました。 要因としては以下が考えられます。 対応工数に関する影響が大きくなってしまった AIに実装を任せるので、多少の差分は無視できる前提で指示するべきだった TODOコメントも考慮に加え、顕在的な課題として評価できると良かった ここは人間の判断基準を詳細に言語化して、プロンプトを磨き込む余地がありそうです。 3. 実装方針を決定 リファクタリング箇所が決まったので、「8. 有効期限計算ロジックの集約」の実装方針についてAIにサンプルコードを出力してもらい、それをレビューする形で方針を固めていきました。 主な観点は以下の通りです。 本当にリファクタリングの価値があるか 保守性向上につながる有効な共通化になっているか 逆にコードの可読性を損なっていないか やりたいことに対して必要最低限の差分になっているか また、この時点で「本当にリファクタリングの価値があるか」を再度見直すことも重要だと感じました。 例えば「1. シリアライザー間のXXXロジックの共通化」の実装方針を検討する際、いくつかの実装パターンを提示してもらいました。しかし、どれも局所最適な共通化に留まり、長期的な保守性向上にはつながらないことが判明しました。 こういったケースについても、実際のコードを見ながら解像度高く判断することで、無駄な実装を避け、効率的なリファクタリングにつなげることができます。 4. 実装 実装フェーズは3ステップに分けて進めます。 a. テストのカバレッジを確認 リファクタリングは、「ソフトウェアの外部から見たときの動作を変えずに、コードの内部構造を改善する作業」です。外部から見たときの動作が変わらないことを担保するため、まずはテストのカバレッジが十分かどうかをAIにチェックしてもらいます。 AIの回答(一部抜粋) ## テストカバレッジの評価 ### 十分にテストされている箇所 1. モデルAのメソッドa: 境界値テストあり 2. モデルBのメソッドa: 複数パターンのテストあり ### テストが不足している箇所 1. モデルAのメソッドb: 直接テストなし(xxx経由で間接的にテスト) 2. モデルBのメソッドb: ユニットテストなし(APIテストのみ) テストが不足している箇所を挙げてくれましたが、間接的にテストされており、必要なパターンは網羅されていたので、問題なしと判断しました。 b. リファクタリング実装 テストが十分だと確認できたら、安心してリファクタリングを実装できます。 実装方針についても既にすり合わせていたので、ほとんど手戻りなく完了しました。 c. テストの追加 最後に、今回は新規クラスを追加したので、その単体テストを追加してもらいました。 これで実装フェーズはコンプリートです。 結果として、有効期限計算ロジックを1箇所に集約することで、保守性とテスト容易性が向上しました。 クラス 変更前の主な責務(Before) 変更後の主な責務(After) 改善効果 Model A ステータス判定 有効期限の計算・判定 ステータス判定 単一責任の達成。 本質的なロジックに集中。 Model B ログ記録 有効期限の計算・判定 ログ記録 疎結合化。 インフラ層からドメインロジックを分離。 Serializer 表示フォーマット 有効期限の計算・判定 表示フォーマット 表示層の純粋化。 計算ロジックを排除。 Model C(新規) N/A 有効期限計算の集約 ロジックの変更箇所が1箇所に集約。 やってみた感想 調査の工数をほぼ0にできた どこを、なぜリファクタリングするのか 安全にリファクタリングできるか(テストは十分か) といった点を調査してまとめるのは、本来時間のかかる作業ですが、ここをAIにサクッとやってもらえたのは良かったです。 優先順位は人間の判断が必要 今回、AIが優先度低めに設定していたリファクタリングを最初にやる判断をしました。 先述したように、優先度の判断基準に関する指示は改善の余地がありそうです。 それに加えて、機能開発と並行してリファクタリングを進める場合、「現在進行中の開発とコンフリクトしないか?」という観点も必要になると思います。 リファクタリングの都合で機能開発のスピードを落とすわけにはいかないので、チームの開発事情と照らし合わせて判断できると良いですね。 チームでどう運用していくか リファクタリングは一度やって終わりではなく、継続してやっていく必要があります。 今回の取り組みを通して、工数をかけず安全にリファクタリングする手順は確認できました。 今後はチームとして安定したコード品質、開発スピードを担保するため、以下の2つに取り組んでいきたいと思います。 技術負債を可視化してチームで共通認識を持てるようにする 機能開発と並行したリファクタリングの実施を、チーム開発のサイクルに落とし込む さいごに この記事では、AIを活用したリファクタリングの実践例をご紹介しました。 AIの支援により、調査工数を大幅に削減しながら、安全にリファクタリングを進めることができました。一方で、優先順位の判断やチーム開発との兼ね合いなど、人間の判断が必要な部分も明確になりました。 今後もAIを上手く活用しながら、チーム全体でコード品質を維持・向上させていく取り組みを続けていきたいと思います。 AIを活用した開発改善や、チームでの継続的なコード品質向上に興味がある方、ぜひ一緒にお話ししませんか? プロダクト採用サイトTOP カジュアル面談申込はこちら
アバター
はじめに こんにちは。タイミーでエンジニアリングマネージャー(EM)をしているshuです。 (本記事は Timee Advent Calendar 2025 シリーズ3の19日目の記事になります。) 最近、社内のEMたちとHeidi Helfand氏の著書『ダイナミックリチーミング(Dynamic Reteaming)』の輪読会を行っています。この本は、従来の「チームは固定化されるべき」という常識を覆し、チーム編成を動的に変えることで組織の健全性と成長を促す手法について書かれた良書です。 読み進める中で、今年自分がアサイン責任者として対応した大規模プロジェクトの記憶が鮮明に蘇ってきました。 「あれ? あの時、必死で判断して実行したあの体制変更、まさにこの本に出てくる『アイソレーションパターン』そのものじゃないか?」と。 今回の記事では、今年発生した緊急プロジェクトでの実践を振り返りつつ、アイソレーションパターンの有効性と、そこで得られた「残された側のチームに起きた意外な副産物」についてシェアしたいと思います。 突発的な大規模プロジェクトと、急造チームの決断 今年、私が担当する領域で、大規模プロジェクトが突発的に立ち上がりました。 その性質は、EMにとっては胃が痛くなるようなものでした。 影響範囲が極めて広範囲に及ぶ 絶対に動かせないハードデッドラインがある 既存チームが片手間でこなせる量ではない 私はこのプロジェクトの立ち上げとチーム組成を担当することになりましたが、プロジェクトの性質に加え、タイミーのシステム特性や現在の開発チーム体制などを総合的に鑑みて、「既存の運用体制のままでは絶対に間に合わない」と判断しました。 そこで断行したのが、あるチームをベースにしつつ、プロジェクトに必要なドメイン知識やケイパビリティを持つメンバーを様々なチームから招集し、専任の「急造チーム」を組成するというリチーミングです。(個人的には、各チームの状況を鑑みながらメンバーを出してもらう、この調整業務が本当に非常に大変でした…) 後から本を読んで整理できたのですが、これは「アイソレーションパターン」と呼ばれる手法そのものでした。 アイソレーションとは、チームを意図的に切り出して分離・隔離し、既存のプロセスやルールから解放された違うやり方で仕事を進める自由を明示的に与えるパターンです。 主な目的: イノベーション: 新しい大胆なアイデアの追求 緊急事態: 予期しない問題への集中対処 停滞の打破: プロセスが重くなった「硬直化の罠」からの脱出 アイソレーションパターン このパターンについては、一般的な推奨事項は5つ紹介されています。その中で自分が重要だと考えているのが、以下の3点です。驚いたことに、今回の急造チームは無意識のうちにこれらのセオリーをなぞっており、それぞれがプロジェクトの成功に大きく寄与していました。 1. 専用スペースへの移動 本では物理的な部屋への移動が推奨されていますが、弊社はフルリモート体制のため、これは「専用チャンネルへの集約」として実践されました。 メンバーを既存チームから引き抜くと同時に、専用のSlackチャンネルを作成し、開発に関するすべてのやり取りや意思決定をそこで完結させるようにしました。オンライン上であっても、あたかも隔離された部屋にいるかのような没入環境を作り出すことで、コミュニケーションコストを最小限に抑えました。 2. プロセスの自由 「隔離」されたチームは、既存組織のルールに縛られず、最適なプロセスを選択できます。 タイミーの開発チームの多くは普段スクラム開発を採用していますが、今回のプロジェクトはハードデッドライン必達かつ手戻りが許されない状況でした。そこで、このチームに関しては普段のやり方に固執せず、PjM/PdMによる強力な進行管理のもと、ウォーターフォールに近い開発スタイルを採用しました。 このプロジェクト専用に最適化された独自のリズムで動くことで、迷いなくゴールへ突き進むことができました。 3. 邪魔をさせない メンバーが目の前の課題に集中できるよう、外部からの干渉を遮断することも重要です。 これについては、プロダクト組織のエグゼクティブ(CXOやVPoXなど)から、このプロジェクトが全イニシアチブの中で最優先事項であると定義・宣言してもらい、全プロダクトメンバーにその認識を持ってもらうことで実現しました。 トップダウンによる強力なバックアップがあったおかげで、他の運用業務や開発などの差し込みが入ることがなく、メンバーは余計なノイズに惑わされることなく開発に集中することができました。 当時は「間に合わせるためにはこれしかない」という必死の判断でしたが、結果としてアイソレーションパターンは極めて有効に機能し、厳しいデッドラインを守り切ることができました。 そして、このリチーミングにはもう一つ、私にとって嬉しい誤算とも呼べるポジティブな副産物がありました。 本には書かれていない「既存チーム」の進化 それは、EMとして最も懸念していた人を引き抜かれた側の状態についてです。 今回のケースでは、複数のチームからドメイン知識を持つメンバーが招集されました。私が管掌するチームからも、フロントエンド領域を専門とするメンバーが1人、プロジェクトにアサインされました。 専門領域を持つメンバーが抜けることで、「残されたチームでの開発は立ち行かなくなるのではないか?」という懸念がありました。 しかし、あくまで私の管掌範囲内での観測にはなりますが、蓋を開けてみると、そこには本には書かれていない意外な化学反応が起きていました。 1. 空白がオーナーシップを醸成 人が減ったことで、物理的にリソースが不足します。すると不思議なことに、「誰かが拾ってくれるだろう」という無意識の前提がなくなりました。 「自分が拾わないと落ちる」 そんな健全な危機感が生まれたように感じます。これはまさに、タイミーが大切にしている新しいバリューの1つ「ジブンゴト」が、極限状態で体現されたと思います。誰かに言われてやるのではなく、構造的な空白が、彼らのオーナーシップを引き出しました。 2. 越境文化がより強まった ここ1年半ほど、タイミーのSA(StreamAligned)チーム(※顧客価値に向き合う最小単位の開発チーム)では、領域を越境した開発が推奨されており、私自身もチームにそれを求めていました。特に今年は、AIコーディングツールの進化もあり、越境のハードル自体は下がっていました。 今回、フロントエンドの専門メンバーが抜けましたが、半分は意図的に、半分は状況的に、あえて即座にそのケイパビリティを持つバックフィルを用意しませんでした(もちろんうまくいかなかった時にサポートできるオプションは持ちつつ)。代わりに、メンバーにはこれを機に越境してほしいと伝えました。 その結果、移動したメンバーやFrontend Chapter(※職能ごとの横断コミュニティ)の力も借りながらではありますが、チームメンバー全体でフロントエンド領域のタスクを巻き取る動きが加速しました。リソースが足りないという状況が、結果としてチーム全体のフルスタック化を、実践レベルで前進させました。 3. MTGの発言量が爆増した 人数が多いMTGだと、どうしても一人ひとりの発言時間は少なくなってしまいがちです。 今回、リチーミングによりチーム人数が減ったことで、全員がより当事者としてスプリントゴールを目指す状況となりました。その結果、ほぼすべてのMTGでマイクをミュートにすることがなくなるほど、一人ひとりの発言量と議論の密度が劇的に向上しました。 まとめ:変化こそが、組織を強くする 今回の経験を通じて、アイソレーションパターンは単なる緊急時の対症療法ではないと痛感しました。 それは、重要なプロジェクトを成功させるための強力な武器であると同時に、既存チームに健全な揺らぎを与え、メンバーの新たな可能性を強制的に(しかしポジティブに)開花させるきっかけでもありました。 人が動くことで、組織全体の成果の総和は減るどころか、むしろ増える。 誰かが抜けた穴は、決してネガティブな空白ではなく、他の誰かが一歩前に踏み出すための「成長の余白」だったのだと思います。 本で理論を学び、現場で実践し、予想以上の成果を得る。EMとして、非常に学びの深い1年となりました。 組織の変化を恐れず、来年もダイナミックに挑戦していきたいと思います。 本質的な課題解決とメンバーの成長を両立させるダイナミックな組織運営に興味がある方、変化を楽しみながら成長したいと思っている方、ご興味があればぜひお話ししましょう! プロダクト採用サイトTOP カジュアル面談申込はこちら
アバター
1. はじめに 本記事は Timee Product Advent Calendar 2025 シリーズ1 19日目の記事です。 こんにちは。株式会社タイミーでiOSエンジニアをしている hayakawa です。 普段はiOSアプリの開発を担当していますが、弊社では職種の垣根を超えて異なる技術領域に挑戦する「越境」が盛んです。また、開発プロセス全体でAI・LLMを活用する流れも加速しています。 今回は、自身の技術領域を広げるためと、チームのケイパビリティ向上のために、Androidの実装を担当しました。本記事では、その際の実践的な知見やAI活用のポイントについて共有します。 2. 筆者のAndroidに関する前提知識 実装開始時点での私のAndroidに関する知識レベルは以下の通りです。 言語: Kotlin(Swiftと似ているという認識程度) UI: Jetpack Compose(SwiftUIに近い宣言的UIフレームワークという認識)。また、従来はXML(iOSのXIBやStoryboardのようなもの)を使って構築する手法があることも、知識としては持っている。 非同期処理: Coroutines(CombineやSwift Concurrencyの概念で理解) 開発環境: Android Studio(基本的な操作方法も不慣れな状態) 「概念は理解しているが、具体的なAPIやIDEの操作は手探り」という状態からのスタートでした。 3. 今回挑戦した実装内容 今回担当したのは、以下の2つの機能実装です。 ① 条件に応じた注意書き表示ロジック サーバーレスポンスに含まれる「未来の時間情報」に基づき、UIを出し分ける機能です。 現在時刻から指定時間までの「残り時間」をカウントダウン表示する。 端末の「通知設定(ON/OFF)」を取得し、文言を切り替える。 ② 条件に応じたUI制御とデザインシステムの拡張 サーバーレスポンスに含まれる特定の値に基づき、View内のコンポーネントを制御する実装です。 デザインシステムに新たなカラーバリエーションを追加定義する。 既存のリスト表示(RecyclerView)の一部に、Jetpack Compose化したViewを組み込む。 組み込んだView内に追加のコンポーネントを表示する。 なお、同様の機能をiOS版でも私が担当しており、そちらは「実装1日、レビュー・マージまで2日」で完了しています。iOS版の実装時点では、Android版はキャッチアップも含めてその1.5倍ほどの工数で完了すると予想していました。 4. AI活用の勘所:メンタルモデルに合わせた翻訳 実装は Claude Code と協調して進めました。 ここで効果的だったのは、単にコードを書かせるのではなく、 「自分の持っているiOSの知識とマッピングさせる」 というプロンプトの出し方です。 プロンプトの工夫:「iOSエンジニア向けに説明して」 具体的には、以下のような指示を行いました。(※例なので実際に入力したプロンプトとは異なります) Prompt: 「{SwiftのAPI名}を使って {やりたいこと} を実装したい。これを {KotlinのAPI名} を使ったコードと、Swiftの概念と比較した実装方針とコードを提示して このように依頼することで、AIは「StateFlowはSwiftでいうCurrentValueSubjectに近い挙動です」といった補足を加えてくれます。これにより、単なるコピペではなく、挙動を正しく理解しながら実装を進めることができました。 5. ぶつかった技術的・文脈的な壁 AIの支援があっても、スムーズにいかない場面がいくつかありました。 ① RecyclerViewとComposeの共存 最も苦戦したのは、既存のRecyclerViewの中にJetpack Composeで作ったViewを組み込む部分です。 SwiftUIであれば UIHostingController 等で比較的直感的にブリッジできますが、Androidの既存実装(ViewHolder)の中に、ComposeViewをライフサイクル的にどのように正しく配置するか 、という点は構文の違い以上に「作法」の違いが大きく、AIの出力したコードをそのまま適用するだけでは、ビルドエラーやレイアウト崩れが発生しました。 ② モデル名の不一致(ドメイン知識の欠如) また、プロジェクト固有の「命名規則」の壁もありました。 例えば、iOSで定義されているモデル名が、Androidでは少し違う名前になっているケースがありました。 例) iOS: ServiceRequest Android: RequestedService 私がiOSの感覚で「 ServiceRequest を拡張して」とAIに指示すると、AIはプロジェクト内に RequestedService が存在することを知らないため、 新しく data class ServiceRequest を定義してしまいました。 これは「AIはプロジェクトの歴史や文脈までは(コンテキストに含めない限り)知らない」という典型的な落とし穴でした。 6. 人間(Androidエンジニア)との協調 AIが出力したコードは「動く」ものの、それが「保守性の高いコード」であるかは別問題です。 そこで、Androidエンジニアのチームメンバーに対して、「同期的な相談」の時間を設けてレビューを依頼しました。 この時、私が意識して聞いたのは「合っていますか?」ではなく、以下の質問です。 「期待通りに動くんですが、Androidの流儀としてもっと良い書き方はありますか?」 AIは汎用的な正解を出しますが、現場のベストプラクティス(例えば、よりモダンなライブラリの選定や、プロジェクト独自の拡張関数の活用など)は、人間の方が詳しいケースが多々あります。このプロセスを経ることで、コードの品質を担保しました。 7. まとめ 今回の挑戦で得られた知見は以下の通りです。 AIは「言語の壁」を限りなく低くする Swiftの知識があれば、適切なプロンプトでKotlinのコードを生成・理解することは容易です。 ドメイン知識とアーキテクチャの理解は人間が補う必要がある モデル名の違いや、既存コンポーネント(RecyclerView等)との整合性は、AI任せにせず人間がハンドリングする必要があります。 「もっと良い書き方」は人間に聞く AIで「0→80点」まで持っていき、最後の「80→100点(最適化)」を専門家との対話で行うスタイルが非常に効率的でした。 AIという強力なパートナーがいれば、iOSエンジニアにとってAndroid開発(あるいはその逆)は、もはや高いハードルではありません。今後も積極的に技術領域を越境していきたいと思います。 タイミーではiOSエンジニアやその他のポジションを含めて採用活動中です! プロダクト採用サイトTOP カジュアル面談申込はこちら
アバター
こんにちは。タイミーでPlatform Engineeringグループのマネージャーを務めている橋本です。先日Architecture Conference 2025で「AI × Platform Engineeringでスケーラブルな組織を作るには」というテーマで発表する機会がありました。本記事では、その内容をもとにブログ記事として詳細にお話できる部分も交えてお伝えします。 登壇内容詳細は以下リンクのspeakerdeckも見ていただけると嬉しいです 😊 speakerdeck.com とはいえ長いので、以下に登壇内容をサマライズしたグラフィックレコーディング風の一枚絵(feat. Google Nano Banana Pro)も掲載します。 登壇内容のサマリー サマライズしすぎると解像度が粗くなってしまうので(& サマライズに少し誤りが含まれるため 😢)文章で補足をさせてください。 成長するプロダクトと組織が直面する課題 他の会社組織でも見られることかもしれませんが、プロダクトの成長に伴い、機能の増加や依存関係の複雑化、ガバナンス要求の増加などが発生し、開発者の認知負荷が高まります。 タイミーにおけるPlatform Engineering(PFE)チームの役割は、こうした認知負荷をオフロードし、開発者が価値提供に集中できるスケーラブルな基盤を提供することです。しかし、ここに大きなジレンマがありました。 PFE × スケーラブルのジレンマ 現在、PFEメンバーは開発組織全体の約5%程度で、開発者と20倍近い人数差があります。開発者を手厚く支援しようとするとPFE自体がボトルネックになってしまいますが、かといって人を増やすのも簡単ではない。いわば「がっつり支援したいけれど、やりすぎるとパンクしてしまう」というジレンマです。 特定チームに深く入り込む「Embedded」型の支援は手厚いですがコストが高く、リソースが枯渇しやすい。一方、ツールや基盤を提供する「XaaS」型はスケーラブルですが、個別具体のコンテキストに対応しにくいという限界がありました。この一例として、弊社、古屋の ブログ記事 に書かれており、以下のようなお話です。 第一段階は私が作った本人でもあることから期待通りになることはすんなり確認できましたが、第二段階ではやはり S3 に関する知識が十分にない状態ではいくらサンプルコードがあっても書くのは難しいと改めてわかりました。 さて、現状はXaaS化を強力に推進しなければチームリソースが枯渇して回らなくなる、というところまでには至っていません。しかし将来、プロダクトや組織のスケーラビリティにPFEのスケーラビリティが追いつけなくなることが想定されます。 AIで突破する:新しい支援モデルの構想 そこで現在進めているのが、「このジレンマ、AIでなんとかならないか?」というアプローチです。とはいえ、この考え自体はあまり目新しさはないかもしれません。 具体的には、DevinのようなAIエージェントをチームの一員として機能させます。以下の絵が全体的なイメージです。なお、Devinを必ずしも使う必要はなく、CursorやClaude CodeなどのCoding AgentとコードのCloneによっても代替可能です。ここでは、ChatOpsな体験が良いこともあり、Devinを採用しています。 そして、左右で仕組みのカタマリが異なり、以下の絵のようになります。 右側:AIが調査・ドキュメント化 現在のリソース設定(As-Is)をAIが出力する仕組みです。ここでの”AI調査”はKiro CLI(Q Developerと呼ばれていたプロダクト)を中心に実現されます。なお 詳細は後述します。 AIはプロンプトに従ってAWS Resource Explorerなどを通じて、実際のクラウドリソースの設定状況(As-Is)を調査し、ドキュメントを生成します。 左側:人間が補足を記述 右側で生成されたドキュメントを元に「なぜこの設定なのか」というコンテキスト(Design Addendum)をPFEエンジニアが書き加えるフェーズです。ここで最大のポイントは、「設定値(As-Is)」だけでは不十分だということです。 「なぜその設定になっているのか(Why)」という背景情報は、設定ファイルの外側 にしかありません。 ドキュメント化のループと回答フロー 以下のようなループが回るイメージです。 AIが調査・ドキュメント化 人間が補足(Addendum)を記述 1 - 2を繰り返すループ AIが統合: これらを統合して、AIが開発者の質問に答える 開発者がAIに質問を投げかけると、Devinを通じてGitHub上の「As-Isの設定ドキュメント」と「Whyの補足情報」が統合されて回答されます。 例えば、開発者が「本番環境の〇〇という名前のS3バケット、なんでPublic Accessブロックされてるの?」と聞いた時に、AIが「それは〇〇というセキュリティ要件のためです」と即答できるようになります。また、ここまで背景を理解していれば、IaCコードの自動生成もスムーズになるため、柔軟な要件定義と実装出力(IaCコードを生成するなど)をAIが行うことも可能になるのではないかと考えています。 細かな実装について ここで、登壇で細かくお話できなかった以下の図の赤い点線枠内にフォーカスを当ててお話しします。 詳細なフロー図は以下になります。 Kiro CLI(Q Developer)は必要か? 今までの流れで「Kiro CLIを使うの?terraform/HCL + Coding Agent + MCPでもできるのでは?」と思われた方もいるかと思います。このブログ執筆時点では、Kiro CLIの方が適していました。AWSの設定確認をAIが行う上で必須となる awscli等の知識をKiro CLIは事前学習済みである ことがスムーズな仕組みに繋がっています。その他のCoding Agentを用いた場合でも AWS Knowledge MCP Server やInternet上の情報等を使うことによって同様の動きにはなるのですが、 オーバーヘッド・試行錯誤が多発する 点が無視できない(図で言う"いろいろ大変"な)部分でした。 なぜAWS Resource Explorerを使うの? Resource Explorerの詳細については、弊社、佐藤の ブログ記事 をご覧ください。AIにAWSリソースを調査させる場合、問題になるのはどのリソースが作成されているかという前提知識がないことです。正攻法でいくのであればAWSの全サービスに対してCrawling(list API)をしていくことになりますが、オーバーヘッドが大きく、regionも加わると対象は膨大です。Resource Explorerが管理するリソースは、ユーザー(我々)が作成したリソースがほとんどであり、Index化されたリソース情報を容易にリストで取得できることが利点です。Resource Explorerは各リソースの情報は持たず、あくまでどんなリソースがどのARNで作成されているかを得るためのIndexとして使っています。 SQLite(sqlite3)は何のために? 当初実装時は、AIにプロンプトを通じてResource Explorerを参照させていました。ただ、APIの返却上限が1,000件のリミットがあったり、ページネーションの挙動などが間に挟まっていると取得挙動が安定せず、あるタイミングで実行した場合には5,000件のリソース取得が期待されるのに、次は3,800件しか取れていないなど、件数が毎回変わる不安定さが見られました。 そこで、ローカルキャッシュとしてSQLiteを使い、ツールで定型的にResource Explorerから取得しsqlite3にデータを保持する仕組みとしました。AIはスキーマやデータ構造をコンテキストとして渡した上で対象をグループ(S3、IAM、RDSなど)化してSQLで取得し、調査をさせることが容易になりました。(もちろん、これらのツールもAIに生成・メンテナンスさせます) いろいろお膳立てをして満を持してAIが 上記のように、アレコレとお膳立てをしてAIが処理しやすい前捌きをしながら、ドキュメント化をさせる機構を作り上げています(まだ絶賛作っている最中で、試行錯誤のタイミングです)。今年の夏頃から徐々に作ったり試行錯誤をしていますが、AIの進化(Q Developerの登場)やAIが取り扱えるコンテキスト量の増加(Claude Sonnet4.5の1Mなど)などの外部環境により改善が一気に進むことを目の当たりにしています。CodingAgent / AI Modelの進化と一緒に暫くは改善・改良を進めていくことになりそうです。 AI時代の新しいPlatform Engineering この仕組みによって、これまで「コストが高いから乱発できない」としていた「Embedded(埋め込み型支援)」を、AIが肩代わりしてくれることが期待されます。AIがドメイン知識やインフラの現状を把握していれば、極端ですが24時間365日、各チームに「Embedded」し続けることができるのです。 これにより期待できる効果は以下のようなものであり、開発者に対する支援だけではなく、PFEチーム内の知識共有やマネージャー・監査部門による確認なども、より気軽に・低コストにできる未来があるかもしれません。 確認・学習コストの低下: 開発者がAI経由で「Why」を学べる 知識共有の加速: PFE内の知識がAIに集約され、担当交代やスケーリングが容易になる 監査・統制: 設定意図が明確になり、監査にも活用できる まとめ Platform Engineeringは開発者の認知負荷を下げるためにありますが、PFEチーム自体がボトルネックになりがちです。この「人のスケーラビリティ」の限界を、「AI支援によって突破する」。これこそが、AI時代の新しいPlatform Engineeringの形になるかもしれないと考えています。 AIを活用することで、これまでコスト面で難しかった「手厚い支援」を擬似的に実現し、開発者がフルサイクルに活躍できる環境を作る。タイミーでは、こうした新しいチャレンジに一緒に取り組んでくれる仲間を絶賛募集中です! プロダクト採用サイトTOP カジュアル面談申込はこちら
アバター
この記事は Timee Advent Calendar 2025 シリーズ 2 の18日目の記事です。 はじめに こんにちは、タイミーのDREチームのchanyouです。データ基盤の開発・運用を行っています。 社内向けのAIエージェントの開発プラットフォームを構築したので、その内容をご紹介します。 なお、この記事は人力で書きました。 「AIエージェント開発プラットフォーム」を作った背景 データ活用の新たなアプローチとして AI エージェントを位置づけ、そのために AI エージェント開発プラットフォームを作りました。ここでは、その背景に触れていきます。 データ基盤のこれまでと生成AI タイミーでは、RDB に保存されたマッチングの記録やCRM に保存された営業の商談記録といった多様なデータを BigQuery に集約し、あらゆる業務で活用しています。 DRE チームではデータの集約を担当しつつ、 BigQuery に集まったデータを dbt を使ってセマンティックレイヤー 1 という形で整え、 Looker で BI として社内に提供しています。 これまでは人間向けにセマンティックレイヤーを作り込んできましたが、複雑なロジックでも一貫した結果を出力できるセマンティックレイヤーは、生成 AI にとっても有用 2 だと考えています。 特に AI エージェントは業務に与えるインパクトが大きいと思われるので、セマンティックレイヤーをAIエージェントが参照できるようにしたいと考えました。 外部サービスを導入するか、内製か 外部サービスの導入で解決できる領域も広い一方で、社内データをセマンティックレイヤーを通して生成AIで利用するソリューションには、まだ決定的なものがない印象です。 生成AIを取り巻く環境の変化は早いとはいえ、ソリューションを待つのも時間がもったいないです。ここは内製に振り切って、AIエージェントが使える未来に到達してしまって、課題を先回りしてつぶしておきたいと考えました。 気軽に作って壊せる開発プラットフォームを作る 単体の AI エージェントで Looker に接続できる構成を磨き込む、という選択もできました。 ただ、将来を見据えると AI エージェントで解ける課題は山積しており、AI エージェントをいくつもデプロイできる構成のほうが望ましいです。技術的にも、 A2A プロトコルの実証など、試したいことは多くあります。 このことから、カジュアルに作って壊せる、社内向けの AI エージェントを早く手軽に開発・運用できるプラットフォームを作りました。 「AIエージェント開発プラットフォーム」の解説 利用イメージ 社内利用のためリッチなUIは求めておらず、普段の業務の延長で AI エージェントを利用できる状態を作りたかったので、ユーザーインターフェイスは Slack に振り切りました。 以下の画像のように Slack で利用できるようになっています。 Devin のようにSlack Bot にメンションをするとスレッドが作成されて、AIエージェントとやり取りできます。 画像にはありませんが、人間と会話しているスレッドの途中で AI エージェントにメンションすると、新しいスレッドを作成して会話を行うこともできます。 AI エージェントとの会話の単位をセッションと呼びますが、このプラットフォームでは Slack のスレッドごとにセッションを作成する方針としました。Slack の同一スレッドであれば、AI エージェントはコンテキストを汲み取って会話を継続してくれます。 Slack に振り切ることで、Webでチャットインターフェースを構える場合と違い、実際にAIエージェントが利用されている様子が確認できて、その場でフィードバックを受け取れたりサポートできたりして、開発者としても体験が良かったです。 インフラアーキテクチャ インフラアーキテクチャは以下の通りです。 graph RL subgraph Slack["Slack Workspace"] Bot[Slack Bot] User[User] end subgraph GCP["Google Cloud Platform"] AE[Vertex AI Agent Engine<br/>ADK] CR[Cloud Run<br/>Slack Bolt App] end User --> |Mention| Bot Bot --> |POST /slack/events| CR CR --> |Query| AE AE --> |Use tool| AE AE --> |Response| CR CR --> |Reply| Bot Bot --> |Display| User style CR fill:#ffeaa7 style AE fill:#74b9ff style Bot fill:#00b894 ユーザーインターフェイスとして Slack Bolt アプリケーションを構築し、その背後に AI エージェントフレームワークである ADK(Agent Development Kit)の実行環境を構築する構成としました。 Slack Bolt アプリケーションの実行環境は Cloud Run を、 ADK の実行環境は Vertex AI Agent Engine を採用しました。 Agent Engine には、AI エージェントとの継続した会話に必要なセッションストレージも内包されており、永続化のためのデータベースを別途用意する必要がなく、非常に手軽に AI エージェントを運用できます。 Cloud Run と Agent Engine が各エージェントごとにデプロイされる構成としています。 リクエストからレスポンスまでの流れは以下の図の通りです。 sequenceDiagram participant User as User participant Slack as Slack Bot participant CR as Cloud Run<br><br>Slack Bolt App participant AE as Vertex AI Agent Engine<br><br>ADK App User->>Slack: "@hello-world-agent 天気を教えて" Slack->>CR: POST /slack/events CR->>AE: クエリ送信 AE->>AE: エージェント処理<br/>ツール実行 AE-->>CR: 応答 CR-->>Slack: 応答を返す Slack-->>User: 応答を表示 コード管理 コード管理はモノレポ構成を採用しています。 Slack Bolt アプリケーションのコードは共通化しており、Slack Bot の挙動(何をトリガーに、どのように返信するか)は AI エージェントによらず共通としています。 AI エージェントの開発者は、 Slack のイベントハンドリングを意識せず、エージェントの開発に集中することができます。 プレビュー環境 AIエージェントの開発に限らず、Coding Agentのおかげで日々の開発スピードは格段に向上しました。 ただ PR がすぐに作れてしまうので、コードレビューがボトルネックになってくる場面が増えてきました。 レビュー負荷を軽減するために PR ごとにプレビュー環境を作成して、各ブランチの動作確認を Slack でできるようにしました。 Slack Bot 宛のメッセージで @hello-world-agent [PR-123] こんにちは のように [PR-番号] を含めることで、その PR の AI エージェントとして振る舞ってくれます。 Slack Bolt アプリケーションで PR タグの有無を確認して、タグを含む場合はプレビュー環境宛にルーティングする仕組みとしています。 プレビュー環境へのリクエストからレスポンスまでの流れは以下の図の通りです。 sequenceDiagram participant User as User participant Slack as Slack participant CR as Cloud Run<br><br>main participant PreviewCR as Preview Cloud Run<br><br>PR-123 participant PreviewAE as Preview Agent Engine<br><br>PR-123 User->>Slack: "@hello-world-agent [PR-123] 新機能をテスト" Slack->>CR: POST /slack/events CR->>CR: PR-123 タグを検出 CR->>PreviewCR: HTTP転送 PreviewCR->>PreviewAE: クエリ送信 PreviewAE->>PreviewAE: エージェント処理<br/>新機能で応答 PreviewAE-->>PreviewCR: 応答 PreviewCR-->>Slack: 応答を返す Slack-->>User: 応答を表示 「AIエージェント開発プラットフォーム」の成果 DRE チームではこの開発プラットフォーム上で、Looker で参照できるデータをもとに営業活動をさらにスムーズに行えるような AI エージェントを開発しています。全社的に展開して利用いただいており、まだ伸びしろはありますが、社内業務の効率化に寄与しています。 Looker を参照しているため、 AI エージェントの応答に含まれる数値に一定の信頼が置けています。これを取得したい指標ごとにクエリを用意するなどしていたら、心が折れていたと思います。セマンティックレイヤー様々です。 また開発者目線では、MCP Tool と Function Tool の使い分けやユーザーの認証情報の取り回し、マルチエージェントシステムのデザインパターンなど、 AI エージェントを使ったアプリケーションを開発する上で学ぶべき点が多々あります。これらの手法をすぐに試して勘所をスピーディに掴めるようになりました。 今後の課題 AIエージェント開発プラットフォームにより、作って使えるまでは爆速で行えるようになりました。 一方で、まだAIエージェントを評価する環境がプラットフォームとして整えられていません。 AIエージェントの評価は、プロンプトのチューニングや基盤モデルの変更の際のリグレッションを防ぐためにも重要なので、評価手法を確立してプラットフォームで下支えしていきたいと思います。 まとめ 今回開発したプラットフォームを通して、データ活用のアプローチとしてもAI エージェントは非常に強力であることが分かりました。しかし、AI エージェントがデータを使った業務を支えるためには、一貫した結果を扱えることが前提にあると実感しました。(毎回ブレブレの回答をされると信頼できなくて使えない) AI エージェント開発プラットフォームが整ったことで、さらにセマンティックレイヤーの重要性が増したと思いました。引き続きプラットフォームを育てつつ、セマンティックレイヤーの拡充も進めていきたいと思います。 AIエージェントを通したデータ基盤のさらなる活用に興味のある方、ご興味があればぜひお話しましょう! 下記よりカジュアル面談がお申込みいただけます。 product-recruit.timee.co.jp プロダクト採用サイトは以下よりご覧いただけます。 product-recruit.timee.co.jp セマンティックレイヤーとは、データ加工処理において、データをビジネス用語や概念に紐づけるレイヤーのことを指します。ビジネス用語や概念の定義をコードで一元管理し、タイミーでは Looker から参照するようにしています。これにより、例えば「売上」といった単純そうで意外と定義が揺れがちな指標の定義を固めておくことで、全社員が Looker を通して共通の指標を見ながら会話することができます。 ↩ もちろんBigQuery へのクエリを直接 Text-to-SQL させるアプローチもありますが、複雑なドメインロジックを全て Text-to-SQL させるのは、クエリ結果の信頼性を担保するのが難しいと考えています。 ↩
アバター
この記事は Timee Product Advent Calendar 2025 の18日目の記事です。 評価業務、面倒ですよね 社会人になってから、特に苦手になった言葉があります。 「個人目標」「評価」の2つです。 「自己評価」「振り返り」など会社によって呼び名は違えど、自身の四半期〜1年程度の期間に実施した業務や成果を上司に報告する機会は、正社員として働いている方にはほぼ必ず巡ってくることと思います。 私も例に漏れず、少なくとも15年以上は評価されたり評価したりしながら過ごしてきました。とはいえ、被評価者のキャリアアップなど目的は会社のためだけでは無いことは理解しつつ、評価期間に費やす時間・マインドシェアを削減して顧客への価値提供に投下するリソースを最大化する術が無いか、というテーマについて日々思考しています。 そんな中でやってきたのが、AI・LLMの波です。評価業務に割くリソースを最適化するチャンスと見て、私は飛びつきました。 というわけで、手探りで実施した自己評価業務におけるAI活用事例を紹介します。 自己評価におけるAIの使いどころ GeminiやChatGPTのようなAIは「私の四半期分の自己評価をまとめたドキュメントを作って」とプロンプトで依頼すれば、過去に自分が彼らに相談した内容からそれっぽいものを作ってくれます。ただ、実際の自身の活動をまとめる上では与えている情報量が足りないので、もっともらしい誤りの内容が出力されてしまうんですよね。 そこで、いかに私の情報をAIにたくさん与えるか、という観点で考えるアプローチにしています。情報源は自らがActionとしてたくさん書き出しておき、それらを会社制度に合わせた観点でまとめてスコア付けをする箇所をAIに任せる形です。 先に言っておくと、このアプローチにかかる労力は決して軽くはありません…。ただし、精神的な負担はかなり軽減された、と私は感じています。 実施手順 以下は2025年10月時点で自己評価をする必要がある組織を想定して記載しています。 AIはCursorというツールでSonnet 4.5(2025年10月時点)を利用して実施しましたが、ローカルにあるファイルを参照できるツールであれば他のツールでも応用可能だと思います。 自己評価の準備手順 自己評価用のディレクトリを作成(1分) 任意のディレクトリに作業用のディレクトリを作成( ~/Documents/workspace/cursor など)し、その直下に「202510_自己評価」というディレクトリを作成 評価に関係する社内ルールをMarkdown形式で書き出す(10分) 「キャリアラダー」ディレクトリ 社員が属するグレードごとに求められる要件をまとめた資料 全グレード分用意 面倒な場合は自分のグレード±1グレード分だけで良いかも バリュー.md ※2025年11月にバリューが更新されたため、現在のバリューとは異なっています 2025年10月時点の弊社のバリューは上記の4つ バリューのタイトルだけでなく、その詳細もセットで書いておく 個人目標ディレクトリを作成(1分) OKR_FY2025_2ndHalfディレクトリに、今期用のOKR目標2つ分のMarkdownを保存 弊社は「期待役割」という名称でも別の目標管理が実施されているため、期待役割_FY2025_2ndHalfディレクトリに今期用の期待役割3つ分のMarkdownを保存 日常的にアクションを書き溜めるためのディレクトリを作成(1分) 「Actions_FY2025_2ndHalf」ディレクトリを作成しました。 自己評価用ディレクトリのルート階層に、サブディレクトリごとの説明を書いたREADME.mdファイルを作成(15分) 上記1.で作成した作業用のディレクトリに内包しているディレクトリ・ファイルの説明用のMarkdownを「README.md」というファイル名で作成しました。 このディレクトリに含まれるファイルの概要は以下の通りです。 ## Actions_FY2025_2ndHalf FY2025下半期に実行した主たるアクションが一つ一つファイル化されているディレクトリ。 ## キャリアラダー 私が所属する企業であるタイミーの評価制度に用いられる、各グレードに期待される働きの定義群がまとまっているディレクトリ。 ## バリュー.md 私が所属する企業であるタイミーにおいて行動の基準となるバリューの定義。 ## 期待役割_FY2025_2ndHalf FY2025下半期の自身のグレードや職能を踏まえて自身に期待されるであろう役割を自ら想定した内容が記載されているファイルをまとめたディレクトリ。 期待役割は◯◯、◯◯、…のn軸から選択でき、その詳細は上記「キャリアラダー」ディレクトリに含まれるファイルにグレード毎に定義されている。 ## OKR_FY2025_2ndHalf FY2025下半期の目標として定めて取り組むOKR目標とその結果をまとめるディレクトリ。 日常的にアクションを書き溜める 評価対象期間(弊社の場合は3ヶ月)ずっと書き足していく必要があります。 1クォーターあたりだいたい10アクション程度の量感を目指して書いています。 個人目標に進捗があり次第、上記2.で書き出した個人目標のMarkdownファイルを更新 上記の手順をすべて実施すると、以下のようなディレクトリ構造が出来上がります。 202510_自己評価/ ├── README.md ├── Actions_FY2025_2ndHalf/ │ ├── アクション1.md │ ├── アクション2.md │ ├── アクション3.md │ └── ... ├── キャリアラダー/ │ ├── グレード1.md │ ├── グレード2.md │ ├── グレード3.md │ ├── グレード4.md │ ├── グレード5.md │ └── ... ├── バリュー.md ├── 期待役割_FY2025_2ndHalf/ │ ├── 期待役割1.md │ ├── 期待役割2.md │ └── 期待役割3.md └── OKR_FY2025_2ndHalf/ ├── OKR1.md ├── OKR2.md └── OKR3.md 自己評価をまとめる手順 「202510_自己評価」ディレクトリにself-assessment.mdを作成 self-assessment.mdに以下の情報を記入 # 前提 私のグレードは以下のとおりです。 - Grade: ◯◯ - Rank: ◯◯ # 自己評価スコア > Self assessment of Abilityは、以下の7項目から選択して採点して下さい。 > 期待通りが4で、それを軸に期待を上回ったか、下回ったを総合的に判断して下さい。 > > - 7. Extremely exceeds expectations > - 6. Greatly exceeds expectations > - 5. Exceeds expectations > - 4. Meets expectations > - 3. Less than expectations > - 2. Greatly less than expectations > - 1. Extremely less than expectations > > Self assessment of Valueは、以下の5項目から選択して採点して下さい。 > 期待通りが3で、それを軸に期待を上回ったか、下回ったを総合的に判断して下さい。 > > - 5. Greatly exceeds standard > - 4. Exceeds standard > - 3. standard > - 2. Less than standard > - 1. Greatly less than standard ## Self assessment of Ability **## Self assessment of Value(理想ファースト) ## Self assessment of Value(やっていき) ## Self assessment of Value(バトンツナギ) ## Self assessment of Value(オールスクラム) # 上記のスコアを付けた理由の深堀り ## 自己評価の背景 ## 自身の振り返り ### 期待役割に対する振り返り ### OKRに対する振り返り ### 総合的な振り返り** Cursorにself-assessment.mdを執筆するよう指示する 私はiOSアプリエンジニアをしています。 この会社の評価制度の中で、現在は自己評価期間となっています。2025年5月から2025年10月までの間に実施した業務と、期首に設定したOKRや期待役割の定義、更にキャリアラダーに基づいて、自己評価をself-assesment.mdファイルにまとめようとしているところです。 202510_自己評価ディレクトリのファイルを網羅的に参照して、私の自己評価業務を手伝うべく、このself-assessment.mdファイルの内容を埋めて下さい。 202510_自己評価ディレクトリに保存されているファイル群の概要は、202510_自己評価/README.mdにまとめてあります。 記入された自己評価をレビューし、違和感がある箇所を後続のプロンプトで手直しさせる 初回は自身の直感と異なるスコア付けがされていたので、こんなプロンプトで調整を加えていきました。 嬉しいんですが、本当にそうですか?さすがにほとんどの項目が最高評価だと、ちょっと疑わしいと感じてしまいます。もっと厳しい目線も加えてもらえませんか? 今のSelf assessment of Abilitのスコアは◯◯ですが、このスコアを+1するとしたらどんな懸念がありますか? 会社が用意した壁打ち用のAIにself-assessment.mdをレビューしてもらい、受けたフィードバックのうち妥当だと感じるものをCursorにプロンプト経由でフィードバックする 会社が用意した壁打ち用の生成AIに現状のself-assessment.mdをレビューしてもらいました。 以下のフィードバックを取り入れたいと思っています。 (以下、壁打ちAIのフィードバックのうち自身が共感した内容をコピー&ペースト) 以降、Cursorが手直ししたself-assessment.mdと壁打ち用AIの間を気が済むまで往復する 今期の自己評価のために用意したファイル群は、来期の目標設定でも役立つ 自己評価が終わるとすぐに待っているのが、目標設定業務です。 前期の評価に対して上司からもらったフィードバックを 202510_自己評価/self-assessment.md に記入しておくと、目標設定業務でそれが大いに役立つことになります。 具体的には、 202604_自己評価 ディレクトリを作って 202510_自己評価 と同様のディレクトリ構成を完成させた上で、以下のようなプロンプトでCursorに相談して目標設定を進めました。 @202510_自己評価/self-assessment.md ここに前期の自己評価と、私の上長から頂いたフィードバックが記載されています。 この内容を基に、202604_自己評価ディレクトリにOKRと期待役割を記入したいです。 どのように進めるのが良いでしょうか? 目標設定については詳細を省きますが、AIが目標設定の進め方を作業レベルまで落とし込んだり、OKR・期待役割のdraft版を提案してくれたりしたので、それらをレビューして調整を繰り返す形で目標設定を終えることができました。 感想 事前準備が全手動なので、トータルの労力としてはそれほどラクではありません。しかし、その事前準備で一番労力のかかる“日常的なアクションの記録”は、例えAIを活用しない場合であっても有効な手段ですし、実際に私は評価業務にAIを活用する前から実施していたことなので、AIを使うために大変になったわけではありません。 そして前述の通り、評価業務に挑む気持ちの面ではかなりラクになったと感じています。人間は事実を記録することに専念して、その事実が会社のキャリアラダーやバリューに沿っているかを客観的に評価する仕事をAIに任せたことで、評価業務においてクリエイティブな領域の多くをAIに頼れたからです。「やれば終わる」という作業的な仕事なら見積もり・見通しも立てやすいですしね。 直近の評価期間から、会社から公式に壁打ち用のAIが提供されたことも追い風になったなと感じています。 会社の評価指標情報は自身でそれなりに網羅的にAIに提供できているつもりですが、それでも壁打ち用AIにレビューさせてみると、別の観点でのフィードバックを受けることが多かったです。そういった評価観点の欠損をAI間で補うループが作れたことで、自身の労力を多く割かずともどんどん自己評価の精度が上がっていく工程は、気持ち良さすら感じる時間でした。 …ただ、たまに「来期は◯◯の研修を受けます」といった私が希望していないNext ActionもAIによって記入されていたので、AIによって記入された内容のレビューには気を抜けません。 こうしてAIを活用して制作した私の自己評価は上司のレビューを比較的スムーズに通過し、結果的に評価期間中も私が本来やりたいと感じていた業務に多くの時間を割くことができました。 開発業務をAIの力で効率化する話はよく挙がりますが、会社員として働くエンジニアの仕事は開発だけではないはずです。 この記事を読んだ皆さんに「自分が苦手な業務をどうにかAIに助けてもらえないか」と思考をしてみるきっかけにこの記事がなっていれば幸いです。 お話ししましょう! 私、岐部( @beryu )はタイミーでiOSアプリエンジニアをしています。iOSアプリ開発の中でのAI活用の情報共有だったり、評価業務の悩みを誰かに話したいだけでも結構ですのでw、ご興味があればぜひお話ししましょう! プロダクト採用サイトTOP カジュアル面談申込はこちら
アバター
この記事は Timee Product Advent Calendar 2025 16日目の記事です。 はじめに 株式会社タイミーでAndroidエンジニアをしているみかみです。今年からはiOSの機能開発にも携わっています。社外ではKotlin Multiplatformを用いた開発やDroidKaigiスタッフとしての活動など、技術とコミュニティの両面から開発に関わっています。 今年は、try! Swift Tokyo 2025とDroidKaigi 2025の2つのカンファレンスに参加しました。どちらも現地ならではの熱気があり、エンジニアとしての視野を広げる貴重な経験でした。技術に向き合う姿勢や、コミュニティの多様さに触れて多くの刺激をもらいました。 本記事では、それぞれのカンファレンスを通じて感じたことや印象に残った出来事、そして今後の活動について振り返ります。 try! Swift Tokyo 2025 去年に引き続き、 try! Swift Tokyo 2025 に参加しました。英語での発表や海外からの参加者も多く、他の国内カンファレンスと比べても国際的な雰囲気が際立っていました。セッション後のASK THE SPEAKERエリアでは、登壇者に質問をする参加者の姿も見られ、登壇者と参加者の交流が活発だったのも印象的です。さらに、カンファレンスアプリには翻訳サービスの Flitto が導入され、セッションの内容をリアルタイムで翻訳して表示する機能が提供されていました。 tryswift.jp セッションはモバイル開発を中心に、Swiftという言語がもつ表現力や技術の進化を感じさせるものが多くありました。Androidエンジニアとして特に気になったのは、「 Swift × Android: Skipが切り拓くクロスプラットフォーム開発の未来 」や「 Foreign FunctionとMemory APIとSwift/Java相互運用性 」といったセッションです。2025年には、SwiftでAndroid開発を公式にサポートすることを目的とした「 Android Workgroup 」の発足も発表されたことも記憶に新しく、Swiftのモバイル領域における立ち位置が変わってきていると実感します。 また、元AppleのデザイナーであるSebastiaan de Withさんの「 素早く実現する優れたアプリデザイン 」も印象的でした。このセッションでは、アプリを単なるツールではなく「アート」として捉え、作り手の情熱やこだわりがユーザーの感情に「共感」する体験を生み出すことの大切さが語られました。こうした視点は、日々の開発業務に追われているとつい忘れがちになるため、プロダクト開発の原点に立ち返る良いきっかけとなりました。 www.youtube.com セッション以外にも、参加者同士の交流を目的としたイベントがいくつかあり、Day 2のパーティやSTORESさん主催のランチイベントにも参加しました。さまざまな企業のiOSエンジニアと開発の話や日常の雑談を交わせたのは貴重な機会でした。立場やプラットフォームを越えた交流を通じて、多くの新しい視点や刺激を得られました。 DroidKaigi 2025 続いて、DroidKaigi 2025にもオフラインで参加しました。 今年もPRチームのボランティアスタッフとして、SNSでの広報や動画収録、YouTube配信のサポートなど、さまざまな活動に携わりました。会場ではカメラを手に歩きながら、たくさんの人でにぎわう様子を眺めたり、スタッフ同士で撮影の段取りを確認したりしていました。 スタッフ業務が中心だったためセッションはあまり聞けませんでしたが、YouTubeでの公開が非常に早く、後からセッションを視聴できたのは助かりました。扱われていたトピックは幅広く、Androidの技術的な深掘りだけでなく、デザインやプロダクト開発、チーム運営やキャリアなど、多様なテーマが取り上げられていました。セッションの感想については、ブログ「 DroidKaigi 2025 参加レポート〜Part 1〜 」でも紹介しています。 tech.timee.co.jp また、今年の登壇者でありAndroidのGDEでもある skydoves さんが執筆した 「Manifest Android Interview」の日本語翻訳 を、DroidKaigiに合わせて進めました。会期中に直接お話しする機会もあり、言語や立場を越えて技術を共有する楽しさを改めて感じました。 引用元: DroidKaigi 2025 エンジニアだけでなく、デザイナーや学生、スポンサー企業の方々など、多様な立場の人がそれぞれの形で関わり合い、学びや交流を楽しんでいたのが印象的でした。技術を軸にしつつも、人とのつながりや会場の温かい雰囲気が心に残るカンファレンスでした。 参加を通して感じたこととこれから カンファレンスに参加すると、技術への意欲が改めて湧いてきます。近年は国内外を問わず、多くのカンファレンスでセッション動画がすぐにYouTubeに公開され、オンラインでも学びやすい環境が整ってきました。 それでも、会場での偶発的な出会いや、リアルタイムで熱を共有する体験には、やはり特別な価値があると感じます。多くの人とコミュニケーションを取る中で、技術やコミュニティに向けられた熱意を肌で感じました。そうした空気に触れるうちに、自分も少しずつ新しいことに挑戦していきたいという気持ちが生まれました。前々から関心のあったOSSへのコントリビュートや海外カンファレンスへの参加など、機会を見つけて取り組んでいけたらと思います。 現在は技術コミュニティで繋がったメンバーを中心に、自分たちが「今欲しい!」と思えるAndroid開発書籍の執筆を進めています。主にテストに関する章を担当しており、着実に形にしていけるよう取り組んでいます。 技術の進化が加速する中で、学ぶことの楽しさや、人とのつながりから生まれる刺激の大きさを改めて感じました。興味を持ったことには素直に手を伸ばしながら、学びや挑戦の輪を少しずつ広げていければと考えています。 おわりに 改めて、技術カンファレンスは知識を得るだけでなく、人とつながり、自分の視野を広げるための場だと感じました。try! Swift TokyoもDroidKaigiも、参加するたびに多くの刺激と学びをもらっています。これからも、その刺激を自分の原動力として、日々の活動を続けていきたいと思います。 最後になりますが、株式会社タイミーでは、現在iOS/Androidエンジニアを募集しています。 「まずは話を聞いてみたい」というだけでも大歓迎ですので、少しでも興味を持っていただけたら、ぜひ採用ページをのぞいてみてください! hrmos.co hrmos.co
アバター
こんにちは、タイミーでバックエンドのテックリードをしている新谷 ( @euglena1215 ) です。 タイミーでは、 dependabot による依存ライブラリのアップデート PR に対して、Devin による自動レビューを導入しています。しかし、CI が失敗しているにもかかわらず、「本プロジェクトへの影響は低いと判断します」というコメントがついてしまうケースがありました。 これはレビュー時点では CI が完了しておらず、Devin がコードの差分だけを見てレビューしていたことが原因です。この問題を解決するために、CI 完了後にレビューを実施するよう、ワークフローを修正しました。 方法 従来の実装 従来は pull_request イベントの opened をトリガーにしていました。 on : pull_request : types : - opened この場合、PR が作成された直後にレビューが開始されるため、CI の結果を考慮することができません。 改善後の実装 workflow_run イベントを使用して、CI ワークフローの完了をトリガーにするように変更しました。 on : workflow_run : workflows : [ "ci branch" ] types : - completed branches : - 'dependabot/**' workflow_run イベントは別のワークフローの完了を待ってから実行されるため、CI の結果を含めたレビューが可能になります。 PR情報の取得 workflow_run イベントでは github.event.pull_request が使えないため、 gh コマンドで PR 情報を取得する必要があります。 - name : Get PR info id : pr-info env : GH_TOKEN : ${{ secrets.GITHUB_TOKEN }} run : | PR_INFO=$(gh pr list \\ --repo my-org/my-repo \\ --head "${{ github.event.workflow_run.head_branch }}" \\ --state open \\ --json number,title,url \\ --jq '.[0]' ) if [ -z "$PR_INFO" ] ; then echo "No open PR found for branch ${{ github.event.workflow_run.head_branch }}" echo "skip=true" >> "$GITHUB_OUTPUT" exit 0 fi { echo "skip=false" echo "number=$(echo " $PR_INFO" | jq -r '.number' )" echo "title=$(echo " $PR_INFO" | jq -r '.title' )" echo "url=$(echo " $PR_INFO" | jq -r '.url' )" } >> "$GITHUB_OUTPUT" ポイントは github.event.workflow_run.head_branch でブランチ名を取得し、そこから gh pr list で該当する PR を検索している点です。 CI結果の取得 CI の結果は github.event.workflow_run.conclusion で取得できます。さらに、失敗したジョブの一覧も取得してレビューの参考情報として渡しています。 - name : Get CI check results id : ci-checks run : | CI_CONCLUSION="${{ github.event.workflow_run.conclusion }} " echo " conclusion=${CI_CONCLUSION}" >> "$GITHUB_OUTPUT" # 失敗したジョブ一覧を取得 FAILED_JOBS=$(gh pr checks "$PR_NUMBER" \\ --repo my-org/my-repo \\ --json name,state \\ --jq '[.[] | select(.state == "FAILURE")] | map(.name) | join(", ")' \\ 2>/dev/ null || echo "取得失敗" ) これにより、Devin へのプロンプトに CI 結果と失敗したジョブ名を含めることができます。 - CI結果: ${CI_CONCLUSION} - 失敗したジョブ: ${FAILED_JOBS:-なし} レビュー指示にも CI 結果を考慮するよう追記しました。 - CI結果を確認し、失敗している場合はCIのログを読み込んで原因を分析する - CIが失敗している場合、ライブラリの更新が原因かどうかを判断する - CIが失敗している場合は、失敗の原因とマージ前に対応が必要かどうかを明記する まとめ workflow_run イベントを使うことで、CI 完了後に別のワークフローを実行できるようになります。dependabot PR の自動レビューのように、CI の結果を考慮したい処理に便利です。 ただし、 pull_request イベントとは異なり PR 情報を直接取得できないため、 gh コマンドで別途取得する必要がある点には注意が必要です。 参考: Events that trigger workflows - GitHub Docs
アバター
Android Chapter の tick-taku です。 この記事は Timee Product Advent Calendar 2025 の15日目の記事です。 はじめに 2025年は AI コーディング・AI エージェント元年であり黎明期の渦中 と言っても過言ではない年だったと感じます。 各社からこぞって AI エージェントがリリースされ、その後も息つく暇もなくアップデートされてきました。単純なコード補完ではなくタスクを任せられるようになった昨今の AI エージェントは今ではすっかりコーディングの相棒です。 実際今年の DroidKaigi や iOSDC でも AI 関連のセッションが増えていた気がします。 そんな中 KotlinFest などで MCP サーバーを作った話を聞いて「この時代に生きてるんだから自分も触れておかなければ(使命感)(遅い)」と思い、せっかく1年も終わろうとしているのでいい機会だし触ってみようとまずは MCP サーバーを作ってみました。 ちなみにこの記事を書くにあたっても AI のサポートを最大限利用しています。時代ですねぇ。。。 Kotlin で MCP サーバー作ってみる では実際に作成していきます。 ハンズオン的なドキュメントを公式が用意してくれているのでそちらも参考になります。 modelcontextprotocol.io 今回は timee-android で運用している LADR を提供する MCP サーバーを作成してみることにしました。LADR については こちら や 数日前にチームのリードエンジニアが取り組みについて投稿 しているためぜひご覧ください。 この記事では jar ファイルをローカルに作成し Claude Code と接続することを目標とします。 事前準備 以下のようなディレクトリ構成を想定します。 timee-ladr ├── ladr │   ├── 0000-ladr-template.md │   ├── ~~~ │ └── assets └── mcp    └── app また、Kotlin で作成するので MCP Kotlin SDK を利用します。 build.gradle はこちら。 dependencies { implementation( "io.modelcontextprotocol:kotlin-sdk:0.7.7" ) } base { archivesName. set ( "ladr-mcp" ) } application { mainClass = "timee.ladr.AppKt" applicationName = "ladr-mcp" } Primitives 実装に移る前に MCP サーバーがコンテキストを提供するための重要な要素に触れておきます。 MCP には Resources , Tools , Prompts と呼ばれる要素があり、この記事で触れる Resources, Tools についてはそれぞれ以下のように定義されています。(Prompts は今回触れないため割愛します) Resources : LLM に追加のコンテキストを提供する読み取り専用のデータまたはコンテンツ Tools : LLM がアクションを実行するための関数のようなもの 今回作る MCP サーバーに当てはめると、LADR の md ファイルを Resources として提供し、LADR ファイルを新規作成したり更新したりする機能を Tools として提供することになります。 Server の初期化 まずは MCP サーバーを初期化します。 fun main() { val server = Server( serverInfo = Implementation(name = "ladr-mcp" , version = "1.0.0" ), options = ServerOptions( capabilities = ServerCapabilities( resources = ServerCapabilities.Resources( subscribe = false , listChanged = false ), tools = ServerCapabilities.Tools( listChanged = false ) ) ) ) { "timee-android 内の LADR を提供する MCP サーバー" } } ここで出てきた Capabilities とはこの MCP サーバーが LLM に対して何を提供しているかを示すものであり、今回の場合は Resources と Tools を提供していることを表しています。 Resources の Capabilities を示す data class の引数はそれぞれ以下のような意味を持っています。 プロパティ 説明 subscribe クライアントが特定リソースの変更を購読できるか listChanged リソース一覧が変更されたときに通知を送るか 今回のサーバーは静的な LADR の md ファイルを提供することが目的なので基本的に更新系は false です。 Resource の登録 LADR のファイルを Resource に登録していきます。 今回は jar を作成し単独でローカルで動作させることを目指しているため、jar 内の resources/ 配下に md ファイルを格納し読み取ることにしました。この辺の実装は AI 頼りです。ありがとう🙏 fun main() { /** Server の初期化 */ getLadrFilePathsFrom()?.forEach { filePath -> val fileName = filePath.substringAfterLast( "/" ) server.addResource( uri = "ladr:/// $fileName " , name = fileName, description = "LADR: $fileName " , mimeType = "text/markdown" ) { request -> ReadResourceResult( contents = listOf( TextResourceContents( uri = request.uri, mimeType = "text/markdown" , text = readResourceFile(filePath) ?: "File not found: $fileName " ) ) ) } } } private fun getLadrFilePaths() = object {}.javaClass.protectionDomain?.codeSource?.let { JarFile(it.location.toURI().path).getLadrFiles() } private fun JarFile.getLadrFiles() = entries().asSequence() .filter { ! it.isDirectory && it.name.startsWith( "ladr/" ) && it.name.endsWith( ".md" ) } .map { it.name } .sorted() .toList() private fun readResourceFile(filePath: String ) = object {}.javaClass.classLoader.getResourceAsStream(filePath)?.let { stream -> BufferedReader(InputStreamReader(stream, Charsets .UTF_8)).use { it.readText() } } Tool の登録 チームで運用している LADR のテンプレートに沿って登録しているため少し長いですが、addTool 内で input に対して output を定義するだけです。 JsonObject の用意が大変ですね… fun main() { /** Server の初期化 */ server.addTool( name = "create-ladr" , description = "与えられたコンテキストから新しい LADR (Lightweight Architecture Decision Record) ドキュメントを作成します。テンプレートに基づいてMarkdown形式のLADRを生成します。" , inputSchema = Tool.Input( properties = buildJsonObject { putJsonObject( "title" ) { put( "type" , "string" ) put( "description" , "LADRのタイトル(何に対しての意思決定を行ったのかがわかるタイトル)" ) } putJsonObject( "number" ) { put( "type" , "string" ) put( "description" , "LADRの通し番号(4桁のゼロ埋め、例: 0001, 0042)" ) } putJsonObject( "status" ) { put( "type" , "string" ) put( "description" , "採用状況: Accepted(採用), Rejected(不採用), On holding(保留)のいずれか" ) putJsonArray( "enum" ) { add(JsonPrimitive( "Accepted" )) add(JsonPrimitive( "Rejected" )) add(JsonPrimitive( "On holding" )) } } putJsonObject( "context" ) { put( "type" , "string" ) put( "description" , "文脈: 経緯(なぜこの意思決定が生まれたのか)、観点(判断した観点)、事情(検討した事情)、参考情報など" ) } putJsonObject( "specification" ) { put( "type" , "string" ) put( "description" , "仕様、やること、やらないこと" ) } putJsonObject( "design" ) { put( "type" , "string" ) put( "description" , "設計: 特筆すべき設計や設計意図" ) } putJsonObject( "decision" ) { put( "type" , "string" ) put( "description" , "決定事項: 想定している運用や制約、再評価となる条件など" ) } putJsonObject( "consequences" ) { put( "type" , "string" ) put( "description" , "結果: 意思決定の結果を評価したタイミングで追記" ) } putJsonObject( "link" ) { put( "type" , "string" ) put( "description" , "関連するLADRへのリンク" ) } }, required = listOf( "title" , "number" , "context" , "specification" ) ) ) { request -> val args = request.arguments val ladrContent = buildString { val title = requireNotNull(args[ "title" ]?.jsonPrimitive?.content) val number = requireNotNull(args[ "number" ]?.jsonPrimitive?.content) appendLine( "# $number - $title " ) appendLine() appendSection( title = "## Date - 日付" , text = LocalDate.now().format(DateTimeFormatter.ofPattern( "yyyy-MM-dd" )) ) appendSection( title = "## Status - 採用状況" , text = args[ "status" ]?.jsonPrimitive?.content ) appendSection( title = "## Context - 文脈" , text = requireNotNull(args[ "context" ]?.jsonPrimitive?.content) ) appendSection( title = "## Specification - 仕様、やること、やらないこと" , text = requireNotNull(args[ "specification" ]?.jsonPrimitive?.content) ) appendSection( title = "## Design - 設計" , text = args[ "design" ]?.jsonPrimitive?.content ) appendSection( title = "## Decision - 決定事項" , text = args[ "decision" ]?.jsonPrimitive?.content ) appendSection( title = "## Consequences - 結果" , text = args[ "consequences" ]?.jsonPrimitive?.content ) appendSection( title = "## Link - 関連するLADRへのリンク" , text = args[ "link" ]?.jsonPrimitive?.content ) } CallToolResult(content = listOf(TextContent(ladrContent))) } } private fun StringBuilder .appendSection(title: String , text: String ?) = apply { appendLine(title) appendLine() if (text.isNullOrEmpty().not()) { appendLine(text) appendLine() } } 本来はファイルを作成するところまでできるとよさそうなんですが、 LADR の性質上 jar の中にファイルを作成しても仕方なく、テンプレートに当てはめたテキストを返すのみとなっています。 Resource の登録と合わせて、本格的にチームで運用する場合はリポジトリをクローンしていることを前提に LADR を格納しているディレクトリの path を環境変数などで MCP サーバーに伝えるなどの方法もありそうですね。 Server の起動 最後に準備した Server を起動させます。 本来 MCP サーバーのトランスポートの方式はいくつかありますが、今回はローカルに build した jar との接続を想定しているのでドキュメント通り STDIO形式 で起動します。 fun main() { /** Server の初期化 */ val transport = StdioServerTransport( inputStream = System.`in`.asSource().buffered(), outputStream = System. out .asSink().buffered() ) runBlocking { val session = server.createSession(transport) val done = Job() server.onClose { done.complete() } done.join() } } 以上でサーバーの実装は完了です🎉 動作確認 作成したサーバーが正しくレスポンスを返してくるか検証しましょう。MCP の検証には MCP Inspector が提供されています。 MCP Inspector を起動する前に以下のコマンドでアプリケーションを用意します。 ./gradlew installDist app/build/install/ 以下に作成されるので、作成されたアプリケーションの path を Inspector の起動時に指定します。 npx @modelcontextprotocol/inspector mcp/app/build/install/ladr-mcp/bin/ladr-mcp ブラウザが起動するので左ペインの Connect を実行すると正しく作成できていれば成功します。 List Resources を実行すると登録された Resource の一覧が確認できます。 MCPInspecter/Resources また、Tools タブ内で List Tools で登録された Tool の一覧が確認できます。 右側のペインに inputSchema に指定した property を入力でき、実行するとレスポンスが返ってきます。enum で指定した status はドロップダウンで選択できるようになっていて便利ですね。 MCPInspecter/Tools Claude Code との接続 では最後に Claude Code と接続して LADR が確認できるか試してみます。 接続の前に jar ファイルを build します。ただし、普通に jar ファイルを build すると resource ファイルなどは格納されないため fatJar(shadowJar) を作成する必要があります。 これは自分が Server Side Kotlin の知見に乏しいので AI に聞いて作成 task を用意してもらいましたが、もっといい方法があるかもしれません。 fatJar 作成の gradle task tasks.register<Jar>("fatJar") { archiveClassifier.set("all") archiveVersion.set("") duplicatesStrategy = DuplicatesStrategy.EXCLUDE manifest { attributes["Main-Class"] = "timee.ladr.AppKt" } from(sourceSets.main.get().output) dependsOn(configurations.runtimeClasspath) from({ configurations.runtimeClasspath.get() .filter { it.name.endsWith("jar") } .map { zipTree(it) } }) } jar ファイルが作成できたら ~/.claude.json に設定を追加します。 "mcpServers": { "ladr-mcp": { "type": "stdio", "command": "java", "args": [ "-jar", "/path/to/timee-ladr/mcp/app/build/libs/ladr-mcp-all.jar" ], "env": {} } } Claude Code を起動して /mcp list を確認して connected になっていたら成功です。試しに timee-android が LADR を採用した経緯を聞いてみると readMcpResource を利用してまとめてくれました。うちの Claude お姉ちゃんは優秀です。 ClaudeCodeによるLADRのサマライズ 最後に 「MCP ってなんかすごいやつでいい感じになんかやってくれるんだな〜」くらいのイメージでいましたが、実際に作って触れてみるとなるほどコンテキストを取り扱うためのものなんだなということがよく分かりました。MCP がいい感じにしてくれるのではなく、コンテキスト接続のプロトコルなのであくまで外部からデータを与えたり作成したりするためのものであり、いい感じにしてくれるのはエージェントだと身をもって理解できました。 秩序という意味でも “AI における USB-TypeC” とはよく言ったものです。 となると次は AI エージェントの作成にチャレンジしてみるしかありませんね。次回は Koog を利用して今回作成した MCP サーバーを利用していい感じに LADR を作成してくれる AI エージェントを試してみようと思います。最近は KMP も熱く、全てが Kotlin で書けるのでもう全部 Kotlin でいいじゃんですね🤗 実際に手を動かしてみることで学びにはなりましたが GitHub のリポジトリに上がっているものなら GitHub CLI で済みそうな気がするので、社内 DB などよりクローズドなデータなら MCP サーバーとして用意する価値があるのかもしれません。とは言え、そんなデータをエージェントにくわせていいのかは…🤔 社内データを活用するために MCP サーバーを自作しておくと色々と捗りそうですが、一方で MCP サーバーはコンテキストを消費するのであんまり追加してもエージェントが処理しきれなくて意味がないと言う主張 もあるそうです。 これからますます便利になっていくであろう AI エージェント界隈、今後の進化を楽しみながら注視していきたいですね! タイミーでは日々の業務に積極的に AI を活用しています。ご興味があればぜひお話ししましょう! プロダクト採用サイトTOP カジュアル面談申込はこちら
アバター
こんにちは、タイミー取締役 事業統括兼CPOのShunです。 Timee Product Advent Calendar 2025 の12/14担当ということで、最近意識しているテーマ「シングルスレッドリーダー」について書きたいと思います。 まず前提として、一定の規模を超えた事業がさらに非連続な成長を遂げるためには(いわゆるSカーブの成長曲線の再現)、往々にして相応の大きな挑戦が必要だと思っています。そのためには、強力なアイデアを形にし、提供価値を進化させ、販促や営業の型をつくり、それをスケールさせるオペレーションを構築しなければなりません。つまり既存のやり方の地続きではない「変革」が必要です。 しかし、変革に着手するのは容易ではありません。なぜなら、一人ひとりが日々の仕事に忙殺されてしまっているからです。顧客対応も、開発も、運用も止められない。止めた瞬間に組織や個々人の目標達成は危うくなり、売上や各種KPIに影響を及ぼす可能性もあります。 そう、みんな、すでに忙しい。 けれども変革には地続きでない追加の努力が必要です。変革は、余裕ができたときに取り組む追加タスクではなく、日常業務そのものを変えるような力学が働かなければ生まれません。新しい価値や仕組み、意思決定、そして組織の再編まで求められる。では、誰がそれをできるのでしょうか? 推進力を設計するという発想:シングルスレッドリーダーとは ここで役に立つと僕が信じているのが、シングルスレッドリーダーの考え方です。シングルスレッドリーダーとは、「特定の事業領域の成功に必要な権限とリソースを与えられた、兼任ではない専任のリーダー」を指す、Amazonで提唱された考え方です。僕の前職であるGoogleにおいても、DRI(Directly Responsible Individual)という名称でほぼ同様に運用されていました。日本人としてはシングルスレッドの方が言いやすいので、僕はそちらの呼び方を使っています。 僕はこれを、単なる「責任者を置く」話だとは捉えていません。シングルスレッドとは、開始点と終着点があるプロジェクト管理の話ではなく、 「推進力の設計」 の話だと思っています。 この仕組みが解決するのは、「スキル・経験がある人ほど兼務状態になりがち」問題です。「話が早いから」「結果が期待できるから」といった理由から、短期的には合理的な側面もある一方で、兼務状態の膨張は、言わずもがな以下のような弊害を生むリスクを抱えています。 当事者の集中が分断される(思考やアクションが積み上がらない) 優先順位が毎回揺れる(何かを決めるまでが長い) 責任が薄まる(最後に腹を括る点が曖昧になる) その結果、複数の領域それぞれの雑務に追われて推進力が弱まり、全体的なアウトカムにも影響してしまうと思っています。 それゆえ、真逆のアプローチで、スキル・経験が豊富な人こそ思い切って「専任である一つのコトに向き合ってもらう」。それだけで、 一人ひとりの目線も、スピードも、アウトプットの質も段違いで変わる というのを目の前で幾度となく見てきています。 タイミーでの実装 タイミーでは、過去1年間で、既存事業とは別に実験的に 6つのシングルスレッド組織 をつくり、それぞれに事業オーナーを立てて推進してきました。 シングルスレッドリーダーたちは、事業の責任者としてバーティカルに特定の領域を管掌し、責任と意思決定権限をダイレクトに持ちます。もし任用時点でそれ以外の事業テーマも管掌していた場合には、任用のタイミングでそれらをすべて手放してもらいます(その領域は別の専任オーナーや既存の事業ラインに委譲し、推進力が分散しない構造に切り替えられるよう、最大限努力します)。多くのケースで戦略策定機能、企画・推進機能、そして営業機能はこのシングルスレッドリーダーの組織に属して、「管掌する事業」にフルコミットでフォーカスします。 一方で、プロダクトやマーケティングはシングルスレッドリーダーの管掌下には置かず、それぞれ独立した本部として残しています。その上で、ホリゾンタルにそれぞれの事業に対して担当を配置していきます。これはよく取られている形式だと思いますが、これらの機能を一箇所に固めた方が、採用・育成・型化・横展開の生産性が高くなることが大きな理由です。 この組み合わせはいわゆるメッシュ構造とも言えますが、古くからあるマトリックス組織との違いは何でしょうか。それは、シングルスレッドリーダーの組織においては「責任の一本化」と「専任性の強制力」が決定的に違うと思っています。マトリックスは事業と機能を掛け合わせる強力な概念ですが、構造上どうしても“責任の曖昧さ”が残り、責任が2軸に分散しやすく、意思決定も調整コストが高くなりがちです。シングルスレッドリーダーの組織においては、この曖昧さを一掃し、責任とリソースと意思決定を1本に束ねるように設計しています。マトリックス型組織の弱点をアップデートした形であり、専任化によって“推進力の失血”を防ぐ仕組みとも言えます。 組織デザインは常にアップデートし続けるもの もちろん、タイミーにおいても組織は日々形を変えています。シンプルなシングルスレッド体制が適する場面もあれば、複数の機能が密に連携した方が早いケースもある。成長フェーズや事業特性によって、求められる“最適な推進構造”は毎月のように変わります。だからこそ、組織デザインは一度つくって終わりではなく、事業の変化速度に合わせて絶えず再構築する「動的なシステム」であるべきだと思っています。 スポットワークというまだまだ進化を続ける業界だからこそ、戦略・戦術・組織あらゆる領域において「変革」に取り組み、事業の成長にあわせて組織も柔軟に形を変えながら、ワーカーの人生の可能性を広げるインフラづくりに真正面から取り組んでいきたいと思います。 タイミーのこういった様々な挑戦にご興味のある方、全方位で採用活動中ですので、ぜひお話ししましょう! プロダクト採用サイトTOP カジュアル面談申込はこちら
アバター
こんにちは。日々プロダクト開発を楽しんでいるsyamです。 「AIがあれば、専門外の領域も一人でなんとかなるのでは」 そんな期待を持って、Androidエンジニアの私はWebフロントとバックエンド開発への越境に挑戦しました。結論から言うと、その期待は半分正解で、半分間違いでした。 この記事では、実際に越境してみて感じた「AIの限界」と、それを乗り越えるために必要だった「人の存在」について書いていきます。 AndroidからWebフロントへの越境は、比較的スムーズでした。 学生時代にWebフロントを触っていた経験があったことに加え、UIを組み立てる感覚や状態管理の考え方など、Androidと共通する部分が多かったためです。リポジトリの構成も比較的理解しやすく、「Androidとは書き方が違うけれど、やりたいことは同じだな」と感じる場面が多くありました。 また、画面で結果をすぐに確認できるのも大きかったです。書いたコードの結果が目に見えるので、試行錯誤がしやすく、AIに書いてもらったコードの検証もすぐにできました。 バックエンドは「異文化」だった 一方で、バックエンドはより苦戦しました。 DB設計、トランザクション管理、API設計……。コードを書くこと自体はAIの力を借りればなんとかなります。ただ、「なぜこの設計にするのか」「このトランザクションの境界はここで正しいのか」といった判断になると、AIに聞いても教科書的な答えが返ってくるだけで、サービスに合った明確な答えが返ってこないことが多いです。(AIの使い方について、自分が不勉強なだけかもしれませんが) さらに厄介だったのが、リポジトリに関する知識の壁でした。リポジトリに合った実装をどうするか。これはコードの書き方以前の問題で、AIに「このリポジトリのルールに従ってコードを書いて」と頼んでも、そもそも自分がリポジトリのルール自体を理解できていなければ、正しい指示すら出せません。 そして何より大きかったのが、既存の稼働コードを壊すことへの恐怖です。ローカルで動いても本番で何が起きるかわからない。テストが通っても、見落としているエッジケースがあるかもしれない。この不安は、専門外だからこそ大きく感じました。 前に進むためにやった3つのこと 1. 悩み続けるより、まずAIに動くコードを書かせる 最初から完璧を目指すと手が止まります。そこで取った方法は「まずAIに動くコードを書かせて、それをたたき台にする」というものでした。 これは予想通り効果的で、動くコードがあると「ここはなぜこう書いているのか」と具体的な疑問が生まれます。白紙の状態で悩むより、何かしらのアウトプットがある方が次のアクションが見えやすくなりました。 2. 複雑な既存コードはAIに「解説」させる 既存のバックエンドコードを読み解くのは時間がかかる作業でした。ここでもAIが役立ちました。 「このコードが何をしているか、ポンコツエンジニアの私にもわかるように説明して」と頼むと、処理の流れや各部分の役割を整理して教えてくれました。 特に、シーケンス図にしたり、流れを図示するとよりわかりやすくなりました。これにより、既存コードの理解が早まりました。 3. AIでカバーできない部分は、素直に人に聞く ここが重要なポイントでした。 特にリポジトリにまつわる設計判断に関わる部分は、AIに聞いても本当に合っているかの評価が難しかったです。 そういった部分は、ペアレビューの際に本職のWebフロントエンジニアやバックエンドエンジニアの方が、素直に質問すれば詳細に教えてくださいました。パフォーマンス計測の際などには、同期でレクチャーしてくださり、非常にありがたかったです。 自分では気づけない観点からのフィードバックは、AIでは得られない価値がありました。 越境できた本当の理由 振り返ると、越境がうまくいった要因は、AIだけではありませんでした。 大きかったのは、 チームに「専門外からの質問を歓迎する雰囲気」ができていたこと です。これは単に「メンバーが優しかった」という話ではなく、組織として専門外の人が質問することを良しとするスタンスがあったからだと思います。受け入れる側のWebフロントエンジニアやバックエンドエンジニアが、丁寧に向き合ってくれたことに本当に助けられました。 一方で、越境する側として意識したこともあります。レビューの負担を少しでも減らすために、事前にヒアリングして疑問点を整理してからレビューに出すようにしていました。「聞ける雰囲気があるから何でも聞く」のではなく、受け入れ側への配慮を持つことも、越境をうまく進めるうえで大事だったと感じています。 得られた成果 この越境チャレンジの結果、手が空いたときに新規画面の開発やAPIの実装などWebフロントやバックエンドのタスクを消化できるようになりました。チームのスプリントゴール達成に、Android以外の形でも貢献できるようになったのは大きな変化でした。 まとめ 「AIがあれば全部できる」わけではありません。 ただ、「AIと、専門外からの質問を歓迎する雰囲気、頼れる仲間」がいれば、越境のハードルはかなり下がります。 AIはコードを書く手助けや既存コードの解説をしてくれます。しかし、「なぜそう書くか」の設計判断やドメイン知識の補完には、仲間のサポートが不可欠でした。 そして、そのサポートがうまく機能するには、受け入れ側の丁寧な姿勢と、越境する側の配慮、その両方が必要だと感じています。 仲間のWebフロントエンジニアやバックエンドエンジニアの方には、非常にお世話になりました。感謝しかありません。 タイミーで、そんな仲間たちとプロダクト開発をしてみたいと思った方は、ぜひ一度お話ししましょう! プロダクト採用サイトTOP カジュアル面談申込はこちら
アバター
はじめに こんにちは、バックエンド・エンジニアのMaxx (マックス) です。 私は現在、オフショア開発チームのブリッジ・エンジニアという役割でプロダクト開発に携わっています。 本記事は Timee Product Advent Calendar 2025 の12日目の記事として、私が2年前から取り組んでいる英語学習の体験を共有します。 英語を学習している方々の参考になれば、または興味がある方々が学習を始めるきっかけになればうれしいです。 オフショア開発チームと英語 「チームの生産性を上げ、成果をたくさん出し、そしてそれを価値につなげていくには私に英語力が必須だ、やるしかない!」 これは私がオフショア開発チームに携わって感じてきたことで、また英語学習のモチベーションを維持させてくれているものです。 私が所属するオフショア開発チームは、私とオフショア先の外国籍の方々で構成され、共通言語は英語です。私の役割は、チーム内の作業管理、チーム内外の中継、またエンジニアとしての技術的な支援などで、情報伝達と意思疎通が必須です。 これらを怠ると、理解の浅さによる考慮漏れ、誤解による手戻り、信頼性の不足または心理的な壁によるモチベーションの低下などを起こします (昔も今もときどき起こります) 。 オフショアメンバーの中に日本語話者がいるので通訳をお願いできるのですが、複雑な仕様や設計の意図などの技術的な話題の場合は、エンジニア間で直接話したほうが効率がよいですよね。 ということで、チームが上記のような問題を防ぎ、よい成果を出すためには英語でのコミュニケーションが必須な環境なのです。 英語学習の動機と目標 そもそも、なぜ英語学習を始めたのか、その根底にあるのは、単純な「好奇心」と「向上心」でした。 実は私はソフトウェア・エンジニアとして20年以上のキャリアがあり、これまでソフトウェア・エンジニアの技能に対する好奇心や向上心によって自身を成長させ、この業界に生き残ってきました。 20周年を迎えて、さらに自身を非連続に成長させそうなものはないかと未知の領域を見渡したときに見つけたのが英語で、そこで次のように考えたのでした。 (今であればLLMも未知の領域の候補になりましたが、当時はこれほど盛り上がっていませんでした。) 「シニアになった私でも、今から成長できるのか? やってみるしかない!」 「英語力が身についたら、人生の可能性はどう広がるのか? やってみるしかない!」 そして、英語の環境であるオフショア開発チームのブリッジ・エンジニアという役割に挑戦したのでした。 目指す英語力 目指す英語力はCEFRのB2です。 CEFR (ヨーロッパ言語共通参照枠) は外国語の習熟度を測る国際基準で、B2は上から3番目、「中の上」にあたるレベルです。 ヨーロッパ言語共通参照枠 - Wikipedia このレベルを目指す理由は、『エンジニア組織の英語化変革 EX』という書籍の内容を参考にしています。この書籍に「開発チームのすべてのコミュニケーションを英語化するにはB2が目安である。」、「英語のバックグラウンドがないフルタイムエンジニアでも約2年で全員がB2レベルに達しており十分に到達できる水準と考えています。」と書かれており、これは具体的 (Specific) 、達成可能 (Achievable) 、期限あり (Time bound) で、かつ2年という長さが自分にちょうどよいと感じました。 direct.gihyo.jp また、初学者がCEFRのB2レベルの英語力を身につけるには、600時間の学習が必要なようです。 今年の学習成果 では、この1年の英語学習を振り返ります。 学習内容と時間 学習教材の約95%は、NHKの語学番組を活用しました。1回5〜15分という長さが継続しやすく、レベル別に番組が豊富なため、自分に合った教材が見つけやすいのが魅力です。 視聴している主な番組 *()はCEFRのレベルです ニュースで学ぶ「現代英語」 (B2) ラジオビジネス英語 (B2~C1) ラジオ英会話 (B1) エンジョイ・シンプル・イングリッシュ (A2~B1) 英会話タイムトライアル (A2) 学習時間は合計で390時間でした。1日平均すると約1.1時間。主に夜22時以降、番組の視聴と教材のテキストで学習しました。 毎日やること、そしてやりすぎないことが私のおすすめです。 やる日とやらない日があると、やらない日の楽さを知っているのでやる日が少し辛く、よしやるぞと心を整えるまで時間がかかります。一方で毎日やる、つまりやるしかない!という状況にすると心を整える必要がありません。 あとは、やりすぎないこと、つまりがんばりすぎないことです。がんばると、短期なら気合いでなんとかなりますが長期は辛いです。 英語力の推移 成長を客観的に測るため、今年は定期的に Duolingo English Test を受験しました(受験費用をサポートしてくれる社内制度「エンジニア桜」に感謝!)。 productpr.timee.co.jp 今年のスコア推移 テスト日 認定スコア CEFR判定 2025年10月11日 95 B1 2025年7月20日 90 B1 2025年4月5日 85 B1 2025年2月10日 85 B1 2024年12月15日 85 B1 ご覧の通り、最初の3回はスコアが全く変わりませんでした。 「もう成長の余地がないのか?」「やり方が間違っているのか?」と不安に襲われることもありましたが、「英語学習の成長曲線はある日突然跳ね上がる」「英語は筋トレと同じだ、続けると必ず上達する」という先人の言葉を信じて継続しました。 その結果、4回目、5回目と連続でスコアが上昇しました。単なる幸運ではなく、着実に力がついていることを実感できた瞬間でした。 オフショア開発チームの成長 次に、私の英語力の成長がチームにもたらした変化を振り返ります。 大きな変化として、チームは1年前と比べて、より影響範囲が広く難易度の高いプロダクトゴールをまかされ、そしてやり遂げられるようになりました。 私の英語力と関連する要因は、もちろん情報伝達や意思疎通の質や量が向上したからかと思いますが、それに加えて私の気持ちも英語でも伝わるようになり、信頼関係を構築できたからだと思います。この変化によって積み上がった成果がPdMの信頼を獲得し、そしてより大きなプロダクトゴールをまかされることに繋がったのだと思います。 小さな変化は、エンジニアたちが私にビデオ通話をしてくれる機会が増えたことです。 私の英語力が上がったことで、私に対する彼らのコミュニケーションの負荷が下がったのだろうと思います、話したほうが早い的な。私のほうは英語での言語化に精一杯で発音も文法もひどいと思うのですが、それでも内容が伝わっているようでうれしいです。 最後に今後の抱負 現在の英語力はDuolingo English Testのスコアが95点で、CEFRのB1です。 このスコアがあと5点上がって100点になると、目標のCEFRのB2になります。 また、学習時間は去年から合計して606時間となり、こちらは目標の600時間を超えました。 ようやく、、、ここまできました。この調子であればおそらく最短で次回のテストで、最長でも半年以内に到達できるかと思います。 次回のテストは今年の年末の予定です。目標を達成して年を越したいところです。 認定スコア CEFR 155 ~ 160 C2 130 ~ 150 C1 100 ~ 125 B2 目標はここ 60 ~ 95 B1 いまここ 10 ~ 55 A1 ~ A2 一方で、自身の英語力が目標に近づいたことで、その英語力がどの程度かを知り、少し期待以下であることに気づきました。 「自分の英語力なんてまだまだだぞ、この程度で満足していいのか?」という気持ちです。 ということで、目標を達成した後も引き続き学習を続ける予定です。 もしかしたら、自分との戦いである点も筋トレと同じで終わりはないのかもしれません。。。笑 引き続き、オフショア開発チームと英語の両方をがんばってまいります! ということで、以上が私の体験談でした。ご参考になればうれしいです。 2025年もお疲れ様でした! 最後に、タイミーでは一緒に働くメンバーを募集してます!ご興味があればぜひお話ししましょう! プロダクト採用サイトTOP カジュアル面談申込はこちら
アバター
この記事は Timee Product Advent Calendar 2025 の12日目の記事です。 1. はじめに こんにちは、タイミーでAndroidエンジニアをしている村田( @orerus )です。 私は2年前の2023年のアドベントカレンダーで、「 Lightweight Architecture Decision Recordsの導入 」という記事を書きました。 当時はAndroidエンジニアの人数も少なく、少人数だからこそ導入しやすかった実験的な施策でしたが、あれから2年が経ち、メンバー数は約3倍にまで急拡大しました。 一般的に、少人数チームで機能していた「全員合意」や「ドキュメント運用」は、人が増えると形骸化したり、ボトルネックになったりしがちです。 果たして、我々の独自LADR(Lightweight Architecture Decision Records)はスケールする組織に耐えられたのか?それとも破綻してしまったのか? 約2年間の運用の「通信簿」を、チームメンバーへのアンケート結果と共にお伝えします。 2. 独自LADRのおさらい(前提共有) 本題に入る前に、我々が2年間運用してきた「独自LADR」について簡単におさらいします。 (導入の経緯や詳細なフォーマットについては、 前回の記事 をご参照ください) 一般的なADR(Architecture Decision Records)はアーキテクチャ選定の記録を主としますが、我々は対象を拡大し、以下の目的で運用しています。 LADRの目的 案件のコンテキスト共有: 「なぜやるのか」「背景は何か」を実装前に同期する 設計レビュー: 実装着手前に設計方針の合意形成を行う(手戻り防止) 意思決定ログ: 「なぜその実装になったか」を未来に残す また、運用ルールとして以下の特徴を持たせています。 「仕様書(Specification)」ではない あくまで「その時点での意思決定のログ」です リリース後に仕様変更があっても、過去のLADRは更新しません。改修時は 「新たなLADR」 を作成してリンクさせる運用です 書くハードルは極限まで下げる 必須項目は 「Context - 文脈」のみ 記述量は執筆者に委ねており、「悩むくらいなら1行でも書いて出す」を是としています この「仕様書としてメンテしない(=数が増え続ける)」という性質が、後述する組織拡大期の課題にも関わってきます。 3. 【定量評価】数字で見るLADRの現在地 実際のところ、LADRはまだまだ元気に運用を続けております! LADR総数も2年前の18個から約175個へと大幅に増加しました。 では、チームが拡大した現在、メンバーはこの運用をどう感じているのでしょうか? 全メンバーにアンケートを実施し、2年前と同じ項目で数値化してもらいました。 ▼ LADR運用に関するアンケート結果 (※各項目10点満点 / 古参メンバー:2年前の導入初期を知るメンバー、新メンバー:その後に加入したメンバー) 評価項目 全体平均 上限 / 下限 古参メンバー平均 新メンバー平均 1. 満足度 7.9 10 / 4 8.7 7.4 2. 効率化 7.1 10 / 3 8.3 6.4 3. コミュニケーション 8.2 10 / 5 9.7 7.4 4. 課題解決効果 7.8 10 / 4 8.7 7.2 5. 学習・成長 6.5 10 / 3 8.3 5.4 6. 他チーム推奨度 7.2 10 / 3 8.3 6.6 数字から見えること まず注目したのは 満足度の高さ(平均7.9点) です。 「人数が増えたら面倒になるだけでは?」という懸念に反し、組織が大きくなっても高い水準で支持されています。また、途中からJoinした新メンバーも一部が「満足度10点」をつけてくれていました。これは率直に嬉しいですね! また、最もスコアが高かったのが 「コミュニケーション(8.2点)」 でした。 Squad(開発チーム)が分かれて普段の業務がバラバラになりがちな組織拡大期において、LADRが「エンジニア同士の会話のハブ」として機能していることがわかります。 一方で、「効率化」や「学習・成長」の項目では古参メンバーと新メンバーで特にスコアに開きが見られました。このギャップについては、LADR導入以前の痛みがある状態を知っている古参メンバーにとっては「LADRはマイナスをプラスに変えてくれるもの」だが、整備された状態で入社した新メンバーにとってはLADRがある状態がスタート地点(あるいは単なる追加タスクという認識)となった為ではないかと推察しています。実際、新メンバーからは「スピードが求められるシーンでボトルネックになる」という率直な意見も挙がっており、ここは今後の改善ポイントです。 4. 【定性評価】3倍規模になってもまだまだ手放せないLADR 一方、アンケートの定量評価(自由記述結果)から、LADRが一定支持されていることが伺えます。そこで、今度はその理由について考察してみます。 (※アンケートの設問と実際の回答内容については文末に付録として掲載します) ① 手戻りの撲滅と設計の民主化 LADRを出すタイミングはコードを書く前を推奨(最遅でも実装PRと同時)しています。これにより、実装後のコードレビュー(Pull Request)で議論が白熱し丸々作り直し…といった事態がなくなります。 実装前に設計のプロセスが強制的に組み込まれること、そのため設計時点でレビューしてもらうことで大規模なロールバックが発生しづらいことは大きなメリットかと思います。 (新メンバーより) また、これから作る機能について「こうしたいんだけど、どう思う?」とLADRを通して気軽に相談できる文化が、心理的な負担を下げているようです。 ② コードレビューの純度向上 LADRで設計の合意が取れているため、実際のコードレビューでは「設計議論」をする必要がなくなります。 コードレビューをする際に、設計周りのコメントをする必要がほぼ無くなる為レビュー側としても楽。 (新メンバーより) これはレビュアー・レビュイー双方にとって大きなストレス軽減になっています。余談ですが、我々はAIコードレビューも導入しており、単純なロジックミス等はAIが先に指摘してくれる状態となっているため、相乗効果で実装PRのレビュアー負担を大きく減らすことができています。 ③ 心理的安全性とオンボーディング 個人的に一番嬉しかったのが、新しく入ったメンバーからの以下の反応でした。 過去ログを参照してみましたが Light なこともあり書き方も人それぞれだったためいい感じに肩の力を抜いて書く事ができました。 実際 LADR を書く中でチームメンバーに質問したときも丁寧に教えてもらえたことを覚えています。 (新メンバーより) 書き方の参考にとてもなった。 足りてない部分や書き方など、チームメンバーが丁寧に指摘してくださった印象があり受け入れ体制は丁寧に感じた。 (新メンバーより) ドキュメント文化が「参入障壁」にならず、むしろ「チームに馴染むためのツール」として機能していました。その結果がコミュニケーションの高得点に繋がっているのかと感じました。 5. 課題をどう乗り越えているか? 〜AIという新たな相棒〜 もちろん、良いことばかりではありません。人数が増え、ドキュメントの数が膨大になるにつれて顕在化した課題と、2年前には予想していなかった解決策について触れておきます。 課題1:過去のドキュメント、どうやって探すのだ問題 「仕様書」として更新せず、ログとして積み上げる運用のため、GitHub上のファイル数は増え続けます(現在約175個)。2年前の懸念通り、人間が目で探すのは困難になりつつあります。 しかし、この課題は AIの進化 によって思わぬ形で解決されていました。 最近は AI が便利なので Claude Code に 「この項目とその時書いた設計を LADR から探してサマライズしてください」 などと投げ掛けています。 (新メンバーより) 新しくLADRをつくる際に既存のLADRをAIに探させることがあったがよく探してくれる印象 (新メンバーより) GitHubのリポジトリをAIに読み込ませることで、「検索性」の問題はAIが解決してくれました。これは2023年時点では想像していなかった嬉しい誤算です。 *1 課題2:レビューのボトルネック化 一方で、組織拡大に伴う悩みもやはり出てきています。現在はLADRが出されるとAndroidメンバー全員がレビュアーにアサインされます。これがスピード感を損ねる要因になりつつあります。 実装とLADRのレビューからマージまでには数日かかっている印象があります。 スピードが求められるシーンでも、LADR をレビューに出しながら並行して実装し PR までたてた後 LADR 側で指摘をもらった場合に、実装の PR を LADR を見ながら修正する必要もありコンテキストが分断されるのでネックかもしれません。 (新メンバーより) マージ条件としては「Android Chapter LeadのApproveのみ必須」という緩めな形にはしているものの、より多くの人の目に触れればそれだけコメントの数も必然的に多くなります。 ここについては、「10人程度までが見れる範囲。15人を超えたらコードオーナー制や分散レビューが必要かもしれない」といった意見も出ており、まさに今のフェーズが運用の転換点であるとも感じています。 課題3:AI時代の「思考停止」リスク AI活用は書くハードルを劇的に下げてくれましたが、副作用も無視できません。 実際、定量評価における 「学習・成長」のスコアが新メンバーで顕著に低かった(5.4点) のは、「AIが下書きをしてくれる分、自分の頭でゼロから言語化して悩む機会が減った」ことの裏返しである可能性があります。 AIにほとんどを書いてもらうため、記述するコストを小さくすることに意識が向くことが多くなったと感じる。 (新メンバーより) AI活用自体は組織的にも推進しており歓迎するところですが、「AIに下書きさせて、人間が思考を整理する」という健全なバランスをどう保つかが、今後の新たな課題点となりそうです。 結論:約3倍規模になってもLADRは必要だったか? 結論として、 「必要だし、むしろ人数が増えた今こそ手放せない」 存在です! 約3倍規模に増えても、LADRは形骸化することなく、チームの意思決定の質とコミュニケーションを支え続けてくれています。 特に、新しく入ったメンバーがこの文化をポジティブに受け入れ、すぐに適応してくれている姿は、導入者として何よりの成果だと感じています。 ただし、(努力目標とはいえ)「全員で全部見る」運用はそろそろ限界に近づいています。 次のフェーズ(10人〜20人規模)に向けて、AI活用を前提としつつ、レビュー体制の分散化など、仕組みのアップデートを進めていくつもりです。 この記事が、拡大するチームでの情報共有やドキュメント運用に悩む方の参考になれば幸いです。 タイミーのプロダクト開発に興味を持ってくださった方、よろしければぜひ一度お話ししましょう! プロダクト採用サイトTOP カジュアル面談申込はこちら 付録: アンケート自由記述の全回答まとめ アンケートの自由記述設問、および全回答です。 クリックしてアンケートの全回答(原文ママ)を見る ### 1. 組織拡大(Scale)に関する変化 **Q. 人数が増えてLADRのレビュー依頼も増えましたが、レビュー負荷や承認までのスピード感はどう変化しましたか?(ボトルネックになっていませんか?)** - CLとして全てのLADRを見るのでその分負荷は増加しているが、いうほどLADRの数自体が多く無いため変化は感じない - LADRが最近になってApproveまでのスピード感が落ちた気がします。他のも見るPRが増えたことや、AIによって書かれる分量が増えたので把握する量が増えたことなどが要因な気がします - 多少のボトルネックは発生しているように感じますが、それを補って余りある効果があると思います - (自分も含め)忙しさの度合いによりLADRのレビューが若干後回しになってしまっている印象があり、開発スピード上がったという印象はそこまで感じていないが、著しく開発スピードが落ちた、という印象もない - レビュー負荷は良いが、レビュー完了までに時間がかかりリードタイムが悪くなるのに貢献している気がして申し訳ない - レビューはLADRがあることでやりやすい - 個人的に事前に設計を考える点はメリットである反面、メンバーの設計をレビューするのは特に自分が持っているコンテキストの外側だと心理的にもハードルが高く、なかなかレビューに参加できなかったりします。実際 LADR のレビューからマージまでには数日かかっている印象があります - 基本的にはみるようにしている、特に負担と感じたことはない。忙しいタイミングかつ多くのメンバーに承認されている状態だとクリティカルではなさそうな気になりはコメントしない・残さないことは何度かあったかもしれない **Q. 過去のLADRの数がかなり増えているはずですが、現在「過去の意思決定」を探すのは容易ですか?** - GitHubの検索機能やローカルでの検索を使っているのでいうほど困ってない - そんなに過去のLADRを探すケースがないので、困っていないです - Githubのblobから検索して探しています。検索容易性は十分あると思います - 過去の意思決定を探すのは容易。すべてのLADRを目を通しているので脳内INDEXがあり AndroidStudio で検索すれば出てくる。最悪思い出せなくても ladr フォルダにまとまっているので探し出すのに困っていない - AIがあるので問題ないかも - 特定のLADRを読んだときに、これは今も正しい情報なのかの確信は持てていない - 最近は AI が便利なので Claude Code に「この項目とその時書いた設計を LADR から探してサマライズしてください」などと投げ掛けています - 普段の開発において既存のLADRを参照する機会があまりないかも(Androidにおける開発の実装方針が大きくはずれることがなさそうなことに起因していそう)。新しくLADRをつくる際に既存のLADRをAIに探させることがあったがよく探してくれる印象 **Q. 書くこと自体の心理的・工数的ハードルについて、現在の率直な感覚は?** - AIによって、より書くハードルは下がった気がします、レビューするハードルは分量の増加によって上がったかもなぁという感じです - どのくらいの内容で書けば良いかはあまり肌感覚がなく、後から「書いてください!」と言われることもあります - 仕様が固まっていなくても方針や予定を含んだ内容で書いてもOKとなっているので、書くことへの心理的ハードルはない。ある程度仕様をまとめたりしなければならないので工数的ハードルは忙しい時は少し気になるが、実装PRレビュー時などに使えることを考えると、工数的ハードルもほとんど感じていない - あまりない - 作りながら仕様が変わるのでドキュメントをアップデートし続けるのが難しい - プロダクトタスクの立ち上がりから実装までの間にどうしても LADR を書く工数が少なからず発生してしまうこと、作りながら仕様を決めることもあるためその都度 LADR に立ち戻ってドキュメントを修正することになり勢いが削がれてしまう点は課題かなと感じます。スピードが求められるシーンでも、LADR をレビューに出しながら並行して実装し PR までたてた後 LADR 側で指摘をもらった場合に、実装の PR を LADR を見ながら修正する必要もありコンテキストが分断されるのでネックかもしれません - AIによって書きやすくなった印象がある。実装を終わらせてから論点を整理させるといった使い方もできそう ### 2. オンボーディング・新メンバー視点 **Q. 入社時や新しい領域を触る際、過去のLADRを読むことは役立ちましたか?** - 役に立ちそうとは思うが、直接恩恵を受けたというエピソードはないかも - 仕様や経緯が記載されているのでその機能に手を加える際の参考になりました。ただ、Git 管理なのでドキュメントの更新も少しハードルがあると感じていて特に仕様について見つけた情報が最新かの判断が難しい気もしています **Q. 初めてLADRを書いた時、既存のLADRは参考になりましたか? また、チームの受け入れ体制はどう感じましたか?** - 書き方の参考にとてもなった。足りてない部分や書き方など、チームメンバーが丁寧に指摘してくださった印象があり受け入れ体制は丁寧に感じた - 既存のLADRは、ある程度参考になった(ある程度、なのは粒度がそれぞれ異なりどれに合わせれば良いか迷ったと思うため)。レビューで指摘してもらえブラッシュアップ可能なため、わからないままで終わるとかがなく受け入れ体制は良いなと感じた - LADRを書くこと以外にも初めてのことが多くて書いたが、あまり深く考えていなかった気がする - 過去ログを参照してみましたが Light なこともあり書き方も人それぞれだったためいい感じに肩の力を抜いて書く事ができました。実際 LADR を書く中でチームメンバーに質問したときも丁寧に教えてもらえたことを覚えています - 他のLADRを参考に書いた記憶、書き手によってフォーマットが異なっていた気がしている。AI主体で書いてくれるようになれば記述のハードルやフォーマットもそろいそう ### 3. 未来へ向けて **Q. 独自LADRの「ここが好き」(一番気に入っている点)** - 自分・所属Squad以外の開発内容についても知れ、自身の意見を述べる機会が与えられるところ。意思決定意図をリポジトリ内に残せるところ - Planモードの先駆けてきな感じで、最初に仕様を自身でも整理できるのが良いですね - みんなでレビューすることにより認識がそろえられるところ - これからこういった機能を開発したい、こういった機能を入れたいんだけどどう思う?を気軽に共有できる点 - 他のメンバー・squadが何をしているのか知ることができる。コードレビューをする際に、設計周りのコメントをする必要がほぼ無くなる為レビュー側としても楽 - とにかく書くハードルを下げていること - 実装前に設計のプロセスが強制的に組み込まれること、そのため設計時点でレビューしてもらうことで大規模なロールバックが発生しづらいことは大きなメリットかと思います **Q. 改善したい点・今後への提言** - もっと書きやすいように項目を取捨選択・整理したい - やはり把握する量が増えるので、LADR管理者の負担が心配になってきます - 全員レビューは人数が増えると限界を迎えると思うので、他に認識を揃える方法を考えるべきだと思います - 15人を超えてくるとすべてのLADRに目を通すことはかなり負担になりそうに感じるため、そこまでスケールはしないやり方かな、というところに限界を感じる。10人くらいまでが見れる範囲だと思っている。もし今の倍の人数になるならば半分くらいのメンバーを自動アサインなどにし...など分散する仕組みがあっても良いかも - レビューを締め切るタイミングが難しい為、一次コメントは3日以内にとか決めたいかも - 仕様書駆動開発になった時にLADRが仕様書っぽくなったりするのか妄想をする - 物理的・心理的ハードルの課題も散見され、特に高速なバリューデリバリーが求められる中で小さくないボトルネックになりつつある気がします。とは言え数10人規模になってくると rails chapter と同様に領域ごとのコードオーナー制も視野に入ると思うのでそこまで人数がネックになることも少ないかなとは感じます *1 : ※AI利用に関しては、社内のセキュリティガイドラインに則り、学習利用されない設定(エンタープライズプラン等)で行っています
アバター
はじめに:「タイミーって、もう完成してるんでしょ?」 「タイミーはIPOもしたし、プロダクトも組織も出来上がっているから、今から入ってもやることがないのでは?」 候補者の方とお話しする中で、そんな声をいただくことがあります。 正直に言います。めちゃくちゃ勿体ない誤解です。 むしろ、IPOを経て確かなアセットが揃った今だからこそ、「プロダクト開発を科学する」という最高に面白いフェーズに入っているのです。 今回は、コンサル・スタートアップの事業統括を経験した私が感じる、「Growth領域の知的な楽しさ」と、その先に待っている景色についてお話しします。 自己紹介 みなさん、初めまして! タイミーでスポットワーク事業のGrowth全体を担当しているYang Haoと申します。 新卒で経営コンサルに5.5年従事し、その後、営業SaaSのスタートアップにてプロダクト責任者・事業統括を2.5年経験しました。2025年4月にタイミーに入社し、現在Group Product Managerとして10名弱のPdMのピープルマネジメントも行っています。 1. Growthとは「コツコツヒットを重ねながら、常にホームランを狙うゲーム」 そもそもGrowthとは何でしょうか。単にUIを微調整してCVRを0.1%上げるだけの仕事ではありません。 私は「顧客価値を提供し続けるために、データドリブンで反復し続けるプロセス」だと定義しています。 GAFAをはじめとする世界のトップテック企業には、一般的に必ずと言っていいほど強力なデータドリブンGrowthチームが存在します。彼らは機能開発チームとは異なる筋肉で、事業を非連続に成長させています。 なぜこれが「面白い」のか? 最大の魅力は、「即座にフィードバックが得られること」と「大胆なホームランを狙えること」です。 通常の機能開発が数ヶ月かけてリリースするのに対し、Growthは毎日バッターボックスに立ちます。 実際にタイミーのGrowthチームでは、 月間10本前後のリリースを行い、常に7〜8本のABテストが走っています。 「この仮説はどうだ?」「ダメか、じゃあ次はこうだ」 すぐに数字としてフィードバックが返ってくるため、高速でPDCAを回しながらヒット(改善)を積み重ねることができます。 しかし、それだけではありません。 確かなデータがあるからこそ、勘や度胸に頼らず、「ここを変えれば事業が跳ねるはずだ」という特大ホームラン(非連続な成長)を狙って打ちにいくことができる。 この「確実性」と「爆発力」の両方を追い求めるヒリヒリ感こそ、Growth PdMの醍醐味です。 2. 「コードを書く」だけが解決策じゃない。総合格闘技としてのGrowth もう一つの面白さは、「解決手段(レバー)の多様さ」にあります。 AIの進化により、「作る」ことのハードルは劇的に下がりました。これからのPdMの真価は、「作る」ことそのものよりも、「どのレバーを引いて事業価値を最大化するか」という意思決定に問われます。 Growth PdMが扱うレバーは、プロダクトだけに留まりません。例えば以下のような選択肢を複合的に組み合わせます。 Productレバー: UI/UXの改善、新機能の追加 Marketingレバー: 獲得ターゲットの変更、メッセージの刷新、新規獲得チャネルの立案 Biz/Opsレバー: 営業オペレーションの変更、自動化によるCS対応コストの削減 Strategyレバー: ダイナミックプライシング、課金モデル、インセンティブ設計の変更 「今回は開発せずに、LPや提案活動で仮説検証をしよう」「ここはプロダクトで自動化して、CSのオペレーションコストを下げながら、リードタイムを短くしよう」 このように、事業全体を俯瞰して最適な手を打つ「総合格闘技」のような面白さがあります。 3. キャリアステージで変わる「Growthの楽しみ方」 Growthの面白さは、PdMとしてのキャリアステージによって味わい深さが変わる領域です。 ジュニアPdM:プロダクト開発の「密度」を味わう とにかく、打席に立てます。0-1フェーズでは仕様策定からリリースまでに数ヶ月かかることもありますが、Growthフェーズではそのサイクルが圧倒的に早いです。 「仮説→要件定義→開発→リリース→検証」というプロダクト開発の一連のプロセスを、短期間で何度も回すことができる。 濃密な開発経験を浴びるように積めることは、PdMとしての足腰を鍛える上で最高の環境です。 ミドルPdM:「再現性」と「チームづくり」の楽しさ 単発の施策ではなく、チームとして勝ち続けるための仕組みづくりが面白く感じられるようになります。 「どうすればABテストの勝率が上がるか」を突き詰め、プロダクトで再現性高く数値を作れるようになると、経営からの信頼(投資)も集まり、チームも急拡大します。 そこで必要になるのが、「人を育て、組織で勝つ」マネジメントの視点です。プレイヤーとしての個人の成果を超えて、チーム全体のレバレッジを効かせる面白さが出てきます。 シニアPdM:「事業そのもの」を動かす楽しさ ここまで来ると、前述した「Strategy」や「Biz/Ops」のレバーを含め、事業全体を動かすダイナミックな采配が可能になります。 プロダクトの変更によって数百名の営業組織の動き方を変えたり、プライシング戦略で収益構造を進化させたりする。 これはもはやPdMという枠を超えて、事業をハンドリングする予行演習そのものです。 4. なぜ「タイミー」がGrowthの実験環境として最高なのか 「Growthが面白いのはわかったけど、別にタイミーじゃなくてもいいのでは?」 そう思うかもしれません。しかし、今のタイミーだからこその環境があります。 ① 「有意差」が出る圧倒的なトラフィック Growthの天敵は「データ不足」です。アーリーフェーズのスタートアップでは、ABテストをしようにも母数が足りず、検証に時間がかかります。 タイミーでは現在、月間100万回以上のマッチングが生まれています。今日打った施策の結果が、明日には明確な「有意差」として現れる。この規模で高速な実験ができる環境は、国内でも極めて希少です。 ② 「攻め」の実験にリソースを投下できる これが一番リアルな話ですが、資金やリソースに余裕のないフェーズでは、どうしても目先のキャッシュ獲得に追われ、大胆な実験ができません。 タイミーは、IPOを経て事業基盤が強固になったからこそ、守りに入るのではなく、「次なる非連続な成長」のためにリソースを大胆に投下できます。 失敗を恐れずに仮説検証にベットできる。この「攻めの姿勢」を支える環境があるからこそ、Growth PdMは思い切りバットを振ることができるのです。 おわりに:キャリアは後からついてくる 冒頭で「Growthは面白い」と書きましたが、結果としてこの領域に熱中することは、キャリア形成においても非常に合理的です。 事業全体を見渡し、あらゆるレバーを引いて数値を伸ばす経験は、将来どのようなプロダクト、あるいは事業を任されたとしても通用する「本質的な事業推進力」になります。 完成された組織でルーティンを回すのではなく、ヒリヒリするようなスピード感で実験を繰り返したい。 プロダクトという枠を超えて、事業を伸ばす手触り感を味わいたい。 そんな「知的好奇心」旺盛な方にとって、今のタイミーは最高の挑戦の場です。 「ちょっと面白そうかも」と思った方、ぜひカジュアルにお話ししましょう。この巨大な挑戦環境で何ができるか、一緒に妄想しませんか? みんなでワイワイ発信活動をやってく環境いいな〜と思う方、ご興味があればぜひお話ししましょう! プロダクト採用サイトTOP カジュアル面談申込はこちら
アバター
はじめに こんにちは! 絶賛採用中 のタイミーのDevPlatformチームの @MoneyForest です。なお、この記事は  Timee Advent Calendar 2025  シリーズ2の11日目の記事です。 本記事ではタイミーの「アプリケーション定点観測会」で取り扱っているDatadogのダッシュボードを改善した件について記載します。 アプリケーション定点観測会とは タイミーにおける「アプリケーション定点観測会」は「アプリケーションの品質に関わるメトリクス、イベント、ログ、トレース(MELT)を週次のサイクルで観測し、それぞれの事実をチーム全員で確認しフィードバックループを回すこと」を目的として行われます。 平たくいうとDatadogのダッシュボードを全員で眺め、認識を合わせたり、確認や改善のアクションを決定する会です。 このような取り組みは各社のテックブログでも散見され、SREの取り組みとしては一般的なもののように思います。(各社「SLO定例」「モニタリング定例」「パフォーマンス観測会」などさまざまな名前がついているようです。) それぞれ何を重視するかで特色があるとは思いますが、基となる考えはおそらくSRE本の「31章 SREにおけるコミュニケーションとコラボレーション」の「31.1 コミュニケーション:プロダクションミーティング」の以下の内容に拠るところではないでしょうか。 しかし、私たちが行うミーティングの中で、平均以上に有益なものが一つあります。それはプロ ダクションミーティングと呼ばれるもので、SREチームが自分たちと他の参加者に対し、担当す るサービスの状況について十分に注意を払って明確に説明をすることによって、すべての関係者の 全般的な認識を高め、サービスの運用を改善するために行われます。概して、これらのミーティン グはサービス指向で行われるもので、直接的に個人の状況のアップデートに関するものではありま せん。このミーティングが目標とするのは、ミーティングが終わった後に、進行中のことに関する 全員の認識が同じになることです。プロダクションミーティングには他にも大きな目標がありま す。それは、サービスに対するプロダクションの知恵を持ち寄ることによって、サービスを改善す ることです。すなわちサービスの運用パフォーマンスの詳細について話し合い、それを設計や設 定、実装と関連づけて考え、問題解決の方法を推奨するということです。定期的なミーティングに おいて設計上の判断をサービスのパフォーマンスと合わせて考えてみることは、きわめて強力な フィードバックループになります。 (出典:Betsy Beyer, Chris Jones, Jennifer Petoff, Niall Richard Murphy 編、澤田武男・関根達夫・細川一茂・矢吹大輔 監訳、玉川竜司 訳『SRE サイトリライアビリティエンジニアリング ―Googleの信頼性を支えるエンジニアリングチーム』オライリー・ジャパン、2017年、p.448) これまでの会とその課題 「アプリケーション定点観測会」は概ね目的を果たしていましたが、 「チームの認識が揃わない」 ということがしばしばありました。 どこを見るかが揃わない: 会議の最初に「各自でダッシュボードを眺めて気になった点を挙げる」という時間を設けていましたが、人によって見始めるウィジェットが違うことで時間内に見切れなかったり、見る人によって解釈が異なったりしていました。 良いか悪いかの判断が揃わない: 例えばCPU Utilizationのようなウィジェットは、100%に達していなければOKと一瞬で判断できる一方、Y軸が100に固定されていないと自動でウィジェットが縮尺してしまうため、パッと見て判断できず無駄な時間がかかることがありました。 次のアクションが揃わない: メトリクスの見方が人によって違うため、「このグラフのこの変化はどういう意味か?」といった 認識合わせの議論に時間が割かれる こともしばしばありました。 このようなケースがときおり発生しており、会が非効率になってしまうことで気づくべき変化を見落としてしまうことは避けたいと考え、ダッシュボードを改善しました。 改善アプローチ 課題に対応する形で、3つの改善を行いました。 課題 改善 どこを見るかが揃わない ダッシュボードの集約 良いか悪いかの判断が揃わない 明確なウィジェット 次のアクションが揃わない 観点の明記 1. ダッシュボードの集約 ─ 「どこを見るか」を揃える プロダクトごとに似たようなダッシュボードが並んでいたので、 テンプレート変数 を使い集約できるようにしました。またプロダクト・非同期処理・データストアなどでダッシュボードが分散していたので、1つのダッシュボードに集約しました。 テンプレート変数とはダッシュボードに定義できる変数のことです。クエリに $ をつけることで変数を参照でき、似たようなウィジェットを複数作らなくてもよくなることで保守性が上がるメリットがあります。 2. 明確なウィジェット ─ 「良いか悪いか」を揃える ウィジェットについて「閾値に抵触していないか?」「変化はリリースによるものか?」といった点がパッとわかるようにしました。 Y軸の固定とマーカー 例えばなんらかの使用率(Utilization)を見る場合、Y軸を100%に固定し、85%と100%にマーカーを引くことで、一目で状態が把握できるようになります。 マーカーを設定する理由は、意思決定をブレさせないためです。たとえばある日ではCPU使用率が80%のときに「なんかやばくね?」と判断して調査したのに、それより上の85%のときは「まだ余裕あるし対応しなくていいか」となってしまうことがあります。人によって、あるいはその日の気分や残り時間によって判断基準が変わってしまうことがあるのです。 では「CPU使用率が85%を超えた場合は一次調査する」と決めるだけでいいかというと、見逃してしまったり忘れてしまったりのリスクが残ります。マーカーで線を引いておけば「85%を超えたら調査や対応を検討する」との決めが視覚的に表現でき、ブレがなくなります。 マーカーを2つ引く理由にも意図があります。 85%(ワーニング) はスケールアウトやスケールアップを検討する目安です。この段階で気づければ、余裕を持って対応できます。観測会では主にこちらを取り扱います。 100%(クリティカル) はアラートが発報されるラインであり、すでに問題が顕在化している状態です。通常こちらはアラートによって取り扱うため、観測会では事後的な確認になります。この2段階にすることで、判断がしやすくなります。閾値自体が大切ではなく、「対応を開始するライン」と「抵触したら問題になるライン」を常に表示しておくことが大切です。 前週比のオーバーレイ表示 Datadogの calendar_shift 関数を使って、前週のデータを点線でオーバーレイ表示しています。これにより「先週と比べてどうか」が一目でわかります。 そもそも前週比がないと何が困るのでしょうか?グラフを見ても「この数値は高いのか低いのか」が判断できません。例えばエラー数が100件あったとして、それが普段通りなのか異常なのかは、比較対象がないとわからないのです。結果として「なんとなく大丈夫そう」という曖昧な判断になったり、正常なのに異常と誤認して無駄な調査をしてしまうことがあります。 「前週比」という点にもポイントがあります。前日比だと曜日による変動に惑わされます。例えばリクエスト数が平日と休日で大きく異なるプロダクトの場合、月曜と日曜を比べてもあまり意味がありません。前月比も同じく週が一致しない場合があるので、使いづらいです。そのため「前週の同じ曜日」との比較がちょうど良いと考えました。この辺りはプロダクトの特性にもよって適切な設定が変わってくると思われます。 リリースとの関連付け メトリクスに変化があったとき「それはいつのリリースが原因か?」を特定したいことがあります。リリースと紐づいていないと、変化の原因を探すために別途デプロイ履歴を確認する手間が発生します。 用いるメトリクスもそういった観点を踏まえて選びます。CloudWatchの aws.ecs.cpuutilization メトリクスはECSサービスレベルしかわからず、どのコンテナを改善すべきか、リリースとの関連がわかりづらいです。Datadog AgentサイドカーのFargateメトリクスで使用率を計算し、 task_version でグルーピングすることでリリースによる使用率の推移を観測できます。(デプロイのイベントをDatadogに送信するのもありかと思います) sum:ecs.fargate.cpu.usage{$service_name} by {task_version} / sum:ecs.fargate.cpu.task.limit{$service_name} by {task_version} * 100 3. 観点の明記 ─ 「次のアクション」を揃える ウィジェットの横にメモを必ず設けるようにしました。 メモがないとグラフが異常なように見えても「で、どうすればいいの?」となってしまうことがあります。自分が詳しければ問題ない、または詳しい人がいれば説明してくれますが、その人が休みだと判断できません。メモに「異常時は〇〇を確認する」と書いてあれば、誰でも次のアクションを取れます。ネクストアクションについて書きすぎると目が滑ってしまうので、あくまで簡単な記載にとどめます。ランブックへのリンクにするのもよいでしょう。 逆にメモが書けないような「とりあえず出してみている」ウィジェットは今回を機にバッサリ整理しました。そのようなウィジェットは時間が余った際に探索的に見るものと位置付けています。 余談ですが、スキルアップやバックログアイテムの発見につながるため探索的に見ることも重要だとは考えています。一方で、「予防」のアクションを取りたいのか「発見」のアクションを取りたいのかで適切なやり方は異なるため、会を分けるべきと考えています。 メモには「メトリクスの説明(どういったメトリクスで、どういった事象を引き起こすか)」「望ましいメトリクスの状態」「異常時に取るべきアクション」などを簡単に記載しています。 実際のダッシュボードでは以下のような形式でメモを記載しています。 ## 🗒️ Check!! - 前週比(点線)で異常に増えていないか - アプリケーションのエラーなのでLogsから原因を確認 ## 🗒️ Check!! - Task Limit(赤線)に抵触してないか - 抵触している場合スケールアップ or 性能改善が必要 ## 🗒️ Check!! - 前週比(点線)で異常に増えていないか - AWSの「Troubleshoot your Application Load Balancers」のドキュメントを参考に対応する - 4xxが跳ねている時はWAFがブロックして403を返していることが多く、 その場合は攻撃を弾いているので特に問題はない おわりに このような工夫をすることで、「どこを見るか」「良いか悪いか」「次に何をするか」について以前よりチームの認識が揃うようになりました。認識合わせに費やしていた時間が減り、その分を「なぜこの変化が起きたのか」という深掘りの議論に当てられるようになっています。 一方で、観測会ではアプリケーションのダッシュボード以外にもセキュリティやコストについても確認しており、「人によって見始めるウィジェットが違うことで時間内に見切れない」という課題は以前より緩和したものの、解消されたとは言い難い状態になっていますので、引き続きの改善を行っていきたいです。(今期からコストは一部別の会議に切り出しています。) 今回ご紹介したダッシュボード改善のプラクティスが、みなさんのチームの参考になれば嬉しいです。 タイミーでは一緒に働くエンジニアを募集しています!興味のある方はぜひカジュアル面談でお話ししましょう。 採用情報はこちら またね〜
アバター
この記事はTimee Product Advent Calendar 2025の11日目の記事です! qiita.com こんにちは。Androidエンジニアの Hunachi( @_hunachi )です。 突然ですが、日常生活において、バーコードを目にしたり、使ったりすることはけっこうありますよね。私もセルフレジでいつもピッピしています 🥦🛒 そんな身近なバーコードの読み取り機能を、Androidアプリに実装してみて失敗したときの話をします。失敗はしましたが、今はすでに安定稼働しているのでご安心ください ✅ このブログでは、コードの詳細は書きません ✂️ なお、ここではiOSの話はしません。iOSはAndroidとはまた別の苦難があり、後日iOSエンジニアの方がブログを書いてくれることを願っています 🙏📱 経緯:ユーザーにコードを読み取ってもらう機能が必要に 🧩 仕様は0から自分たちで考えており、制約の範囲内でコードタイプも自由に決められる状況でした。 他の箇所でQRコードを使っていたため、ユーザーが混同しないよう一次元バーコードを採用しました。 社内の技術以外の制約により、チェックデジットなしの形式を選ぶ必要がありました。 Pixelなど主要端末での手動確認では問題は見つかりませんでした。 チームメンバーを含む複数人での確認も実施済みでした。 今回使用した、バーコード読み取りの主要技術 🛠️ ML Kit(Google ML Kit) CameraX(Android Jetpack) 補足注: 「チェックデジット」は、読み取り誤りを検出するための検査用桁です。今回は発行側の事情で付けない形式を採用しました。 リリース後に発生した問題 🚨 問題1:一部端末で読み取りが難しい(もしくは実質不可)📵 ユーザーからの問い合わせで発覚しました。 分析の結果、影響は一部の数種類の端末に限られそうだと分かりました(おそらく100ユーザー以下)。 低スペック端末だけの問題ではなく、高性能カメラの端末でも発生していました。 特定端末を検証用として購入し、手元で再現を確認しました。 高価な端末にもかかわらず、検証用として迅速に手配してもらえました(関係各位に感謝です 🙇‍♀️)。 完全に不可能というほどではないものの、かなり読み取りにくいことが分かりました。 問題発生確率の調査方法 🔍 厳密な定量分析は難しいため、「本来読み取られるはずの回数」に対する「実際に読み取られた割合」が極端に低い端末や、問い合わせがあった端末を特定して調べました。 対応策(暫定) 🧯 画像からバーコードを登録できる機能を追加しました。 撮影方法の説明を強化し、誤った方法で操作してしまう可能性を下げました。 問題2:誤読(別のコードとして読み取ってしまう)🔀 本来そのユーザーが読み取るはずのないコードが読み取られる事象が発生しました。正しいコードが読み取れないと、そのユーザーが特定の機能を正しく使えなくなるため、重大な問題です ⚠️ バーコード読み取り機能に欠陥がある可能性を疑いました。 CameraX経由の読み取りで、ブレた画像から別コードとして解釈されるケースがあると分かりました。 即時フィードバックが難しい背景 ⏱️ 裏側の仕組み上、ワーカーが読み取ってすぐに誤りに気づけない場合があります。 多くはすぐに弾けますが、条件次第では弾けないことがあります。 問題発生確率の調査方法 🧮 手元での再現は運に左右され、難しいです。 無効データ検出時のログを分析して、発生確率を推定しました。 対応策(暫定) 🛡️ CameraX経由の読み取りに限り、「同一コードが1秒以上連続で読み取られた」場合のみ読み取り成立と判定するようにしました。 これにより、従来は弾いていた分も含め、読み間違いが減少しました。 1秒という閾値は、UXの観点も踏まえて決めました。 恒久的な対策 ♻️ バーコードをやめ、QRコードへの全面置き換えを決めました。 QRコードには誤り訂正やチェックデジットがあり、問題2の発生確率がほぼ0に近づきます。 バーコードにチェックデジットを付ける選択肢もありましたが、誤読時に二桁同時誤りが起きる可能性があり、精度面でQRコードに劣ると判断し、QR化に舵を切りました。 学びと所感 📝 アプリから読み取る × 一次元バーコード(特に発行側の制約でチェックデジットがない形式)の画像読み取りは、採用しない方が良いです!🙅‍♀️ 低スペック端末だけが問題になるとは限らず、高性能カメラ端末でも問題が起き得ると分かりました。 初期の選択は誤りでしたが、問題が見つかるたびにすぐ解決策を模索し、両OSとも最短に近い速度で対応できたのは良かったです 🚀 ユーザーに追加操作を強いることなく、UI/UXを損なわない形で解決できた点も良かったです 🙆‍♀️ 今年も失敗から多くの学びを得ました 😌 次回以降は、ユーザーさんに影響を全く与えない形で失敗するようにしたいです 😭 みんなで楽しく発信していける環境、いいなと思ってくださった方は、ぜひ気軽に声をかけてください!📣  product-recruit.timee.co.jp product-recruit.timee.co.jp (画像はAIで生成しています🍌)
アバター
こんにちは!タイミーでエンジニアリングマネージャーをしている恩田です。 この記事は  Timee Advent Calendar 2025  の10日目の記事です。 はじめに 前置き・プラットフォームエンジニアリング部門の役割 PO/PdM不在のチームは「やるべきこと」をどうやって決めるのか? 定量情報の観測 アプリケーション定点観測会 内部品質定点観測会 定性情報の観測 ポストモーテムを眺める会 スプリントレポート報告会 開発者体験アンケート オフィスアワー おわりに We are hiring! はじめに この記事では、私が所属するプラットフォームエンジニアリング部の活動の紹介、特に課題探索を目的としてどのような活動をしているかをご紹介したいと思います。前置きとして、弊社におけるエンジニア組織およびプラットフォームエンジニアリング部の役割やメインミッションの紹介もしており、本題まで少し前置きが挟まります。また、あくまで弊社組織での実例紹介であり、ベストプラクティス等を意識したものではない点にご留意いただきつつ、どなたかのご参考になれば幸いです。 前置き・プラットフォームエンジニアリング部門の役割 タイミーのようなプロダクト主導型組織において狭義のプロダクト戦略とは、マーケティングとイノベーションに対して戦略的意図(顧客ニーズに応える新しいプロダクトやサービスをどう生み出し、どう市場に届けるか)を策定することを指します。この戦略的意図を実現するための具体的なアクションプランをタイミー社内ではプロダクトイニシアチブと表現しています。開発者目線であえて端的な表現をすれば「ユーザ価値を届けるためのプロダクト機能開発」に類する仕事です。タイミーのエンジニアの大部分は、このプロダクトイニシアチブの実行/推進を主たる業務とする組織に所属しており、職能横断的なチーム構成のもと企画から設計、開発、テスト、リリース、施策評価までを一貫して行える組織設計を意図して組成されています。 その一方、プラットフォームエンジニアリング部門ではチームのユニット単位を「職能」で定義しており、WebFront領域に専門性を持つエンジニアで構成されるチーム、バックエンド領域に専門性を持つエンジニアで構成されるチーム、クラウドインフラ領域に専門性を持つエンジニアで構成されるチーム、QAエンジニアで構成されるチーム、セキュリティ領域に専門性を持つチーム、といった具合です。 その上で、組織のミッションと存在理由を タイミーユーザ目線のあたりまえ品質を提供する プロダクト開発組織がプロダクトイニシアチブを爆速でデリバリできる状態を提供する と定義しています。そのため、プロダクトイニシアチブに則った開発プロジェクトにプラットフォームエンジニアリング部が直接・間接的に参画寄与することもありますが、メイン業務は上記を達成するための技術改善/支援となります。 [NOTE] 「プラットフォームエンジニアリング」とは、安全で管理されたフレームワーク内の改善された開発者エクスペリエンスとセルフサービスを通じて各開発チームのセキュリティ、コンプライアンス、コスト、およびビジネス化までの時間に関する価値を向上させることを目的として、DevOps 原則から構築されたプラクティスである、と一般的に定義されています(定義話は長くなるのでこの記事ではこれ以上は触れません)その上で、弊社におけるプラットフォームエンジニアリング部は、上記に掲げるミッション/目標達成のために上記プラットフォームエンジニアリング(プラクティス)を「手段として必要に応じて選択、実践するもの」と捉えています。 PO/PdM不在のチームは「やるべきこと」をどうやって決めるのか? 前置きが長くなりましたが本題です。我々が上記ミッションを達成するために、どのようなアクションプランを立てるべきなのか - この意思決定の材料の1つが顧客の声です。我々にとっての顧客とは、タイミーのエンドユーザ(プロダクト品質の受益者)と社内開発者が該当します。 プラットフォームエンジニアリング組織にはいわゆる「プロダクトマネージャー」と呼ばれる役割を設置しておらず、各チームは定量軸と定性軸の一次情報、すなわちタイミーの各種システムモニタリングと社内開発者のVOC(Voice of the Customer)の継続的な収集を通じて課題仮説の言語化と打ち手仮説を立て、検証とアクションプランの実行をエンジニア全員が主体となって継続しています。これを各チームが各々定期イベントとしてチーム業務に組み込んでいます。 以下、具体的にどのような定期業務イベントでどのような定量、定性情報を日々収集し、課題仮説立てに用いているのかを紹介します。 定量情報の観測 アプリケーション定点観測会 タイミーのシステム信頼性、パフォーマンス、コスト、セキュリティ等にまつわる様々なメトリクス/指標を観測する会です。現状とトレンドの事実確認を行い課題仮説を立てアクションにつなげる / 直近の改善施策の効果を確認し、対策を継続すべきかクローズすべきか等の判断を行うことを目的としています。具体的には以下のような指標を同期ミーティングで集まり確認をしています。 信頼性/パフォーマンス観点 タイミーのBackend API群のレイテンシ、エラーレート、コンテナの各種メトリクス、スケーリング傾向やリクエスト傾向(シーズナリティ/スパイク傾向) データストア層(MySQL, Redis, ElasticSearch) の各種メトリクス、クエリパフォーマンスやスロークエリ、Cache Hit Rate、etc Sidekiq Jobのスループット、Jobs count推移、Workerのスケーリング傾向 バッチジョブのメトリクス、起動失敗率 外部SaaS類へのリクエスト数推推移やスループット、メールのバウンスレートやPUSH配信のエラーレート等 Security観点 CSPM等によるAWS構成不備の新規逸脱検知状況のチェック ECRイメージ脆弱性検査状況の定点チェック GuardDutyの検出結果振り返り コスト観点 AWS、Datadog、GitHub等利用料の大きいSaaS類の利用状況トレンドの把握。 月次/年次予算対比での上振れリスク 利用内訳(group by service, product, etc)の確認と、内訳比率に大幅な変化がないかのチェック RI Coverageの状況 Observability観点 メトリクスの不備、不足などについての課題提案 アラートの過不足、およびしきい値の調整予定についての課題提案 ダッシュボードの見直しなど、観測設計そのものを改善対象としての改善点洗い出し 内部品質定点観測会 タイミーのバックエンドアプリケーションにおける開発者体験を司る各種指標を定点観測する会です。目的はアプリケーション定点観測会と同様で、現状とトレンドの事実確認を行い課題仮説を立てアクションにつなげる / 直近の改善施策の効果を確認し、対策を継続すべきかクローズすべきか等の判断を行うことを目的としています。具体的には以下のような指標を同期ミーティングで集まり確認をしています。 CI/CDパフォーマンス観点 CI, CD の失敗率・失敗要因の分析 CI, CD の実行時間、実行時間変化の分析 PRのレビュープロセス観点 レビューリードタイム推移 マージしたPR数のトレンドと各チームの開発状況との因果関係考察 テストの健全性観点 Flaky Test の新規発生・修正状況 遅いテストの抽出と高速化余地の洗い出し 定性情報の観測 組織として現在収集できているメトリクスから開発生産性の全容を捉えるのは難しい側面があります。特に開発のバリューストリーム上のボトルネックやToilはコーディング、テスト、リリースといった開発工程の外にあるケースも多いです。観測しやすいメトリクス (4keysやGitHub上で観測できるLead time to Change等)だけを追っていても改善対効果の高い課題仮説が浮かび上がらないケースもあります。ビジネス要件の把握、仕様策定、コードベースの把握、レビュー、手動/自動テスト、承認、リリース作業、etc,,。開発工程のどこにボトルネックが発生しているか課題仮説を立てる材料として、開発者からの定性情報(これがツライ、わからない、知らない、etc)は貴重な情報源となります。 ポストモーテムを眺める会 タイミーの開発組織では、障害発生後にポストモーテムを行う文化が定着しています。ポストモーテムは障害対応/収束を担当したチームが中心となって実施します。このポストモーテムの内容(議事録)に記された議論過程やNext Actionをプラットフォームエンジニアリング部門のチームでクロスレビューし、「どのような支援(技術的改善、プロセス/ガードレール整備、知識/情報の非対称性の解消等)を行うと価値がありそうか」を探索しています。 スプリントレポート報告会 プラットフォームエンジニアリング部のチームがデリバリした開発者の生産性向上、体験向上を目的とした各種施策のサマリをレポートし、顧客(社内開発者)からのFBや要望を受け取る会です。 スプリントレポートはチームの作業計画に沿ったアウトプットです。アウトプット内容を共有しつつ、同時に社内開発者から「こんなことで困っている」といった一次情報を受領する相互情報交換を目的としています。 開発者体験アンケート 「開発者が自信を持ってリリースできる状態の実現」をゴールとした、開発者体験の現状を把握し改善につなげるためのアンケートを実施しています。また、アンケート収集後に内容を精査、具体的な改善アクションにつなげるため、必要に応じて回答者へインタビュー等も実施します。SDLCの各フェーズ毎、プラットフォームエンジニアリング部門のエンジニアが独自に策定した論点を元に質問を作成しており、技術的負債、業務プロセス、知識/情報の非対称性、様々な確度から課題の種情報を収集しています。 オフィスアワー 主にクラウドインフラ領域の技術に関するオープンドア形式のQ&Aセッションです。特定時間にslackのhuddleを開き、参加者は自由に出入りできる形で場を運営しています。 クラウドインフラチームが専売特許となりがちな技術領域、例えば監視設計やデータストア選定、データマイグレーション計画のノウハウ、CI/CDパイプラインやAWS全般に関する疑問や質問、興味のあることを何でも気軽に同期で質問・相談できる場として設計しています。 この場を通じ、開発組織全体で信頼性エンジニアリングのプラクティス実践を推進するにあたり障壁となる知識/情報の非対称性や、技術/組織課題の探索の場として活用しています。 おわりに この記事では、弊社プラットフォームエンジニアリング組織における各種課題探索の実例を紹介しました。実例の一つとして参考になれば幸いです。 We are hiring! タイミーでは絶賛エンジニアを募集中です。興味があればぜひお話ししましょう! プロダクト採用サイトTOP カジュアル面談申込はこちら
アバター