KINTOテクノロジーズのブログ - TECH PLAY

TECH PLAY

KINTOテクノロジーズ

KINTOテクノロジーズ の技術ブログ

1123

この記事は KINTOテクノロジーズアドベントカレンダー2025 の22日目の記事です🎅🎄 はじめに こんにちは。KINTOテクノロジーズ株式会社(略して、KTC)で iOS, Androidモバイルアプリを開発している、方茂碩(バン・ムゥソク、Bahng Mooseok)です。 これまで「Global KINTO App」、「KINTO かんたん申し込みアプリ」などを担当し、現在は 「KINTO Unlimited」の開発を行っています。 「KINTO かんたん申し込みアプリ」は、新車のサブスクサービスであるKINTOの見積りから審査までができるアプリで、「KINTO Unlimited」は、契約内容の確認、ドライブサポートやクルマのアップグレードの申し込みなどができるアプリです。 今回は、WWDC25に参加してきましたので、テックブログにまとめてみました。 私は2008年からiOSアプリ開発に携わっており、当時はまだ「iOS」ではなく「iPhone OS」と呼ばれていた時代です。 長年にわたって、WWDCは技術情報の収集や最新技術のキャッチアップにおいて最も重要なイベントだと感じてきました。にもかかわらず、今回が初の現地参加となり、とても感慨深い体験となりました。 やはり現地ならではの没入感は、オンライン参加とはまったく違いました。 Check-in and welcome reception @Apple Infinite Loop 日曜日の午後、Appleの旧社屋「Apple Infinite Loop」にて、事前チェックインとウェルカムレセプションが行われました。 WWDCのバッジとグッズを受け取り、そのまま夕方までウェルカムパーティが開催されました。 WWDC25の参加バッジ、KTCからはほとんどのアプリを TOYOTA FINANCIAL SERVICE CORPORATIONの名前でリリースされています WWDCも、この場所も憧れだったので、結構並びますが、WWDC25のモニュメント前での記念撮影は必須です!行列にはなりますが、並ぶ価値ありです。 前日夜には日本からの参加者が集まる交流会にも参加していたため、その時に出会った方々と話したり、会場内にいるAppleの社員と話したりと、楽しい時間を過ごせました。Appleの偉い方から「あそこが Steve Jobsのオフィスでしたよ」と直接説明を聞けたのは、貴重な経験でした。 そして、Apple Japanの方ともお話する機会があり、日本に戻ってからのアプリ改善に向けた取り組みについて相談することができました。 Main Event @Apple Park - Keynote, Platforms State of the Union WWDC期間中、自分を苦しめたのが時差ボケです。メインイベントの日もちょっと寝坊してしまい、Keynoteの時間にギリギリ到着。 屋根のある良い席も確保できず、Caffe Macsでの朝食も慌ただしくなってしまいました。メインイベントの日は早めに行動するのをおすすめします。 遠い&日差しが強い! いよいよKeynoteが始まります。 Keynoteの冒頭では、Apple制作の映画F1の予告編がサプライズで上映されました。ちなみに、まだ映画館で公開前でしたが、WWDCの三日目の火曜日の夜、Steve Jobs Theaterで特別上映されました。もちろん席に限りがあるので、申し込みが必要。私はメール確認が遅れ、申し込みに間に合いませんでした。突発的なイベントにも対応できるよう、WWDC期間中は常にメールをチェックすることを強くおすすめします。 Keynoteが終わると、ランチです! Cupertinoの夏は日差しが非常に強いですが、Apple Parkの内庭でのランチは最高です。 前夜から全て無料で提供される食事、デザートもWWDC現地参加の楽しみの一つです! 午後は「Platforms State of the Union」が開催。開発者向けにより技術的な内容が発表されます。 今回のKeynoteと Platforms State of the Unionの目玉は、Liquid Glass UIと Apple Intelligenceでした。 Liquid Glassは、他の参加者からも好評で、私も非常に洗練された印象を受けました。 Apple Intelligenceでは、新しいFoundation Models Frameworkが登場。Appleアプリ開発において今後、非常に重要な基盤技術になると感じました。 In-person Labs WWDC中でも特に貴重なのが「In-person Labs」です。Appleのエンジニアやデザイナーに直接質問できる機会です。 想像以上に多くの方が対応をしていて、あまり待たずに相談することができました。 ただし一つ反省点が。この時間は概念的、抽象的な質問よりは具体的なケースに基づく質問の方が向いていると思いました。Conciergeの方が質問内容に応じて専門スタッフに繋いでくれるのですが、内容が曖昧だと割り振りにも困っているように見えました。 でも、WWDC期間中、Appleの社員と話せる機会は In-person Labsだけではありません。 ウェルカムパーティや、三日目の Developer Activitiesなど、機会は十分にあるので、聞きたいことをたくさん準備すると、より濃い体験になると思います。 Developer Activities @Apple Developer Center Cupertino 公式イベントの三日目、火曜日です。 Apple Developer Centerで Developers Activitiesが開催されました。 このイベントは事前申請が必要で、WWDCの一週間前ぐらいに案内メールが届きますが、ちょっと遅くなると参加できなくなるか、当日会場の前で空きを待つしかないので、メールが届いたら、即申し込み推奨です。 今回のテーマはLiquid Glass UI。 登壇したAppleのデザイナーやエンジニアたちが、UIの哲学や開発エピソード、さらにはライブコーディングまで披露してくれました。 このセッションはオンライン配信もされない、現地限定コンテンツなので、非常に価値の高い体験でした。 非公式カンファレンス、イベント - One More Thing Conference, Core Coffee WWDC開催中は、Cupertino周辺で多くの非公式Apple系イベントも開催されています。 twostrawsで知られるPaul HudsonさんがWWDCごとにまとめてくれているイベントリストがあるので、要チェックです! https://github.com/twostraws/wwdc 今回はその中から、「One More Thing Conference」と 「Core Coffee」に参加しました。 「One More Thing Conference」では、公式発表された新技術をその場で実装・検証しながら、実用的な知見を深められるのが印象的でした。 非公式ながら、世界中の開発者と深く交流できる機会となりました。 まとめ 毎年WWDCの内容を追いかけてきた私にとって、今回、初めて現地で参加できたことは、とても意義深い経験となりました。 特にApple純正のFrameworkの理解は、品質・メンテナンス性の高いアプリを作るうえで欠かせないものです。 現地参加を通じて、その重要性をあらためて実感し、新たな刺激とモチベーションを得ることができました。
この記事は KINTOテクノロジーズアドベントカレンダー2025 の22日目の記事です🎅🎄 はじめに こんにちは、KINTOテクノロジーズ Mobile Assistanceマネージャー&KMPチームリードのYena Hwangです。 本記事は「Compose MultiplatformとSwiftUIで作るハイブリッドモバイルアプリ」シリーズの最終回Part 3です。Part 1ではハイブリッド開発を選んだ背景を、Part 2では具体的な実装方法を紹介しました。今回はSwiftUI連携の詳細、CMP vs Flutter比較、そして実践で直面した落とし穴と導入戦略を解説します。 本シリーズの構成 Part 1:なぜハイブリッドなのか Part 2:実装ガイド Part 3:SwiftUI連携と技術Tips ← 現在の記事 SwiftUIとCMPの相互埋め込み ハイブリッドアーキテクチャの核心は、SwiftUIとCompose Multiplatform(CMP)を自由に組み合わせられることです。ここでは、共通モジュールを実際にネイティブ画面に、どう統合するのかをご紹介します。 ComposeをSwiftUIに埋め込む SwiftUIにComposeを埋め込む方法です。 まず、CMP側では UIViewController を返します。 // AppComposeUI.kt fun createProfileVC( user: User ): UIViewController { return ComposeUIViewController { ... } } そしてSwiftUI側では UIViewControllerRepresentable を使って、そのコントローラをラップします。 // ComposeViewContainer.swift import SwiftUI import shared // Import the shared KMP framework struct ComposeViewContainer: UIViewControllerRepresentable { let user: User func makeUIViewController(context: Context) -> UIViewController { // Use the Compose wrapper to create the UIViewController return AppComposeUIKt.createProfileVC(user) } func updateUIViewController(_ uiViewController: UIViewController, context: Context) { } } これでSwiftUIの中にCMPの画面が自然に表示されます。 以下は ComposeViewContainer に user を渡している例です。 // ContentView.swift struct ContentView: View { let user: User var body: some View { VStack { Text("SwiftUI Header").font(.headline).padding() // Embed the Compose UI inside SwiftUI. ComposeViewContainer(user: user) .frame(height: 250) List { Text("SwiftUI Item 1") Text("SwiftUI Item 2") } } } } このように書くだけで、 CMPの画面をそのままSwiftUIのコンポーネントとして扱える ようになります。 SwiftUIをComposeに埋め込む 今回は、逆に、 SwiftUIをComposeに埋め込む方法 です。 まずKotlin(iosMain)側にエントリーポイントを用意します。SwiftUIをComposeに埋め込むための入口です。KotlinはSwiftUIを生成しません。Swiftから () -> UIViewController のファクトリを受け取ります。 // ComposeEntryPointWithUIViewController.kt fun ComposeEntryPointWithUIViewController( createUIViewController: () -> UIViewController ): UIViewController = ComposeUIViewController { Column( Modifier .fillMaxSize() .windowInsetsPadding(WindowInsets.systemBars), horizontalAlignment = Alignment.CenterHorizontally ) { Text("Embedding SwiftUI into Compose") UIKitViewController( factory = createUIViewController, modifier = Modifier.size(250.dp).border(2.dp, Color.Blue), ) } } そしてCompose側では UIKitViewController() を使って、SwiftUIビューを表示します。 次にSwift側の実装です。ここでは MySwiftUIView を定義して、 UIHostingController でラップします。 // MySwiftUIView.swift struct MySwiftUIView: View { let userName: String var body: some View { VStack(spacing: 8) { Text("Native SwiftUI Content").font(.headline) Text("Welcome, \(userName)") } } } // Pass SwiftUI to Kotlin entry point struct ComposeViewControllerRepresentable: UIViewControllerRepresentable { func makeUIViewController(context: Context) -> UIViewController { // Pass a factory to Kotlin that returns a UIViewController. // Here we wrap our SwiftUI view in a UIHostingController. return Main_iosKt.ComposeEntryPointWithUIViewController(createUIViewController: { UIHostingController(rootView: MySwiftUIView(userName: "Yena Hwang")) }) } func updateUIViewController(_ uiViewController: UIViewController, context: Context) {} } そして、そのコントローラを ComposeEntryPointWithUIViewController にファクトリとして渡します。このようにして、結果的に SwiftUIの画面をComposeの中に表示する ことができます。 ネイティブUIコンポーネントの埋め込み:MapView 次に、ネイティブUIコンポーネントを利用した例です。CMP側にネイティブUIコンポーネントを埋め込んだアプリの動作をご覧ください。このMapViewはiOSの ネイティブコンポーネント です。 // MapContainer.kt // commonMain @Composable expect fun MapContainer( modifier: Modifier = Modifier, dealers: List<Dealer> ) // iosMain @Composable actual fun MapContainer( modifier: Modifier, dealers: List<Dealer> ) { UIKitView( factory = { // platform.MapKit MKMapView(frame = CGRectZero.readValue()).apply { showsUserLocation = true delegate = MapDelegate( ... ) } } ) } 共通コードでは expect 関数を宣言し、iOS側では actual を実装しています。そして UIKitView を使って、 MKMapView をそのまま埋め込んでいます。 このように、 expect/actual パターンを使うことで、共通インターフェースを維持しながらプラットフォーム固有のネイティブコンポーネントを自由に埋め込むことができます。 CMP vs Flutter:なぜCMPを選んだのか ここまでCMPとネイティブUIの使い分けについて見てきましたが、実は他のクロスプラットフォームのフレームワークでも同じような課題があります。 ネイティブビュー統合方式の決定的な違い 例えばFlutterの公式ドキュメントには、『Platform Viewにはパフォーマンス面でトレードオフがある』と明記されています。 区分 CMP Flutter レンダリング Inline Rendering 😄 Overlay 🥲 特徴 高速で効率的 重いビューでカクつき 技術的な違い CMPとFlutterでは、ネイティブUIと埋め込みUIの相互運用方式が異なり、パフォーマンスに大きな差が出ます。 Host UI → Embedded UI Rendering path Performance impact Native → CMP Android: AndroidView inside Compose (same View system) iOS: CMP Skia surface hosts a UIKit view via UIKitView Very Low (Android) / Low–Moderate (iOS) CMP → Native Android: ComposeView in a ViewGroup (Compose runs on platform renderer) iOS: SwiftUI/UIViewController hosts ComposeUIViewController (Skia surface inside) Low (Android) / Moderate (iOS) Native → Flutter Flutter renders via Skia/Impeller; native view injected as PlatformView (texture/layer composition) Moderate; visible stutter on heavy views (Map, WebView) Flutter → Native Native Activity/VC hosts Flutter engine surface Extra startup cost (engine warm-up), stable after warm-up CMPの強み ネイティブMapViewをそのまま使用し、ネイティブAPIでアイコン/経路レンダリング MKMapViewなどのネイティブコンポーネントを直接配置 コンポーネント単位で交換可能 ネイティブパフォーマンスとアクセシビリティ維持 複雑なハイブリッドUIパフォーマンス比較 Framework Startup Time Memory Usage UI Smoothness Native ⭐⭐⭐ ⭐⭐⭐ ⭐⭐⭐ CMP + Native ⭐⭐⭐ ⭐⭐ ⭐⭐⭐ Flutter + Native ⭐⭐ ⭐⭐ ⭐⭐ 実践で直面した落とし穴 "Every solution breeds new problems." — Arthur Bloch ここまでCMPとネイティブUIの組み合わせの利点を見てきましたが、どんな技術にも課題はあります。私たちがKMP/CMP開発で実際に直面した落とし穴を紹介します。 KMPロジックレイヤー 1. HTTP/TLS/リダイレクト/クッキー 症状:プラットフォーム別エンジンが異なり、クッキー永続性、リダイレクト、TLSピニングが異なる動作 解決:タイムアウト/キャッシュ/ロギング共有設定 + DIやexpect/actualでプラットフォーム別エンジン+セキュリティポリシー注入 2. 正規表現の違い 症状:JVMはjava.util.regex、iOS/Nativeは ICUベースエンジン使用。 \R 、可変幅lookbehindなどがiOSで異なる動作またはサポートなし 解決:複雑な機能を避ける、シンプルなサブパターンに分離、エンジン交換可能なアダプター構成 3. タイムゾーン & DST 症状:プラットフォーム別タイムゾーンDBとフォーマッティング規則が異なる 解決:すべての計算はkotlinx-datetimeで、フォーマッティングはexpect/actualでプラットフォームに委任 CMP UIレイヤー 1. フォント & タイポグラフィ(CJK/絵文字) 症状:プラットフォーム別フォールバックが異なり、行の高さ、省略、絵文字幅が異なる 解決:フォントバンドル、フォントファミリー/ウェイト明示的宣言、lineHeight/letterSpacing明示的設定 2. 省略/テキスト測定の違い 症状:iOS/SkikoテキストレイアウトがAndroidとピクセル単位で一致しない 解決:maxLines + TextOverflow.Ellipsis使用、「ぴったり」な仮定を避ける、主要画面スクリーンショットリグレッションテスト 3. スクロール & ジェスチャー物理 症状:iOSの慣性がより「滑らか」で、ネストスクロールの感触が異なる。また、CMPのScrollの中にネイティブのScrollを入れると、内側のScrollが動作しない問題もある 注意:スクロール物理設定を抽象化してプラットフォーム別分岐、複雑なネストスクロールページは単純化。Scroll ViewのUXは設計段階から調整が必要 導入戦略:プロダクト段階別アプローチ CMP/KMPの真の強みは 柔軟性 です。共有コードとネイティブコードの比率を自由に調整できるため、プロトタイプでは再利用を最大化し、プロダクトが成熟したらネイティブ比率を高めることができます。 新規プロダクト:共有比率を高くスタート 段階 共有比率 目標 リソース状況 Start Stage ~99% 迅速なリリース、アイデア検証 限られた開発リソース Growth Stage ~80% プロダクト拡張 + ネイティブUX強化 標準開発リソース Maturity Stage ~50% パフォーマンス最適化、長期保守性、チーム専門化 豊富な開発リソース 既存プロダクト:段階的導入 1. Start Small(1%) 最も安全なエントリーポイント。最も小さくリスクの低い領域にKMP/CMP導入 2. Stepwise Expansion(20%) 安定性と確信を確保しながら導入範囲を拡張 3. End Stage(~50%) 共有コードとネイティブコードの持続可能なバランスポイントに到達 おわりに ハイブリッドアーキテクチャを導入して得られた成果をまとめると: 項目 Before(従来・ネイティブ) After(ハイブリッド) 開発効率 両OS別々に実装 50%削減、一箇所でバグ修正 コスト 重複作業・すり合わせ必要 コミュニケーション・QA・保守削減 チーム OS別に専門エンジニア必要 少人数で両プラットフォーム対応 品質 ネイティブ品質 ネイティブ品質を維持しながら共有 柔軟性 ネイティブのみ 必要な部分だけ共有可能 ネイティブの強みを活かしながらコードを共有できる ——これがハイブリッド戦略の最大のメリットでした。 DroidKaigiで発表しながら、多くの方々が同じ悩みを持っていることを感じました。これからKMP・CMPの導入を検討しながら、両OSのネイティブコードも活かしたハイブリッドアーキテクチャを準備している方々に、私たちのチームの経験が少しでも参考になれば幸いです。 重複作業を減らし、両OSに効率よく対応しながら、高品質なアプリを素早くユーザーに届ける——KMP・CMPを活用したハイブリッド開発を、ぜひ検討してみてください。 こちらは「Compose MultiplatformとSwiftUIで作るハイブリッドモバイルアプリ」シリーズのPart 3(最終回)です。
こんにちは、 @ahomu です。この記事は KINTOテクノロジーズ Advent Calendar 2025 の22日目の記事です🎅🎄 2025年2月に KINTOテクノロジーズの開発組織を強くしたい Engineering Office のご紹介 という記事でご紹介した弊チームについて、発足から1年弱経過した現状とメンバー紹介を書きます。 1年を振り返って 今年の中頃にFindyさんの開発生産性カンファレンスでも弊チームについて登壇させてもらいました。 https://findy-tools.io/articles/kinto-technologies-dev-productivity-con-2025/133 我々は「トヨタグループの内製開発部隊たるKINTOテクノロジーズ(KTC)の開発力・組織力を高めるためにケイパビリティやカルチャーを獲得/変化するための働きかけ」という、抽象的なミッションを担っています。 学びと理解と関係づくり 登壇時にも言及したことですが、我々のような社歴の浅いメンバー/チームが横軸活動を進める上で大事なことは、独りよがりにならず、これまでとこれからをセットで示すことです。 これまでのトレードオフを知ることで、現状の意味・意義を知る 問題や不足を見つけるのではなく、今できていることを知った上で伸び代を見つける EOは各人の領域でこの動きをしっかり行うことができたと思います。また、実際に頼りにしてもらえる機会も増えてきており、まだ小さいながらも着実に変化を起こせています。 全社のカバレッジとしては不足もありつつですが社内各所、各レイヤーとも様々な関係を築けました。 個人商店と多様性のシナジー 活動が本格化するにつれて専門性の異なる個人商店的なチームであることの明確な強みが出てきたように感じています。専門領域以外にも出身業界や属性に多様性があるチームなので、ひとりひとりが様々な視点をもって全社に向けてアプローチをしています。 その過程であつまった情報や知見を持ち寄ると、同じ対象にも色々な物の見方や、立場による見解の差異がよく見えてきます。所感と事実を正しく扱うことで、KTCの次の可能性や、より具体的な打ち手を考える中で大きな助けになっています。 また、ひとりひとりが社内営業であると同時に、組合として助け合うことで「この仕事はこのひとのほうが得意だからパスしちゃお」がうまくワークすることも増えています。個人的な経験だと同質性による強行突破を図るような仕事が多かったので、今のこのチームで多様性のメリットが強く感じられることに面白みを感じています。 実際の取り組みとゆかいななかまたちを紹介するぜ 今年のAdvent Calendarの中で各自が取り組みを紹介しているので、ここでは記事リンクとあわせてメンバー紹介をしていきます。(ドコドコドコ……🥁 🚀 「一人二役、開発プロセス改善の北風と太陽」Y.Naitoさん https://blog.kinto-technologies.com/posts/2025-12-17-releasefirst/ SPI (Software Process Improvement) スペシャリストとしてEO発足以前から社内各所で活動しています 記事にある「リリースファースト」はまさにNaitoさんの真骨頂。スクラムの雰囲気に乗っかってきただけの自分としては、開発プロセスという一連の営みに対する解像度の高さを学ばせていただいております 北風と太陽、モードを使い分けてるけど、なんにせよパワフルさに社内で定評がある。 亀十のどら焼きを布教するプロ 🎨 「EOの特異点、KTCのデザインをデザイン中」emimさん https://blog.kinto-technologies.com/posts/2025-12-11-userfirst2025/ チーム名称的にエンジニアが増えるかと思いきや、emimさんはデザイナーです。デザインエンジニアとかでもなく純粋にプロダクトデザインが直近の専門 記事では、形骸化しがちな「ユーザーファースト」を再定義する挑戦が綴られています。開発の中でデザインとエンジニアリングのブリッジをしてきた経験を活かし、EOとして内製開発組織の変革に挑戦してくれています 「社内フリーランスで動き回る前提で、しくじると社内無職まっしぐらですよ!(乱暴な意訳)」という珍妙な求人訴求に興味を示してくれた奇特な方。 おいしいコーヒーだいすき 🍔 「バーキン担当アクセシビリティ番長(仮)」辻さん https://blog.kinto-technologies.com/posts/2025-12-09-What-I-want-to-achieve-as-blind-person-at-mobile-company/ 入社したてホヤホヤ。アクセシビリティエンジニアとして幅広く社内外でご活躍予定 一連の活動を通してアクセシビリティ〜ユーザビリティが直接的に高まる → グループ会社としての使命を本質的に果たせるようになることはもちろん、多様な利用環境に関する気付きを得られるので広くユーザーに対して深い洞察を得られる組織の育成につながると考えています(筆者観点) 東京のオフィス近くにあるバーガーキングで ワッパーを食べる約束?をしている 👔 「Engineering Office は心の主務」ahomu じつは7月から人事マネージャーを兼任している。プロ人事の皆さんに支えられています EOではアウトプットや進め方のレビューだけしてるマネージャー業 EOが仕掛けている組織の変化に備え、私は人事としてチェンジマネジメントに携わっている、というのが正しいフォーメーション説明 さいごに KTCのEngineering Officeのご紹介でした。年明けにはSET(Software Engineer in Test)としての専門性を持つメンバーもジョイン予定です。 まさか1年でこんな人が増えるとは思っておらずびっくりですが、求人要件がファジーすぎて難しいので、引き続きリファラル中心で積極的な採用はしていません。 👉 KINTOテクノロジーズ 採用情報(オープンポジション)はこちら Engineering Office決め打ちでなくても大丈夫なので、ご興味がある方は何らかの手段でコンタクトとっていただければ色々お話させていただきますので、よろしくお願い致します。
この記事は KINTOテクノロジーズ Advent Calendar 2025 と 技術広報 Advent Calendar 2025 の21日目の記事です🎅🎄 何の記事? 本記事は、私が技術広報として働く中で「発信すること」について発見したこと、感じたこと、ある考えに至ったことをまとめたものです。 端的に結論を書くと「発信しよう!」ということなのですが、そこに思い至った経緯なども合わせて読んでいただければ嬉しいです。 想定読者 エンジニアの(特に発信が苦手、嫌い、やったことない、という)方 発信を呼び掛けてる技術広報の方 テック企業に勤めている非エンジニアの方 SNSや社内ブログで発信をめちゃくちゃやっている方(レビュアーとして意見もらえたら嬉しいです) 簡単に自己紹介 はじめまして。Bambooこと竹中( @shell_in_bamboo )です。 7月にKINTOテクノロジーズに入社し、Fukuoka Tech Labの立ち上げと技術広報グループのマネージャーを兼任しています。 新卒で12年ほど独立系のSIerでエンジニアやPMを経験し、前職では福岡の金融機関の内製開発組織でスクラムマスターをやっていました。スクラムマスターってなにするの?とよく聞かれるのですが、「組織やチームのことを考えてる人」と最近では答えてます。あんまりよくわからねーですね。笑 マインドチェンジ さて、そんな私がKINTOテクノロジーズに入社して技術広報を担うことになったのですが、それまでは発信することに積極的ではありませんでした。 ちょっと前までの考え方 自己紹介で書いたとおり、前職までは組織やチームのことを考えて働いていたので「外に発信してる余裕なんてない!」という感じでした。イベントやセミナーで情報を仕入れることはあっても、自分から情報発信はほとんど行っていませんでした。 そういう役割をやっている人もいたし、向いている人がやるんだろうな~がんばれ~ありがとう~という考え方でした。 考え方がかわったタイミング ハッ! ・・・としたタイミングはなかったです。どちらかというと、技術広報って何だろう?どうあるべきだろう?と調べたり考える中で徐々に変わっていった感覚です。 しかし、エンジニア時代の経験や、スクラムマスターとしての考え方が「発信すること」に確かにつながった感覚があります。 で、どう変わったの? 「間違ってた!発信はやれたらやるものでもなく、やれる人がやるものでもなく、自分も含めみんながやった方がいい!」 です。 暑苦しいですね。一気に離脱者が増えそうです(技術広報としてビュー数を意識する私偉い)。 なぜそう思ったのか? 1つ目は、エンジニア時代にたくさんの技術記事やブログに助けられた経験を思い出したからです。 何も技術がわからない新人時代、ある程度開発ができるようになってきたとき、PMとしてプロジェクトを管理していたとき・・・どんなときでも検索して出てくる先達や同士の情報に救われていました。これは、「発信してくれる」人がいなければ得られないものでした。 それにも関わらず、私自身は発信をほとんどせず、恩を返すこともできていなかったわけです。 2つ目は、スクラムマスターとして自分がアジャイルな行動をできていないことに気づいたからです。 簡潔に言うと「早くリリースして早く検証する」という考え方があるのですが、私は「早く」どころかリリース自体をしていなかったわけです。自分で良いと思ったものも、逆に良くないと避けてるものも、外に出してみないと正しいのかどうかわかりません。 私が独りよがりで信じたものをチームや組織の誰が受け入れるでしょうか。間違っていても、失敗しても、発信をして、フィードバックをもらうべきだったのです。 Learning in Public このブログを書くにあたり調べていると、"Learning in Public" という言葉が海外にはあることを知りました。 自分の学びの途中経過を公開しながら成長していく姿勢・文化のことを言うらしいです。 Learning in Publicの効果としては、以下のようなものが挙げられています。 学びの定着が圧倒的に早くなる。 人に伝える、教えることは理解をより深めることにつながります。説明する力もつきますね。 同じことで悩む誰かの助けになる。 失敗は悪いことではありません。誰かが失敗をシェアすることで同じ轍を踏む同士を救えます。エンジニアリングの現場では「自分の環境だけで起きているわけではない」という情報は重要なヒントにもなり得ます。 フィードバックがもらえる。 「自分は未熟だから」と発信を戸惑いますよね。けれど、未熟だからこそ発信をしてフィードバックを得て成長するチャンスを掴む、と前向きにとらえることができます。 他にもありますが、いくつかピックアップしました。この考え方は、まさに私が技術広報として今考えに至ったものでした。 アクションプラン 格好つけようとしてこんな見出し付けたらAI感出ますね。。安心してください、(手で)書いてますよ。笑 さてさて、どれだけマインドが変わっても、具体的な行動に移すのは難しいものです。かくいう私も、この投稿が今の会社に入って初投稿です。上司には秘密ですよ。(バレてる) 「いつだったらブログ書けるかな??」 「仕事が落ち着きそうなときにイベント登壇しようかな・・・」 こんな感じで時期を見計らっていてはいつまで経っても先に進めません。目の前の仕事、割り込みの依頼などなどは、なかなか途切れることはないですからね(´・ω・`) では、どうすればいいんでしょう。 発信する日を勢いで適当に決める 勢い?適当?そんなことでいいのか! と、思われたでしょうか? いいんです。 そんな真面目なあなたは、きっと決めた期限までに完成させるでしょう。笑 実はこれは「仕事の量は、完成のために与えられた時間を全て満たすまで膨張する」というパーキンソンの第一法則というものを逆手に取っています。 期限を先に決めることで、人はその期限に向かって頑張るわけですね。プロジェクトで先にリリース日を決めるのもこんな効果があったりします。 日付は、自分の中だけで決めるのではなく、ある程度強制力を持たせた方が効果的です。アドカレやイベントに登録してしまうのがわかりやすいと思います。 できるかどうかはさておき、まず、記念すべき発信の日を決めてみてください! 発信するペースを決める 2つめの方法は、ペースを決めることです。 ペースを維持することで人はそれに慣れてきます。 余談ですが、スクラムのスプリントも、一定のペースを保つことが推奨 ^1 されています。 1ヶ月に1本ブログ書く! とかだと、月初になったり月末になったりペースが狂うので、日単位ぐらいで固定化したほうがいいかなと思います。 おわりに ここまでお付き合いいただきありがとうございました。 こんなことを書いておきながら、まだまだ筆不精な面はありますし、億劫な気持ちも残ってはいます。 けれど、せっかくだから自分をアップデートしようと前向きな気持ちの方が大きいです。何よりも、少しでも世の中に還元できるようになれたら嬉しいというワクワク感があります。 次の記事が1年後とかにならないように頑張ります。笑 ではでは~
この記事は KINTOテクノロジーズアドベントカレンダー2025 の21日目の記事です🎅🎄 目次 1. メリークリスマス!2025年のAI活用推進を振り返って 2. 個人活用の成功と組織活用の課題   2-1. 個人活用普及率8割の達成   2-2. 組織的な活用とは   2-3. 業界全体の課題 3. イノベーションの二つの潮流   3-1. AIネイティブとAIドリブン   3-2. つまずきの4つのパターン 4. GenAIパラドックスの構造   4-1. 効率向上と収益の乖離   4-2. 属人性という課題   4-3. 視点の転換 5. 本質的な問いの立て直し   5-1. 汎用AIツールの特性   5-2. 技術導入前の課題整理   5-3. 再現性が高い既存フレームワークの活用   5-4. 人間中心のシステム思考の活用   5-5. つまずきの4つのパターンの正体   5-6. 問題発掘に有益だったこと 6. 実践的な解決アプローチ   6-1. 中長期と短期の両立 7. おわりに:本質的な価値創造へ メリークリスマス!2025年のAI活用推進を振り返って こんにちは!AI FirstグループでAI活用推進を担当しているShiori( @shor_t8q )です。企業のDX担当者、AI推進リーダー、そして「個人でのAI活用は進んでいるのに、事業や収益に関して期待した効果が出ていない」という課題を感じているすべての方へ、「組織のAI活用」と業務変革のヒントをお伝えできればと思います。 個人活用の成功と組織活用の課題 個人活用普及率8割の達成 2025年、私たちは「個人のAI活用」と「組織のAI活用」という両輪でAI活用を推進してきました。 まず社内の現状を共有します。社内AIツールのデータから、従業員のAI活用率は夏の時点で約8割に達しました。多くの社員がAIチャットツールやAIコーディングツールを日常的に活用し、個人の業務効率向上を実現することができました。 しかし、そこである気づきがありました。 「個人の効率は向上しているものの、組織としての成果が見えにくいのでは?」 そこで、組織的なAI活用推進をさらに強化することにしました。実際に取り組みを進める中で分かったのは、「組織的な活用」は「個人的な活用」とは異なる性質を持ち、異なるアプローチが必要だということです。 組織的な活用とは 組織的な活用とはどのような状態を指すのでしょうか。私たちはこう定義しました。 組織的なAI活用 (KINTOテクノロジーズ社内資料より) 複数グループや部門などが連携し、組織横断プロジェクトで、業務・開発プロセス・システムにAIを導入し、事業や収益に対して何らかのインパクトを与えること。 この定義に照らし合わせたとき、「組織的な活用が、想定以上に進まない」という現実に直面しました。 業界全体の課題 社外の動向を調べてみると、McKinseyの Seizing the agentic AI advantage に興味深いデータが掲載されていました。 特定のビジネス機能やプロセスに組み込まれた垂直的な活用事例の課題 (McKinseyレポートより) By contrast, vertical use cases—those embedded into specific business functions and processes—have seen limited scaling in most companies despite their higher potential for direct economic impact (Exhibit 2). Fewer than 10 percent of use cases deployed ever make it past the pilot stage, according to McKinsey research. 「対照的に、特定のビジネス機能やプロセスに組み込まれた垂直的な活用事例は、直接的な経済効果がより高い可能性があるにもかかわらず、ほとんどの企業では限定的なスケーリングしか見られていません。マッキンゼーの調査によると、展開された活用事例のうち、パイロット段階を超えるものは10%未満です。 出典: McKinsey "Seizing the agentic AI advantage" つまり、特定のビジネス機能やプロセスに組み込まれた垂直的な領域でAIを活用しようとしている企業の約9割が、パイロット段階(試験運用)を超えることができず、実証実験の段階で終わっている状況です。 これは「パイロット・パーガトリー(実証実験の煉獄)」と呼ばれる現象で、弊社だけの問題ではなく業界全体の傾向だったのです。 業界全体で「組織的なAI活用は容易ではない」という課題が報告されている状況です。私たちは、この課題に向き合うため、まずは社内の現状を分析することから始めました。 イノベーションの二つの潮流 AIネイティブとAIドリブン 社内の取り組みを俯瞰してみたとき、大きく分けて2種類のイノベーションラインがあることが分かりました。 AIネイティブ(AI Native) AIがあることを前提として、ゼロからプロダクトや体験が設計されているもの 仕組みの中に自然にAIが組み込まれている AIドリブン(AI Driven) 既存のシステムやプロダクトに、後からAIを組み込んでいくもの 既存業務や既存システムの一部をAIで代替・置換する取り組み ここで明らかになったのは、「AIネイティブな取り組みは比較的進んでいるが、AIドリブンは難航している」という傾向でした。 AIネイティブな領域では、社内のアーリーアダプターたちが相互にボトムアップで連携し、新しい価値を生み出してプロダクトやシステムをローンチすることが実現しています。一方、AIドリブン——つまり既存業務や既存システムの置き換え——は、関係者が多く抱えている問題も複雑で進めることが難しい現状があります。 つまずきの4つのパターン 社内の状況を整理していくと、AI活用で進捗が滞っているケースは、おおむね4つのパターンに分類できることが見えてきました。 1. 技術先行型(Tech First) 「新しい技術が登場したので、まず検証してプロトタイプを作成した」というケース。技術力のあるエンジニアが速やかに作成できるのですが、その後で「このプロトタイプをどこで活用すべきか」と、解決すべき課題を後から探すことになります。 2. トレンド先行型(Trend First) 「AIエージェントを使って〇〇を実現したい」というケース。手段(AIトレンド)が目的化してしまい、誰のどのような課題を解決するのかが明確になっていません。 3. 目的不明瞭型(Lost in Possibility) 「AIを使って〇〇を実現したい。ただ、何をすればよいのか分からない」。意欲はあるものの、入口で立ち止まってしまっているケースです。 4. 優先度判断困難型(Priority Paralysis) 「AIを導入して解決したい課題はある。今の技術であればさまざまな箇所に適用できそうだ。ただ、何から手をつければよいか迷う」。適用すべき箇所の目利きはできているが、どこから着手すべきか判断できず、可能性(適用範囲の幅や深さ)の中で方向性を見いだせないパターンです。 さらに、これらとは別の軸で、「AI環境整備の課題」も存在しました。「AIを活用したいが、方針・ルールの整備がAIに最適化されていないので意思決定ができない」、「利用したいデータが集約されていない」といった、ガバナンス、インフラ、リソースの問題で進捗が滞るケースです。 ※「AI環境整備の課題」は範囲が広いので、今回の記事ではこのテーマには言及しません。 上記パターンは、各々解決しなければプロジェクトは前に進みません。私は、組織として「AIプロジェクトの推進モデル」を構築する必要性を感じました。 GenAIパラドックスの構造 効率向上と収益の乖離 この1年、現場の状況を確認する中で GenAIパラドックス と呼ばれる現象を実感してきました。これは、「AIによって個人の業務効率は確実に向上しているのに、組織としての収益や成果には必ずしも直結していない」という状況です。 「GenAIパラドックス」について、McKinseyの Seizing the agentic AI advantage では、以下のように定義されています。 GenAIパラドックスとは? (McKinseyレポートより) 「10社中8社近くがGenAIを何らかの形で導入していますが、ほぼ同じ割合の企業が収益に大きな影響はないと報告しています。私たちはこれを『GenAIパラドックス』と呼んでいます。」 "Nearly eight in ten companies have deployed gen AI in some form, but roughly the same percentage report no material impact on earnings. We call this the 'gen AI paradox.'" 出典: McKinsey "Seizing the agentic AI advantage" なぜ、このパラドックスが発生するのでしょうか。弊社の分析から、いくつかの要因が浮き彫りになりました。 取り組みの断片化 : 個別の検証や単発の取り組みになっており、体系的に繋がっていない デリバリーモデルの未定義 : 「どのように価値を届けるか」という型が確立されていない ガバナンスと整備不足 : AIを受け入れるための基盤(ルール、インフラ、データ、プロセス)が整っていない McKinseyの Seizing the agentic AI advantage でも、同様の内容が言及されています。 属人性という課題 さらに根本的な問題として、 業務の言語化不足 があります。 現在のAI技術、例えばAIエージェントを業務ワークフローに組み込もうとすると、そのワークフロー自体が明確に定義され、言語化されている必要があります。しかし、多くの現場では「ここはAさんの判断で」「ここはBさんの経験則で」といった、人間の判断(属人性)で運用されている部分が非常に多いのです。 「AIを導入したい」と考えても、AIは「暗黙知」を理解することができず、属人的になっている領域には、そのままではAIを適用できません。 まず業務を整理し、定義し直す必要があります。ここに至る組織的認知、具体的なアクションプランをステークホルダーで合意形成し、着実に進めていかなければいけないということが、AI活用の大きなハードルとなっていたのです。 視点の転換 そこで、私は 「AIを導入したからといって、イノベーションが加速するわけではない。イノベーションを加速させるために、AIを活用するのだ」という視点の転換が必要なのだと考えるようになりました。 本質的な問いの立て直し 汎用AIツールの特性 ChatGPT、Gemini、Claudeのような、いわゆる「汎用的なAIチャット」は非常に高性能です。相談すれば、速やかに質の高い解決策を提示してくれます。 しかし、ここに注意すべき点があります。AIは、私たちが投げかけた質問には答えてくれますが、「デフォルトのチャットウィンドウでは、私たちが抱える問題の深掘りまでは行わない」のです。 ただし、これは汎用AIチャットをデフォルト設定のままで使用した場合です。深掘り機能を持つAIエージェントを構築し、そのAIと対話することで、問題を探索する質問を引き出し、課題を整理できることは既に実証済みです。 ユーザーが「これを作りたい」と伝えたとき、AIは素直に作成方法を提案します。しかし本来は、「なぜそれを作りたいのですか?」「もっと本質的な課題は別にありませんか?」といった、コンサルタントのような深掘りこそが必要な場面が多々あります。 技術導入前の課題整理 「できる・できない」ではなく「誰に・どのような価値か」 例えば、「社内のお問い合わせの対応が大変なので、お問い合わせをAIで対応できるようにしたい」という相談が現場から寄せられたとします。これに対して、すぐに「RAG(検索拡張生成)を使って社内Wikiを読み込ませたチャットボットを構築しましょう」と提案するのは容易です。しかし、それでは本質的な解決にならないことがあります。 ここで私たちは問い直す必要があります。 「そもそも、なぜお問い合わせが発生するのか?」 「マニュアルが分散していて知りたい情報にアクセスできないことが原因ではないのか?」 「あるいは、〇〇についてマニュアルはあるが、従業員が判断しにくい内容になっていることが原因ではないか?」 もし後者であれば、AIに回答させる前に、マニュアルの内容を更新するのが適切かもしれません。マニュアル精度が高くないと、AIがハルシネーション(誤った情報)を生成するリスクが高まります。 再現性が高い既存フレームワークの活用 「問題の特定」、「課題定義」と「合意形成」を進める上で、私たちがAIプロジェクトにおける課題整理で採用したアプローチは、「デザイン思考」や「システム思考」などの世の中で既存の課題解決フレームワークです。 デザイン思考 (Design Thinking)は、ユーザーへの共感をベースにした人間中心アプローチです。ユーザーニーズを深く理解し、反復的なプロトタイピングを通じて創造的な解決策を生み出します。 一方、 システム思考 (Systems Thinking)は、要素間の相互関係と全体最適を重視し、複雑な組織システムの根本原因を特定します。 デザイン思考とシステム思考を組み合わせることで、個々のステークホルダーの課題(デザイン思考)と、それらが生じている業務や組織全体の構造的問題(システム思考)の両方に目を向けられます。この融合は、関係者の認識を合わせるための有効な手法と成り得るという仮説を持ちました。 人間中心のシステム思考の活用 私たちは複数のプロジェクトにおいて、 デザイン思考 と システム思考 を組み合わせた「人間中心のシステム思考」というアプローチを導入しました。これは、ユーザーへの共感をベースに関係者と信頼関係を築きながら進める創造的なプロセスとシステム全体を俯瞰し、問題構造を把握する分析的な視点を融合させたものです。 このアプローチにより、以下のことが可能になります: 視点の切り替え : システム全体と個々のステークホルダー、両方の視点を行き来できる 共感の醸成 : 人々の課題だけでなく、システム自体が抱える構造的な問題にも目を向けられる 行動変容の促進 : 根本原因を理解した上で、効果的な介入ポイントを設計できる 組織におけるAI活用の課題は、まさに「人間システム」の問題です。複数のステークホルダーが絡み合い、それぞれが異なるニーズや制約を抱えています。人間中心のシステム思考は、この複雑性に対処するための有効な課題解決手段となりました。 デザイン思考 と システム思考 の違いを知りたい方は、 Systems Thinking vs Design Thinking, What’s the Difference? の記事が参考になります。 つまずきの4つのパターンの正体 人間中心のシステム思考を用いた課題解決では、以下のステップで進めることが効果的です。 ユーザー・ステークホルダーへの共感(Empathize with Stakeholders) : 関係者へのヒアリングや観察を通じて、現場の状況を深く理解する 問題の発掘(Discover Problems) : 顕在化している問題だけでなく、対話を通じて潜在的な問題も引き出す システム構造の分析(Analyze System Structure) : システム思考を用いて、問題の真因や要素間の関係性を特定する 課題の定義(Define Issues) : 取り組むべき課題を整理し、優先順位をつける 解決策の検討(Design Solutions) : 課題に対する解決アプローチを設計する 技術選定(Select Technology) : AI、インフラ、ツールなど最適な技術スタックを選定する プロトタイプ構築(Build Prototype) : 小さく素早く動くものを作り、仮説を検証する 反復と拡大(Iterate & Scale) : アジャイル開発プロセスに基づき、フィードバックを取り入れながら改善・拡張を繰り返す つまずきの4つのパターンは、6(技術選定)や7(プロトタイプ構築)からスタートして行き詰まり、1(ユーザー・ステークホルダーへの共感)~5(解決策の検討)を考え始めるというプロセスになっていることがわかりました。 AIによってプロトタイプを構築しやすくなった反面、従来のプロダクト開発で定義していた1(ユーザー・ステークホルダーへの共感)〜5(解決策の検討)がスキップされる傾向があるため、「システムは構築できたが、誰かの具体的な問題を解決しているわけではない」という状況が見えてきました。 ※社内では、6(技術選定)や7(プロトタイプ構築)からスタートし、1(ユーザー・ステークホルダーへの共感)〜5(解決策の検討)を経て、成功しているケースも複数あるので、6(技術選定)や7(プロトタイプ構築)からスタートするプロトタイプドリブンのアプローチも有効だと実証されています。そのため、6(技術選定)や7(プロトタイプ構築)からスタートすることがネガティブな要素というわけではありません。あくまで傾向の話です。 しかし、6(技術選定)や7(プロトタイプ構築)からスタートすることで、「採用した技術や構築したプロトタイプを活かしたい」という潜在的なバイアスが先行し、1(ユーザー・ステークホルダーへの共感)〜5(解決策の検討)のプロセスを、後から中立的に進めることが難しくなることに留意する必要があります。 問題発掘に有益だったこと フレームワークを導入したからといって、すぐに問題解決がスムーズになるわけではありません。まずは、関係者とシステム全体の課題整理を行う必要がありました。最初にワークショップを行い、ステークホルダーが抱える問題をデジタルホワイトボードで整理しようと試みたのですが、想定以上に難航しました。 原因を分析すると、関係するステークホルダーが多く、問題を引き起こしている要素が複数あるような複雑性が高い問題は、言語化のハードルが高いため、ホワイトボード上に網羅的に問題を書き出すことが難しいということがわかりました。 そこで、ホワイトボード形式ではなく、2on2や1on2でヒアリングを実施し、対話を通して潜在課題まで発掘できるようなコミュニケーションアプローチを取りました。 結果として、グループや部署を横断するような業務改革を行うときは、最初は対話を通じて信頼関係を築くことが重要であり、次に対話を通して問題発掘を行い、関係者の問題解像度が上がってきた時点で、適宜ワークショップを実施して課題を整理することが効果的だということがわかりました。 実践的な解決アプローチ 中長期と短期の両立 とはいえ、「業務フローや課題を全て整理してからAIを導入しましょう」と言っていたら、プロジェクトの推進が遅れてしまいます。そこで私たちは、「中長期」と「短期」を分けて、並行して進める戦略を推奨しています。 アプローチ 目的 アクション 中長期(Slow) 本質的な課題解決、方針策定 組織全体の課題整理、ワークフローの再定義、関係者との合意形成 短期(Fast) スピード感、現場の改善 目の前の明確な課題に対して、AI技術を適用し、プロトタイプを作成し、改善を繰り返す 全体の方針を策定しつつ(中長期)、現場では迅速に改善を回していく(短期)。この両軸で進めることで、スピード感を維持しながら、点と点を線に繋げていくことができます。 おわりに:本質的な価値創造へ 最後に、2025年の1年で得た最も重要な学びを共有します。 「AIを活用すること自体を、目的化してはいけない。」 「AIで何ができるか」よりも、「私たちが本当に解決すべき問題は何か」「それを解決したとき、誰にどのような価値があるのか」——この原点に立ち返ること。そして、その価値を最大化するために、AIの 人間の能力を拡張する力 や 処理速度を向上させる力 や 数や量を出す力 をどう活用するかを考えることが重要だと気づきました。 AI導入は、単なるツールの活用ではありません。それは、私たちが自分たちの仕事のやり方、ひいては 本質的な価値 を見つめ直す過程でもあります。組織的AI活用のハードルが「自分たちの業務の未定義さ」や「目的の曖昧さ」や「問題の真因を見極める力」にあると認識できれば、乗り越える方法は必ず見つかります。特にAI活用の問題は技術ではなく、業務、人と組織、マインド、仕組みやルールにあるケースがほとんどです。 今回の考察が、同じ課題に取り組む皆様の参考になれば幸いです。 2025年は技術革新の激動の中、皆様大変お疲れ様でした! 2026年もさらに未知な技術や概念が現れるかもしれませんが、共に頑張りましょう! Made with Drive♥️
この記事は KINTOテクノロジーズアドベントカレンダー2025 の21日目の記事です🎅🎄 KINTOテクノロジーズで my route for iOS を開発しているRyommです。 最近、my routeアプリ内にTipKitを導入しました。その際TipKitで外部から表示状態をコントロールする方法が少し癖があったので、紹介します。 実際のTipKit使用箇所 背景 TipKitとは、iOS17以降で使えるようになった、アプリの機能を見つけるのに役立つヒントを出すためのフレームワークです。 https://developer.apple.com/documentation/tipkit/ TipKitを使うと、手軽に吹き出しのポップアップなどを出せたり、TipKit内で表示状態のコントロールを行えたりします。 しかし、TipKit内で全てが完結するということは、Viewとロジックが密接に絡み合ってしまうということでもあります。これでは既存のアーキテクチャと齟齬が生じてしまいます。 また、my routeでは以前からTipKitを使わずに似たような表示コントロールを行なっていたため、既存のロジックをTipKitに持ってこようとすると一度全てのユーザーの表示状況がリセットされてしまう問題もありました。 そこで、UserDefaultなどに保存してある既存の状態を維持したまま、どうにかTipKitに外部から表示状態を差し込みたいと考えました。 TipKitの基本の使い方 TipKitは基本的に、以下のように書いて使います。TipViewStyleを使ってスタイルをカスタマイズすることもできます。 import TipKit struct FavoriteLandmarkTip: Tip { // 表示文言 var title: Text { Text("Save as a Favorite") } // 表示状態の条件を制御するマクロ @Parameter static var userIsLoggedIn: Bool = false var rules: [Rule] { #Rule(Self.$userIsLoggedIn) { // ログイン状態ならTipを表示 $0 == true } } } TipKit内にユーザーアクションを定義して追跡することもできます。 struct FavoriteLandmarkTip: Tip { // 追跡するユーザーアクションを一意のIDを持つイベントとして定義 static let didViewLandmark: Event = Event(id: "didViewLandmark") var rules: [Rule] { #Rule(Self.didViewLandmark) { // イベントが3回以上発生したらTipを表示 $0.donations.count > 3 } } } このように、TipKit側で独自に表示状態の条件を管理しています。 しかしこのままでは上述の通りに問題があります。 TipKitに外部から表示状態を差し込めるようにする @Parameter マクロを利用して、表示状態を差し込めるようにします。 @Parameterでラップされた値が変更されると、依存するTipルールが再評価されます。 そこで、外部の値を @Parameter を経由して変更してあげることで、TipKitの状態をコントロールすることができます。 https://developer.apple.com/documentation/tipkit/tips/parameter まず、TipKit自体は以下のように定義します。ここでは呼び出し側のViewに定義してある @Parameter をみてTipの表示有無を判断しています。 import TipKit struct MemoTip: Tip { var title: Text { Text("気に入った記事のURLはこちらからおでかけメモに追加ができます") } var rules: [Rule] { #Rule(ParentView.$isPresentingMemoTip) { $0 == true } } } 外部から値を受け取るためのパラメータとは別に、TipKit用に @Paramter にラップしたパラメータを用意します。 onAppear と onChange によって2つのパラメータが同期するようにしています。 struct ParentView: View { @Binding var showTip: Bool // 外部から値を受け取るパラメータ。本当はもっと構造体になってたりObservedObjectだったりする。 @Parameter static var isPresentingMemoTip: Bool = false // TipKit用に外部の値をラップするパラメータ var memoTip = MemoTip() var body: some View { SomeView() .safeAreaInset(edge: .bottom) { memoButton .popoverTip(memoTip, arrowEdge: .bottom) // チップを出す場所 .onAppear { // Viewがつくられた最初はonChangeが動かないので、初期値を挿入 ParentView.isPresentingMemoTip = showTip } .onChange(of: showTip) { _, newValue in // 外部から変更があったら、@Parameterマクロに値を挿入 ParentView.isPresentingMemoTip = newValue } } } } こうすることで、ロジックをViewから切り離せるようになりました。 ViewModelなどで表示状態の条件のロジックを書いて、その状態をshowTipに渡してあげればTipKit側の状態も更新されます。いい感じです。 まとめ TipKitの表示状態を外部からコントロールできるようにする方法を紹介しました。 TipKitはiOS17から利用できるので、これから利用するケースも徐々に増えていくと思います。 完全に新規の機能として作成するのであればTipKitで完結させる方が良いとは思いますが、既存のものを移行する場合は困るシーンもあるので、この記事が役立つと良いなと思います。 それでは、メリークリスマス🎄
この記事は KINTOテクノロジーズアドベントカレンダー2025 の20日目の記事です🎅🎄 はじめに こんにちは、KINTOテクノロジーズ Mobile KMPチームです。 本記事は「Compose MultiplatformとSwiftUIで作るハイブリッドモバイルアプリ」シリーズのPart 2です。Part 1ではハイブリッド開発を選んだ背景とアーキテクチャ概要を紹介しました。今回は具体的な実装方法を詳しく解説します。 本シリーズの構成 Part 1:なぜハイブリッドなのか Part 2:実装ガイド ← 現在の記事 Part 3:SwiftUI連携と技術Tips(近日公開) 実装事例 プロジェクト構造 プロジェクトのディレクトリ構成 my-cmp-app/ ├── composeApp/ │ ├── src/ │ │ ├── commonMain/ // CMP Shared code │ │ ├── androidMain/ // Android-specific │ │ └── iosMain/ // iOS-specific ├── iosApp/ │ ├── Views/ // SwiftUI views │ ├── Screens/ // Native screens │ └── ComposeViewContainer.swift └── shared/ // KMP domain layer ├── viewmodels/ └── models/ まず composeApp です。 commonMain にはCMPの共通コード、 androidMain / iosMain には各プラットフォーム固有の実装を入れています。 次に iosApp 。SwiftUIのViewやネイティブ画面が含まれています。特に ComposeViewContainer.swift ファイルでCMPコンポーネントをiOS側に組み込んでいます。 最後に shared 。KMPのドメイン層で、viewmodelsやmodelsを共通化しています。 このように、ディレクトリレベルでも 共通化できる部分はまとめ、ネイティブ依存部分は分離 しています。 ハイブリッドUIの実例 実際に作成したPoCアプリの画面構成を紹介します。 MainScreenでは、ボトムナビゲーションに4つのタブを配置しています。 タブ UI実装 Application CMP Lineup CMP HelpCenter CMP Settings SwiftUI on iOS Application、Lineup、HelpCenter はCMPで共通UIを実装 Settings だけはネイティブ(iOSではSwiftUI)で作っています このように、共通UIとネイティブUIを組み合わせても、タブ切り替えはシームレスに行えます。 iOS固有のUIが活きるSettings Tab ネイティブからCMPベースのハイブリッドナビゲーションへの移行 このような構成では、ネイティブ中心のナビゲーションからCMPベースのハイブリッドナビゲーションへ移行する必要がありました。どのように移行したのか、具体的な方法をご紹介します。 既存のナビゲーションスタックをリファクタリングし、ネイティブとCMP間でルーティング プラットフォーム固有のナビゲーションロジックを共有インターフェースの背後に抽象化 ルートベースのナビゲーション戦略 先ほど紹介したPoCアプリのタブ構造を振り返ると、1〜3番目のタブはCMP、4番目はSwiftUIで実装しています。 PoCアプリのタブ構造 このような構成でルーティングを実現するために、各画面のルートをstring constantで定義しておきます。 // Routes.kt - Navigation routes defined in shared code object Routes { const val LOGIN = "login" const val SCREEN_A = "screen_a" const val SCREEN_B = "screen_b" const val SCREEN_C = "screen_c" const val SCREEN_D = "screen_d" } プラットフォームごとに実装を分けて、AndroidではCompose Navigation、iOSではSwiftUI NavigationでComposeをつなぐ Bridge をします。 Kotlinナビゲーション実装 こちらは ComposeViewController.kt の例です。パラメータとして initialRoute を受け取り、そのルートに応じてwhen分岐で 遷移先を切り替え ています。 // ComposeViewController.kt fun createComposeViewController( initialRoute: String, onCallback: (Boolean) -> Unit = {} ): UIViewController { return ComposeUIViewController { MyAppTheme { when (initialRoute) { "login" -> LoginNavigation(onLoginSuccess = onCallback) "screen_a" -> ScreenANavigation() "screen_b" -> ScreenBNavigation(iosCallback = onCallback) "screen_c" -> ScreenCNavigation() "screen_d" -> ScreenDNavigation() else -> FallbackNavigation() // default fallback } } } } 例えば、"login"なら LoginNavigation へ、"screen_a"や"screen_b"なら、それぞれの画面のNavigationを呼び出します。このように、ルートを定義しておけば、プラットフォーム固有のナビゲーション処理と簡単に接続できます。 iOS側でCompose Navigationを統合する仕組み まず ComposeViewContainer を定義して、 UIViewControllerRepresentable を実装します。これによってSwiftUIの中に Compose UIを埋め込む ことができます。 // ComposeViewContainer.swift struct ComposeViewContainer: UIViewControllerRepresentable { let initialRoute: String let onCallback: (Bool) -> Void func makeUIViewController(context: Context) -> UIViewController { // Wrap the Swift callback into the KotlinBoolean signature let kotlinCallback: (KotlinBoolean) -> Void = { kotlinBool in onCallback(kotlinBool.boolValue) } // Create the Compose UIViewController, passing the wrapped callback return ComposeViewControllerKt.createComposeViewController( initialRoute: initialRoute, onCallback: kotlinCallback ) } func updateUIViewController(_ uiViewController: UIViewController, context: Context) { // No dynamic updates needed here } } 次に、 makeUIViewController の中でKotlin側の createComposeViewController を呼び出します。 iOS Navigationの実践 こちらは、統合コードを使ったiOS Navigation codeです。 TabView の中に4つのタブを定義しています。1〜3番目のタブは CMP画面 で、 NavigationView の中に ComposeViewContainer を埋め込み、初期ルート"screen_a"を指定しています。 // MainScreen.swift struct MainScreen: View { var body: some View { TabView { // Tab 1~3: CMP screen NavigationView { ComposeViewContainer(initialRoute: "screen_a", onCallback: { _ in }) }.tabItem { Label("Application", systemImage: "doc.plaintext") } ... // Tab 4: SwiftUI screen NavigationView { SettingsScreen() }.tabItem { Label("Settings", systemImage: "gearshape.fill") } } } } 4番目のタブはSwiftUIネイティブの SettingsScreen() を使用しています。このように、CMPとネイティブ画面を同じナビゲーション構造内で自然に共存させることができます。 Koinによるモジュール化 ここまでナビゲーション統合を見てきましたが、実際のアーキテクチャはCMP + MVVMでどんどん複雑になります。そこで、Multiplatform向けDIの Koin を導入しました。結果、構造がシンプルになり、テストや保守もしやすくなりました。 Koinの利点: 依存関係をきれいに管理 できる 同じ定義を使って 複数プラットフォームで再利用 できる モジュール単位で分離 でき、構造がシンプルになる テストのしやすさ が向上 // commonMain/di/AppModule.kt val appModule = module { single { NetworkClient() } single { AuthRepository(get()) } viewModel { HomeViewModel(get()) } viewModel { ProductViewModel(get()) } factory<Validator> { ValidatorImpl(get(), get()) } } single や viewModel をシンプルに書くだけで、依存関係を自動的に解決できます。 プラットフォーム固有のDI Koinでは、iOSとAndroidそれぞれに 専用のモジュール を定義できます。 // iosMain/di/PlatformModule.ios.kt val iosModule = module { single<HttpClientEngine> { Darwin.create {} } single<DataStore<Preferences>> { createDataStore() } single { IOSLocationService() as LocationService } single { AppStoreConnectTracker() as AnalyticsTracker } } // androidMain/di/PlatformModule.android.kt val androidModule = module { single<HttpClientEngine> { OkHttp.create {} } single<DataStore<Preferences>> { createDataStore(androidContext()) } single { AndroidLocationService() as LocationService } single { FirebaseAnalyticsTracker() as AnalyticsTracker } } iOS側では iosModule を定義し、 Darwin.create() を使った HttpClient を登録しています。一方Android側では androidModule を定義し、 OkHttp.create() を使った HttpClient を登録しています。 このように、 プラットフォーム固有の実装はモジュールごとに分離 しながら、共通のインターフェースを通して利用できるようにしています。 Koinの初期化 ここではKoinの初期化方法です。まず共通コード側に initKoin 関数を用意しておきます。 // commonMain/di/KoinSetup.kt fun initKoin(platformModule: Module) = startKoin { modules(appModule, networkModule, platformModule, ...) } // Android Application class class MyApplication : Application() { override fun onCreate() { super.onCreate() initKoin(androidModule) } } Androidでは Application クラスの onCreate から androidModule を渡して初期化します。 // iOS AppDelegate func application(_ application: UIApplication, didFinishLaunchingWithOptions...) { KoinKt.doInitKoin(platformModule: IOSPlatformModuleKt.iosModule) return true } iOSでは AppDelegate から iosModule を渡すだけです。このようにして、 両方のプラットフォームで同じ初期化処理を共通化 できます。 Koinでの動的モジュールロード 次に、Koinでの 動的モジュールロード です。 // Feature module definition val featureModule = module { viewModel { FeatureViewModel(get(), get()) } factory { FeatureValidator() } single { FeatureRepository(get()) } } // Register dynamically after the Koin's initialization loadKoinModules(featureModule) まず featureModule を定義して、ViewModel・Validator・Repositoryを登録します。その後、 loadKoinModules に featureModule を渡してロードします。 Koin初期化後にモジュールを動的にロード できます。これにより、大規模アプリでも 必要な機能だけを後から読み込む構成 が可能になります。これがKoinの強みです。 開発効率化事例:Validator統合 問題状況 メール、電話番号、郵便番号、パスワード強度、日付形式など、様々な検証ロジックが必要でした。 従来方式で実装した場合: Android:24個のValidator(Kotlin) iOS:24個のValidator(Swift) 合計48個の実装 合計48個のValidationResult 合計48セットのユニットテスト KMPソリューション すべての検証ロジックを共有KMPモジュールに移動しました。 Kotlinで各Validatorを一度だけ実装 共通関数/クラスとして公開 CMP画面、Android/iOSネイティブ画面すべてから呼び出し可能 結果: 実装量50%削減 テストコード50%削減 プラットフォーム間検証ロジックの一貫性保証 バグ修正も一箇所で完了(両OS同時に修正される) 次回予告 Part 2では、プロジェクト構造、ナビゲーション統合、Koin DI、Validator統合など具体的な実装方法を紹介しました。 Part 3:SwiftUI連携と技術Tips では、SwiftUIとCMPの相互埋め込み、CMP vs Flutter比較、実践で直面した落とし穴、導入戦略などを詳しく解説します。お楽しみに! こちらは「Compose MultiplatformとSwiftUIで作るハイブリッドモバイルアプリ」シリーズのPart 2です。
はじめに この記事は New Relic Advent Calendar 2025 20日目の記事です。 こんにちは、KINTOテクノロジーズ(以下KTC)SREチームの手﨑です。 本記事では、先日のAWS re:Invent 2025で発表されたAWS DevOps Agentと、普段KTCで利用しているNew Relicを連携させて、障害調査をどこまで自動化できるのか検証した結果をご紹介します。 注意事項 AWS DevOps Agentは本記事執筆時点(2025年12月)ではプレビュー版です。 GA(一般提供)までに仕様が変更される可能性があります。 AWS DevOps Agent とNew Relicの連携 AWS DevOps Agent とは AWS DevOps Agentは、インシデントを解決、予防し、信頼性とパフォーマンスを継続的に向上させるフロンティアエージェントです。詳細は以下の公式ページをご覧ください。 AWS DevOps Agent 特徴的な点はCapabilitiesという設定で、DevOps Agentが扱える情報(能力)を拡張できることです。 今回もこのCapabilitiesを利用してNew Relic MCP経由で障害調査を行います。 他にもCapabilitiesには以下のような設定が可能です。 Cloud 他のAWSアカウントのリソースへのアクセス Telemetry オブザーバビリティSaaSのテレメトリーデータへのアクセス Pipeline ソースコードが管理されているリポジトリやデプロイパイプラインの情報へのアクセス Communications Slackなどのコミュニケーションツールとの連携 MCP Server MCPサーバーを使った情報の収集 Webhook Webhook経由でのサードパーティ製アプリケーションやサービスへのアクセス New Relic との連携方法 AWS DevOps Agentの初期設定 AWS DevOps Agentの初期設定はエージェントスペースの作成から始まり、Roleの作成などが必要ですが、ここではNew Relicとの連携設定の箇所に絞って記載します。 以下のページにあるようにTelemetryの設定にNew Relicを追加することでNew RelicからAWS DevOps Agentを実行するためのwebhook URLを取得できます。 Connecting New Relic この設定により、New Relic remote MCP も利用されるようになります。 Telemetryの設定 AWS DevOps AgentのSettingsから「Telemetry」-「New Relic」を選択します。 New RelicのaccountIDとAPIキーを入力し、Regionを選択します。 webhook URLとsecret keyが発行されるため、保存しておきます。 エージェントスペースを選択し、「Capabilities」タブから「Telemetry Sources」に「New Relic Server」 を追加します。 New Relicのアラートの設定 New RelicのアラートからAWS DevOps Agentをwebhookで起動するために、New RelicのDestinationsとWorkflowの設定を行います。 Destinationsの設定 New Relicの「Alerts」から「Destinations」を選択し、「Add a destination」から「Webhook」を選択します。 「Name」に任意の名前を入力し、以下のとおり設定値を入力します。 Name: New Relic Webhook Endpoint URL: https://event-ai.us-east-1.api.aws/webhook/generic/****** //Telemetryの設定の発行画面で発行されたURL Authorization: Bearer Authorization Value: ****** //Telemetryの設定の発行画面で発行されたsecret key 設定を保存します。 Workflowの設定 New Relicの「Alerts」から「Workflows」を選択し、「Add a workflow」から新しいWorkflowを作成します。(もしくは既存のWorkflowに対して設定を追加します) NotifyのAdd channelからWebhookを選択し、「Destinationsの設定」で追加したDestinationを選択します。 PayloadのTemplateに以下の内容を入力します。 { "eventType": "incident", "incidentId": {{ json incidentIds.[0] }}, "action": "created", "priority": {{ json priority }}, "title": {{ json annotations.title.[0] }}, "description": {{ json state }}, "service": {{json entitiesData.names.[0]}}, "timestamp": {{#timezone activatedAt 'Asia/Tokyo'}}{{/timezone}} } 以上でAWS DevOps AgentとNew Relicの連携設定は完了です。 実際に試した結果 実際にNew RelicのアラートからAWS DevOps Agentをwebhookで起動してみます。 連携の流れ 実際に連携を試した際の流れは以下の通りです。 New RelicのアラートからAWS DevOps Agentへwebhookする New Relicでアラートが発生すると、AWS DevOps Agent に webhook が送信されます AWS DevOps AgentからNew Relicのテレメトリを取得して分析する AWS DevOps Agentは自律的にNew RelicのMCP経由でテレメトリデータの取得を繰り返し、分析を行います 同時にAWSリソース内も調査する New Relicのテレメトリ分析と並行して、AWSリソースの状態も調査します Root Causeレポートが生成される 分析結果を基に、根本原因(Root Cause)レポートが自動生成されます 修正案の計画を指示できる 生成されたレポートを基に、修正案の計画を指示することができます 調査結果 調査状況をweb appから確認すると以下のような結果となります(表示しているものはサンプルのアプリケーションです) New Relic MCPを利用してアラートに関する情報を取得しています。 今回のアラートはサンプルアプリケーションのため必ずエラーが発生する作りであることを Root Cause として結論付けられています。 追加の調査として直近のデプロイとアラートの発生に関連性があるか確認してもらいました。 AWS側の調査により、Fargate Spotのプロビジョニング遅延によって起動が遅れたことと、直近でデプロイが実施されていないことが報告されました。 結果 New RelicのアラートをトリガーにAWS DevOps Agentをwebhookで起動し、MCP経由で取得したNew RelicのテレメトリとAWSリソース情報を組み合わせて自動調査させるところまで確認できました。 AWS DevOps Agentのweb appは対話形式で追加の調査を行うことができ、AWSリソースの直接参照とNew Relicのテレメトリ分析の両方を自律的に実施してくれるため、他の連携先が増えても柔軟に対応することができそうです。 まとめ 本記事では、AWS DevOps AgentとNew Relicを連携させて障害調査の自動化を試しました。 New RelicのアラートをトリガーにAWS DevOps Agentをwebhookで起動し、MCP経由で取得したNew RelicのテレメトリとAWSリソース情報を組み合わせて分析することで、自律的にRoot Causeレポートを生成できることを確認しました。プレビュー段階ではありますが、障害発生時の初期調査を自動化できる点は非常に価値があると感じています。 また、今回は試していませんが、将来のインシデントを予防するPrevention機能を利用すれば、New Relic MCP経由でAPMの情報を参照してパフォーマンスチューニングのような改善サイクルにも活用できると考えています。 引き続きGA版の様子も見ながら検証していきたいと思います。 以上です。
この記事は KINTOテクノロジーズ Advent Calendar 2025 の20日目の記事です🎅🎄 はじめに ラスベガスで開催された AWS re:Invent 2025に弊社から6名が参加してきました。 世界中からエンジニアが集まり、AWSの新サービスが発表されたり、ワークショップを通じて使い方を学べたりする、年に一度の巨大イベントです。 期間:12/1(月)〜12/5(金) 参加者数:現地約6万人(うち日本からの参加者は約1,900人)/オンライン約200万人 セッション数:3,044 ※これらの数値は、re:Invent 2025中の公式セッション「Japan Wrap-up Session & Werner's Keynote (GBL105)」(現地時間12/4 14:45-17:30)で発表された公式情報です。 2025年6月に日本で行われたAWS Summit Japan 2025のセッション数が160以上とのことなので、規模の違いが容易にわかります。 この記事では現地に行くまで知らなかったことや、参加して本当に役立ったTipsをまとめています。 来年以降、参加を検討している方の参考になれば幸いです。 準備(持っていってよかったもの) 録音機器 セッション中にメモを取る必要がほとんどなくなります。 私は Plaud NotePin をレンタルしました。 録音し、AI要約して整理してくれるので、目の前の内容に集中できます。 なお録音することが不安な場合は、あらかじめ講師やスタッフに確認すると良いです。 私が確認した際には「もちろん!」という回答をもらえました。 ケトル いきなりケトル?と思いますが、ラスベガスのホテルでは置いていないところが多い(らしい)です。 朝一番のキーノートに行く方はカンファレンスのご飯を食べていては間に合わない場合もあるので、用意しておくと良いでしょう。 また時差ボケにより、夜活動してしまう人にも便利です。 各セッションTypeの違い セッションが多すぎてどれを選んでいいか分からない方へ、まずはセッションTypeの違いを意識すると良いです。 Breakout Session 最もオーソドックスな講義形式。新サービスの解説やベストプラクティスなど幅広いです。 人気なセッションはタイトルに[OVERFLOW]と書かれた中継形式のものがありますので、拠点移動が間に合わない場合などはそれに参加するのも手です。 ただし座席間が狭いためPCを広げるのは至難の業でした。どれぐらい狭いかというと、日本の電車の座席より狭く、腕組みしようものなら横の人と当たるレベルでした。 後日YouTubeで配信されるので、優先度が高くなければそれを待つのもありです。 Builder’s Session 講師1人に対して10人程度が参加するハンズオン形式のセッション。事前説明後にハンズオン手順が配られるので、それに従って進めます。 講師との距離が近いので、気になる機能を深掘りしたい方は参加すると良いでしょう。 PC(laptop)が必須です。ハンズオンの手順を見ながら進められるよう、PCとは別に小さなモニターがあると便利です。 自分は過去の参加レポートを見て、iPadを持参して画面拡張できるようにしていました。 日本からの参加者以外ではあまりやっている人はいなかったですが、気にせず広げて問題なかったです。 ![sub_screen](/assets/blog/authors/yuji_morimoto/re_invent_2025/sub_screen.jpg =500x) 講師の方も「それいいね!」と思わず感心してました Workshop こちらもPCが必須です。 数時間かけて行われるハンズオン形式のセッション。Builder’s Sessionと比べて大規模な部屋に数人の講師がいます。 こちらも講師を捕まえれば質問はできますが、参加者が多く、順番が回ってくるまで時間がかかる場合もあります。 Gameday こちらもPCが必須です。 テーブルに集まったメンバーで課題を解決することで順位を競うセッションです。 まず講師から事前説明があります。その後、チームメンバーと役割分担しながらゴールを目指します。 自分以外のメンバーと合わず、居心地が悪いと感じたら、席を移動してしまっても問題なさそうです。 実際にそのようにしている方はいました。 他の方の参加レポートでは事前知識不要という方もいますが、私が参加した会ではある程度のインフラ知識が必要でした… Chalk Talk 少人数の聴衆を対象とした対話形式のセッションです。講師による短い講義と、その後の参加者とのQ&Aで構成されます。実世界のアーキテクチャの課題を中心とした技術的な議論をします。 他のセッションと比べると講師に質問できる時間が多く、また記録にも残らないので、まさに現地に行って参加する価値のあるコンテンツとなっています。 英語に自信がある方はぜひ参加して発言してみてください。 Code Talk 講師が実装しながらサービスについて解説をするセッションです。 Lightning Talk 20分程度の短時間セッションです。 セッションとセッションの隙間時間で聴くことができます。 回り方のTips 会場が異なるセッション移動は1時間見込む 会場が異なるセッションの場合は1時間を見込んでおくと安全です。 ちなみにre:Inventはラスベガスの複数のホテル・コンベンションセンターで同時に開催されました。 北から以下の通りの並びになっており、1つ1つの会場が大きいです。 Wynn Venetian Caesars Forum MGM Grand Mandalay Bay 参加したいセッションが開催されている会場に時間までに向かう必要があります。 1.会場間の移動 まず移動に時間がかかります。移動手段としては以下のものがあります。 徒歩 モノレール シャトルバス タクシー/ライドシェア 隣り合った会場のWynn↔︎Venetianであっても、徒歩15分程度かかりました。 また各会場間はシャトルバスが走っており、会場出てすぐそばに発着するのでアクセスが良くおすすめですが、運行間隔が15〜20分程度空くこともあります。 ライドシェアの場合は呼べる場所が制限されている場合があり、目の前を乗車場所に指定できないことがあります。 ![shuttle_bus](/assets/blog/authors/yuji_morimoto/re_invent_2025/shuttle_bus.jpg =500x) 会場前にあるシャトルバス 各会場ごとに分かれている 2.荷物検査 会場に到着しても荷物検査があるので、混雑具合によっては時間を要します。 PCやタブレットを取り出してセキュリティを通過する必要があります。 呼び止められてしまったら、入念に荷物をチェックされます。 3.予約していてもセッション開始10分前には会場へ re:Inventには「Walk-up」という当日枠があります。 事前予約が埋まってしまっても入れる可能性があるこの枠ですが、セッション開始10分前に予約した人を対象とした受付を一旦締め切り、当日枠の入場を開始してしまいます。 これにより、事前予約していても入れなくなることがあるので注意が必要です。 ![walk_up](/assets/blog/authors/yuji_morimoto/re_invent_2025/walk_up.jpg =500x) 並ぶ列が予約枠と当日枠で分かれている 1日1つの会場にこもってみる 移動が大変であれば、特定の拠点に1日こもってセッションを梯子するのもアリです。 各会場には朝食・昼食・軽食(コーヒー、紅茶やお菓子など)が用意されているので、食事面も心配ありません。 次のセッションまで時間がある場合は前のセッションの内容を見直すのがおすすめです。 会場の廊下には床に座ってPCを開いている人がたくさんいました。 ![people_seated](/assets/blog/authors/yuji_morimoto/re_invent_2025/people_seated.png =500x) 奥の窓際に人が座っており、各々の作業をしている 新機能について紹介する[NEW LAUNCH]が突如出てくる re:Invent開催前や期間中、またKeynoteで発表された新機能は、セッションタイトルの頭に[NEW LAUNCH]と記載されているものが突然出てくる場合があります。 気になる新機能の場合はセッション一覧をときどき探してみて、新しく追加されていないか見ると良いでしょう。 SNSで情報を探る 上記のような新機能のセッション情報や、突然始まるSWAG(ノベルティ)配布情報など、SNSで拡散されていることがあります。 気になる新機能のセッションが実は2時間前に終了していたということもあったので、逐一チェックすることをおすすめします。 5日間もあるので頑張りすぎない セッションを詰め込みすぎると体力を消耗します。 日本からの移動の疲れ、日々の移動の疲れなどが知らない間に蓄積していきます。 楽しむにも体力がいるので、無理せずに行動しましょう。 疲れが溜まった時には認定者ラウンジに行くのもおすすめです。 テーブル席やソファ席などがあり、軽食も用意されています。 会場の廊下で仮眠を取るのは心配ですが、このラウンジでは何人か仮眠している人がいました。 ![certificated_lounge](/assets/blog/authors/yuji_morimoto/re_invent_2025/certificated_lounge.jpg =500x) Venetianにある認定者ラウンジ イベントを楽しむ AWS公式が企画しているイベントが毎日何かしらあります。 セッションがない朝や夜の時間で開催されているので、息抜き(兼ネットワーキング)に参加してみましょう。 私は4つ参加してみました。 APJ Kick Off Party APJ(アジア太平洋・日本)の参加者向けのイベント ビンゴ大会 5k race チャリティーを目的とした5kのランニング re:Play 4日目の夜に開催される、セッションに頑張って参加した参加者へのご褒美イベント ![5k_race](/assets/blog/authors/yuji_morimoto/re_invent_2025/5k_race.jpg =500x) 朝6時に会場に集まった参加者 コミュニケーションを全力で楽しむ re:Inventに参加して強く感じたのは、現地で得られる価値の多くはコミュニケーションから生まれていたということでした。 英語に自信があるわけではありませんでしたが、AWSという共通言語があることで、思っていた以上に会話はできました。セッションの感想を一言伝えたり、ふと感じた疑問を質問したりすると、新しい視点や気づきを得られる場面が多かったです。 日本人同士であっても、参加しているセッションや注目しているトピックはそれぞれ異なり、会話を通じて自分1人では拾えなかった情報を得ることができました。 (お酒の場でも名刺を交換するところにも日本人らしさを感じ、嬉しくなりました。) 現地の熱量を最も強く感じられたのも、人と直接コミュニケーションを取っている瞬間でした。 Keynote後のざわつきや、セッション終了後の高揚感は、その場で誰かと共有することでより鮮明に感じられました。 旅の恥はかき捨てという言葉通り、うまく話せなかったとしてもその場限り、それならと遠慮せずにどんどん話しかけて、現地で感じる熱量を最大化するのは良かったと思います。 実際にその体験は、上手く行かなかったこと含め、日本に戻ってからの学習意欲やモチベーションとして確実に自分の中に残りました。 まとめ re:Inventは「柔軟さ」がカギだと感じました。 参加前は3,000を超えるセッションの中から何を選べばいいか分からず、参加したいセッションは予約開始と同時に埋まってしまう。満足にセッションに参加できないまま終わってしまうのではないか、そんな不安を抱えながらラスベガスに向かいました。 しかし、それは杞憂でした。 Walk-upと呼ばれる当日枠を活用すれば予約なしでも参加できますし、セッションによっては開始後も空席があれば入場できました。「どうせ無理だろう」と諦めず、果敢に挑戦してみることの大切さを学びました。 Gamedayのような参加者同士でコミュニケーションを取る場も、最初は英語力への不安がありましたが、ギリギリ会話ができることを実感できたので参加してよかったです。もちろん、「言いたかったことはそうじゃなかった…」と歯がゆい思いをすることもありましたが、それが「もっと英語を学ぼう」という具体的なモチベーションに変わりました。 5日間、業務を離れて学びに集中できる環境は貴重でした。技術を深掘りし、気になることがあればその場で質問できる、こんな贅沢な場はそうそうありません。そして、これだけ多くのAWSファンが世界中から集まり、熱量を注いでいる光景を目の当たりにできたことも大きな収穫でした。 これから参加される方も、計画通りにいかないことを恐れず、その場その場で新しい選択肢を見つけてみてください。 (2026年は11/30〜12/4と決定しているみたいです。)
この記事は KINTOテクノロジーズ Advent Calendar 2025 の20日目の記事です🎅🎄 1. はじめに こんにちは! セキュリティ・プライバシー部でサイバーセキュリティに関する業務を担当している、 たなちゅー です! 今回は、AI エージェントを活用して SOC 監視業務を半自動化し、 作業時間を約半分に短縮 した取り組みについてお話しします。 「AI エージェントを使えばすぐできそう!」と思って始めましたが、実際に取り組みを進めてみると試行錯誤の連続で、 想定外の落とし穴 や 失敗 がたくさんありました。この記事では、うまくいったことだけでなく、 失敗からの学び も含めて共有したいと思います。 2. 背景:SOC 業務の課題 SOCとは? SOC(Security Operation Center)は、組織の IT 環境を監視し、サイバー攻撃や不正アクセスなどのセキュリティ脅威を検知・分析・対処する役割を担います。 主な業務内容は以下の通りです。 ログ・アラート監視 :システムのログやアラートを監視し、異常を検知 脅威分析 :検知したアラートが本当の脅威かどうかを分析・判断 インシデント対応 :セキュリティインシデント発生時の初動対応や調査 レポーティング :監視結果や対応状況を関係者に報告 いわば、組織のサイバーセキュリティにおける「最前線」です。 監視業務の課題 ログ・アラート監視の業務には、リアルタイムのアラート監視と定期的なログ監視・分析があります。今回、半自動化の対象としたのは後者の定期的なログ監視です。 定期的なログ監視では、SIEM(Splunk Cloud)を使い、以下の作業を手動で行っていました。 ダッシュボード上のイベント内容を確認 深掘り調査のための SPL クエリを実行 セキュリティインシデントか否かを判断 調査結果のレポートを作成 この手動運用は、1回あたり2〜3時間の作業時間がかかり、大きな業務負担になっていました。また、ログ解析スキルや SPL の知識が必要なため、特定の担当者に知識やノウハウが集中し、属人化が進んでいるという課題もありました。 これらの課題を解決するため、AI エージェント(OpenAI Codex IDE)と Splunk MCP を活用した半自動化に取り組みました。 使用したツール MCP クライアント OpenAI Codex IDE:OpenAI の AI エージェント「Codex」の VSCode 拡張機能。MCP サーバーと連携し、プロンプトに基づいた処理を実行 モデルは「GPT-5.1-Codex-Max」、推論は「High」に設定 MCP サーバー Splunk MCP:Splunk Cloud へのログ検索を実行 その他 Splunk Cloud:システムのログ集約・分析基盤(SIEM) Github:メンバー間でのプロンプト共有基盤 3. 実現したこと 結論から言うと、この取り組みにより監視業務の作業時間を2〜3時間から1〜1.5時間へ、約半分に短縮できました。ここからは、Before/After の運用フローを比較しながら、具体的に何が変わったのかを紹介します。 Before:半自動化前の運用フロー 半自動化以前は、以下の流れで定期的な監視業務を手動で実施しており、1回あたり2〜3時間を要していました。特にステップ1「一次調査」とステップ2「深掘り調査の要否判断」はログ解析スキルや SPL の知識が必要なため、属人化が課題となっていました。 一次調査を実施 ダッシュボードに表示された各イベントごとに、Splunk Cloud を使用して以下のような一次調査を実施 対象イベント前後のタイムラインを確認 対象イベントの調査の軸となる情報を基に異常性の有無を確認 一次調査結果を各イベントごとに整理 深掘り調査の要否判断 整理した情報を基に、深掘り調査の必要性を判断 深掘り調査の実施 ヒアリング SIEM 外の情報収集(チャット内容、社内ナレッジなど) セキュリティインシデントか否かの判断 深掘り調査の結果を基に、セキュリティインシデントかどうかを判断 セキュリティインシデント対応 関係者と連携し、セキュリティインシデント対応を実施 After:半自動化後の運用フロー AI エージェントがステップ1・2を担当し、人間は品質チェックと最終判断に集中する形としました。これにより作業時間は約半分(1〜1.5時間)に短縮。さらに、属人化していた監視業務の標準化も進み、チームとして運用できる体制が整いました。 一次調査を実施(AI エージェント) Splunk MCP でダッシュボード相当の検索を実行し、各イベントごとに、以下のような一次調査を実施 対象イベント前後のタイムラインを確認 対象イベントの調査の軸となる情報を基に異常性の有無を確認 一次調査結果を各イベントごとに整理 深掘り調査の一次要否判断(AI エージェント) 整理した情報を基に、深掘り調査の必要性を一次判断 一次調査結果と判断内容を整理したレポートを作成 レポートの品質チェック・深掘り要否判断(人間) AI エージェントが作成したレポートの品質を人間がチェック 品質チェックと合わせて、深掘り調査の必要性を人間が判断 深掘り調査の実施(人間) ヒアリング SIEM 外の情報収集(チャット内容、社内ナレッジなど) セキュリティインシデントか否かの判断(人間) 深掘り調査の結果を基に、セキュリティインシデントかどうかを判断 セキュリティインシデント対応(人間) 関係者と連携し、セキュリティインシデント対応を実施 Before/After の運用フローを図で比較すると、このような形です。 Before/After の運用フローの比較図 具体例:半自動化後の運用フロー では、実際にどのように監視業務を進めているのか、具体的な流れを紹介します。前述の6ステップを、実務の観点から5つの作業に整理しています。 監視用プロンプトを準備 :GitHub リポジトリから最新の監視用プロンプト(md ファイル)を取得 クローンした監視用プロンプト Codex で一次調査(深掘り調査含む)を実行 :プロンプトファイルを指定して Codex に処理を実行 指示例:xxxxx/prompts/yyyyy.md のタスクを実行してください 処理時間:1プロンプトあたり10〜20分程度 Codexへの指示 レポートの品質チェック・深掘り要否を判断 :AI エージェントが作成したレポートを確認し、深掘り調査の必要性を判断 ログ件数や日時、調査内容の妥当性をチェック 品質チェック用ダッシュボードを作成し、チェック作業を効率化 AI エージェントによる監視レポート 品質チェック用ダッシュボード 深掘り調査を実施 :必要に応じて追加調査を行い、セキュリティインシデントか否かを判断 Splunk Cloud で手動検索 Codex + Splunk MCP を活用した追加調査 セキュリティインシデント対応 :インシデントと判断した場合、関係者と連携して対応を実施 4. 学んだこと ...と、ここまでは「うまくいった話」です。 ここからは、半自動化にたどり着くまでに経験した失敗や学びを共有します。 【学び1】すべては「手順の明確化」から始まる 最初に試したのは、Codex やその他の生成 AI とチャットで対話しながらプロンプトを作るアプローチでした。 「SOC の監視を自動化するプロンプトを作りたいんだけど...」 「こんな感じで...」 「うーん、もうちょっとこうして...」 このようなやり取りを何度も重ねて作成した初期のプロンプトは、以下のような構成でした。 ## 1. メタデータ - 出力先、必要ツール、タイムゾーン ## 2. ロール/前提 - SOC 調査アナリストとしての役割定義 - 前提 ## 3. 共通解析手順(全 SPL 共通) 1. 調査対象イベントの特定(主指標の定義) 2. 深掘り(タイムレンジ拡張、ピボット観点) 3. エラー/事象の分類 4. 30日観測 5. 優先度判定 6. 不明点の明確化 7. 調査ログ(実行した SPL クエリ一覧) ## 4. 優先度判定基準(全SPL共通) - 要(即時対応)/ 観察 / 不要 の3段階と具体的条件 - **要(即時対応)** - ベースライン比 ≥ 2.0 または P95超過、かつ分母 ≥ 30 - 条件1 → 条件2:60分以内に失敗 ≥ 2 - 条件3:xxx_count ≥ 2 かつ yyy_count ≥ 3 ...(以下、複雑な条件が続く) ## 5. 調査結果整理 - 時間帯別サマリ表のヘッダー定義 - 主指標(SPL 別の記載ルール) ## 6. 調査用 SPL 一覧 - 調査観点① - 調査観点② ...(以下、いくつかの調査観点が続く) ## 7. 出力フォーマット(必須) - 調査概要 - 時間帯別サマリ表 - 調査ログ(実行した SPL クエリ一覧) 一見すると形になっているように見えますが、実際に運用してみると以下の問題が発生しました。 基準が曖昧 :「ベースライン」の算出方法が不明確で、P95の計算に必要なデータ量も現実的ではなかった 条件が複雑すぎる :AI エージェントが正しく解釈できず、人間でさえ理解が難しいケースがあった。結果として、一次調査レポートの品質にブレが生じた 横展開できない :プロンプトが特定システムに過度に最適化されており、別システムへ展開する際はゼロから作り直しが必要だった 根本原因は明確でした。SOC 監視業務において「何を」「どういう基準で」判断しているのか、どのような出力を期待しているのか。これらを詳細に整理・文書化できていなかったのです。 解決策:手順書駆動プロンプト開発 そこでアプローチを変えました。やったことはとてもシンプルです。 まず「手順書」を作成する(人間が読んでも迷わず実行できる調査手順・判断基準を明文化) その手順書を生成 AI に渡して「この手順書に沿って SOC 監視用のプロンプトを作って」と依頼する すなわち、バイブコーディング感覚でプロンプトを作成するのではなく、仕様書駆動開発の考え方に倣い、期待値を先に整理してからプロンプトを作成してもらうアプローチです。 調査観点などを記載した手順書 効果は劇的でした。 最初のアプローチでは、1〜2週間かけて試行錯誤を繰り返しても納得のいくプロンプトが作れませんでした。しかし、手順書駆動プロンプト開発に切り替えたところ、手順書作成を含めて約2日間で期待通りの一次調査レポートを出力できるプロンプトが完成しました。 さらに、同じ要領で他システム向けのプロンプトも作成できるため、レポートフォーマットを統一しながら横展開も容易になりました。 以下は、このアプローチで作成したプロンプトの構成です。 ## 1. メタデータ - 出力先、必要ツール、タイムゾーン ## 2. 役割定義 - SOC 調査アナリストとしての役割 ## 3. 前提条件 - 監視対象期間 - 既知情報(静観対象) - 無害化ルール ## 4. 監視項目 各監視項目ごとに以下を記載: - 監視目的 - SPL クエリ - サーチマクロを活用することで、トークン節約、ブレ軽減 - 判断基準 - 「調査必須:〇〇期間に〇〇件以上のイベント」など明確な基準を記載 - 深掘り手順 - 深掘り時の観点や使用する SPL を記載 - 出力要件 - 出力時の必要情報を明記 ## 5. 出力フォーマット 各監視項目ごとに具体的なフォーマットを記載: - 監視概要・サマリ - 詳細結果 - 表形式で出力(項目名や値の記述フォーマットなども明記) - 総合所見・推奨対応 - 調査ログ - 実際に使用した SPL と検索結果サマリ等を全て調査履歴として記録 ## 6. 注意事項 - 必須ルールを箇条書き ## 7. 実行手順 - 実行手順をいくつかのステップに分けて記載 学び 急がば回れ。まず業務内容を整理・文書化する。それを基にプロンプトを作成することで、AI エージェントとの認識のズレがなくなり、期待通りの出力が得られる。 【学び2】「できること」と「やるべきこと」は違う これが一番の失敗談かもしれません。 AI エージェントと Splunk MCP を組み合わせると、「過度に複雑な調査」が気軽にできてしまいます。「せっかくだから、この観点も追加しよう」「もっと深掘りできるな…」と、気づけば監視対象の観点を広げすぎて、本来注力すべきポイントがぼやけていました。 さらに厄介なのは、「やっている感」が出てしまうことです。AI エージェントが大量の分析をしてくれるので、なんとなく仕事をした気になります。しかし実際には、生成されたレポートのレビューに時間がかかり、本末転倒な状態に陥っていました。 あくまで「半自動化」であり、最終判断は人間が行います。人間がレビューできる範囲で、本来注力すべき観点に絞ること。この意識が大事だと学びました。 学び AI エージェントができることを最大限やるのではなく、人間のレビューも含めた全体を俯瞰し、「監視の意図」に立ち返る。「やっている感」に惑わされない。 【学び3】業務の標準化効果は想定以上だった! 当初は「作業時間の短縮」を主な目的としていましたが、「業務の標準化」という副次的効果が想定以上でした。 詳細な手順書を作成したことで、判断基準が明文化されたことに加えて、ログ解析スキルや SPL の知識を要する部分を AI エージェントが担当することで、専門知識の有無に関わらず、誰が実施しても一定の品質で監視業務が行えるようになりました。 結果として、引き継ぎがしやすくなり、チーム全体の対応力向上にもつながっています。 学び AI エージェント活用は効率化だけでなく、業務の標準化・属人化の解消にも大きな効果がある。 5. まだ課題として残っていること 半自動化を実現したものの、正直に言うとまだ改善の余地があります。 品質チェックに一定時間がかかる AI エージェントの出力を鵜呑みにはできないため、人間によるレビューは必須です。ログの日時や件数、判断内容の妥当性チェックには、依然として一定の時間を要します。 ナレッジの蓄積・反映の仕組み 日々の調査で得られる「このパターンは実は〇〇だった」といった細かなナレッジを、プロンプトへフィードバックする仕組みが整っていません。現在、調査履歴を参照する形で解消できないか検証中です。 手順書やプロンプト、監視観点のメンテナンス 新しい脅威パターンや監視から得られた知見に合わせて、手順書・プロンプト・監視観点(SPL)を更新する必要があります。現状、これらについては属人的で、メンテナンスプロセスの標準化が今後の課題です。 6. まとめ 今回の取り組みを通じて学んだ3つのことを振り返ります。 すべては「手順の明確化」から始まる 急がば回れ。まず業務内容を整理・文書化する。これを基にプロンプトを作成することで、AI エージェントとの認識のズレがなくなり、期待通りの出力が得られる。 「できること」と「やるべきこと」は違う AI エージェントができることを最大限やるのではなく、人間のレビューも含めた全体を俯瞰し、「監視の意図」に立ち返る。「やっている感」に惑わされない。 業務の標準化効果は想定以上 効率化だけでなく、業務の標準化・属人化の解消という効果も大きい。 「AI エージェントで業務効率化」というと華やかに聞こえますが、実際には地道な言語化作業と試行錯誤の連続でした。 この取り組みを通じて感じたのは、「業務効率化」ではなく「業務の棚卸しと標準化」と捉えること、そして完全自動化ではなく「半自動化」という現実的なゴールを設定することの大切さです。 この記事が、AI エージェントの業務活用を検討している方の参考になれば幸いです。
この記事は KINTOテクノロジーズアドベントカレンダー2025 の19日目の記事です🎅🎄 KINTOテクノロジーズで Unlimited(Android)アプリの開発を担当している kikumido と申します。 これまで Android の UI 実装では、Figma のデザインを見ながら色・タイポグラフィー・レイアウト・アセットを手作業で Compose へ落とし込む必要があり、どうしても時間と労力がかかっていました。 しかし、Figma が提供する MCP(Model Context Protocol) と、Anthropic の Claude Code を組み合わせることで、このワークフローが大きく変わります。 Figma MCP を通じて AI がデザインデータを直接読み取り、Claude Code が Compose コードを自動生成 してくれるため、これまで手作業で行っていた工程が一気に効率化されます。 本記事では、この「Figma MCP × Claude Code」による UI 実装高速化の流れを、設定方法からプロンプト例、生成結果までまとめて紹介します。 目次 Figma MCP を有効にする MCP クライアントを導入する API Token(PAT)を設定する Figma のファイル URL を指定する Claude Code に実装を依頼する 実行結果 まとめ 1. Figma MCP を有効にする デスクトップ版 Figma の MCP サーバー機能をオン にするだけで準備は完了です。 公式ヘルプに非常にわかりやすい手順があります。 🔗 https://help.figma.com/hc/ja/articles/32132100833559-Figma-MCP%E3%82%B5%E3%83%BC%E3%83%90%E3%83%BC%E3%81%AE%E3%82%AC%E3%82%A4%E3%83%89 2. MCP クライアントを導入する 本記事では、チームで使用している Claude Code を MCP クライアントとして設定します。 Claude Code は Figma MCP に公式対応しており、設定も非常に簡単です。 🔗 https://developers.figma.com/docs/figma-mcp-server/remote-server-installation/#claude-code 3. API Token(PAT)を設定する Figma の API を利用するためには Personal Access Tokens(PAT) が必要です。 セキュリティを考慮し、Claude Codeに直接PATを記載するのではなく 環境変数に保存して使用する方法が安全 です。 3.1 環境変数が安全とされる理由 誤ってAIに送信されない Git に誤コミットされるリスクを防げる PC(OS)のユーザー権限で保護される 3.2 PAT の取得方法 Figma にログイン 右上の自分のアイコン → Settings 左メニューの Personal Access Tokens Generate new token 名前を入力して生成 → 表示されたトークンをコピー(再表示不可) 3.3 環境変数への設定(例:macOS / Linux) echo 'export FIGMA_TOKEN="あなたのPAT"' >> ~/.zshrc source ~/.zshrc PAT の詳細: 🔗 https://www.figma.com/developers/api#access-tokens 4. Figma のファイル URL を指定する Claude Code に Figma の URL を渡すだけで、 ノード階層・レイアウト・色・フォント・画像アセット を自動で読み込みます。 4.1 正しい Figma ファイル URL の取得方法 対象の フレーム / コンポーネント / レイヤー を選択 右クリック Copy → Copy link(リンクをコピー) → ?node-id=xxx を含む正しい URL がコピーされます。 4.2 環境変数への設定(例:macOS / Linux) echo 'export FIGMA_FILE_KEY="コピーしたリンク"' >> ~/.zshrc source ~/.zshrc 5. Claude Code に実装を依頼する 以下は、Figma のデザインを Jetpack Compose に落とし込むためのプロンプト例です。 ご自分のプロジェクトに合わせて適宜調整してください。 目的: Figma MCP を使い、Figma のデザインデータを直接参照して Jetpack Compose の UI コードを生成してください。 前提: - FIGMA_TOKEN(環境変数) - FIGMA_FILE_KEY(環境変数) ■ デザイン情報 - Figma に存在する色・Typography のみ使用し、未定義の値は追加しない - 以下のファイルに分割して実装 - Color.kt - Type.kt - Theme.kt - 上記テーマを使って Screen.kt を実装 - @Preview を追加 - 不明点は推測せず、Figma MCP が取得したデータを使用する ■ 画像アセットの扱い - SVG の場合: - Figma MCP から取得したファイルを基に、正確に Android VectorDrawable(.xml)へ変換して配置 - PNG の場合: - Figma の Export 設定に従う - Export 設定がなければ以下 5 種類の密度で PNG を生成して配置 - mdpi / hdpi / xhdpi / xxhdpi / xxxhdpi - アセット名は Figma 名を Android の命名規則(lower_snake_case)へ変換して作成する 6. 実行結果 Claude Code は、指定された Figma ノードから 色・Typography・レイアウト・画像アセット を取得し、 Color.kt / Type.kt / Theme.kt / Screen.kt / Preview を自動生成します。 これにより、手作業で行っていた 色のコピペ フォント設定 画像書き出し レイアウト再現 といった作業が大幅に自動化され、 UI 実装の速度と正確性が飛躍的に向上します。 それでは、Claude Code にプロンプトを渡した結果を確認してみましょう。 6.1 UIを確認する 左が Figma 、右が Claude Code が実装した Compose のPreviewです。 良い精度で再現できていると思います。 ※「×」はSVGからVectorDrawableに変換された画像、アバターはPNG画像です。 Figma ComposeのPreview ![Figma](/assets/blog/authors/kikumido/figma.png =200x) ![Compose](/assets/blog/authors/kikumido/preview.png =200x) コードも確認してみましょう。 6.2 コードを確認する 画像は以下のように実装されていました。 Image( painter = painterResource(id = R.drawable.ic_avatar_large), contentDescription = "メインアバター", modifier = Modifier .size(106.dp) .clip(CircleShape), contentScale = ContentScale.Crop ) Textは以下のように実装されていました。 styleや色も Figma で指定されたtypography、colorが適切に指定されています。 // ドライバー名 Text( text = driverName, style = KintoTheme.typography.labelLarge, color = KintoTheme.colors.textPrimary ) 入力欄の幅が Figma は固定値なのに対し、Compose は fillMaxWidth() を使用し横幅いっぱいに広がるようになっていました。 こちらはFigmaを正とするのであれば実装を修正するべきですが、横幅の広い端末を考慮しデザイナーと相談しても良いかもしれません。 入力欄の間の余白が14dpであることも Figma 通りに再現できています。 同じ見た目の入力欄が一つの InputField として実装されている点も注目です。 さらに、選択状態に合わせてボーダーの色が変わるようにすでに実装されてもいます。 var selectedField by remember { mutableStateOf<SelectedField>(SelectedField.BirthYear) } // 入力フィールド Row( modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.spacedBy(14.dp) ) { // 生年月 InputField( label = "生年月", value = birthYear, isSelected = selectedField == SelectedField.BirthYear, onClick = { selectedField = SelectedField.BirthYear }, modifier = Modifier.weight(1f) ) // 普段の起床時刻 InputField( label = "普段の起床時刻", value = wakeUpTime, isSelected = selectedField == SelectedField.WakeUpTime, onClick = { selectedField = SelectedField.WakeUpTime }, modifier = Modifier.weight(1f) ) } InputField は Figma の仕様どおりに実装されており、onClick などの挙動もパラメータで柔軟に渡せる設計になっています。 また、入力ボックス内のテキストに typography が設定されていない点も、Figma の定義を忠実に反映した結果です。 なお、プロンプトで「未定義の値は追加しない」と指定しない場合、Claude Code が推測で適切そうな typography を補完してしまいます。 しかし、望ましいアプローチはアプリ側で補正することではなく、Figma のデザイン側を修正し、正しい typography を設定することだと考えています。 その方が、UI の一貫性やメンテナンス性が大きく向上するためです。 @Composable private fun InputField( label: String, value: String, isSelected: Boolean, onClick: () -> Unit, modifier: Modifier = Modifier ) { Column(modifier = modifier) { // ラベル Text( text = label, style = KintoTheme.typography.labelMedium, color = KintoTheme.colors.textPrimary ) Spacer(modifier = Modifier.height(8.dp)) // 入力ボックス Box( modifier = Modifier .fillMaxWidth() .height(53.dp) .border( width = if (isSelected) 2.dp else 1.dp, color = if (isSelected) KintoTheme.colors.borderFocused else KintoTheme.colors.borderDefault, shape = RoundedCornerShape(8.dp) ) .clickable { onClick() } .padding(horizontal = 16.dp), contentAlignment = Alignment.CenterStart ) { Text( text = value, style = TextStyle( fontFamily = FontFamily.SansSerif, fontWeight = FontWeight.Normal, fontSize = 16.sp, lineHeight = 21.sp ), color = KintoTheme.colors.textPrimary ) } } } 先述のプロンプトでは文字を strings.xml に定義するように指示をしていないので、コード上にそのまま記載されています。 先のプロンプトを修正したり、追加で指示を出せば strings.xml に定義した上で使用することもしてくれます。 7. まとめ まとめとして強調したいのは、 実装の精度は Figma 側のデザインシステムが適切に整備されているかに大きく左右される という点です。 Figma のスタイルが未整理だったり、コンポーネント化が不十分な場合、AI が取得する情報も不完全になり、結果的にコードの手直しが必要になってしまいます。 逆に、デザイナーとエンジニアが協力してデザインシステムをしっかり構築しておけば、 UI 実装の速度・正確性は飛躍的に向上し、保守性も格段に高まります。 そのためにも、 日頃から密に連携し、同じ前提でデザイン・実装を行うことが不可欠 です。 さらに、Compose Multiplatform と組み合わせて Figma MCP を活用すれば、 プラットフォームをまたいだ UI 実装の高速化にもつながり、よりスピーディに高品質なアプリ開発が可能になります。 質の高いアプリを素早く届けるためにも、 エンジニアとして継続的に知識をアップデートし、より良いワークフローを探求していくことが重要だと感じています。
この記事は KINTOテクノロジーズアドベントカレンダー2025 の19日目の記事です🎅🎄 はじめに こんにちは、KINTOテクノロジーズ Mobile Assistanceマネージャー&KMPチームリードのYena Hwangです。 2025年9月にDroidKaigi 2025で「 Compose MultiplatformとSwiftUIで作るハイブリッドモバイルアプリ 」というテーマで登壇する機会をいただきました。本記事では、発表内容をもとに、私たちKMPチームがハイブリッド開発を導入した背景と実際の経験を共有したいと思います。 DroidKaigi 2025セッションページ から発表動画をご覧いただけます。また、 発表スライド も公開していますので、ぜひご参照ください。 本シリーズの構成 Part 1:なぜハイブリッドなのか ← 現在の記事 Part 2:実装ガイド(近日公開) Part 3:SwiftUI連携と技術Tips(近日公開) 私たちのチーム紹介 Mobile KMPチームは元々 Androidエンジニアのみで構成されたチーム でした。しかし、Kotlin Multiplatform(以下KMP)とCompose Multiplatform(以下CMP)を導入することで、 iOSアプリの開発まで担当できるチームへと進化 しました。 これこそがハイブリッドアーキテクチャの大きなメリットの一つです。AndroidエンジニアがKotlinの知識をベースにiOS開発まで担当できるようになり、逆にiOSエンジニアもKotlinを習得することで共有コードの開発に参加できます。各OS専門のエンジニアを別々に確保するより、はるかに効率的なチーム運営が可能です。 チーム構成(3名): メンバー スキル拡張 Yao Xie ( Tech blog ) Android → KMP, CMP, iOS Yonghui Chen ( Tech blog ) iOS, Android → KMP, CMP Garamoi Choi ( Tech blog ) API, Android → KMP, CMP, iOS この 3名のチーム で、Androidアプリの開発に加え、iOSチームに提供する共有ライブラリ/SDKの開発も担当しています。KMP/CMPで作成したロジックやUIコンポーネントをライブラリ形態でiOS側に提供することで、iOSチームは共有モジュールを統合するだけで同じ機能を実現できます。 現在、私たちのチームはAndroid/iOSアプリで共通利用できるSDKの開発を担当しています。 なぜハイブリッド開発を選んだのか 現実的な制約条件 昨年(2024年)に、既存のコードベース(Jetpack Compose + SwiftUI)を活用して新しいプロダクトを開始することになりました。プロトタイプ段階から求められた条件は明確でした: High Speed :非常に短い期間 Low Cost :少人数の開発チーム High Quality :ネイティブアプリレベルのUIパフォーマンス しかし現実では、この3つを同時に達成することは「不可能な三角形」と呼ばれるほど難しいことです。通常は2つを選ぶと、残り1つを諦めなければなりません。 KMP + CMPという解答 すでにKMPでビジネスロジックを共有していた私たちにとって、2024年にCMPのiOSサポートがBetaになったことは、UIレイヤーまで共有する挑戦を始める絶好のタイミングでした。ロジックだけでなくUIまで共有することで、この「不可能な三角形」を破れると考えました。 このアプローチが約束すること: 少人数チームでも迅速なプロトタイプリリース ネイティブレベルのパフォーマンス 既存のJetpack Composeコンポーネント再利用 ロジックとUIコード共有による効率最大化 タイトなデッドライン達成 AndroidとiOSを別々のチームで開発していたら実現できなかった、不可能な三角形を破る実用的な方法でした。 KMPとCMPとは 本記事では以下の略称を使用します: KMP(Kotlin Multiplatform) :ビジネスロジックをAndroid/iOS/Desktop/Web間で共有 CMP(Compose Multiplatform) :Jetpack ComposeベースのUIをプラットフォーム間で共有 KMPでロジック層を、CMPでUI層を共有することで、効率的なクロスプラットフォーム開発が可能になります。 ハイブリッドアーキテクチャとは レイヤー別技術選択基準 私たちが確立した実用的なガイドラインです: レイヤー 技術 適した領域 KMP Kotlin Shared ビジネスロジック、APIサービス、データ管理 CMP Compose Multiplatform リスト/カード/フォーム画面、データ中心の詳細画面 Native SwiftUI/UIKit ナビゲーション/ジェスチャー、Map/Camera/Wallet、プラットフォーム固有スタイリング なぜ100% CMPではなくハイブリッドなのか もちろん、100% CMPで構築することも可能です。しかし、私たちの場合は以下の理由でハイブリッドを選択しました。 Best of Both Worlds: プラットフォーム別UI/UXガイドライン準拠が可能 ネイティブコンポーネント統合(Maps、Camera) 段階的マイグレーションパス確保 チームの既存専門性活用 適したユースケース: 既存ネイティブアプリがある場合 プラットフォーム別デザイン要件がある場合 複雑なネイティブ統合が必要な場合 以下は、私たちがPoCアプリで実際に使用したハイブリッドアーキテクチャです。 End-to-End Blueprint ハイブリッドアーキテクチャを実現するための全体像です。 要素 説明 Module layout 共有コードとプラットフォーム固有コードを明確に分離 Shared ViewModel UIからロジックを切り離すための共通契約 Bidirectional UI interop CMPビューをネイティブ画面に埋め込む ネイティブコンポーネントをCMP画面に埋め込む Navigation & State プラットフォーム間で動作するナビゲーションと状態管理戦略 次回予告 Part 1では、ハイブリッド開発を選んだ背景とアーキテクチャの全体像を紹介しました。 Part 2:実装ガイド では、実際のプロジェクト構造、ナビゲーション統合、Koin DIの設定など、具体的な実装方法を詳しく解説します。お楽しみに!
こんにちは、Engineering Office……もとい、技術広報グループのemimです。 主業務はEngineering Officeのデザイナーなのですが、社外交流や社内の勉強会、さらに今回のようなイベント出展にて技術広報メンバーの手を煩わせる機会が多くなりそうだな……という試算から、少し前から技術広報チームの一員としても活動しています。 この記事は、 KINTOテクノロジーズ Advent Calendar 2025 の18日目の記事として執筆しています。 今回は、首題のとおり、アクセシビリティカンファレンス福岡2025にKINTOテクノロジーズ株式会社(以下KTC)が「おやつスポンサー」として協賛したので、そのレポートを行います。 アクセシビリティカンファレンス福岡とは https://fukuoka.a11yconf.net/ アクセシビリティカンファレンス福岡は、2023年より毎年福岡で開催されている「アクセシビリティ」をテーマとしたカンファレンスです。今年で3回目の開催です。私は過去2回も現地で参加しています。 福岡から始まった地方カンファレンスですが、これまで賛同者による派生版として、名古屋(愛知)、石川、千葉など他地方でも開催されています。「アクセシビリティカンファレンス」は表記も発話も長いので、いずれの場合でも略して「アッカン」と表されます。 さて、アクセシビリティとは、誰もがどんな状況にあっても容易に利用・参加できる状態や仕組み、及びその状態(利用可能性)のことを指す言葉です。物理的な環境や情報、サービスなど、さまざまな面で誰もが平等にアクセスできることを意味し、特にソフトウェア分野では最低限の品質の閾値として捉えても齟齬はないでしょう。 そのため、アクセシビリティへの興味関心の高いあらゆる職種の方は、総じて、高いスキルと感度を持ち合わせていると個人的に考えています。 話をKTCに戻すと、今年はたまたま当社の 福岡オフィスの開所が決まった 年でした。そこで、そんなに意識の高い方たちの集まるカンファレンスが、タイミングよく福岡で開催されるならば!と採用とKTCの感度の高さアピールを目的に、なんらかスポンサーができないか、と考えたのが始まりです。 そうは言っても、KTCでの具体的なアクセシビリティに関する取り組みはまだほとんどありません。 過去2回の参加経験から、 会場参加者の印象に残りやすい 会場で一定の交流ができる 展示物や具体の成果アピールが必ずしも必要ではない という3点をカバーできる「おやつスポンサー」がKTCには適していると考え、前のめり気味で応募しました。 おやつスポンサーの内容 おやつ……! 参加されていない方には何も伝わらないですよね。かくいう当社でも、このゆるふわなスポンサー区分名について「これでは(威厳=期待値が薄れて)申請が通らないかもしれない」という懸念が上がり、内部的な申請の際に横文字な名称でカモフラージュされたとかなんとか…… (個人的には、これがとてもアッカンらしいユーモラスな名称でいいな、と感じています。) 具体的なおやつスポンサーの役割は、クッキーとコーヒー及びアッカン公式チロルチョコを食べ放題/飲み放題の形で提供する、ブースへのスポンサーです。ブースで担当者がクッキーやコーヒーを提供するついでに、自社の事業内容などをアピールする機会を得られます。 この軽食サービスは、カンファレンスの最初の開催の2023年当初から提供されています。 他のカンファレンスに比べ、アッカンでは色々な障害がある人でも「ここにいる。^[「ここにいる。」とは、アクセシビリティカンファレンス福岡2023のテーマでした。]」ことが当たり前の世界です。長時間同じ姿勢がしんどいような方や、ずっと同じ所に居続けることに不安のある方もいるかもしれません。会場内には託児所などもあるので、子供の声も聞こえていました。そんな方々でもカンファレンスを楽しめるように、各セッションの時間が短めだったり、休憩時間が長めだったりという工夫がなされています。 そこにマッチするのが、コーヒー^[中にはコーヒーが苦手な方もいらっしゃったようで、提供はコーヒーだけなので少し窮屈な思いをさせてしまったようです。]とクッキーです。甘いものと苦いもので、疲れた脳と心を癒やしてくれます。会場のみの提供となってしまいますが、参加者が長丁場のカンファレンスで疲れないように配慮されたサービスです。 昨年まではアイシングクッキーが配られていましたが、今年はシンプルなクッキーに希望の図柄のプリントされたクッキーに変更となっていました。 後日、隣席の同僚が「なんだ〜、アイシングの方がいいじゃん……って最初思ったけど高級クッキーじゃん!!」と小躍りしたクッキーです。 コーヒーは、福岡で有名な REC COFFEE とスターバックスのものがサーバーで用意されました。 カンファレンスの様子(と前夜祭の様子) 前夜祭について カンファレンスの前日夜には、LINEヤフーさんの博多オフィスにて、 アクセシビリティカンファレンス福岡 前夜祭 が開催されていました。 私は別件の予定があり不参加だったのですが、当社からは 11月からジョインした辻 がLTで登壇し、スクリーンリーダーの NVDA を用いてKindleの書籍を読む方法(「『聴く』読書から『読む』読書へ」という副題が添えられています)が紹介された他、福岡オフィスのメンバーなどが聴講者として参加をしました。辻については、転職の記事が公開されていない時期だったこともあり、会場でざわめきを作ったと聞いています。 さらに後から聞いた感想では、自称アクセシビリティ初心者な人たちでも「自分にもできるかもしれない」となれるような、代替テキストについてなどの話題提供が心に残ったそうです。当社の参加メンバーから、当日福岡にいなかったチームメンバーにも「ぜひ聞いてほしかった」との声を聞きました。 カンファレンス当日について カンファレンス当日は、開場より少し早めに会場入りをしてブース設営などを行いました。我々は他のカンファレンスなどでも利用する、KINTOのキャラクターである「 くもびぃ 」とともにブースに立ちました。 ちなみに、アッカンは他のカンファレンスやセミナーに比べて、運営メンバーにも参加者にも女性が多い印象です。ブースに来てくれる方々も、すれ違う方々も、開場前のアッカン福岡実行委員会やボランティアスタッフなど、とにかく多くの方から「かわいい〜」という声を聞けたのが嬉しかったです。 スポンサーブースエリアは本会場と別ながらも、大きなスクリーンとクリアな音声(スピーカー)で、カンファレンス本編の内容がサテライト放映されていました。スポンサーブースにずっといたとしても、講演内容が楽しめるようになっています。 KTCブースでは、前日にLTを行った辻も端にずっと居て、普段利用しているスクリーンリーダーや点字ディスプレイを利用し、デモの披露など行っていました。途中、カンファレンスの手話通訳の方が「視覚障害者がどのように情報を受け取られているのか」と話しを聞きにきてくれたり、聴覚障害の方も点字ディスプレイの様子を見に来てくれたりしたそうです。 他のイベントではスポンサーブースに居ると、なかなかカンファレンス本編を楽しめなかったりするのですが、その辺りもみんなで楽しめるように計算されているように感じます。「お客さんと楽しむ」だけではないことが幸いし、スポンサーブースにいただけでも学びの多かったKTCスタッフは「せっかくなら、アクセシビリティに興味のあるメンバーも参加できたらよかった…次回はぜひ!」と話していました。 また、現地ではカンファレンスの後に懇親会も開催されました。KTC福岡のスタッフ陣が、熱冷めやらぬまま福岡の各社の方々と情報交換を行い「引き続き勉強会などを開催しましょう!」と意気投合したと聞いています。大変楽しみです。 この記事では本編の様子に全然触れられていないのですが、前夜祭と当日のXの様子が公式にまとめられています。当日Xでは、ハッシュタグ付きポストの多さからか度々「本日のニュース」に取り上げられたりしていました。少しでも盛り上がりを感じたい方は、以下のまとめをご覧ください。 https://posfie.com/@FukuokaA11yconf/p/OD58dzG 後日アーカイブも公開されるそうです。 https://x.com/FukuokaA11yconf/status/1997858020148330885?s=20 アクセシビリティカンファレンス福岡実行員会の皆様及び、ご登壇の皆様、のみならず各スポンサーブースの方々、オフライン/オンラインの各参加者の皆様、お疲れ様でした。そして交流くださって、ありがとうございます。また来年も(開催が予告された)アッカン福岡に参加できることを楽しみにしています。 おまけレポート:ブース出展に伴う制作物 今回、ブースでの配布物にくもびぃの紙クリップを用意しました。過去、別の機会でも配布していたノベルティです。せっかくなので触って形のわかってもらえるもの、そして使えそうなもの、かつお菓子といっしょにもらっても困らないサイズのもの、ということで選びました。この「触ってわかる」という点は好評でした。 さらに、スタッフとして参加していないのに「これがあると『今日会場に来ているのはこの人』って説明ができるんです!」と参加スタッフのアクスタ(アクリルスタンド)を ゆかちさん が作ってくれました。まさかのアクスタデビューです。 土台の部分にはNFCタグが組み込まれており、個々人のSNSに繋がっていたりします。これが(意外にも?)好評で、他社の広報チームでも「真似したい」という意見をもらいました。 ちなみに辻に「視覚障害の場合は、名刺をもらうよりもNFCの方が便利ですか?」と事前に確認をしたところ、「会場(うるさい所)で忙しくNFCで操作するよりも、家に帰ってから名刺を改めて確認できる方がいいように思います」との意見をもらいました。なるほど。 今回ブースにいたメンバーは、SNS上でアイコンの方が知られている人も多かったです。そのため「この人だよ」と紹介をするのにもアクスタが役立った、というポイントも補足しておきます。
この記事は KINTOテクノロジーズ Advent Calendar 2025 の18日目の記事です🎅🎄 はじめに KINTOテクノロジーズのクリエイティブグループ所属の福田です。 Osaka Tech Lab に所属しています。 トヨタグループ内コミュニティ「TURTLE」にて、2025年4月にデザイン分科会を設立しました。 アンバサダーとして分科会の勉強会企画・運営に携わったので、振り返りと今後の意気込みをまとめます。 TURTLEとは TURTLE(Toyota cloud UseR TechnicaL alliancE)は、トヨタグループのクラウド技術に関するエンジニアが集まり、知見を共有するために設立されたコミュニティです。 「社外コミュニティでは話せないことが多く、参加しづらい」「社内にインプット・アウトプットの場がない」「同じものを複数社で開発しているのはもったいない」 こうした現場の声を背景に、トヨタグループとしてエンジニアのコミュニティをみんなで作ろうという想いから誕生しました。 なぜデザイン分科会なのか 近年、ビジネスにおけるデザインの重要性は急速に高まっています。 デザインは単なる見た目の美しさを超え、ユーザー体験やブランド構築、サービスの使いやすさにまで影響を及ぼし、企業活動の前線に立つ存在となっています。 しかし、私が所属するクリエイティブグループでは、トヨタグループ内でデザインに関する知見やノウハウを共有できる場がほとんどありませんでした。 特に、デザインに関連する事例や成果物には社内専用の情報が多く、社外コミュニティでは安心して話すことが難しい状況もありました。 こうした背景から、Osaka Tech Labに所属し、TURTLEの他分科会で企画・運営を担っているアンバサダーに相談しました。 その結果、グループ横断でデザイン領域の知見を共有できる場の必要性を再認識し、TURTLE事務局に相談した後、2025年4月に『デザイン分科会』が正式承認されました。 分科会設立までの流れ 2025年2月 TURTLE総会で設立準備中の案内 デザイン分科会の勉強会企画・運営を共に担うアンバサダー募集開始 2025年3月 デザイン分科会アンバサダーのキックオフMTG開催 分科会設立申請 2025年4月 デザイン分科会設立が事務局にて正式承認 2025年2月のTURTLE総会での案内時の写真です。この開設準備発表がきっかけでトヨタグループ他社のアンバサダーの仲間を集めることができました。 活動実績(2025年4月~9月) 設立当初、デザイン分科会には2社から6名のアンバサダーが参加し、隔週で定例会を開きながら情報共有と関係構築に努めてきました。 勉強会開催 半年間でオンライン勉強会を2回実施し、質疑応答や投票など参加型コンテンツを簡単に作成できるインタラクションツール「 slido 」や、チームでのアイデア出しや共同作業をスムーズに行えるオンラインホワイトボードツール「 FigJam 」を活用することで、オンラインでも双方向のコミュニケーションを重視した勉強会を実現しています。 第1回:「コーポレートサイトのリニューアル」 コンセプトの重要性やデザインプロセスを共有 第2回:「デザインシステム導入とFigma運用の最適化」 実践的なツール活用法を紹介 まとめ 2025年12月時点で、デザイン分科会の参加企業数は30社、参加者数は179名に達しています。 明日(2025年12月19日)には第3回勉強会「UX入門勉強会」の開催も予定しています。 現在、アンバサダーの構成は2社7名による運営です。 今後もグループ全体でデザインに関する知見やノウハウを共有し、新たなグループ会社からのアンバサダーの仲間集めにも取り組み、学びの多い場を目指します。 デザイン分科会は「デザインをビジネスの前線に」というビジョンのもと、トヨタグループ全体でのデザイナー同士の知見共有を加速させ、より良いユーザー体験の創出を目指して活動を続けていきます。 最後まで読んでいただき、ありがとうございました!
この記事は KINTOテクノロジーズ Advent Calendar 2025 の17日目の記事です🎅🎄 Engineering OfficeのNaitoです。KINTOテクノロジーズ(以下、KTC)には4つの2025年注力テーマ(インテンシティ、AIファースト、ユーザーファースト、リリースファースト)があります。 以前のブログ で2025年注力テーマの1つ、リリースファーストについてお伝えしました。 今回はリリースファーストにまつわるこの1年の取り組みや変化について紹介します。 最初に認識合わせをしておくと、KTCではリリースファーストは、「アイディア創出からリリースまでの期間を短くし、ユーザー・顧客に早く価値を提供する」としています。 2025年1月〜3月 Engineering Officeが立ち上がりました。 メンバーは ahomu と私(当時入社3ヶ月)の2人です。 Findy Team+の導入・活用支援という切り口で開発チームとの対話を通し、各チームの状況やメンバーのことを知り始めた状態で、その結果わかったことは以下のようなことでした。 自分たちの現状を定量的に把握できているのは一部のチームにとどまっている Findy Team+を導入したが、うまく計測・可視化できないチームもある Findy Team+の1機能である、プロセスタイム分析(JiraをINPUTとして各工程ごとのリードタイム)の計測・可視化ができるチームはゼロ 開発パフォーマンスの計測・可視化に取り組んでいるチームにおいても一部の人で計測データを見て試行錯誤しながら、改善活動に取り組んでいる。チーム全体には広がっていない 計測・可視化に関心があっても先行しているチームがどんな状況なのかはわからず、情報収集ができない 現在(2025年末) Engineering Officeはなんと4名に増えました。それぞれの専門領域を最大限発揮しつつ、コラボレーションしてチームで活動しています。 「一緒にやろう」と複数チームから声をかけていただき(ありがたい!)、私たちはこの1年間で約20チームに関わらせていただきました。 各チームは、 注力テーマに紐づいた目標を設定し、取り組んでいる リリースファーストの第一歩は自分たちの現状を定量的に定性的に把握することからという意識が全社に広がっており、社内の主なプロダクト、開発チームはFindy Team+を導入して開発パフォーマンスの計測を行っている Findy Team+ではFour Keysについては全チームが計測可能な状態になっている Findy Team+を見て話し合うことがチーム全体に広がっているところも増え、改善事例が少しずつ共有されている Findy Team+の1機能である、プロセスタイム分析(JiraをINPUTとして各工程ごとのリードタイム)は3プロダクトが計測できている チームを超えたリリースファーストのタスクフォースが発足し、業務のかたわら、プロダクト横断でリリースファーストを実現するための仕組みづくりを実施中 ある部門では部門全体で役割分担や開発プロセスを見直し、役割間・チーム間のコラボレーションを強化中 チームのレビュープロセスを見直した結果、レビュー時間が向上した事例 この変化がどうやって起こったのか?正直、各チームの頑張りの賜物なわけですが。Engineering Office(横軸組織)から見た目線でお伝えしていきたいとおもいます。 注力テーマを理解する 各プロダクトにおいては注力テーマの意味はなんとなくわかるけど具体的にどういうこと?というのが当時の状況でした。 そのため、最初の2−3ヶ月は推進メンバー全員で注力テーマについて社内に浸透させるところから始まりました。 まずは社内で言葉の認識合わせを行い、「なぜこれがいまKTCにとって大事なのか」また「リリース期間だけ短くなればよいということではなく、ユーザー・顧客に向き合い、価値を提供することに意味がある」「ユーザーファーストをないがしろにしてリリースを優先しても技術的負債になってしまう」ということを伝える活動を続けました。 プロダクトやチームごとに自分たちにとってのリリースファーストを考える 注力テーマについて各人が理解すると、次はプロダクトごと、チームごとに自分たちは注力テーマを実現するために何をしたらいいのか?自分たちの現状ってどんな感じなのか?ということが話し合われました。 各方面で注力テーマについて考えた結果、私のところにも以下のような声が届いてきました。 リリースが早くなったかどうかBefore/Afterをわかるようにしたい AIを活用して実装スピードあげたい リリースまでの流れってどうなっているのか 統合テストに時間かかっている ユーザーが遠くて価値が届いているのかわからない 設計・実装より前のフェーズにボトルネックがあるように思うが計測できていない 自チームだけでは前に進めるのは難しい。関係者で集まって話し合いたい こういった課題感共有や話し合いを経て、プロダクトやチームで注力テーマを実現するための自分たちのチームの目標を定めていきました。 取り組み 以下はリリースファーストに関する取り組みの一部です。複数のチームで同様の取り組みをしているケースもあります。 なぜ開発パフォーマンスを計測するのかとFindy Team+導入の説明会 GitHubのブランチ戦略・運用ルール変更 PRレビュープロセスの改善 Findy Team+を見合う会 チームのケイパビリティの可視化 Jiraを使った工程ごとのリードタイムの計測(そのためにJiraの運用ルール見直し) 全社横断でのAI利活用状況の計測・可視化 Value Streamの可視化 部門全体でのValue Streamの改善 アジャイルトレーニングの実施 ユーザー視点で要求を整理し、PRDを作成するワークの実施 プロダクト毎のテスト環境構築 インシデント対応プロセス改善 テストデータ作成方法の見直し Techラウンドテーブル(チーム間の情報共有) トヨタ生産方式勉強会入門編 ここに挙げたのは私が関わった取り組みだけですので、社内には他にもたくさんの取り組みがあります。 ボトルネックを特定し、Value Streamを改善した事例 Techラウンドテーブル @Osaka Tech Lab まとめ 上記のような取り組みを1年間繰り返し続けてきた結果が冒頭のような変化に繋がっています。 当初のリリースファーストの目標を実現しているチームもまだ途中のチームもいますが、どのチームも自分たちの行動で起きた変化は実感していることとおもいます。 社内の風土としてボトムアップで様々なことが進むことが多いです。そのため、今回の注力テーマの各取り組みにおいてもまずは自分のチームの範囲でやってみようという形で始まることが大半でした。 一方で、KTCのプロダクトは複数のチームで構成されていることが多いです。リリースファーストやユーザーファーストを実現するためには、プロダクト全体を俯瞰する視点が欠かせません。 自チームが整うと、自然とメンバーの視野も広がりより広い範囲に目を向けるようになります。そのため、2025年後半にはチームを超えた「リリースファースト」の取り組みが増えてきました。 チームを超えると部門が異なる人や他の役割の人たちと課題を共有し、目線合わせをしていく必要があるのですが、専門領域や役割の違いにより見えているもの感じているものが異なる場合も多く、ゴール設定や進め方で躓くことも多いです。 このような時にはビジネス・技術・プロセスを統合して見えているマネージャーのアドバイスや方向性づけ、判断というのがとても大事になります。 それによりチームを超えた様々な関係者がまとまり、取り組みが加速するというの目の当たりにしています。 今年の変化が成果となって表れるのが来年です。来年、リリースファースト・ユーザーファーストの活動を加速させ、より多くの成果に結びつけていくためにはマネージャーの関与は不可欠です。 本当の意味でリリースファーストを実現するプロダクトがどれだけ増えるのか今からとても楽しみです。 リリースファースト、ユーザーファーストは一年で終わる話ではありません。プロダクト開発に携わる以上は継続的に取り組んでいくテーマです。 Engineering Officeは来年も引き続き各チームとともにリリースファースト、ユーザーファーストに取り組んでいきます。 お知らせ Regional Scrum Gathering Tokyo 2026 のDay1(1/7)に出ます。具体の取り組みのいくかについて話す予定です。みなさんよかったら見に来てくださいね。 「リリースファースト」の実感を届けるには〜停滞するチームに変化を起こすアプローチ〜
この記事は KINTOテクノロジーズアドベントカレンダー2025 の17日目の記事です🎅🎄 1.はじめに こんにちは! KINTOテクノロジーズのデジタル戦略部DataOpsG所属の上平です。 普段は社内のデータ分析基盤と「cirro」というAIを活用した社内アプリの開発・保守・運用を担当しています。 以前、下記の記事で、Strands Agentsの導入前の検証事例をご紹介させていただきました。 https://blog.kinto-technologies.com/posts/2025-07-18-try-strands-agent/ 当時より発展し、現在「cirro」はAmazon Bedrock × Strands Agentsという構成になっています。 本記事では、「cirro」にStrands Agentsを利用し、GA4への問い合わせ画面を構築した事例を紹介します。 2.本記事の対象者 本記事は、Amazon BedrockをConverse APIやInvoke Model経由で利用した経験があり、 Strands Agents等エージェント開発SDKへの切り替えを迷っている方が対象となります。 3.GA4への問い合わせ画面構築の背景、概要 3.1.背景 GA4 (Google Analytics 4) は、Webサイトやアプリに 「誰が」「どこから来て」「何をしたか」 という、 訪問者のアクセス状況を分析できる非常に便利なサービスです。 しかし、その分析できる項目の種類があまりにも多いため、 初めて使う方にとっては、どこを見たらいいのか、どうデータを読み解けばいいのか、かなり難しいです。 GA4のデータは、主に次の2種類の要素で構成されています。 ディメンション:データを分類したり切り口としたりする「属性」を示す項目です。 「どこから」アクセスしたか(例:Google検索、Twitterなど) 「どの国・地域」から来たか 「どのページ」を見たか 「どんなデバイス」を使ったか(例:スマートフォン、PC) メトリクス:具体的な量や頻度を表す「数値」を示す項目です。 Webサイトへのアクセス数(セッション数) 特定のページが表示された回数(表示回数) ユーザーがサイトに滞在した時間 サイトを訪れたユーザーの数 これらのディメンションやメトリクスの項目が200項目・300項目の規模で存在するため、 慣れていないと欲しい情報にたどり着くこと自体が課題です。 Google公開資料:アナリティクスのディメンションと指標 この課題について、例えば「今週のアクティブユーザ数が知りたい」「アクセス数が多いページは?」等、 自然言語で問い合わせできるようになれば、サイトやアプリの管理者が簡単に傾向を見ることができ 改善に役立つのでは…と構築に着手しました。 3.2.概要 GA4への問い合わせ画面は、よくあるシンプルなチャット画面です。 以下の流れでユーザの問い合わせに対し、GA4の内容を応答します。 ユーザの問い合わせを入力 AIがGA4のAPIから現在有効なディメンションとメトリクスの一覧を取得 AIが適したディメンションとメトリクスを選択し、GA4へ問い合わせる GA4の結果をAI側で表示用の形式に変換し、回答を出力 シンプルですが、ユーザはディメンションやメトリクスを把握せずともAIを介してGA4のデータにアクセスできます。 初心者には単純にデータアクセスの補助として、 ディメンションやメトリクスを全て把握していない中級者の方には、 どの項目で必要なデータが取得できそうかの当たりをつけることに役立ちます。 4.要素技術・アーキテクチャの紹介 ここからは、「GA4への問い合わせ画面」を構築時に使用した要素技術やアーキテクチャをご紹介していきます。 4.1.Strands Agentsとは? 2025年5月16日にAWS Open Source Blogで公開されたオープンソースのAIエージェントSDKです。 以下は、AWSのAmazon Web Services ブログで公開されている図です。 図のように、ツールを備えたAIを実装するには、Agentic Loopと呼ばれるループ処理が必要です。 この処理では、AIの応答がユーザーへの回答なのか、ツールを使ってさらに処理を進めるべきかを判断します。 Strands Agentsを使えば、このループ処理を開発者が自前で実装することなく、AIエージェントを構築できます。 参考、図の出典:Strands Agents – オープンソース AI エージェント SDK の紹介 4.2.cirroってどんなサービス? 私の所属するDataOpsGでは下記ミッションを目的に活動しています。 「全社のデータを分析用に整備、AI-Readyなデータ分析基盤を提供することでデータドリブンな意思決定を支援する」 AIは、非エンジニアでも容易にデータにアクセスするための入り口として注目しており、 cirroはDataOpsGで独自に開発・運用している生成AIの活用基盤です。 UI等可能な限り共通化し、チャットや問い合わせ画面のような画面構成であれば、 プロンプトと参照データの追加のみで 金太郎飴的に量産できる構成となっています。 図のように、①UI/コンピューティング機能と、②システムプロンプトや参照データを分離し、 ②を切り替えることで1つのシステムで複数のAIの機能を実現しています。 また、URLパラメータで使用するツールを指定することができ、ツールを持ったAIエージェントとして稼働することも可能です。 今回はこの機能を利用し、cirroでGA4への問い合わせ画面を構築しました。 4.3.GA4の問い合わせ用のツール Googleが公開する2つのAPIをStrands Agentsが使用するツールとしてラップし構築しました。 cirroはツールを使用して、「利用できるディメンションとメトリクスの取得」と「ユーザの質問に合ったデータをGA4から取得」を実現しています。 4.3.1.getMetadata GA4で使用できるメトリクスとディメンションを取得するAPI getMetadata詳細 4.3.2.runReport 指定したプロパティID、メトリクス、ディメンション等から、合致するデータを取得するAPI runReport詳細 5.実装時のポイント 本記事では、MCPを使用せずツールの形で機能追加を実現しました。 ここではMCPを使用しなかった理由や、ツールでの実装を採用したメリットをご紹介します。 5.1.MCPを使用しなかった理由 cirroはLambdaがコンピューティングエンジンです。 そもそもがツールでできることについて、より工数をかけてMCPサーバを立てることにメリットを見いだせなかった背景もありますが、 Lambda主体とすることで以下の課題があり、確実に機能提供するためツールでの実装を採用しました。 Lambdaでの起動方法や、起動時のオーバヘッドの課題 Googleが公開するMCPサーバはローカル稼働前提になっている 別途ECS等を使用し自前でリモートサーバとして用意する方法もあるが、Lambda主体の維持管理が容易なcirroのコンセプトと異なる。 Lambdaの特性上、うまくMCPサーバと通信できるかの課題 MCPサーバとAIの通信は、調べる限り別プロセスを立ち上げ、標準出力を介してやり取りしている。 Lambda上でMCPサーバと通信できるか調査期間では確証が持てなかった。 5.2.ツールでの実装を採用したメリット ツールとして実装することによるメリットもありました。 5.2.1.クレンジング処理の追加が容易 API「getMetadata」は大量のディメンションやメトリクスの内容を応答します。 おそらくすべてのディメンションやメトリクスが必要なケースは少ないのではないでしょうか? 私の環境でも、使用していなかったり、想定するユーザ(GA4初心者)にとって不要と思われる項目を、 ツール内で除去しています。 AIに与える情報を削減することで、精度の向上や応答速度、トークン消費量を抑える工夫をしました。 5.2.2.カスタムが容易 ローカルでも稼働するツールとすることで、実装と確認を容易にしました。 また各クライアントで資源を共有するMCPサーバでなく、ツールとして独立するため、 案件ごとの個別の変更を他に影響なく実施できます。 修正前後の比較も、新たなツールと旧ツールそれぞれ共存させ、確認することが容易です。 5.2.3.親子構成のマルチエージェントが構築しやすい ツールはただの関数です。当然関数内でBedrock等AIのサービスを呼び出すことができます。 AIを呼び出すツールを用意すれば、メインのAIとツール内の子AIが存在するマルチエージェントの構成が組めます。 本記事では採用しませんでしたが、例えば自由記述の文面の前処理や、AIの出力内容のチェック等、 ロジックベースの処理では難しい内容を子エージェント側で処理させるようなこともできそうだ…と考えています。 MCPが注目される昨今ですが、ツールにはツールのメリットがあり小規模で個別開発が発生するようなケースの場合、 まだまだツールでの実現の選択肢は残るだろうな...と個人的には思っています。 6.おわりに 今回は、デジタル戦略部で展開しているAI活用システム「cirro」を活用し、 GA4への問い合わせ画面を構築した事例を紹介させていただきました。 「AIにツールを持たせる」というと難しく感じるかもしれませんが、Strands Agentsを使えば驚くほどシンプルです。 元々「Converse API」を使用したただのチャットボットだったcirroが、 「Strands Agents」に切り替えるだけで、ツールを使ってAPIを呼び出すエージェントに進化しました。 AIエージェント開発に興味はあるけれど、何から始めればいいか分からない...という方は、 まずStrands Agentsで簡単なツールを1つ持たせてみることから始めてみてはいかがでしょうか? きっと、AIができることの幅が一気に広がる体験ができると思います。
はじめに KINTOテクノロジーズのデジタル戦略部DataOpsG所属の西です。 普段は社内のデータ分析基盤の開発・保守・運用を担当しています。 データガバナンスの一環としてのデータ分析基盤へのアクセス制御のため、AWS Lake Formation、その機能であるハイブリッドアクセスモードとLFタグを扱う機会がありました。 はじめてLake Formationを触ると、その仕様や用語を理解するだけでも大変だと思います。(自分は、なかなか苦労しました。) そのため本記事ではLake Formationの主要な概念や設定方法をご紹介します。 Data lake locations、Data permissions、Data locations、IAMAllowedPrincipalsについて ハイブリッドアクセスモードについて LFタグによるアクセス制御について ハイブリッドアクセスモード、LFタグによるアクセス制御の設定方法 :::message なお、本記事はGlue Data Catalog(以下、Glueデータカタログ)上のリソースに対するLake Formationのアクセス制御を前提として書かれています。 ::: またLake Formationを触って気づいた注意点として、下記を本稿後半の 注意点 に記します ハイブリッドアクセスモード運用における新規作成IAMロールの関係について ハイブリッドアクセスモードとCloudFormation Amazon Athenaビューへのアクセス制御 AWS Lake Formation データ分析基盤のデータカタログにGlueデータカタログを採用している場合、IAMポリシーやS3バケットポリシーよりもさらにきめ細かいアクセス制御を実施するには Lake Formationの導入検討が必要になると思います。 Lake Formation自体の詳細はAWSから出ている下記ドキュメントをあたってください。 デベロッパーガイド AWS Black Belt ← 個人的に、Lake Formationの概要を掴むのにわかりやすい資料でした Data lake locations Lake Formationでアクセス制御する対象を登録する機能 対象:S3パス 説明:ここに登録されたS3パス配下をLake Formationによるアクセス制御対象として登録する 例:Glueデータカタログ上のデータベースをアクセス制御したい場合、データベースのS3ロケーションはData lake locationsに登録されたS3パス配下である必要がある 注意点:ここにS3パスを登録するだけではLake Formationによるアクセス制御は実施されない Data locations 対象:プリンシパル ^1 とS3パス 説明:Glueデータカタログのデータベースやテーブルへの作成や変更の権限を付与する。ここで行う設定はデータロケーション(S3リソース)へのメタデータをプリンシパルに作成、変更する権限 Data permissions 対象:プリンシパル、Glueデータカタログのデータベースやテーブル 説明:下記のアクセス権限をプリンシパルに付与する データベースに対して Create Table、Alter、Update、Drop、Describe テーブルに対して Select、Insert、Delete、Describe、Alter、Drop 注意点: Data lake locationsの設定を事前におこなっておく メタデータを作成、変更する権限(Create Table/Alterなど)をData locationsで事前に設定しておく AWS Black Belt のP19,P20 がわかりやすいです。 IAMAllowedPrincipals IAMAllowedPrincipals について Lake Formation 許可のリファレンス に下記の通り説明があります。(2025/11) 「Lake Formation は、データカタログ内のすべてのデータベースとテーブルに対する Super アクセス許可を、デフォルトで IAMAllowedPrincipals というグループに設定します。このグループアクセス許可がデータベースまたはテーブルに存在する場合、アカウント内のすべてのプリンシパルが、 AWS Glueの IAM プリンシパルポリシーを介してリソースにアクセスできるようになります。」 IAMAllowedPrincipalsにSuper権限があるため、Lake Formationのデフォルト設定時では、GlueデータカタログリソースにIAMポリシーでアクセスが可能です。 Glueデータカタログのデータベースやテーブルのアクセス制御について、IAMポリシーでのアクセス制御からLake Formationでのアクセス制御に移行するには IAMAllowedPrincipalsの設定の排除が必要 それぞれのIAMプリンシパルに対して、Lake Formationでアクセス制御(メタデータ、データロケーションへの制御)を設定する 上記を実施する場合、既存IAMプリンシパルの棚卸が必要になります。 この棚卸に漏れがあると、GlueデータカタログのリソースにアクセスできないIAMプリンシパルが発生することに注意が必要です。 また、Lake Formationのアクセス制御を解除し元のIAMによるアクセス制御に戻す際は、手順の逆を実施することになります。 こちらにその手順とスクリプトが公開されています Using only IAM access controls ハイブリッドアクセスモード これまでの方式では、Lake Formationでアクセス制御を実施するには、IAMAllowedPrincipalsの設定を排除しLake Formationを設定する必要があります。(この方式はLake Formationモードと呼ばれます) 一方、ハイブリッドアクセスモードの場合はIAMAllowedPrincipalsが付与されていてもLake Formationのアクセス制御が優先されるため、IAMAllowedPrincipalsの設定を排除せずにLake Formationのアクセス制御を有効にできます。 つまり、IAMAllowedPrincipalsが付与されていてもLake Formationによる制御を強制的に⾏わせる機能です。そのため、上述のIAMプリンシパルの棚卸を行わずにLake Formationによるアクセス制御を有効にできます。 ハイブリッドアクセスモードの場合、下記が可能になります。 選択したリソースとプリンシパルについてLake Formationのアクセス制御を有効化(ハイブリッドアクセスモードのオプトイン) Lake Formationアクセス制御を解除するには、ハイブリッドアクセスモードのオプトインを解除する LFタグ Glueデータカタログのリソース(データベース、テーブル、カラム)にタグを割り当て、そのタグに基づいてプリンシパルにアクセス権限を付与するための機能です。 LFタグを定義(例: Key=Confidential, Value=True/False) リソースにLFタグを付与する プリンシパルに、LFタグに対するアクセス権を付与する LFタグを使うと、リソースとプリンシパル間の権限関係を疎結合に保つことができます。 LFタグを使わない場合、リソースとプリンシパル間で直接アクセス権を設定する必要があります。この場合、リソースやプリンシパルが増えると、アクセス権の管理が煩雑になります。 設定方法 以下、Lake FormationのハイブリッドアクセスモードとLFタグ方式によるアクセス制御の手順を記します。 前提条件 今回は、下記のペルソナのもとアクセス制御を実施したいと思います。 ペルソナとLFタグ ペルソナ 役割 対象IAMロール名 対象LFタグ 許可する権限 データレイク管理者 Lake Formationの操作権 lf-test-001 Confidential = True, False Super データユーザー 許可されたテーブルにアクセスできる lf-test-001-user Confidential = False Select、Describe 手順 Lake Formationでアクセス制御を実施するには、大まかには、下記を実施します。 データレイク管理者に登録する Glueデータカタログのメタデータへのアクセス制御のため、S3パスをData lake locationsに登録し、そのS3パスをLake Formationで制御可能状態にする Glueデータカタログのメタデータの作成の制御として、Data locationsの設定。これでテーブルのCreateやAlter権限をLake Formationで付与 LFタグの設定 Data lake administratorsの設定 Lake Formationの操作設定権をIAMロールに付与する Data lake administratorとして今回はlf-test-001というIAMロールをセットする Data lake locationsの設定 GlueデータカタログのデータベースのS3ロケーションを設定する Hybrid access modeを選択する Data locationsの設定 Data locationsの設定として、ハイブリッドアクセスモードでアクセス制御をしたいプリンシパルと制御対象のS3プレフィックスを登録する この制御対象のS3プレフィックスはGlueデータカタログのデータベースのうち、ハイブリッドアクセスモードでアクセス制御したいデータベースのS3ロケーションを設定している LFタグを作成 キーはConfidential、バリューはTrue、Falseを作成する LFタグへのアクセス権を設定 「Permissions」の「Data permissions」からアクセス権を設定します。 Lake Formationで権限を渡したいプリンシパルを選択する Lake Formationで管理したいLFタグを選択する 今回は、lf-test-001-userというIAMロールに対して、LFタグのキーがConfidentialでバリューがFalseにアクセス権を付与する Lake Formationで許可したいアクセス権を選択する lf-test-001-userはキーがConfidential、バリューがFalseのリソースに対して、データベースの場合Describeを付与、テーブルの場合Select、Describeを付与する LFタグを管理対象リソースに設定する 今回はconfidential というデータベースのtable_001、table_002 というテーブルに下表のようにLFタグを付与します。 データベース名 テーブル名 LFタグのキー名 LFタグのバリュー名 confidential table_001 Confidential True confidential table_002 Confidential False table_001にはキー=Confidentialのバリュー=True、table_002にはキー=Confidentialのバリュー=Falseを設定する ハイブリッドアクセスモードを有効化する 管理したいリソース(テーブル)を設定 今回はデータベースを設定しないため、データベースはIAMポリシーでのアクセス制御が継続される アクセス制御したいプリンシパルを設定 動作確認 アクセスさせないテーブルについて lf-test-001-user にスイッチロールするとConfidential=Trueであるtable_001はUI上から見えない confidential.table_001 へのクエリは失敗する アクセス許可しているテーブルについて Confidential=Falseであるtable_002 はUI上から見える confidential.table_002 へのクエリは成功する 解除手順 ハイブリッドアクセスモードをRemove(解除)することでLake Formationによるアクセス制御は解除される 注意点 最後にLake Formationを触ってみて気づいた注意点を書いておきます。 異なるキーのLFタグによるリソースへのアクセス制御はLFタグの AND条件ではなく OR条件になる 例:キーがConfidential=TrueのLFタグとキーがDepartment=SalesのLFタグが付与されたリソースに対しては、プリンシパルにキーがConfidential=TrueのLFタグへのアクセス権またはキーがDepartment=SalesのLFタグへのアクセス権を持つ場合、アクセス可能になる 運用時にはハイブリッドアクセスモードでは新規作成されたIAMロールには対応できない。Lake Formation管理者とIAM管理者が異なる場合、Lake Formation管理者が予期せぬIAMロールがGlueデータカタログにアクセスする可能性がある ハイブリッドアクセスモードのオプトイン操作はCloudFormationには現時点で非対応と思われる。 ハイブリッドアクセスモードのオプトインの実施(CreateLakeFormationOptIn)が必要だが、CloudFormationには現時点では見当たらない。 ^2 CloudFormationでリソースの作成後、下記が必要なのではないかと思われる。(今後の検証が必要) Lake FormationコンソールやAWS CLIなどでプリンシパルのオプトインの設定を行う CloudFormationのカスタムリソースを用いて、Lambda関数からCreateLakeFormationOptIn APIを実行する Athenaで作成したビューに対するアクセス制御は基礎となるテーブルの権限と一致させておく必要がある。そのためAthenaビューとテーブルのアクセス制御は同じものとなる ^3 ※1 データカタログビューを使うとテーブルとは異なるアクセス制御をビューに設定できる。 ^4 ※2 データカタログビューはハイブリッドアクセスモードのIAMAllowedPrincipalsを排除が不要という恩恵を受けられない ^5 データカタログビューの作成には下記が必要 データカタログビュー作成にはIAMAllowedPrincipalsのアクセス権限をビューの基のテーブルから外す テーブルが所属するデータベースからデフォルトで設定されている[Use only IAM access control for new databases] を外す データカタログビューを作成するIAMロールに対して、Lake Formationでビューの基のテーブルに対するアクセス権限を設定する あとがき Lake Formationを使うとGlueデータカタログのリソースに対してきめ細かいアクセス制御が可能になることは分かりました。 一方で、Lake Formation自体の理解と設定に学習コストがかかる印象を受けました。 そのためチーム内で知見を十分に共有できていないと、誰もアクセスできないリソースが発生しそれを解決できる人間がわずかしかいないという状況に陥りかねないと感じました。ドキュメントの整備、ハンズオンの実施などでチーム内の知見を高めることが重要と思います。 また、Lake Formation管理下のテーブルとビューのアクセス制御については、テーブルとビューで異なるアクセス制御を実施したい場合は注意が必要です。 既存のIAMロールの管理体制、Glueデータカタログの運用方法とLake Formationの仕様を十分に検証することが重要と思います。
この記事は KINTO テクノロジーズ Advent Calendar 2025 の 16 日目の記事です 🎅🎄 はじめに こんにちは! KINTO 開発部 KINTO バックエンド開発 G マスターメンテナンスツール開発チーム、技術広報 G 兼務、Osaka Tech Lab 所属の high-g( @high_g_engineer )です。フロントエンドエンジニアをやっています。 現在、筆者はプロジェクトで TanStack Query を利用しています。 TanStack Query は、 useQuery や useMutation のおかげで、 React Hooks を扱う感覚でデータの取得・更新が可能で非常に便利なライブラリです。 しかし、キャッシュの扱いで少し癖があり、理解が浅いと、以下の様な挙動に振り回されてしまいます。 データをキャッシュで賄えるはずの場面で無駄にフェッチしてしまっている サーバーのデータを更新したはずなのに、古い情報が画面に表示されてしまっている 闇雲にキャッシュ削除を連発してしまっている 本記事は、こういった挙動に振り回されないように、TanStack Query の公式ドキュメントを読んで、 筆者自身がキャッシュ周辺の挙動を理解するため の内容となっております。 本記事の構成 TanStack Query とは? TanStack Query のキャッシュの基本である stale と gc を理解する TanStack Query のキャッシュの挙動を理解する クエリの無効化 ミューテーション時のクエリの無効化 プロジェクト内でよく利用している QueryClient のメソッドの紹介 TanStack Query とは? https://tanstack.com/query/v5 本記事では、TanStack Query v5 の利用を前提にしています。 TanStack Query(旧 React Query)は、フロントエンドアプリケーションにおけるサーバー状態管理のためのライブラリです。 サーバー状態とは、API から取得するデータのように、アプリの外部に存在し、非同期で取得・更新が必要なデータのことです。 以下を非常にシンプルなコードで実現してくれます。 データ取得&データ更新のシンプル化 キャッシュ管理 バックグラウンド更新 ローディング・エラー状態の管理 TanStack Query のキャッシュの基本である stale と gc を理解する まず、TanStack Query のキャッシュの挙動を理解するために、 stale (古いデータ) と gc (ガベージコレクション) について理解する必要があります。 以下の記事が TanStack Query のキャッシュを理解するうえで一番最初の入口として読むべきドキュメントです。 https://tanstack.com/query/latest/docs/framework/react/guides/important-defaults stale について stale とは、「古くなった」または「更新が必要な可能性がある」状態のデータを指します useQuery または、 useInfiniteQuery のようなデータ取得系のフックは、デフォルトでクエリ(※)のデータを stale として扱います stale は、 staleTime を設定することで再フェッチの頻度を制御できます staleTime のデフォルトは 0 なので、データ取得直後に stale となります stale なデータは、新しいクエリのマウント、ウィンドウの再フォーカス、ネットワーク再接続時に自動で再フェッチされます ※ クエリとは、取得データ、状態、メタ情報、キー、データ取得関数をひとまとめにした管理単位のことです。 gc について 使用しなくなったキャッシュを削除する機能のことです useQuery , useInfiniteQuery はアクティブなインスタンスがなくなった場合、「非アクティブ」というラベル付けが行われ、再使用される場合に備えてキャッシュに残ります 「非アクティブ」の場合、デフォルトだと、5 分後に gc されます gcTime を設定することで、 gc が発生するまでの時間を変更できます stale と gc について、 staleTime と gcTime (v4 より以前は cacheTime という名称) をもとに考えると分かりやすいです。 staleTime → クエリを再取得するまでの時間 gcTime → gc するまでの時間(キャッシュにメモリを保持する時間) staleTime が過ぎても、クエリはキャッシュに残っていますが、 gcTime が過ぎると、クエリがキャッシュから消えるということになります。 それ以外の細かいオプションなども書かれてはいますが、 TanStack Query のキャッシュの基本を理解するために、まずは stale と gc が理解できていれば問題ないと思います。 TanStack Query のキャッシュの挙動を理解する 以下のドキュメントでは、TanStack Query の useQuery がクエリのデータをキャッシュ、キャッシュしたデータの利用、そして gc するまでの流れが解説されています。 https://tanstack.com/query/latest/docs/framework/react/guides/caching useQuery は、 useQuery({ queryKey: ["todos"], queryFn: fetchTodos }); といった記述が基本になりますが、こちらがどのように動作するかを順番に解説します。 本題の前に useQuery の基本コードを簡単に紹介 キャッシュの挙動理解の本題に入るまでに、 useQuery を利用した簡単なサンプルを紹介します。 useQuery が利用される場合、以下のようなコードが記述されることが一般的です。 // データ取得関数 const fetchTodos = async () => { const response = await fetch("/api/todos"); return response.json(); }; // コンポーネント内で使用 const TodoList = () => { // useQuery の記述 const { data, isPending, error } = useQuery({ queryKey: ["todos"], queryFn: fetchTodos, }); if (isPending) return <p>読み込み中...</p>; if (error) return <p>エラーが発生しました</p>; return ( <ul> {data.map((todo) => ( <li key={todo.id}>{todo.title}</li> ))} </ul> ); } useQuery の引数として与えられているオブジェクトには、 queryKey と queryFn というプロパティがありますが、それぞれについては以下の意味があります。 queryKey → キャッシュを識別するためのキー。配列で指定。同じキーを持つクエリはキャッシュを共有 queryFn → データをフェッチするクエリ関数 TanStack Query のキャッシュの一連のライフサイクルを理解する ここまで出た queryKey , stale , gc を元に useQuery のキャッシュ周辺の流れを整理すると、以下のようになります。 1. 初回の useQuery({ queryKey: ['todos'], queryFn: fetchTodos }) を実行 まだ、 queryKey: ['todos'] に紐づけられたクエリのデータが存在しないため、データを取得する為に queryFn で指定された fetchTodos を実行します。 クエリ関数の実行が完了すると、レスポンスは、 ['todos'] キーのもとにキャッシュされます。 staleTime はデフォルトで 0 なので、この時のデータは即座に stale になります。 2. 再度、 useQuery({ queryKey: ['todos'], queryFn: fetchTodos })  を実行 この時、 ['todos'] キーのもとにキャッシュされたデータが stale として存在するため、 stale なデータがレンダリングに利用されます。 それと同時に queryFn で指定された fetchTodos がバックグラウンド実行されます。 クエリ関数の実行が完了した時点で、キャッシュが新しいデータで更新されます。(初回と同じく、 staleTime が 0 なので、即座に stale になります) そして、この時点で更新されたデータを元にまたレンダリングが更新されます。 3. useQuery({ queryKey: ['todos'], queryFn: fetchTodos }) がマウント解除され、使用されなくなる この時、アクティブなインスタンスがなくなったため、クエリは「非アクティブ」のラベルが付与され、 gcTime を利用して、 gc を実行するための時間設定を行います。 gcTime のデフォルトは 5 分なので、何もなければ、5 分後に ['todos'] キーに紐づいたキャッシュデータは gc されますが、5 分以内に再度 useQuery({ queryKey: ['todos'], queryFn: fetchTodos }) が実行されるようなことがあれば、 gc のタイマーはリセットされ、同じ様な流れでキャッシュの更新が行われます。 一連のライフサイクルを図示すると以下のようになります。 queryKey によるキャッシュ管理について 少しだけ脱線しますが、 queryKey については、以下のドキュメントで詳しく解説されています。 https://tanstack.com/query/latest/docs/framework/react/guides/query-keys TanStack Query は、 queryKey に基づいて、キャッシュを管理します。 queryKey の型は unknown[] なので、シンプルな文字列のみで構成された配列から文字列とオブジェクトのネストなどの複雑な配列まで対応しています。 大切なことは、TanStack Query は queryKey を一意のキーとして、キャッシュを管理するため、キャッシュしたクエリのデータを再利用したい場合は、正しく配列を指定する必要があります。 例えば、以下のように、 queryFn に対して同じクエリ関数を指定しているが、異なった queryKey を指定している場合、キャッシュは全く別のもとして扱われます。 useQuery({ queryKey: ['todos'], queryFn: fetchTodos }) useQuery({ queryKey: ['todos1'], queryFn: fetchTodos }) また、逆に queryFn は異なったクエリ関数を指定しているが、同じ queryKey を指定している場合、同一のキャッシュが扱われます。 useQuery({ queryKey: ['todos'], queryFn: fetchTodos1 }) useQuery({ queryKey: ['todos'], queryFn: fetchTodos2 }) queryKey の指定が正しくないだけで、そもそもキャッシュが正しく効かない状態になるので、注意が必要です。 ただし、以下のように、 queryKey にオブジェクトが扱われている場合、オブジェクトの中身(キーと値)が同じであれば、オブジェクト内のキーの順序に関係なく、同じキャッシュとして扱われます。 useQuery({ queryKey: ['todos', { status: 'done', page: 1 }], queryFn: fetchTodos }) useQuery({ queryKey: ['todos', { page: 1, status: 'done' }], queryFn: fetchTodos }) ここまでの内容が理解できれば、TanStack Query のキャッシュの基本はかなり押さえられたと思います。 クエリの無効化 staleTime に基づいた自動的なキャッシュ更新のみだと、必ずしも効果的でない場面は存在します。 例えば、ユーザーの何らかの操作によって、キャッシュが古くなっていることが確実な時や、意図的にキャッシュを更新したい時などです。 そういった場面に利用できるのが、 QueryClient に存在する invalidateQueries メソッドです。 これを利用することで、クエリのデータを強制的に stale にします。そのクエリが現在レンダリング中(アクティブ)であれば、即座にバックグラウンドで再取得されます。 import { useQuery, useQueryClient } from "@tanstack/react-query"; // QueryClient からコンテキスト取得 const queryClient = useQueryClient(); // キャッシュ内のすべてのクエリを無効化 queryClient.invalidateQueries(); // todos キーを持つ全てのクエリを無効化 queryClient.invalidateQueries({ queryKey: ["todos"] }); 注意点として、 invalidateQueries() はクエリのデータを stale にするだけであり、キャッシュを削除したり、 gc したりするわけではありません。 キャッシュを削除する場合、 removeQueries() を利用する必要があります。 ミューテーション時のクエリの無効化 TanStack Query を扱う上で最も挙動に振り回されるタイミングがミューテーション(更新、削除などの操作)後のレンダリングだと筆者は思います。 正直なところ、ここまでの説明は、この項目を説明するための長い前置きでした。 (本当に長くてすみません・・・。) ドキュメントとしては、以下を読んで終わりなのですが... https://tanstack.com/query/latest/docs/framework/react/guides/invalidations-from-mutations ドキュメントで扱われているサンプルコードを記載します。 import { useMutation, useQueryClient } from "@tanstack/react-query"; const queryClient = useQueryClient(); const mutation = useMutation({ mutationFn: addTodo, onSuccess: async () => { // パターン1: 単一のクエリのデータを無効化する場合 await queryClient.invalidateQueries({ queryKey: ["todos"] }); // パターン2: 複数のクエリのデータを無効化する場合 // ※ 実際はパターン1かパターン2のどちらかを使用します await Promise.all([ queryClient.invalidateQueries({ queryKey: ["todos"] }), queryClient.invalidateQueries({ queryKey: ["reminders"] }), ]); }, }); ミューテーション後に queryClient.invalidateQueries({ queryKey: ["todos"] }) を実行することで、キャッシュに保持しているクエリのデータを手動で無効化し、バックグラウンドで再取得が行われます。これにより、キャッシュのデータを最新の状態に更新できます。 この記述がない場合、キャッシュの更新が staleTime に依存するため、タイミングによってはミューテーションでデータを更新したにもかかわらず、画面の表示が古いままになることがあります。 ここまでで紹介したドキュメントに目を通した方なら、なぜ onSuccess のタイミングで、 queryClient.invalidateQueries({ queryKey: ['todos'] }) を実行しているのか?を正しく理解できると思います。 ただ、このドキュメントを読むだけだと正しい理解ができず、更にこのドキュメントでもそこまで触れられていない為、 useMutation を利用した後は、対応する queryKey を invalidateQueries() に記述するだけで終わってしまうのではないかと思います。 実際、筆者はそうでしたし、未だにプロジェクト内にはそういったコードが散在しています。 プロジェクト内でよく利用している QueryClient のメソッドの紹介 最後に、プロジェクト内でよく利用している QueryClient のメソッドを紹介します。 invalidateQueries queryClient.invalidateQueries({ queryKey: ["todos"] }); 指定したクエリキーのクエリを無効化し、キャッシュを stale にマークします。 キャッシュは即座に削除されません そのクエリを使用しているコンポーネントがアクティブな場合、バックグラウンドで再フェッチが自動的に実行されます 用途: データ更新後に関連するクエリを再取得させたいとき refetchQueries await queryClient.refetchQueries({ queryKey: ["todos"] }); 指定したクエリキーのクエリを即座に再フェッチします。 invalidateQueries とは異なり、アクティブなコンポーネントの有無に関係なく強制的に再取得 await で完了を待つことが必要 用途: 更新後に最新データが確実に取得されていることを保証したいとき removeQueries queryClient.removeQueries({ queryKey: ["todos"] }); 指定したクエリキーのキャッシュを完全に削除します。 キャッシュからデータが消えるため、次回アクセス時は新規フェッチが必要 用途: エンティティが削除された後など、キャッシュに残っていると問題になるケース setQueryData queryClient.setQueryData([`/v1/versions/${variables.id}`], data); 指定したクエリキーのキャッシュデータを直接書き換えます。 サーバーへのリクエストなしでキャッシュを更新 用途: Mutation の結果をそのままキャッシュに反映したいとき(楽観的更新など) まとめ TanStack Query というライブラリは処理を非常にシンプルに記述でき、ドキュメントをそこまで読まなくても利用できてしまうほど便利なライブラリです。 ただ、キャッシュ周辺に関しては、ある程度ドキュメントを読み込んで理解しておかないと、挙動に振り回されて、書かなくても良いようなコードを書いて、場当たり的な対応をしてしまうことになります。 この記事が TanStack Query のキャッシュ周辺で悩んでいる方の助けに少しでもなれば幸いです。 最後まで読んでいただきありがとうございました。 参考記事 https://tanstack.com/query/v5 https://tanstack.com/query/latest/docs/framework/react/guides/important-defaults https://tanstack.com/query/latest/docs/framework/react/guides/caching https://tanstack.com/query/latest/docs/framework/react/guides/query-keys https://tanstack.com/query/latest/docs/framework/react/guides/query-invalidation https://tanstack.com/query/latest/docs/framework/react/guides/invalidations-from-mutations https://tanstack.com/query/latest/docs/reference/QueryClient
Introduction Hello. I'm Sato, a frontend developer at KINTO Technologies Corporation (KTC). In this article, I'd like to introduce my team developing a website for KINTO used vehicles, sharing how we proceed with the development and how our team structure looks like. I recently started using a sun umbrella for the first time in my life. For learning more about myself, please check here What Is the KINTO Used Vehicle Website Development Team? In general, when you sign up with KINTO, a subscription with a new vehicle is started. At the end of the subscription, you need to return the vehicle. Our team mainly work on developing and operating KINTO used vehicles (only in Japanese) , a website that sells the returned vehicles as used vehicle subscriptions online. A major difference of the e-commerce site from the one for KINTO new vehicles is that vehicle inventory fluctuates daily as used vehicles are basically one-of-a-kind items sold on a first-come, first-served basis. We implement e-commerce-specific initiatives and approaches, considering how to display inventory and recommendation sections, which is very worthwhile. Team Structure (as of November 2025) One product manager One producer Five frontend engineers Eight backend engineers Team Atmosphere My team members working at our office Our frontend (FE) team, backend (BE) team, and contract partners are able to communicate casually without barriers and freely share opinions. Since we're close to the business teams related to used vehicles, I think we are in the mindset of sharing opinions and growing the used vehicle e-commerce site together! Sometimes people from other divisions join our regular project meetings, giving very pleasant comments like, "This meeting has a really great atmosphere." **Introducing Some Team Members!** Some of our used vehicle frontend team members have written articles, so please check them out too! NAKAHARA Yuki Loves cheering for soccer Boosting work efficiency with his custom-built keyboard! NAKAHARA Yuki's article (below) Website Image Optimization with Lambda@Edge & Next.js ![Ren.M](/assets/blog/authors/Keita.S/2025-10-20-UpTeamWebsiteImprovement/minakawa.png) Ren.M - Basketball club captain! Shining as a point guard - When it comes to iPhone, the high-end model is the best! - Ren.M's articles (below) - [Introduction to TypeScript](/posts/2024-04-10-TypeScript入門/) - [Introducing In-House Club Activities: Basketball Club](/posts/2024-09-26-社内部活動紹介-バスケ部編/) Project Team Structure The used vehicle e-commerce site is developed and operated by KTC members in different teams. Team Role Affiliation Used vehicle business team Business owner KINTO Corporation Used vehicle site development team Handles all development KTC Creative team Handles project direction and website design KTC Analytics Team Manages numbers of website access and CVR KTC :::message Did you know the role of KINTO Technologies (KTC)? ::: KTC is a tech company founded to drive mobility services developed by companies in the Toyota Group using diverse technologies and our creativity. It handles in-house development of KINTO, which is one of Toyota's mobility services. By dividing business domains into two organization—KINTO Corporations (KINTO’s service operation domain) and KTC (KINTO’s development domain)—and working together, we are able to leverage each other's strength. How We Develop Products In developing the used vehicle e-commerce site, we determine what to do based on regular project meetings, and we growth hack the website through running PDCA cycles using the HCD development methodology. We proceed with the development in four different teams led by the business team, and everyone shares opinions while developing with a sense of ownership. What Is HCD? User testing is underway HCD stands for Human Centered Design, a methodology that focuses on understanding user needs and how to translate them into products. We, the used vehicle team, specifically conduct surveys and user testing, organize website improvement points and user demands to make a better e-commerce site. User testing involves communicating with users about what they're thinking while operating the website, which helps us to explore unexpected insights and is a very valuable experience for the website developers as well. Example of How We Proceed PDCA Cycle Content Responsible Team Plan Set goals and improvement plans based on analytics team reports, customer feedback, and achievements as a commercialized project Everyone shares opinions to make decisions on structure, design, etc. (repeat the above activities several times until we finalized the project) ・Used vehicle business ・Used vehicle development ・Creative ・Analytics Do Development to release ・Development Check Check metrics Discuss results ・Used vehicle business ・Used vehicle development ・Creative ・Analytics Action Plan next steps based on checked points, if needed ・Used vehicle business ・Used vehicle development ・Creative ・Analytics Regular Project Meetings Project members attending regular business meeting In weekly meetings, we share information with the used vehicle business team while discussing improvements and considering service expansion. The used vehicle business team, creative team, and analytics team attend meetings from their own working positions. I personally like how Kitahata-san from the used vehicle business team facilitates—there's no formal icebreaker segment, but he keep things running in a great atmosphere throughout. For more about Kitahata-san, see here The regular meeting agenda is structured like this: Updates from individual teams Used vehicle business Used vehicle development Analytics Creative Topics Planning improvement measures based on inquiries received Proposing ideas on what we want to do Sharing results of initiatives, etc. Development Team Initiatives We implement various initiatives alongside development. Recently, we've been actively adopting AI-powered development and using the external service Findy Team+ to improve our development process. Item Details AI-related ・Devin  ・Minor fixes, document creation, etc. ・Copilot  ・Source code review  ・Implementation assistance ・RCA (Root Cause Analysis)  ・AI-powered critical alert root cause analysis Internal development meetings ・Scrum events ・Study sessions ・Pair programming Development process improvement ・Findy Team+ ・Process improvements related to code review Interview I, Sato, interviewed some of members involved with the e-commerce site development. ![開発FEリーダー佐藤](/assets/blog/authors/Keita.S/2025-10-20-UpTeamWebsiteImprovement/sato.png) Sato, leader of the development FE team "Nobe-san, it's been about 3 months since you joined. What are your impressions of the used vehicle website development team?" ![開発P野辺](/assets/blog/authors/Keita.S/2025-10-20-UpTeamWebsiteImprovement/nobe.png) Nobe, producer of the development team "By participating in various development meetings, I was particularly impressed that everyone speaks up and thought that this is an environment allowing everyone to share opinions." "And I could feel that opinions are quickly adopted, and everyone wants to make things better together." ![開発FEリーダー佐藤](/assets/blog/authors/Keita.S/2025-10-20-UpTeamWebsiteImprovement/sato.png) Sato, leader of the development FE team "Thank you. I'm very grateful that you've already shared your opinions and made many improvement suggestions." "How are things going with the BE team lately, Kaneda-san?" ![開発BE(リーダー)金田](/assets/blog/authors/Keita.S/2025-10-20-UpTeamWebsiteImprovement/kaneda.png) Kaneda, leader of the development BE team "Well, the BE team is also trying to boost productivity and holding study sessions to raise the skill level of team members." "Recently, we've been focusing on domain-driven development." ![開発FEリーダー佐藤](/assets/blog/authors/Keita.S/2025-10-20-UpTeamWebsiteImprovement/sato.png) Sato, leader of the development FE team "Thank you. The BE team's initiatives and success stories that you share are always helpful for my FE team’s improvements too." "I'd like us to enhance our products as a whole team, regardless of FE or BE." "Let's also talk with Kitahata-san from the used vehicle business team. What do you think about the used vehicle website development structure?" ![中古車ビジネスチーム北畑](/assets/blog/authors/Keita.S/2025-10-20-UpTeamWebsiteImprovement/kitahata.png) Kitahata, member of the used vehicle business team "I always feel that new features are released at a good pace and progress are being made daily. The style of 'just try it first and run PDCA' feels like a very good match for us." "What's great about this project team is that anyone can say anything regardless of job title or position. The development side often proposes things we, the business side, never thought of, and it feels like we're all doing business together." ![開発FEリーダー佐藤](/assets/blog/authors/Keita.S/2025-10-20-UpTeamWebsiteImprovement/sato.png) Sato, leader of the development FE team "Thank you. I also feel that each team is united in development and operations." "I'd like to continue increasing KINTO fans one by one." "Finally, a question for Mizuuchi-san, our product manager. What do you expect from the development team?" ![開発PDM水内](/assets/blog/authors/Keita.S/2025-10-20-UpTeamWebsiteImprovement/mizuuchi_1.png) Mizuuchi, product manager of the development team "It's not just about doing development. We discuss in meetings how to improve the website, expecting the service to grow in mind. That's why I want project members to speak up and make the website even better." "As an ideal way of working, I don't intend to fix a role, like 'this is your job,' so I want people to proactively do what they can and what they notice for any improvements." "Technology is a means of achieving what you want to do, so I want the members who can develop with a service-first mindset rather than technology-first. We bring members with that perspective in mind." ![開発FEリーダー佐藤](/assets/blog/authors/Keita.S/2025-10-20-UpTeamWebsiteImprovement/sato.png) Sato, leader of the development FE team "So it is ideal that we have members who are service-first and can develop proactively." "I also thought this is an important perspective in terms of growing all services in KTC. Thank you." In Closing I hope this has given you at least a glimpse of how we develop the used vehicle e-commerce site and the atmosphere of our team. We've also introduced our team atmosphere and processes here! If you're interested, please read it, which makes me very happy. A Development Culture That Starts with "Let's Just Try It." The KINTO Used vehicle Team Talks About the Driving Force and Flexibility Behind the Scenes (only in Japanese)
はじめに こんにちは。KINTOテクノロジーズ株式会社(以下、KTC)でフロントエンド開発をしている佐藤です。 この記事では私が属しているKINTO中古車サイト開発チームについて紹介させていただきます。 主に開発の進め方や体制などをお伝えできればと思います。 最近日傘デビューしました。佐藤について詳しくは こちら KINTO中古車サイト開発チームって? 通常KINTOで契約すると新車でサブスク開始となり その後契約終了するとその車両が返却されます。 返却された車両を中古車のKINTOとして 再びEC販売する「 KINTO 中古車 」のプロダクトを 開発、運用をメインとしているチームです。 「KINTO 新車」と大きく違うポイントとして、 中古車は基本的に早い物勝ちの一点物商品となりますので 日々在庫変動があるECサイトとなります。 在庫の見せ方、おすすめコーナーなど ECサイトならではの施策や打ち出し方がやりがいの一つでもあります。 チーム内体制(2025年11月時点) プロダクトマネージャー 1名 プロデューサー 1名 フロントエンドエンジニア 5名 バックエンドエンジニア 8名 チームの雰囲気 チームの様子 フロントエンド(FE)、バックエンド(BE)チーム、業務委託のパートナーさんとも 垣根なく気軽に会話コミュニケーション、意見が言い合える雰囲気です。 また中古車のビジネスチームとも距離が近く、 意見を言ったり一緒に中古車サイトを育てていこう!という気持ちで 皆同じ方向を向いていると思います。 たまに他部署の方がビジネス定例会議に参加される事があるのですが、 「非常に雰囲気の良い会議ですね」のようなありがたいお言葉を 耳にすることもあり嬉しい限りです。 **チームメンバーを一部ご紹介!** 中古車フロントエンドのチームメンバーが執筆した記事もありますので ぜひこちらもチェックしてみてください! NAKAHARA Yuki サッカーの応援が大好き 自作キーボードで作業効率UP! NAKAHARA Yukiさんの記事↓↓ Lambda@Edge & Next.jsによるサイト画像最適化 ![Ren.M](/assets/blog/authors/Keita.S/2025-10-20-UpTeamWebsiteImprovement/minakawa.png) Ren.M - バスケ部部長!ポイントガードで輝いています - iPhoneはハイエンド機種に限る! - Ren.Mさんの記事↓↓ - [TypeScript入門](/posts/2024-04-10-TypeScript入門/) - [社内部活動紹介-バスケ部編-](/posts/2024-09-26-社内部活動紹介-バスケ部編/) 体制 中古車サイトは様々なステークホルダーと 関わりながら運用されています。 チーム 役割 所属 中古車ビジネスチーム ビジネスオーナー 株式会社KINTO 中古車サイト開発チーム 開発全般を担当 株式会社KINTOテクノロジーズ クリエイティブチーム ディレクションやサイトデザインを担当 株式会社KINTOテクノロジーズ 分析チーム アクセス数やCVRなどを管理 株式会社KINTOテクノロジーズ :::message 豆知識「KINTOテクノロジーズ(KTC)の役割」 ::: KTCはトヨタグループ各社が展開するモビリティサービスをテクノロジーとクリエイティビティでリードするために創設されたテックカンパニーです。KINTOもトヨタモビリティサービスの一つとして、KTCが内製開発を担っています。 KINTO(KINTOの運営領域)、KTC(KINTOの開発領域)と 専門領域を分担し協業することによって強みを活かしております。 開発の進め方 中古車サイトの開発ではビジネス定例を軸としてやることを決めていき、 HCDという開発手法を元にPDCAのサイクルでECサイトをグロースハックしています。 ビジネスチームを中心とした4チームで進めており、 皆で意見を出し合いながら主体性を持って開発しております。 HCDとは ユーザーテストの様子 人間中心設計(Human Centered Designの略称)のことを指し、 ユーザーのニーズを理解し、 どうやって製品に反映させるかを中心に設計する手法となります。 中古車チームでは 具体的に実際にアンケートやユーザーテストを行い、 サイトの改善点、ユーザーの欲求などを整理して改善に繋げています。 ユーザーテストは何を思って操作しているかなど、 コミュニケーションをとりながら実施するので 予想外な気づきがあったり 開発者としても非常によい経験となっております。 進め方の例 PDCAサイクル 内容 担当チーム Plan(計画) 分析チームのレポートやお客様の声、 ビジネスとして実現した事などを元に目標、 改善案などを設定 皆で意見出し合い、構成、デザインなどを決めていく (fixするまで何度か繰り返す) ・中古車ビジネス ・中古車開発 ・クリエイティブ ・分析 Do(実行) 開発〜リリース ・開発 Check(評価) 数値をチェック 結果の議論 ・中古車ビジネス ・中古車開発 ・クリエイティブ ・分析 Action(改善) 評価を元に必要であれば次の計画へ ・中古車ビジネス ・中古車開発 ・クリエイティブ ・分析 ビジネス定例 ビジネス定例の様子 週次ミーティングで中古車ビジネスチームと情報共有をしつつ、 改善の相談やサービス拡大の対応を検討しています。 中古車ビジネスチーム、クリエイティブチーム、分析チームがあり ミーティングではそれぞれの立場で参加しています。 中古車ビジネスチーム北畑さんのファシリテートが私は好きで アイスブレイクなど形式張ったコーナーはないのですが 終始とても良い雰囲気で進行してくださります。 北畑さんについては こちら 定例はこのようなアジェンダ構成になります。 各チーム共有 中古車ビジネス 中古車開発 分析 クリエイティブ トピックス 問い合わせがあった内容をもとに改善策を皆で考える やりたい事の相談 施策の結果など 開発チームでの取り組み 開発に伴い、さまざまな取り組みを実施しています。 最近ではAIを使った開発や 外部サービスのFindy Team+を活用した開発プロセスの改善など を積極的に取り入れています。 項目 詳細 AI関係 ・Devin  ・軽微な修正や、資料作成など ・Copilot  ・ソースコードレビュー  ・実装の補佐 ・RCA(Root Cause Analysis)  ・AIによるクリティカルアラート原因分析 開発内部定例 ・スクラムイベント ・勉強会 ・ペアプロ 開発プロセス改善 ・Findy Team+ ・コードレビュー周りのプロセス改善 インタビュー 私、佐藤が関係者にインタビューしてみました。 ![開発FEリーダー佐藤](/assets/blog/authors/Keita.S/2025-10-20-UpTeamWebsiteImprovement/sato.png) 開発FEリーダー佐藤 「野辺さん入社して3ヶ月ほど経ちましたが中古車サイト開発チームについて感じた事などありますか?」 ![開発P野辺](/assets/blog/authors/Keita.S/2025-10-20-UpTeamWebsiteImprovement/nobe.png) 開発P野辺 「各開発定例に参加させていただき、皆発言していて意見が言いやすい環境なんだなと特に印象的に感じました」 「そしてすぐ意見を取り入れ皆でよくしていこうという気持ちが伝わってきましたね」 ![開発FEリーダー佐藤](/assets/blog/authors/Keita.S/2025-10-20-UpTeamWebsiteImprovement/sato.png) 開発FEリーダー佐藤 「ありがとうございます。野辺さんからも早速ご意見いただいたり、改善の提案をたくさんいただいているので非常に感謝しています」 「BEチームの最近はいかがでしょうか?金田さん」 ![開発BE(リーダー)金田](/assets/blog/authors/Keita.S/2025-10-20-UpTeamWebsiteImprovement/kaneda.png) 開発BE(リーダー)金田 「そうですね、BEチームも生産性アップの試みや勉強会なども開催し、チームメンバーのスキル底上げをしていますね」 「最近だとドメイン駆動開発に注力しています」 ![開発FEリーダー佐藤](/assets/blog/authors/Keita.S/2025-10-20-UpTeamWebsiteImprovement/sato.png) 開発FEリーダー佐藤 「ありがとうございます。いつもBEチームの取り組みや成功事例などご共有していただきFEチームの改善にも参考になっております」 「FE、BE問わずチーム全体としてよりよくしていきたいですね」 「中古車ビジネスチーム北畑さんともお話ししてみましょう。中古車サイトの開発体制についていかがでしょうか?」 ![中古車ビジネスチーム北畑](/assets/blog/authors/Keita.S/2025-10-20-UpTeamWebsiteImprovement/kitahata.png) 中古車ビジネスチーム北畑 「いつもテンポよく新しい機能などがリリースされ日々改善されていく事を実感しています。まずやってみてPDCAを回すスタイルは我々にとって非常にマッチしたやり方だと感じています」 「職責や役職に関係なく、誰が何を言ってもよいのがこのチームの良いところです。ビジネス側で思いもつかなかったことを開発側が提案してくれることも多く、皆でビジネスをしている感覚です」 ![開発FEリーダー佐藤](/assets/blog/authors/Keita.S/2025-10-20-UpTeamWebsiteImprovement/sato.png) 開発FEリーダー佐藤 「ありがとうございます。それぞれのチームが一丸となって開発、運用ができていると私自身も感じております」 「引き続きKINTOのファンを一人でも増やしていきたいですね」 「最後にPDM水内さんに質問です。開発チームに期待していることはどんな事ですか?」 ![開発PDM水内](/assets/blog/authors/Keita.S/2025-10-20-UpTeamWebsiteImprovement/mizuuchi_1.png) 開発PDM水内 「開発だけやっていればいいわけではなく、サービスが成長することを念頭にサイトをどう改善していくかをミーティングで会話している。そのためメンバーにも発言してもらってより良いサイトにしていきたい」 「理想の働き方として、あなたの業務はこれですと決めるつもりはないので各自出来ること、気づいたことを自発的にやってもらいたいです」 「技術はやりたいことを叶えるための手段なので技術ファーストではなく、サービスファーストで開発できるメンバーであってほしいです。その観点でメンバーを採用しています」 ![開発FEリーダー佐藤](/assets/blog/authors/Keita.S/2025-10-20-UpTeamWebsiteImprovement/sato.png) 開発FEリーダー佐藤 「サービスファーストであり、自発的に開発できる方が理想なのですね」 「私も自社サービスを育てていくという意味で重要な視点だと思いました。ありがとうございます」 さいごに 少しでも中古車サイトの開発の進め方や雰囲気が伝われば幸いです。 また他にもチームの雰囲気や進め方などこちらでもご紹介しております! ご興味のある方はぜひ一度読んでいただけると幸いです。 “とりあえずやってみる”から始まる開発文化。KINTO 中古車チームが語る、推進力と柔軟性の裏側