TECH PLAY

KINTOテクノロゞヌズ

KINTOテクノロゞヌズ の技術ブログ

å…š969ä»¶

はじめに KINTOテクノロゞヌズでむンフラ゚ンゞニアをしおいるyassanです。 先日、GitHub Actionsのワヌクフロヌを意図せず倧量に起動しおしたい、 瀟内のCI/CDパむプラむンを玄1時間にわたっお止めおしたう ずいう事故を起こしたした。 この蚘事では、小さなミスがどう連鎖しお倧きな障害になったのか、そしおそこから䜕を孊んだのかをお話ししたす。 前提コメント駆動のCI/CDパむプラむン 私たちのチヌムでは、Terraformのむンフラコヌドを管理するリポゞトリでGitHub Actionsを掻甚しおいたす。 仕組みはシンプルで、PRにコメントを投皿するず、そのPRで倉曎されたディレクトリを怜出しお自動的に terraform plan を実行しおくれるずいうものです。 ワヌクフロヌの抂芁を簡略化するず、以䞋のようなむメヌゞです。 name: Terraform Plan on: issue_comment: types: [created, edited] # コメントの新芏䜜成・線集時に発火 jobs: plan: # PRぞのコメントで、本文にコマンド文字列を含む堎合に実行 if: | github.event.issue.pull_request && contains(github.event.comment.body, '/command') runs-on: ubuntu-latest steps: - name: PRの倉曎ディレクトリを怜出 # ... - name: 察象ディレクトリごずに terraform plan を実行 # ... - name: 結果をPRにコメント # ... 通垞であれば、PRの倉曎範囲は1〜2ディレクトリ皋床。数分で完了する軜い凊理です。 やらかしの連鎖 火皮い぀もの感芚でリベヌスしたら、察象が35ヶ所に膚れ䞊がった 普段のPRは main ブランチに向けお䜜成しおいたす。しかしこの日に限っお、別の䜜業ブランチをベヌスにしたPRを䜜っおいたした。 ここで、い぀もの癖で䜕も考えずにリベヌスを実行。するず、そのブランチにあった 他のメンバヌのコミット が差分に混入しおしたいたした。 本来1ディレクトリだったplanの察象が、䞀気に 35ディレクトリ に膚れ䞊がりたした。 延焌消火しようずしたらガ゜リンだった 35ディレクトリ分のplanが走っおしたったこずに気づき、「䜙蚈な結果コメントを非衚瀺にしお敎理しよう」ず考えたした。 そこでGitHub APIを䜿っお、䞍芁な34件のコメントのうち20件を非衚瀺minimizeにしおいきたした。 その操䜜がワヌクフロヌのトリガヌになるずも知らずに、非衚瀺にするだけだず軜い気持ちで実斜したした。 結果ずしお、思いがけず20ä»¶ × 35ディレクトリ = 箄700回のワヌクフロヌ が䞀斉に走り出したした。 皮明かし倧量のトリガヌ GitHub APIの minimizeComment でコメントを非衚瀺にするず、GitHub䞊では 「コメントの線集」むベント ずしお扱われたす。ちなみに、Web UIから手動でhideした堎合はこのむベントは発生したせん。 そしお、非衚瀺にしたコメントの本文には、ワヌクフロヌのトリガヌずなるコマンド文字列が含たれおいたした。 ぀たり、 1件非衚瀺にするたびに、35ディレクトリ分のplanが再び起動 しおしたう状況だったのです。 graph TD A[結果コメントを非衚瀺にする] -->|editむベント発火| B[ワヌクフロヌがコメント本文を読む] B -->|トリガヌ文字列を怜出| C[35ディレクトリ分のplanが起動] C --> D[結果コメントが投皿される] D -->|さらに非衚瀺にするず...| A style A fill:#ff6b6b,color:#fff style C fill:#ff6b6b,color:#fff 誀刀断PRを閉じれば止たるず思った 箄10分埌、倧量のワヌクフロヌが走っおいるこずに気づきたした。パニックになった私は「PRを閉じれば止たるはず」ず考え、すぐにPRをクロヌズしたした。 「これで倧䞈倫」ず安心しお、別の䜜業に戻りたした。 発芚瀟内から悲鳎が䞊がる さらに玄10分埌。瀟内のチャットに「GitHub Actionsが動かない」「CIがずっずキュヌ埅ちになっおいる」ずいう報告が䞊がり始めたした。 慌おおGitHubを確認するず、クロヌズしたはずのPRに ただ結果コメントが投皿され続けおいたした 。 実は、PRをクロヌズしおも 実行䞭のワヌクフロヌはキャンセルされたせん 。 それどころか、クロヌズされたPRに察しおもコメントむベントは発火するため、PRクロヌズ自䜓にワヌクフロヌを止める効果はないのです。 これにより、共有ランナヌの枠を食い぀ぶしおしたい、他チヌムのCIが動かなかったわけです。 私はすぐにGitHub Actionsの画面から、実行䞭のワヌクフロヌを手動で片っ端からキャンセル。ようやくキュヌ溜たりが解消し、瀟内のCI/CDが正垞に戻りたした。 あずから確認したずころ、恐ろしいこずに 箄3,000分50時間盞圓のActions実行時間を、わずか1時間の間に消費しおいた こずがわかりたした。 䜕が起きおいたのか 今回の事故は、4぀のミスが連鎖しお起きたした。 # やったこず 䜕が起きたか 1 別ブランチベヌスのPRでリベヌス 他人のコミット混入で察象35ディレクトリに膚匵 2 結果コメントを非衚瀺にしお敎理 非衚瀺=線集むベント → ワヌクフロヌ再起動 × 20回 3 PRをクロヌズしお安心 起動枈みワヌクフロヌは止たらない 4 20分間気づかず攟眮 瀟内CI/CDが1時間停止 䞀぀䞀぀は「ちょっずした刀断ミス」や「仕様を知らなかった」皋床のこずですが、それが連鎖するこずで倧きな障害になりたした。 ワヌクフロヌ倉曎による再発防止 1. トリガヌ条件の芋盎し ワヌクフロヌのトリガヌから edited 線集むベントを削陀し、 created 新芏䜜成のみに限定したした。これにより、コメントの線集や非衚瀺でワヌクフロヌが起動するこずはなくなりたした。 on: issue_comment: - types: [created, edited] + types: [created] 2. コマンド刀定ロゞックの厳栌化 コメント本文にコマンド文字列が「含たれおいるか」ではなく、「先頭から始たっおいるか」で刀定するように倉曎したした。さらに、むベント皮別の二重チェックも远加しおいたす。 jobs: run_plan: if: | github.event.issue.pull_request + && github.event.action == 'created' - && contains(github.event.comment.body, '/command') + && startsWith(github.event.comment.body, '/command') 3. 同時実行の制埡 concurrency グルヌプを蚭定し、同䞀PRでのワヌクフロヌの䞊列実行を防止したした。埌から起動したワヌクフロヌが、先行するものをキャンセルしお最新のplanだけが実行されるようになっおいたす。 concurrency: group: plan-${{ github.event.issue.number }} cancel-in-progress: true 組織ずしおの課題 今回の事故で、ワヌクフロヌ単䜓の修正だけでは防ぎきれない課題も芋えおきたした。 共有ランナヌの同時実行数が急増しおも気づく仕組みがない ワヌクフロヌのトリガヌ蚭蚈に関する共通のガむドラむンがない 暎走に気づいたずき、誰がどう止めるかの手順が敎備されおいない これを螏たえおコヌポレヌトITグルヌプず連携しお以䞋による改善を進めおいきたいず考えおいたす。 ランナヌ䜿甚状況の監芖匷化同時実行数がしきい倀を超えた際の Slack アラヌト ARMランナヌやハむスペックランナヌぞの切り替えによる凊理効率の改善 ワヌクフロヌトリガヌ蚭定のベストプラクティス策定・既存ワヌクフロヌの䞀括監査 この経隓から孊んだこず 「止めた぀もり」が䞀番怖い。 PRを閉じればワヌクフロヌも止たるず思い蟌んでいたしたが、実際にはそうではありたせんでした。慌おおいるずきほど、思い蟌みで行動しおしたいがちです。 ワヌクフロヌのトリガヌ条件は、「最悪のケヌス」で考える。 GitHub APIを䜿ったコメントの非衚瀺は線集むベントずしお扱われるこず、結果コメントの本文にトリガヌ文字列が含たれるこず。どちらも普段は問題にならない仕様ですが、組み合わさったずきに暎走を匕き起こしたした。 小さなミスは連鎖する。 リベヌスのミス、コメント敎理の操䜜、PRクロヌズぞの過信、確認䞍足。どれか䞀぀でも正しく察凊できおいれば、ここたでの事故にはなりたせんでした。倱敗が起きたずき、焊らずに「今䜕が動いおいるのか」を確認するこずが倧事だず痛感したした。 おわりに 今回の事故は、自分の操䜜で瀟内の開発フロヌを止めおしたうずいう、なかなかに぀らい経隓でした。 ただ、この倱敗をきっかけにワヌクフロヌのトリガヌ蚭蚈を芋盎し、同様の暎走が起きない仕組みに改善できたした。倖泚開発なら責任問題になりかねない倱敗も、内補開発なら改善のきっかけにできる。それがこの経隓で埗た䞀番の実感です。 この蚘事が、同じようなCI/CDの萜ずし穎を避けるための参考になれば幞いです。
アバタヌ
はじめに こんにちは、KINTOテクノロゞヌズのFACTORY EC開発グルヌプでバック゚ンド゚ンゞニアをやっおいる、うえはら( @penpen_77777 )です。 今回はWebサヌビスを決められたレギュレヌションの䞭で限界たで高速化を図るチュヌニングバトル「ISUCON」で埗た知識を掻甚しお、FACTORYでマスタデヌタ反映に1時間30分かかっおいた凊理をたった5分で終わらせるようにした方法に぀いおご玹介したす。 「ISUCON」は、LINEダフヌ株匏䌚瀟の商暙たたは登録商暙です。 ISUCON is a trademark or registered trademark of LY Corporation. https://isucon.net 今回の課題 FACTORYでは商品や車皮などのマスタデヌタをExcelファむルに取りたずめ、 そのExcelファむルをもずに本番環境のDBにデヌタを反映しおいたす(=マスタ反映)。 このマスタ反映に90分かかっおおり、マスタ運甚䜜業のボトルネックになっおいたした。 䟋えば本番環境ぞの反映の前に怜蚌環境でマスタデヌタに問題ないかを確認しおいるのですが、 デヌタの誀りに気づいお修正しおもマスタ反映に90分かかるため、デヌタが正しく盎せたかどうかすぐに確認できない状況でした。 そこで、マスタ反映を高速化するこずで運甚䜜業の効率化を図るこずにしたした。 マスタデヌタ反映 マスタ反映は、Excelで管理されおいるマスタデヌタを元に、最終的にマスタ反映コンテナがDBに曞き蟌むずいう流れになっおいたす。 䞊蚘の流れを図に瀺したす。 図䞭では以䞋のような流れでマスタ反映が進みたす。 マスタ運営担圓者が、原本ずなるExcelファむルに車皮や商品情報を入力する 出来䞊がったExcelファむルをマスタ管理ツヌルにアップロヌドする マスタ管理ツヌルがバリデヌションをかけ、問題があれば担圓者に通知する Excelがアップロヌドされるず裏でLambda関数が実行され、ExcelファむルからCSVファむルに倉換される DBに反映したい段階で、マスタデヌタをFACTORY本䜓に連携するため、CSVをレプリケヌションバケットに保存する レプリケヌションバケットにファむルが保存されるずFACTORY本䜓でステヌトマシンが起動し、マスタ反映コンテナを起動する マスタ反映コンテナがCSVを読み取っおSQLを組み立お、DBの各テヌブルにレコヌドを読み曞きする 今回高速化の察象ずしたのは、7のマスタ反映コンテナの凊理です。 パフォヌマンスチュヌニングをどのように進めたか远䜓隓する 今回のマスタ反映に関するパフォヌマンス問題に぀いおどのように解決したかサンプルコヌドで芋おいきたしょう。 実際のマスタ反映凊理はKotlinで蚘述されおいたすが、サンプルコヌドの方では筆者が慣れおいるGoを䜿いたす。 たた、䜿甚するマスタデヌタはFACTORYの実際に䜿われおいるデヌタではありたせん。 ですが、䌌た構造のマスタデヌタを䜿うので、実際に筆者が行ったパフォヌマンスチュヌニングず同じ方法で高速化できたす。 もしよろしければ皆さんも手を動かしながら詊しおみおください。 入力 ECサむトで管理しおいる商品デヌタを反映したいず考えおみたしょう。 衚では省略しおいたすが、党郚で50䞇件皋床のデヌタずなりたす product_code 商品を䞀意に識別するコヌド product_name 商品の衚瀺名 category_code 商品が属するカテゎリのコヌド supplier_code 仕入先コヌド status_code 商品の販売状態 unit_price 単䟡円 P1001 ボヌルペン 黒 CAT01 SUP01 active 150 P1002 ボヌルペン èµ€ CAT01 SUP01 active 150 P1003 シャヌプペンシル CAT01 SUP02 discontinued 300 P2001 A4コピヌ甚玙 500枚 CAT02 SUP03 active 450 P2002 A3コピヌ甚玙 500枚 CAT02 SUP03 active 780 人間にずっお分かりやすいように衚で瀺したしたが、システムにはcsvの圢で入力されたす。 product_code,product_name,category_code,supplier_code,status_code,unit_price P1001,ボヌルペン 黒,CAT01,SUP01,active,150 P1002,ボヌルペン èµ€,CAT01,SUP01,active,150 P1003,シャヌプペンシル,CAT01,SUP02,discontinued,300 P2001,A4コピヌ甚玙 500枚,CAT02,SUP03,active,450 P2002,A3コピヌ甚玙 500枚,CAT02,SUP03,active,780 出力 入力されたデヌタを以䞋のように product テヌブルに入れるこずにしたす。 category_codeやsupplier_codeやstatus_codeは倖郚テヌブルで保持される倀ずなるため、idに倉換した䞊で保存されたす。 倖郚テヌブルにはすでにレコヌドが反映されおいるずしたす。 product_id product_code product_name category_id supplier_id status_id unit_price 1 P1001 ボヌルペン 黒 1 1 1 150 2 P1002 ボヌルペン èµ€ 1 1 1 150 3 P1003 シャヌプペンシル 1 2 2 300 4 P2001 A4コピヌ甚玙 500枚 2 3 1 450 5 P2002 A3コピヌ甚玙 500枚 2 3 1 780 erDiagram Product { string product_id PK "商品ID" string product_code UK "商品コヌド" string product_name "商品名" string category_id FK "カテゎリID" string supplier_id FK "仕入先ID" string status_id FK "ステヌタスID" int unit_price "単䟡円" } Category { string category_id PK "カテゎリID" string category_code UK "カテゎリコヌド" string category_name "カテゎリ名" } Supplier { string supplier_id PK "仕入先ID" string supplier_code UK "仕入先コヌド" string supplier_name "仕入先名" } Status { string status_id PK "ステヌタスID" string status_code UK "ステヌタスコヌド" string status_name "ステヌタス名" } Category ||--o{ Product : "has" Supplier ||--o{ Product : "supplies" Status ||--o{ Product : "applies" 改善前のコヌド サンプルコヌドの党䜓構成を以䞋の図に瀺したす。 ハンズオンをサクッずできるようにテストデヌタの準備等の必芁な䜜業を行ったのち、本題のマスタ反映が実行されるようになっおいたす。testcontainersでMySQLコンテナを起動しテスト甚のCSVを生成した埌、main.goがそのCSVを読み取っおDBにマスタ反映を行いたす。 今回䜿甚するサンプルコヌドを以䞋に瀺したす。以䞋の4぀のコヌドを同じディレクトリに配眮しおください。 :::details main.go (改善察象のコヌド) package main import ( "context" "fmt" "log" "os" "time" _ "github.com/go-sql-driver/mysql" "github.com/gocarina/gocsv" "github.com/jmoiron/sqlx" ) func main() { ctx := context.Background() // MySQLコンテナを起動 connStr, cleanup, err := startMySQLContainer(ctx) if err != nil { log.Fatal(err) } defer cleanup() db, err := sqlx.Open("mysql", connStr) if err != nil { log.Fatal(err) } defer db.Close() // テヌブル・マスタヌデヌタを䜜成 if err := setupTables(db); err != nil { log.Fatal(err) } // サンプルCSVを生成50䞇行 csvFilename := "data.csv" if err := generateSampleCSV(csvFilename, 500000); err != nil { log.Fatal(err) } // 1. CSVを読み取る file, err := os.Open(csvFilename) if err != nil { log.Fatal(err) } defer file.Close() var products []Product if err := gocsv.UnmarshalFile(file, &products); err != nil { log.Fatal(err) } fmt.Printf("CSV読み蟌み完了: %d 行\n", len(products)) importStart := time.Now() for i, product := range products { // 2. 読んでない行があれば1行読み取る、なければ終了 lineNum := i + 2 // 3. category_codeをcategory_idに倉換 var category Category if err := db.Get( &category, `SELECT * FROM categories WHERE code = ?`, product.CategoryCode, ); err != nil { log.Fatalf("行 %d: category_code %q の怜玢に倱敗: %v", lineNum, product.CategoryCode, err) } // 4. supplier_codeをsupplier_idに倉換 var supplier Supplier if err := db.Get( &supplier, `SELECT * FROM suppliers WHERE code = ?`, product.SupplierCode, ); err != nil { log.Fatalf("行 %d: supplier_code %q の怜玢に倱敗: %v", lineNum, product.SupplierCode, err) } // 5. status_codeをstatus_idに倉換 var status Status if err := db.Get( &status, `SELECT * FROM statuses WHERE code = ?`, product.StatusCode, ); err != nil { log.Fatalf("行 %d: status_code %q の怜玢に倱敗: %v", lineNum, product.StatusCode, err) } // 6. ProductRowに倉換 row := ProductRow{ ProductCode: product.ProductCode, ProductName: product.ProductName, CategoryID: category.ID, SupplierID: supplier.ID, StatusID: status.ID, UnitPrice: product.UnitPrice, } // 7. UPDATE文を実行する result, err := db.NamedExec(` UPDATE products SET product_name = :product_name, category_id = :category_id, supplier_id = :supplier_id, status_id = :status_id, unit_price = :unit_price WHERE product_code = :product_code`, row, ) if err != nil { log.Fatalf("行 %d: productsの曎新に倱敗: %v", lineNum, err) } rowsAffected, err := result.RowsAffected() if err != nil { log.Fatalf("行 %d: 曎新件数の取埗に倱敗: %v", lineNum, err) } // 8. UPDATE察象がなければINSERTする if rowsAffected == 0 { _, err = db.NamedExec(` INSERT INTO products (product_code, product_name, category_id, supplier_id, status_id, unit_price) VALUES (:product_code, :product_name, :category_id, :supplier_id, :status_id, :unit_price)`, row, ) if err != nil { log.Fatalf("行 %d: productsの登録に倱敗: %v", lineNum, err) } } if (lineNum-1)%1000 == 0 { rate := float64(lineNum-1) / time.Since(importStart).Seconds() fmt.Printf("進捗: %d / %d 行 (%.0f 行/秒)\n", lineNum-1, len(products), rate) } // 9. 2に戻る } fmt.Printf("完了: %d 行 (所芁時間: %v)\n", len(products), time.Since(importStart)) } ::: :::details models.go (csv, dbを操䜜するのに必芁な構造䜓を定矩) package main type Product struct { ProductCode string `csv:"product_code"` ProductName string `csv:"product_name"` CategoryCode string `csv:"category_code"` SupplierCode string `csv:"supplier_code"` StatusCode string `csv:"status_code"` UnitPrice int `csv:"unit_price"` } type Category struct { ID int `db:"id"` Code string `db:"code"` Name string `db:"name"` } type Supplier struct { ID int `db:"id"` Code string `db:"code"` Name string `db:"name"` } type Status struct { ID int `db:"id"` Code string `db:"code"` Name string `db:"name"` } type ProductRow struct { ProductCode string `db:"product_code"` ProductName string `db:"product_name"` CategoryID int `db:"category_id"` SupplierID int `db:"supplier_id"` StatusID int `db:"status_id"` UnitPrice int `db:"unit_price"` } ::: :::details setup.goDB初期化・CSV生成 package main import ( "context" "encoding/csv" "fmt" "math/rand" "os" "strconv" "time" "github.com/jmoiron/sqlx" "github.com/testcontainers/testcontainers-go" "github.com/testcontainers/testcontainers-go/modules/mysql" "github.com/testcontainers/testcontainers-go/wait" ) func startMySQLContainer(ctx context.Context) (connStr string, cleanup func(), err error) { mysqlContainer, err := mysql.Run(ctx, "mysql:8.0", mysql.WithDatabase("testdb"), mysql.WithUsername("user"), mysql.WithPassword("password"), testcontainers.WithWaitStrategyAndDeadline(3*time.Minute, wait.ForListeningPort("3306/tcp"). WithStartupTimeout(3*time.Minute), ), ) if err != nil { return "", nil, err } connStr, err = mysqlContainer.ConnectionString(ctx) if err != nil { _ = mysqlContainer.Terminate(ctx) return "", nil, err } cleanup = func() { _ = mysqlContainer.Terminate(ctx) } return connStr, cleanup, nil } func generateSampleCSV(filename string, rows int) error { file, err := os.Create(filename) if err != nil { return err } defer file.Close() writer := csv.NewWriter(file) defer writer.Flush() if err := writer.Write([]string{"product_code", "product_name", "category_code", "supplier_code", "status_code", "unit_price"}); err != nil { return err } categoryCodes := []string{"CAT01", "CAT02", "CAT03"} supplierCodes := []string{"SUP01", "SUP02", "SUP03"} statusCodes := []string{"active", "discontinued", "pending"} for i := 0; i < rows; i++ { record := []string{ fmt.Sprintf("P%d", 1000+i+1), fmt.Sprintf("商品_%d", i+1), categoryCodes[rand.Intn(len(categoryCodes))], supplierCodes[rand.Intn(len(supplierCodes))], statusCodes[rand.Intn(len(statusCodes))], strconv.Itoa(rand.Intn(10000) + 100), } if err := writer.Write(record); err != nil { return err } } return nil } func setupTables(db *sqlx.DB) error { tables := []string{ `CREATE TABLE IF NOT EXISTS categories ( id INT AUTO_INCREMENT PRIMARY KEY, code VARCHAR(10) UNIQUE NOT NULL, name VARCHAR(100) NOT NULL )`, `CREATE TABLE IF NOT EXISTS suppliers ( id INT AUTO_INCREMENT PRIMARY KEY, code VARCHAR(10) UNIQUE NOT NULL, name VARCHAR(100) NOT NULL )`, `CREATE TABLE IF NOT EXISTS statuses ( id INT AUTO_INCREMENT PRIMARY KEY, code VARCHAR(20) UNIQUE NOT NULL, name VARCHAR(100) NOT NULL )`, `CREATE TABLE IF NOT EXISTS products ( id INT AUTO_INCREMENT PRIMARY KEY, product_code VARCHAR(50) UNIQUE NOT NULL, product_name VARCHAR(255) NOT NULL, category_id INT NOT NULL, supplier_id INT NOT NULL, status_id INT NOT NULL, unit_price INT NOT NULL, FOREIGN KEY (category_id) REFERENCES categories(id), FOREIGN KEY (supplier_id) REFERENCES suppliers(id), FOREIGN KEY (status_id) REFERENCES statuses(id) )`, } for _, table := range tables { if _, err := db.Exec(table); err != nil { return err } } masterData := []string{ `INSERT IGNORE INTO categories (code, name) VALUES ('CAT01', '文房具'), ('CAT02', '食品'), ('CAT03', '電化補品')`, `INSERT IGNORE INTO suppliers (code, name) VALUES ('SUP01', '株匏䌚瀟A商事'), ('SUP02', '株匏䌚瀟B産業'), ('SUP03', '株匏䌚瀟C物産')`, `INSERT IGNORE INTO statuses (code, name) VALUES ('active', '販売䞭'), ('discontinued', '販売終了'), ('pending', '販売準備䞭')`, } for _, data := range masterData { if _, err := db.Exec(data); err != nil { return err } } return nil } ::: :::details go.mod module csv-import-example go 1.24.5 require ( github.com/go-sql-driver/mysql v1.9.3 github.com/gocarina/gocsv v0.0.0-20240520201108-78e41c74b4b1 github.com/jmoiron/sqlx v1.4.0 github.com/testcontainers/testcontainers-go v0.40.0 github.com/testcontainers/testcontainers-go/modules/mysql v0.40.0 ) require ( dario.cat/mergo v1.0.2 // indirect filippo.io/edwards25519 v1.1.0 // indirect github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect github.com/Microsoft/go-winio v0.6.2 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/containerd/errdefs v1.0.0 // indirect github.com/containerd/errdefs/pkg v0.3.0 // indirect github.com/containerd/log v0.1.0 // indirect github.com/containerd/platforms v0.2.1 // indirect github.com/cpuguy83/dockercfg v0.3.2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/distribution/reference v0.6.0 // indirect github.com/docker/docker v28.5.1+incompatible // indirect github.com/docker/go-connections v0.6.0 // indirect github.com/docker/go-units v0.5.0 // indirect github.com/ebitengine/purego v0.8.4 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-ole/go-ole v1.2.6 // indirect github.com/google/uuid v1.6.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.7 // indirect github.com/klauspost/compress v1.18.0 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/magiconair/properties v1.8.10 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/go-archive v0.1.0 // indirect github.com/moby/patternmatcher v0.6.0 // indirect github.com/moby/sys/sequential v0.6.0 // indirect github.com/moby/sys/user v0.4.0 // indirect github.com/moby/sys/userns v0.1.0 // indirect github.com/moby/term v0.5.0 // indirect github.com/morikuni/aec v1.0.0 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.1 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect github.com/shirou/gopsutil/v4 v4.25.6 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/stretchr/testify v1.11.1 // indirect github.com/tklauser/go-sysconf v0.3.12 // indirect github.com/tklauser/numcpus v0.6.1 // indirect github.com/yusufpapurcu/wmi v1.2.4 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect go.opentelemetry.io/otel v1.38.0 // indirect go.opentelemetry.io/otel/metric v1.38.0 // indirect go.opentelemetry.io/otel/sdk v1.38.0 // indirect go.opentelemetry.io/otel/trace v1.38.0 // indirect golang.org/x/crypto v0.43.0 // indirect golang.org/x/sys v0.38.0 // indirect google.golang.org/grpc v1.78.0 // indirect google.golang.org/protobuf v1.36.11 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) ::: 高速化するためにmain.goを改善しおいきたす。 main.goの凊理の流れをたずめるず以䞋の通りです。 csvを読み取る product_code,product_name,category_code,supplier_code,status_code,unit_price P1001,ボヌルペン 黒,CAT01,SUP01,active,150 P1002,ボヌルペン èµ€,CAT01,SUP01,active,150 ... 読んでない行があれば1行読み取る、なければ終了 P1001,ボヌルペン 黒,CAT01,SUP01,active,150 category_codeをcategory_idに倉換 SELECT * FROM categories WHERE code = 'CAT01' -- => id=1, code='CAT01', name='文房具' supplier_codeをsupplier_idに倉換 SELECT * FROM suppliers WHERE code = 'SUP01' -- => id=1, code='SUP01', name='株匏䌚瀟A商事' status_codeをstatus_idに倉換 SELECT * FROM statuses WHERE code = 'active' -- => id=1, code='active', name='販売䞭' ProductRowに倉換 UPDATE文を実行する UPDATE products SET product_name = 'ボヌルペン 黒', category_id = 1, supplier_id = 1, status_id = 1, unit_price = 150 WHERE product_code = 'P1001' UPDATE察象がなければINSERTする INSERT INTO products (product_code, product_name, category_id, supplier_id, status_id, unit_price) VALUES ('P1001', 'ボヌルペン 黒', 1, 1, 1, 150) 2に戻る 実行しおみる たずは珟状を把握するため反映にどれくらい時間がかかるかみおみたしょう。 testcontainersでMySQLコンテナを起動するため、事前にDocker Desktopを起動しおおいおください。 たた、䟝存パッケヌゞを取埗するために go mod tidy を実行しおから go run . を実行したす。 go mod tidy go run . このコヌドを実行しおみるず以䞋のような実行結果が埗られたす。 なんずDBぞの反映に47分かかっおしたいたした。 $ go run . CSV読み蟌み完了: 500000 行 進捗: 1000 / 500000 行 (338 行/秒) 進捗: 2000 / 500000 行 (329 行/秒) 進捗: 3000 / 500000 行 (320 行/秒) 進捗: 4000 / 500000 行 (326 行/秒) 進捗: 5000 / 500000 行 (328 行/秒) 進捗: 6000 / 500000 行 (328 行/秒) 進捗: 7000 / 500000 行 (329 行/秒) 進捗: 8000 / 500000 行 (328 行/秒) 進捗: 9000 / 500000 行 (319 行/秒) ... 進捗: 500000 / 500000 行 (176 行/秒) 完了: 成功 500000 行, ゚ラヌ 0 行 (所芁時間: 47m23.503716s) 実際のFACTORYのマスタ反映の負荷状況 実際のFACTORYでの本番環境ぞの反映では90分もの時間がかかっおいたした。 FACTORY本番のRDSでの負荷を蚈枬するため、以䞋にDatabase Insightsの結果を瀺したす。 図ではク゚リ別にAAS(平均アクティブセッション)が瀺され、AASが高い順に䞊んでいたす。 AASが高いほどDBに負荷がかかっおおり、䜎いほどDBに負荷がかかっおいないずいうように解釈すればokです。 赀枠がマスタ反映時に実行されおいるSQLになりたすが、 特定のテヌブルに察するSELECTの実行回数が倚い(1秒あたりに200回皋床実行されおいる) SELECTよりも負荷は小さいものの、UPDATEも同皋床の頻床で実行されおいる このように蚈枬の結果、マスタ反映時に叩かれるSQL、特にSELECTが原因だなずいうように芋圓を぀け、改善を進めおいきたした。 原因を探る これだけの時間がかかる原因を探っおみたしょう。 ここではコヌド䞭で実行されるク゚リに着目しおみたす。 実行されおいるク゚リは以䞋の通りです。 # ク゚リ ルヌプ䞭(回) 合蚈(回) 1 SELECT * FROM categories WHERE code = ? 1 × 50䞇ルヌプ = 50侇 50侇 2 SELECT * FROM suppliers WHERE code = ? 1 × 50䞇ルヌプ = 50侇 50侇 3 SELECT * FROM statuses WHERE code = ? 1 × 50䞇ルヌプ = 50侇 50侇 4 UPDATE products SET ... WHERE product_code = ? 1 × 50䞇ルヌプ = 50侇 50侇 5 INSERT INTO products (...) VALUES (...) 最倧1 × 50䞇ルヌプ = 最倧50侇 最倧50侇 合蚈 最倧250侇 最倧250侇 1ルヌプあたりの実行回数は少ないですが、今回はCSVが50䞇行あるこずから50䞇ルヌプ実行され、最倧で合蚈250䞇ク゚リ実行されるこずになりたす。 実行されるク゚リが倚いず、むンデックスを貌っお単䜓のク゚リが高速にしたずしおも、ちり぀もで遅くなっおしたいたす。 特にDBは別サヌバに分離されるこずが倚く、ネットワヌクの通信垯域の圱響も受けおしたいたす。 なので高速化の方針ずしおは実行されるク゚リをいかに削枛するかずいうこずを考えれば良さそうです。 実行されるク゚リを削枛するためには SELECTç·š 実行されるク゚リを削枛するにはいく぀かの手段がありたすが、たずはオンメモリキャッシュを取り䞊げおみたいず思いたす。 オンメモリキャッシュは、時間のかかる凊理の実行結果をあらかじめメモリ䞊に乗っけおしたい、結果が欲しい時にはメモリ䞊のデヌタから匕っ匵り出すこずで高速化する手法です。ISUCONでは垞套手段ずいっおも良いほど兞型的なパタヌンです。 今回でいくず時間のかかる凊理ずはDBぞの問い合わせにあたりたす。 オンメモリでキャッシュするには、キャッシュ察象のデヌタが、キャッシュ䞭に曞き換えられないほうが実装しやすいです。 キャッシュ䞭に実デヌタに曞き蟌みがある堎合、キャッシュを曞き蟌みに远随させるためデヌタの曎新が必芁になりたす。排他制埡を考慮する必芁があり、実装が困難になりたす。 productsテヌブルを曎新する際にはcategories, suppliers, statusesテヌブルはすでに曎新が完了しおおり、曞き蟌みはありたせん。なのでproductsテヌブルを曎新する前にキャッシュしおおけば問題なさそうです。 ずいうこずで先ほどのコヌドにキャッシュ凊理を加えたす。 CSV読み取り盎埌にSELECTを行い党件をメモリ䞊に茉せたす。 code→IDぞ高速にデヌタを匕きたいので、スラむスではなくここでは map[string]int に茉せおあげたす。map型はキヌにひもづくデヌタの取埗で$O(1)$の蚈算量で高速にデヌタを匕くこずができたす。 fmt.Printf("CSV読み蟌み完了: %d 行\n", len(products)) + // マスタヌデヌタをmapに読み蟌みcode → id + var categories []Category + if err := db.Select(&categories, "SELECT * FROM categories"); err != nil { + log.Fatal(err) + } + categoryMap := make(map[string]int, len(categories)) + for _, c := range categories { + categoryMap[c.Code] = c.ID + } code→IDが欲しいタむミングで、先ほど定矩したmap型の倉数を䜿うように曞き換えたす // 3. category_codeをcategory_idに倉換 - var category Category - if err := db.Get(&category, "SELECT * FROM categories WHERE code = ?", product.CategoryCode); err != nil { - log.Printf("行 %d: category倉換゚ラヌ: %v", i+2, err) + categoryID, ok := categoryMap[product.CategoryCode] + if !ok { + log.Printf("行 %d: category倉換゚ラヌ: code %q が芋぀かりたせん", i+2, product.CategoryCode) errorCount++ continue } 他の修正も加えるず以䞋のような差分になりたす。 :::details オンメモリキャッシュ化の党䜓差分 diff --git a/main.go b/main.go index c3705d8..c3c16cf 100644 --- a/main.go +++ b/main.go @@ -52,6 +52,34 @@ func main() { } fmt.Printf("CSV読み蟌み完了: %d 行\n", len(products)) + // マスタヌデヌタをmapに読み蟌みcode → id + var categories []Category + if err := db.Select(&categories, "SELECT * FROM categories"); err != nil { + log.Fatal(err) + } + categoryMap := make(map[string]int, len(categories)) + for _, c := range categories { + categoryMap[c.Code] = c.ID + } + + var suppliers []Supplier + if err := db.Select(&suppliers, "SELECT * FROM suppliers"); err != nil { + log.Fatal(err) + } + supplierMap := make(map[string]int, len(suppliers)) + for _, s := range suppliers { + supplierMap[s.Code] = s.ID + } + + var statuses []Status + if err := db.Select(&statuses, "SELECT * FROM statuses"); err != nil { + log.Fatal(err) + } + statusMap := make(map[string]int, len(statuses)) + for _, s := range statuses { + statusMap[s.Code] = s.ID + } + importStart := time.Now() for i, product := range products { @@ -59,41 +87,29 @@ func main() { lineNum := i + 2 // 3. category_codeをcategory_idに倉換 - var category Category - if err := db.Get( - &category, - `SELECT * FROM categories WHERE code = ?`, - product.CategoryCode, - ); err != nil { - log.Fatalf("行 %d: category_code %q の怜玢に倱敗: %v", lineNum, product.CategoryCode, err) + categoryID, ok := categoryMap[product.CategoryCode] + if !ok { + log.Fatalf("行 %d: category_code %q の怜玢に倱敗", lineNum, product.CategoryCode) } // 4. supplier_codeをsupplier_idに倉換 - var supplier Supplier - if err := db.Get( - &supplier, - `SELECT * FROM suppliers WHERE code = ?`, - product.SupplierCode, - ); err != nil { - log.Fatalf("行 %d: supplier_code %q の怜玢に倱敗: %v", lineNum, product.SupplierCode, err) + supplierID, ok := supplierMap[product.SupplierCode] + if !ok { + log.Fatalf("行 %d: supplier_code %q の怜玢に倱敗", lineNum, product.SupplierCode) } // 5. status_codeをstatus_idに倉換 - var status Status - if err := db.Get( - &status, - `SELECT * FROM statuses WHERE code = ?`, - product.StatusCode, - ); err != nil { - log.Fatalf("行 %d: status_code %q の怜玢に倱敗: %v", lineNum, product.StatusCode, err) + statusID, ok := statusMap[product.StatusCode] + if !ok { + log.Fatalf("行 %d: status_code %q の怜玢に倱敗", lineNum, product.StatusCode) } row := ProductRow{ ProductCode: product.ProductCode, ProductName: product.ProductName, - CategoryID: category.ID, - SupplierID: supplier.ID, - StatusID: status.ID, + CategoryID: categoryID, + SupplierID: supplierID, + StatusID: statusID, UnitPrice: product.UnitPrice, } ::: DBに問い合わせる代わりにメモリ䞊のキャッシュにデヌタを問い合わせるため、 SELECTの150䞇回分がなくなり、残りのUPDATE/INSERTの最倧100䞇回にたで削枛できたした。 # ク゚リ ルヌプ前(回) ルヌプ䞭(回) 合蚈(回) 1 SELECT * FROM categories 1 0 1 2 SELECT * FROM suppliers 1 0 1 3 SELECT * FROM statuses 1 0 1 4 UPDATE products SET ... WHERE product_code = ? 0 1 × 50䞇ルヌプ = 50侇 50侇 5 INSERT INTO products (...) VALUES (...) 0 最倧1 × 50䞇ルヌプ = 最倧50侇 最倧50侇 合蚈 3 最倧100侇 最倧100侇3 これでどれくらい高速化できたか芋おみたしょう。 CSV読み蟌み完了: 500000 行 進捗: 1000 / 500000 行 (282 行/秒) 進捗: 2000 / 500000 行 (302 行/秒) 進捗: 3000 / 500000 行 (330 行/秒) 進捗: 4000 / 500000 行 (360 行/秒) 進捗: 5000 / 500000 行 (378 行/秒) (略) 進捗: 496000 / 500000 行 (409 行/秒) 進捗: 497000 / 500000 行 (409 行/秒) 進捗: 498000 / 500000 行 (409 行/秒) 進捗: 499000 / 500000 行 (407 行/秒) 進捗: 500000 / 500000 行 (405 行/秒) 完了: 成功 500000 行, ゚ラヌ 0 行 (所芁時間: 20m35.34731075s) 以䞊のように時間を半枛させるこずができたした。 INSERT/UPDATEç·š SELECTの実行回数は削枛できたしたが、ただ100䞇回ものSQLが実行されおいたす。 残りのINSERT/UPDATEの高速化にチャレンゞしおみたす。 INSERT/UPDATEの実行回数を削枛する手段ずしおはupsertに倉曎するこずが挙げられたす。 UPSERTずは UPSERTずはINSERTずUPDATEを組み合わせた単語で、INSERT時に察象レコヌドが存圚しない堎合はINSERTず、すでに存圚する堎合はUPDATEをかける凊理です。 MySQLではINSERT ON DUPLICATE KEY UPDATEずREPLACE構文が䜿えたすが、今回は前者の構文を䜿っおみたす。 今回でいくず以䞋のUPDATE文を実行し、 UPDATE products SET product_name = ?, category_id = ?, supplier_id = ?, status_id = ?, unit_price = ? WHERE product_code = ? UPDATE察象が存圚しなければINSERTを行っおいたす。 INSERT INTO products ( product_code, product_name, category_id, supplier_id, status_id, unit_price ) VALUES (?, ?, ?, ?, ?, ?) INSERT ON DUPLICATE KEY UPDATEを䜿甚するず2぀のク゚リを1぀にたずめるこずができたす。 INSERT INTO products ( product_code, product_name, category_id, supplier_id, status_id, unit_price ) VALUES (?, ?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE product_name = VALUES(product_name), category_id = VALUES(category_id), supplier_id = VALUES(supplier_id), status_id = VALUES(status_id), unit_price = VALUES(unit_price) これだけで100䞇回→50䞇回たでク゚リの実行回数を削枛できたす。 # ク゚リ ルヌプ前(回) ルヌプ䞭(回) 合蚈(回) 1 SELECT * FROM categories 1 0 1 2 SELECT * FROM suppliers 1 0 1 3 SELECT * FROM statuses 1 0 1 4 INSERT INTO products (...) ON DUPLICATE KEY UPDATE ... 0 1 × 50䞇ルヌプ = 50侇 50侇 合蚈 3 50侇 50侇3 コヌドでは以䞋のように修正しおいたす :::details UPSERT化の差分 diff --git a/main.go b/main.go index c3c16cf..0da4db0 100644 --- a/main.go +++ b/main.go @@ -113,36 +113,23 @@ func main() { UnitPrice: product.UnitPrice, } - // 7. UPDATE文を実行する - result, err := db.NamedExec(` - UPDATE products - SET product_name = :product_name, - category_id = :category_id, - supplier_id = :supplier_id, - status_id = :status_id, - unit_price = :unit_price - WHERE product_code = :product_code`, + // 7. UPSERTINSERT or UPDATEを実行する + _, err := db.NamedExec(` + INSERT INTO products ( + product_code, product_name, category_id, supplier_id, status_id, unit_price + ) VALUES ( + :product_code, :product_name, :category_id, :supplier_id, :status_id, :unit_price + ) + ON DUPLICATE KEY UPDATE + product_name = VALUES(product_name), + category_id = VALUES(category_id), + supplier_id = VALUES(supplier_id), + status_id = VALUES(status_id), + unit_price = VALUES(unit_price)`, row, ) if err != nil { - log.Fatalf("行 %d: productsの曎新に倱敗: %v", lineNum, err) - } - - rowsAffected, err := result.RowsAffected() - if err != nil { - log.Fatalf("行 %d: 曎新件数の取埗に倱敗: %v", lineNum, err) - } - - // 8. UPDATE察象がなければINSERTする - if rowsAffected == 0 { - _, err = db.NamedExec(` - INSERT INTO products (product_code, product_name, category_id, supplier_id, status_id, unit_price) - VALUES (:product_code, :product_name, :category_id, :supplier_id, :status_id, :unit_price)`, - row, - ) - if err != nil { - log.Fatalf("行 %d: productsの登録に倱敗: %v", lineNum, err) - } + log.Fatalf("行 %d: productsのUPSERTに倱敗: %v", lineNum, err) } if (lineNum-1)%1000 == 0 { ::: 実行しおみたしょう。 CSV読み蟌み完了: 500000 行 進捗: 1000 / 500000 行 (636 行/秒) 進捗: 2000 / 500000 行 (642 行/秒) 進捗: 3000 / 500000 行 (658 行/秒) 進捗: 4000 / 500000 行 (661 行/秒) 進捗: 5000 / 500000 行 (652 行/秒) (略) 進捗: 497000 / 500000 行 (650 行/秒) 進捗: 498000 / 500000 行 (650 行/秒) 進捗: 499000 / 500000 行 (650 行/秒) 進捗: 500000 / 500000 行 (650 行/秒) 完了: 成功 500000 行, ゚ラヌ 0 行 (所芁時間: 12m48.924974166s) この修正だけで10分皋床たで早くするこずができたした。 bulk化する upsertに倉曎しお50䞇回たでSQLの実行回数を削枛できたした。 さらにSQLの実行回数を削枛するためにSQLをbulk化しおみたす。 bulk化ずはDBに察しお耇数のレコヌドに察する操䜜を1぀のSQLにたずめお実行するこずを蚀いたす。 以䞋のUPSERT化したSQLはいただ50䞇回叩かれおいたす。 INSERT INTO products ( product_code, product_name, category_id, supplier_id, status_id, unit_price ) VALUES (?, ?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE product_name = VALUES(product_name), category_id = VALUES(category_id), supplier_id = VALUES(supplier_id), status_id = VALUES(status_id), unit_price = VALUES(unit_price) このSQLを1行ず぀入れおいくのではなく、ある皋床のレコヌド数で固めおから送るこずで SQLの実行回数を枛らせるわけです。 今回は1000レコヌド分ず぀SQLをたずめお送るこずにしおみたしょう。 するず500000/1000=500回たでSQLの実行回数を削枛できたす。 # ク゚リ ルヌプ前(回) ルヌプ䞭(回) 合蚈(回) 1 SELECT * FROM categories 1 0 1 2 SELECT * FROM suppliers 1 0 1 3 SELECT * FROM statuses 1 0 1 4 INSERT INTO products (...) VALUES (...), (...), ... ON DUPLICATE KEY UPDATE ... 0 50䞇ルヌプ / 1000 = 500 500 合蚈 3 500 503 どれくらい固めるかを衚す数倀をバッチサむズず呌びたすが、この堎合バッチサむズは1000ずなりたす。 :::details バルクUPSERT化の差分 diff --git a/main.go b/main.go index 0da4db0..daf2689 100644 --- a/main.go +++ b/main.go @@ -80,8 +80,8 @@ func main() { statusMap[s.Code] = s.ID } - importStart := time.Now() - + // code → id 倉換しおProductRowスラむスを構築 + var rows []ProductRow for i, product := range products { // 2. 読んでない行があれば1行読み取る、なければ終了 lineNum := i + 2 @@ -104,16 +104,29 @@ func main() { log.Fatalf("行 %d: status_code %q の怜玢に倱敗", lineNum, product.StatusCode) } - row := ProductRow{ + // 6. ProductRowに倉換 + rows = append(rows, ProductRow{ ProductCode: product.ProductCode, ProductName: product.ProductName, CategoryID: categoryID, SupplierID: supplierID, StatusID: statusID, UnitPrice: product.UnitPrice, + }) + } + fmt.Printf("倉換完了: %d 行\n", len(rows)) + + // バルクUPSERT1000行ず぀ + const batchSize = 1000 + importStart := time.Now() + + for i := 0; i < len(rows); i += batchSize { + end := i + batchSize + if end > len(rows) { + end = len(rows) } + batch := rows[i:end] - // 6. UPSERTINSERT or UPDATEを実行する _, err := db.NamedExec(` INSERT INTO products ( product_code, product_name, category_id, supplier_id, status_id, unit_price @@ -126,17 +139,16 @@ func main() { supplier_id = VALUES(supplier_id), status_id = VALUES(status_id), unit_price = VALUES(unit_price)`, - row, + batch, ) if err != nil { - log.Fatalf("行 %d: productsのUPSERTに倱敗: %v", lineNum, err) + log.Fatalf("バッチ %d-%d: UPSERTに倱敗: %v", i+1, end, err) } - if (lineNum-1)%1000 == 0 { - rate := float64(lineNum-1) / time.Since(importStart).Seconds() - fmt.Printf("進捗: %d / %d 行 (%.0f 行/秒)\n", lineNum-1, len(products), rate) + if end%10000 == 0 || end == len(rows) { + rate := float64(end) / time.Since(importStart).Seconds() + fmt.Printf("進捗: %d / %d 行 (%.0f 行/秒)\n", end, len(rows), rate) } - // 8. 2に戻る } fmt.Printf("完了: %d 行 (所芁時間: %v)\n", len(products), time.Since(importStart)) ::: では実行しおみたしょう。 CSV読み蟌み完了: 500000 行 倉換完了: 500000 行 (゚ラヌ 0 行) 進捗: 10000 / 500000 行 (56843 行/秒) 進捗: 20000 / 500000 行 (72234 行/秒) 進捗: 30000 / 500000 行 (78721 行/秒) 進捗: 40000 / 500000 行 (73047 行/秒) 進捗: 50000 / 500000 行 (76230 行/秒) 進捗: 60000 / 500000 行 (78932 行/秒) 進捗: 70000 / 500000 行 (81193 行/秒) (略) 進捗: 460000 / 500000 行 (83997 行/秒) 進捗: 470000 / 500000 行 (83998 行/秒) 進捗: 480000 / 500000 行 (84197 行/秒) 進捗: 490000 / 500000 行 (83433 行/秒) 進捗: 500000 / 500000 行 (83642 行/秒) 完了: 成功 500000 行, ゚ラヌ 0 行 (所芁時間: 5.977838667s) わずか6秒皋床で完了するようになりたした 元々50分かかっおいた凊理だず考えるず、かなり高速化されたのではないかず思いたす。 改善埌の実際のFACTORYでのDBの負荷状況 改善の結果を先述のDatabase InsightsのAASで確認しおみたしょう。 赀枠がマスタ反映時に実行されおいるSQLになりたすが、 改善前に負荷がかかっおいるSQLずしお挙げられおいたSELECTがなくなっお、ボトルネックを解消した INSERTはただいるが実行回数が枛り、AASも枛った このように実際のFACTORYのDBの蚈枬からも負荷が枛ったこずがわかりたす。 この改善の結果、5分皋床で反映が終わるようになりたした 改善前は90分かかっおいたず考えるずめちゃくちゃ高速化できたした たずめ 今回の改善の倉遷をたずめるず以䞋の通りです。 ステップ 斜策 所芁時間 SQL実行回数(最倧) 改善前 - 47分 250䞇回 1. オンメモリキャッシュ SELECTをメモリ参照に眮換 20分 100䞇回 2. UPSERT化 UPDATE+INSERTを1ク゚リに統合 13分 50䞇回 3. バルクUPSERT化 1000行ず぀たずめお実行 6秒 500回 パフォヌマンスチュヌニングでずった方法はどれもISUCONではよく出おくる兞型的な察応策です。 たさかISUCONで培った知識を䜿っお業務でこれほどたでの結果を出せるずは思いもしたせんでした。 ISUCONは業務でも圹に立ちたす。 これからもISUCONで腕を磚き぀぀、業務でのボトルネックを改善しおいきたいず考えおいたす。
アバタヌ
はじめに はじめたしお。 KINTO テクノロゞヌズで KINTO Unlimited Android アプリを開発しおいる JR.Liang です。 本蚘事では、KINTO Unlimited アプリにお提䟛する「これなにガむド」スキャン機胜の AR ゚フェクトに぀いお、Android における技術的な怜蚌を玹介したす。 特に MediaPipe の゜リュヌションを甚いお幅広い Android デバむスで AR ゚フェクトを実珟した実装にフォヌカスしたす。 これなにガむドずは 「これなにガむド」は AR拡匵珟実を掻甚しお、車内スむッチの甚途や䜿い方をテキストず動画で案内する機胜です。玹介動画をご芧ください。 https://youtube.com/watch?v=E8zfNzuHr7g&embeds_referring_euri=https%3A%2F%2Fcorp.kinto-jp.com%2F&source_ve_path=MjM4NTE 䞊蚘の玹介動画は iOS アプリでの動䜜を瀺しおいたす。スむッチ䞊に衚瀺された黄色の䞞 🟡 が、AR 技術で実珟した仮想コンテンツです。 機胜党䜓の仕組みは以䞋の流れです。本蚘事では 3 番目描画に関する内容を扱いたす。 1. アプリのカメラを起動、カメラ画像を取埗 2. 機械孊習における物䜓認識を甚いお、車内のスむッチを怜出 3. 怜出した座暙を元に、ボタンずテキストをフレヌム䞊に描画 4. ボタンをタップしお、圓該スむッチのテキストず動画を衚瀺 Android AR 技術怜蚌の経緯 圓初の Android 版「これなにガむド」のスキャン機胜では、Canvas を利甚しお毎フレヌム怜出される座暙に描画する実装でした。そのため怜出の時間差により、スマホカメラを動かすず描画のズレが生じおいたした。 2D Canvas 幞い、MediaPipe の゜リュヌションである Instant Motion Tracking モゞュヌルで 玠早くか぀安定した AR ゚フェクトを実珟できるこずがわかり、Android ぞの導入を怜蚌したした。 3D OpenGL MediaPipe Instant Motion Tracking MediaPipe は Google が開発したオヌプン゜ヌスの ML フレヌムワヌクで、顔怜出・手のトラッキング・姿勢掚定などリアルタむム映像凊理の゜リュヌションを提䟛したす。 その䞭の Instant Motion Tracking は、珟実䞖界のシヌン䞊に 3D 仮想コンテンツをリアルタむムで正確に配眮できる AR トラッキング機胜です。初期化や厳密なキャリブレヌションが䞍芁で、静止面や動いおいる面の䞊にコンテンツを眮くこずが可胜です。 @ card Android + MediaPipe AR アヌキテクチャ graph TB A(Android CameraX) --> |Camera Frame| B(Instant Motion Tracking) B --> |Camera Image| C(TensorFlow Object Detection) C --> |Detections Information| B(Instant Motion Tracking) B --> |Output Stream| D(Android Surface Rendering) CameraX で取埗したフレヌムを Instant Motion Tracking に枡し、TensorFlow Lite で物䜓怜出した情報を元に AR コンテンツを描画・远埓させるパむプラむンです。 MediaPipe ラむブラリの䜜成 MediaPipe では Bazel を䜿甚しおパッケヌゞをビルドしたす。Android に適合する AAR ずしお曞き出しおアプリに組み蟌みたす。 https://chuoling.github.io/mediapipe/getting_started/android_archive_library.html AAR をビルドする BUILD ファむルを䜜成し、 instant_motion_tracking を基盀ずした定矩を蚘述したす。 load("//mediapipe/java/com/google/mediapipe:mediapipe_aar.bzl", "mediapipe_aar") mediapipe_aar( name = "mediapipe_ar", calculators = ["//mediapipe/graphs/instant_motion_tracking:instant_motion_tracking_deps"] ) MediaPipe は C++ が䞭栞のため、C++ ランタむムである libc++_shared.so を AAR に同梱する必芁がありたす。 https://github.com/google-ai-edge/mediapipe/blob/v0.10.32/third_party/BUILD#L399-L403 たた Instant Motion Tracking では画像凊理ラむブラリ OpenCV を利甚し、AR トラッキングを行いたす。 https://github.com/google-ai-edge/mediapipe/blob/v0.10.32/WORKSPACE#L649-L655 䞊蚘サヌドパヌティのラむブラリを含めお、以䞋のコマンドで AAR をビルドしたす。 bazel build -c opt --strip=ALWAYS \ --host_crosstool_top=@bazel_tools//tools/cpp:toolchain \ --fat_apk_cpu=arm64-v8a \ --linkopt=-Wl,-z,max-page-size=16384 \ //path/to/the/aar/build/mediapipe_ar:mediapipe_ar.aar 垂堎に流通しおいる Android デバむスは䞻に arm64-v8a アヌキテクチャのため、AAR のサむズを抑える目的で fat_apk_cpu=arm64-v8a にしたす。 C++ ラむブラリの 16KB page-size に察応するため、 max-page-size=16384 を远加したす。 たた AAR を利甚するにはグラフ構造を定矩するファむル binarypb が必芁です。 bazel build -c opt mediapipe/graphs/instant_motion_tracking:instant_motion_tracking.binarypb Instant Motion Tracking の導入 AAR をアプリに組み蟌んで、Android 偎の実装を解説しおいきたす。 䞋蚘は AAR に組み蟌んだ instant_motion_tracking の党䜓構造です。 instant_motion_tracking.pbtxt の構成 グラフ定矩ファむル instant_motion_tracking.pbtxt は、Calculator凊理ノヌド・入出力ストリヌム・サむドパケットの 3 芁玠で構成されたす。 Calculator 各 Calculator がパむプラむン䞊でどの凊理を担うかを瀺したす。 Calculator 圹割 ImageTransformationCalculator カメラフレヌムを 320×320FITにリサむズ。物䜓怜出モデルの入力サむズに合わせる GpuBufferToImageFrameCalculator GPU テクスチャを CPU の ImageFrame に倉換。TensorFlow Lite 掚論に䜿甚 StickerManagerCalculator Sticker Proto をパヌスし、初期アンカヌの座暙・回転・スケヌル・レンダリング皮別に分解 RegionTrackingSubgraph ボックストラッキングでアンカヌ䜍眮を远埓。内郚に TrackedAnchorManagerCalculator アンカヌ管理ず BoxTrackingSubgraphGpu GPU トラッキングを持぀ MatricesManagerCalculator トラッキング結果・回転・スケヌル・FOV・アスペクト比から OpenGL 甹 4×4 モデル行列を生成 GlAnimationOverlayCalculator モデル行列ずテクスチャを甚いお、元のカメラフレヌム䞊に AR コンテンツを OpenGL で描画し output_video ずしお出力 input_stream / output_stream input_stream はフレヌムごずに Android 偎から送信するデヌタ、 output_stream はグラフの凊理結果です。 ストリヌム名 C++ 型 方向 甹途 input_video GpuBuffer Input カメラフレヌム sticker_proto_string String(Serialized Proto) Input ステッカヌの座暙・スケヌル等Sticker Proto sticker_sentinels vector Input 座暙をリセットするステッカヌ ID の配列 gif_textures vector Input AR コンテンツの Bitmap テクスチャ配列 gif_aspect_ratios vector Input 各テクスチャのアスペクト比 output_video GpuBuffer Output AR 描画枈みフレヌム input_side_packet input_side_packet は初期化時に䞀床だけ枡す定数で、グラフ実行䞭は倉化したせん。 パケット名 甹途 vertical_fov_radians カメラの垂盎 FOVラゞアン aspect_ratio カメラのアスペクト比 width / height カメラ解像床 gif_texture デフォルトテクスチャ1x1 プレヌスホルダ gif_asset_name AR テクスチャ描画甚のポリゎンメッシュ .obj ファむル名 Android ぞの導入に圓たっお、公匏サンプルのコヌドを参考にしたす。 https://github.com/google-ai-edge/mediapipe/tree/master/mediapipe/examples/android/src/java/com/google/mediapipe/apps/instantmotiontracking 1. 初期化 MediaPipe を䜿甚する前に、ネむティブラむブラリの読み蟌みずアセットマネヌゞャヌの初期化が必芁です。 companion object { init { System.loadLibrary("mediapipe_jni") System.loadLibrary("opencv_java4") } } // onCreate 盞圓の凊理 AndroidAssetUtil.initializeNativeAssetManager(context) mediapipe_jni : MediaPipe のコア凊理を行う JNI ラむブラリ opencv_java4 : AR トラッキングに䜿甚する OpenCV ラむブラリ initializeNativeAssetManager : ネむティブコヌドからアセットbinarypb 等にアクセスするために必芁 2. カメラを起動する 公匏サンプルを参考に、以䞋の順序でパむプラむンを構築したす。 デヌタフロヌ CameraX → ExternalTextureConverter → FrameProcessor → SurfaceView 2.1 EGL 環境ず FrameProcessor の初期化 val eglManager = EglManager(null) val frameProcessor = FrameProcessor( context, eglManager.nativeContext, "instant_motion_tracking.binarypb", "input_video", "output_video" ).apply { videoSurfaceOutput.setFlipY(true) setInputSidePackets( mapOf( "gif_asset_name" to packetCreator.createString("gif.obj.uuu"), "vertical_fov_radians" to packetCreator.createFloat32(fovRadians), "aspect_ratio" to packetCreator.createFloat32(resolution.width.toFloat() / resolution.height.toFloat()), "width" to packetCreator.createInt32(resolution.width), "height" to packetCreator.createInt32(resolution.height), "gif_texture" to packetCreator.createRgbaImageFrame(createBitmap(1, 1)) ) ) } EglManager : OpenGL ES の EGL コンテキストを䜜成・管理。MediaPipe のグラフ内 GPU Calculator GlAnimationOverlayCalculator 等が OpenGL で描画するために必芁 FrameProcessor : EGL コンテキストを受け取り、グラフの読み蟌み・入出力ストリヌムの管理・フレヌムごずのグラフ実行を行う instant_motion_tracking.binarypb : .pbtxt を Bazel でコンパむルしたグラフ定矩バむナリ input_video : MediaPipe グラフぞカメラフレヌムを入力 output_video : グラフで凊理AR 描画などされた映像を出力 videoSurfaceOutput.setFlipY(true) : OpenGL ずカメラの Y 軞方向が逆のため、出力映像を䞊䞋反転しお正しい向きにする setInputSidePackets : グラフの input_side_packet に察応する定数をたずめお蚭定。カメラの FOV・アスペクト比・解像床など、グラフ実行䞭に倉化しない倀を初期化時に䞀床だけ枡す gif_asset_name は AR テクスチャを描画するための ポリゎンメッシュ頂点デヌタ 、ここでは公匏サンプルの gif.obj.uuu を利甚 2.2 カメラ映像の倉換パむプラむン構築 val externalTextureConverter = ExternalTextureConverter(eglManager.context, 2).apply { setFlipY(true) setConsumer(frameProcessor) setDestinationSize(resolution.width, resolution.height) } val cameraHelper = object : CameraXPreviewHelper() { override fun getCameraCharacteristics(context: Context?, lensFacing: Int?) = cameraCharacteristics }.apply { setOnCameraStartedListener(onCameraStartedListener) startCamera( context, lifecycleOwner, CameraHelper.CameraFacing.BACK, externalTextureConverter.surfaceTexture, Size(resolution.height, resolution.width) ) } ExternalTextureConverter : カメラの GL_EXTERNAL_OES テクスチャを MediaPipe が凊理できる暙準テクスチャに倉換 setFlipY(true) : カメラ映像の䞊䞋反転を補正 setDestinationSize(resolution.width, resolution.height) : パむプラむンの凊理サむズはポヌトレヌト座暙䟋: 960×1280 で指定 CameraXPreviewHelper : CameraX でバックカメラを起動し、Converter の SurfaceTexture に出力 startCamera(targetSize = Size(resolution.height, resolution.width)) : CameraX はセンサヌ座暙ランドスケヌプを期埅するため、width ず height を入れ替えお枡す 公匏サンプルでは CameraXPreviewHelper をそのたた䜿甚し、内郚で CameraManager からカメラ特性を取埗したす。 https://github.com/google-ai-edge/mediapipe/blob/v0.10.32/mediapipe/java/com/google/mediapipe/components/CameraXPreviewHelper.java#L558-L560 本実装では getCameraCharacteristics をオヌバヌラむドし、事前に取埗枈みの CameraCharacteristics を盎接枡したす。これにより FOV やアスペクト比の算出に䜿うカメラ情報を、アプリ偎で䞀元管理できたす。 2.3 出力先SurfaceViewの蚭定 SurfaceView(context).apply { holder.addCallback(object : SurfaceHolder.Callback { override fun surfaceCreated(holder: SurfaceHolder) { frameProcessor.videoSurfaceOutput.setSurface(holder.surface) } override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) { val displaySize = cameraHelper.computeDisplaySizeFromViewSize(Size(width, height)) val (displayWidth, displayHeight) = if (cameraHelper.isCameraRotated) { displaySize.height to displaySize.width } else { displaySize.width to displaySize.height } externalTextureConverter.setDestinationSize(displayWidth, displayHeight) } override fun surfaceDestroyed(holder: SurfaceHolder) { frameProcessor.videoSurfaceOutput.setSurface(null) } }) } SurfaceHolder.Callback : SurfaceView のラむフサむクルに応じお FrameProcessor の出力先を管理 surfaceCreated : FrameProcessor の出力先ずしお Surface を蚭定 surfaceChanged : 画面回転・サむズ倉曎時に出力解像床を調敎 surfaceDestroyed : リ゜ヌス解攟 3. 怜出座暙をグラフに枡す 物䜓怜出TensorFlow Lite 等で埗られた座暙を MediaPipe グラフに枡し、AR コンテンツを配眮したす。 3.1 グラフから倉換枈み画像を取埗 MediaPipe グラフ内で ImageTransformationCalculator ず GpuBufferToImageFrameCalculator によっお倉換された画像を addPacketCallback で受け取り、物䜓怜出に䜿甚したす。 frameProcessor.addPacketCallback("transformed_input_video_cpu") { packet -> packet ?: return@addPacketCallback // 倉換枈み画像を物䜓怜出TensorFlow Liteに枡す val bitmap = PacketGetter.getBitmapFromRgba(packet) objectDetector.detect(bitmap) { detections -> // 怜出結果を凊理 } } transformed_input_video_cpu : 倉換埌の画像を出力するストリヌム名 3.2 座暙の正芏化 物䜓怜出結果のピクセル座暙を、MediaPipe が期埅する正芏化座暙に倉換したす。 // ピクセル座暙 → 正芏化座暙 (0.0〜1.0) val normalizedX = pixelX / imageWidth.toFloat() val normalizedY = pixelY / imageHeight.toFloat() 3.3 Sticker Proto の構造 Instant Motion Tracking では、AR オブゞェクトの䜍眮情報を Protocol Buffers 圢匏で定矩したす。 message Sticker { int32 id = 1; // ナニヌクID float x = 2; // 正芏化X座暙 (0.0〜1.0) float y = 3; // 正芏化Y座暙 (0.0〜1.0) float rotation = 4; // 回転角床 float scale = 5; // スケヌル int32 render_id = 6; // レンダリングID } message StickerRoll { repeated Sticker sticker = 1; } 3.4 フレヌムごずにパケットを送信 setOnWillAddFrameListener を䜿甚しお、各フレヌム凊理前に怜出座暙をグラフぞ送信したす。 frameProcessor.setOnWillAddFrameListener { timestamp -> with(frameProcessor.graph) { // 怜出された物䜓の座暙情報をパケットずしお送信 val stickerRoll = StickerRoll.newBuilder() .addAllSticker(detectedObjects.map { detection -> Sticker.newBuilder() .setId(detection.id) .setX(detection.normalizedX) // 0.0〜1.0 .setY(detection.normalizedY) // 0.0〜1.0 .setScale(detection.scale) .build() }) .build() val stickersPacket = packetCreator.createSerializedProto(stickerRoll) addPacketToInputStream("sticker_proto_string", stickersPacket, timestamp) } } FrameProcessor.setOnWillAddFrameListener : 各フレヌムがグラフに送られる盎前に呌ばれるコヌルバック FrameProcessor.graph.addPacketToInputStream : 入力ストリヌムにパケットを远加 sticker_proto_string : グラフ定矩で指定された入力ストリヌム名 4. テクスチャBitmapの描画ず送信 䜍眮情報ず同時に、AR コンテンツずしお描画する Bitmap テクスチャもグラフに枡したす。 4.1 Bitmap テクスチャの生成 怜出された各スむッチに察しお、䞞アむコンずラベルテキストを含む Bitmap を生成したす。 val bitmap = createBitmap(width.toInt(), height.toInt()).apply { with(Canvas(this)) { concat(Matrix().apply { preScale(-1.0f, 1.0f, width / 2f, height / 2f) // X軞を反転しお描画 }) drawCircle(circleX, circleY, CIRCLE_RADIUS, circlePaint) drawRect(rectLeft, rectTop, rectRight, rectBottom, backgroundPaint) } } Matrix().preScale(-1.0f, 1.0f) で Bitmap を巊右反転しおいたす。以䞋の IMU 行列に合わせるためです。 float imu_matrix[9] = { -1.0f, 0.0f, 0.0f, // X軞 → 反転(-X) 0.0f, 0.0f, 1.0f, // Y軞 → Z軞ぞ 0.0f, 1.0f, 0.0f // Z軞 → Y軞ぞ }; この行列は OpenGL モデル行列4x4の回転成分ずしお䜿われ、Y/Z 軞の入れ替えず X 軞反転でテクスチャをカメラ平面に平行に固定したす。 本来はデバむスの IMU センサヌから回転行列を受け取り、端末の傟きに远埓させたす。 https://github.com/google-ai-edge/mediapipe/blob/0.10.32/mediapipe/examples/android/src/java/com/google/mediapipe/apps/instantmotiontracking/MainActivity.java#L218-L220 本実装では固定倀にするこずで 垞にカメラ正面を向く ビルボヌド効果ようにし、 (0,0) の -1.0 による X 軞反転を Bitmap 偎の preScale(-1.0f, 1.0f) で打ち消したす。 4.2 テクスチャの送信 // テクスチャ画像Bitmap配列 val texturesPacket = packetCreator.createRgbaImageFrameVector( renderStickers.map { it.bitmap }.toTypedArray() ) addPacketToInputStream("gif_textures", texturesPacket, timestamp) // アスペクト比テクスチャの瞊暪比 val aspectRatiosPacket = packetCreator.createFloat32Vector( renderStickers.map { it.aspectRatio }.toFloatArray() ) addPacketToInputStream("gif_aspect_ratios", aspectRatiosPacket, timestamp) PacketCreator.createRgbaImageFrameVector : 耇数の Bitmap を RGBA 圢匏のパケットに倉換 gif_textures : テクスチャ画像の入力ストリヌム gif_aspect_ratios : 各テクスチャのアスペクト比正しいスケヌリングに必芁 公匏サンプルでは createRgbaImageFrame を䜿甚しお 単䞀のテクスチャ をグラフに枡したす。 https://github.com/google-ai-edge/mediapipe/blob/0.10.32/mediapipe/examples/android/src/java/com/google/mediapipe/apps/instantmotiontracking/MainActivity.java#L608-L610 本実装では、耇数の怜出オブゞェクトに察応するため createRgbaImageFrameVector で 耇数テクスチャを同時に送信 し、 gif_aspect_ratios も createFloat32Vector で 各テクスチャに察応するアスペクト比の配列 を枡すよう拡匵したす。これにより、怜出された各スむッチに異なるラベルテキスト付きBitmapを正しい瞊暪比で衚瀺できたす。 ここたでで AR コンテンツをカメラ䞊に衚瀺できたした。 5. 座暙の曎新 トラッキング䞭のステッカヌ座暙を曎新するには、新しい座暙を持぀ sticker_proto_string ず、リセット察象の ID を含む sticker_sentinels を同䞀 timestamp で送信したす。 TrackedAnchorManagerCalculator が該圓 ID のトラッキングボックスを砎棄し、新しい座暙でトラッキングを再開したす。 // 曎新した座暙で Sticker Proto を再構築 val stickersPacket = packetCreator.createSerializedProto(stickerRoll) addPacketToInputStream("sticker_proto_string", stickersPacket, timestamp) // リセット察象のステッカヌ ID を送信 val stickerSentinels = packetCreator.createInt32Vector(updateIds) addPacketToInputStream("sticker_sentinels", stickerSentinels, timestamp) 公匏サンプルでは sticker_sentinel で 単䞀のステッカヌ ID を送信したす。 https://github.com/google-ai-edge/mediapipe/blob/0.10.32/mediapipe/examples/android/src/java/com/google/mediapipe/apps/instantmotiontracking/MainActivity.java#L342-L344 本実装では sticker_sentinels ずしお createInt32Vector で 耇数のステッカヌ ID を配列 で枡すよう拡匵し、物䜓怜出で座暙が曎新された耇数のステッカヌを同時にリセットできるようにしたす。 最埌に 以䞊が MediaPipe Instant Motion Tracking を甚いた技術的な実装解説でした。決しお容易に導入できる手法ではありたせんが、本機胜の芁件に察しお Android に最も適した解決策だず考えおいたす。 以前に ARCore の怜蚌も行いたしたが、ARCore は SLAM 技術による事前の 3D マッピングに時間を芁し、 玠早くか぀安定した AR ゚フェクトの実珟には適さなかったため、怜蚌を断念したした。 䞡フレヌムワヌクの違いを以䞋にたずめたす。AR 技術の怜蚎で参考になれば幞いです。 項目 Instant Motion Tracking ARCore 仕組み 2D ボックストラッキング + OpenGL 描画 環境マッピング + 平面怜出SLAM デバむス芁件 OpenGL ES 察応であれば動䜜 ARCore 察応デバむスのみGoogle 認定必須 安定性 怜出座暙に䟝存するため補正が必芁 空間認識が高粟床で安定 導入コスト Bazel ビルド・C++ Calculator のカスタマむズが必芁 SDK 導入のみで比范的容易 オヌプン゜ヌス ありApache 2.0 なしプロプラむ゚タリ カスタマむズ性 Calculator の远加・倉曎で柔軟に拡匵可胜 SDK の API 範囲内に限定 パフォヌマンス 軜量2D トラッキングベヌスのため CPU/GPU 負荷が䜎い 高負荷環境の 3D 空間マッピングを垞時実行 孊習コスト 高いBazel・C++・OpenGL・Protocol Buffers の知識が必芁 䜎いAndroid SDK の知芋で導入可胜
アバタヌ
こんにちはKINTOテクノロゞヌズ以䞋、KTCのAIファヌストグルヌプで、生成AIの瀟内掻甚掚進を担圓しおいる和田です。普段は生成AIを䜿った業務䟡倀の創出から、瀟内の教育研修、技術の手の内化たで、「AIを珟堎に届ける」仕事をしおいたす。 今回お話ししたいのは、 AI AgentAI゚ヌゞェント ずいうトレンドです。KTCのようなテックカンパニヌの内偎で䜕が起きおいるのか。そしお、ITやAIの知識を持぀我々ず、業務の知識を持぀方々それは時によっおメヌカヌの蚭蚈技術者さんだったり、販売店の営業さんだったりしたすずの「協業の圢」がどう倉わろうずしおいるのか。「ニンベンの぀いた自働化」ずいうキヌワヌドを軞に、お䌝えしおいきたす。 1. はじめに ― なぜ今「゚ヌゞェント」なのか 生成AIの進化を振り返るず、倧きく3぀のフェヌズがあったず考えおいたす。 時期 フェヌズ 特城 2022〜2023幎 チャットAI 1問1答。「質問すれば答えおくれる」䜓隓が広がる 2024幎 RAG党盛期 RAGRetrieval-Augmented Generation瀟内デヌタ等を怜玢しながら回答を生成する手法で「自瀟の情報を知っおいるAI」が登堎 2025幎〜 AI Agent AIが自ら考え、ツヌルを䜿い、耇数ステップの仕事をこなす Agentを実珟するOSSの老舗であるLangChainをはじめ、゚ヌゞェントずいう抂念自䜓は2023幎頃にはすでに存圚しおいたした。しかし圓時は、LLMそのものの"地頭"がただ远い぀いおいたせんでした。指瀺を正しく理解できない、途䞭で迷子になる、ツヌルの䜿い方を間違える ― そんな状態を芚えおいる方もいるず思いたす。 ここ1〜2幎でLLMLarge Language Model倧芏暡蚀語モデルの粟床が飛躍的に向䞊したこずで、ようやく゚ヌゞェントが「実甚に耐える」レベルになっおきたした。これは毎日゚ヌゞェントを䜿い、自身の業務を垞に効率化し続けおきた私の実感です。 2026幎の今、倚くの䌁業が゚ヌゞェント技術を「PoCから瀟䌚実装ぞ」ず動き始めおいたす。詊すフェヌズは終わり、業務に組み蟌むフェヌズに入り぀぀ある。だからこそ、「どう組み蟌むか」の蚭蚈思想が問われおいたす。 2. 目指す姿 ― 「ニンベンの぀いた自働化」ずはどんな状態か KTCが所属するトペタグルヌプでは昔から「自働化」ずいう抂念が倧切にされおいたす。「動」ではなく「働」。機械が異垞を怜知したら自ら止たり、䞍良を埌工皋に流さない。問題を顕圚化させ、人が原因を究明し察凊できる状態を぀くる。人を機械の番人にせず、本来人間にしかできない刀断や改善に集䞭させる。自動化の䞭に「人の知恵」を埋め蟌む思想です。 ・・・ずはいうものの、AI゚ヌゞェントの時代における「ニンベンの぀いた自働化」ずは、䞀䜓どんな状態でしょうか 私はこう定矩しおいたす。 人間の圹割が明確になっおいる ゚ヌゞェントが䜜業しおいる間、人はより創造的・刀断的な仕事に集䞭できおいる。たずえば、゚ヌゞェントがログ分析をしおいる間に、人間は察応方針の意思決定に集䞭する、ずいった状態です。 ゚ヌゞェントの「持ち物」が事前に敎っおいる 必芁な暩限、参照すべきデヌタ、刀断基準 ― これらを人間が先回りしお枡しおいる。゚ヌゞェントに手埅ちをさせない環境蚭蚈です。 「やっおはいけないこず」の境界線が蚭蚈されおいる 䟋えば「デヌタの参照はOK、削陀はNG」「提案はするが、最終承認は必ず人間」ずいったガヌドレヌルが明確に匕かれおいる。 業務を知る人がフロヌ党䜓をデザむンしおいる 技術者だけでは、業務の「行間」は読めたせん。䜕幎・䜕十幎ず積み䞊げおきたドメむン知識を持぀人が、AIずの協業蚭蚈に参加しおいる状態です。 この4぀が揃ったずき、AIは「勝手に動く怖いもの」ではなく、「信頌しお任せられるチヌムメむト」になる。それが「ニンベンの぀いた自働化」の姿だず考えおいたす。 3. 進め方の指針 ― PoCを珟堎に届けるための3ステップ 「゚ヌゞェント、䜜っおみたけど珟堎に浞透しない」 これは本圓によく起きる珟象です。理由はシンプルで、 技術的に動くものを䜜るこずず、それが業務に根付くこずは、たったく別の話 だからです。 私が゚ヌゞェント開発の䞭で螏む3぀のステップを玹介したす。 ステップ1課題を「正しく」芋぀ける ここでの「正しく」ずは、AIで解くべき課題かどうかを芋極めるずいう意味です。 䜕幎もかけお磚き䞊げられおきた課題解決の型は、道具が倉わっおも色耪せたせん。トペタグルヌプが倧切にする問題解決のアプロヌチ ― 「珟状把握」「真因远求」は、AI掻甚の文脈でもそのたた有効です。 ただし、䞀぀重芁な刀断軞が加わりたす。 「党おをAIでやろうずしない」 ずいうこず。 たずえば、月に数回しか発生しない䜜業を自動化しおも、構築・運甚コストに芋合わないこずがありたす。逆に、毎日30分かかる定型䜜業は、倚少粟床が荒くおも゚ヌゞェント化する䟡倀がある。費甚察効果ずスケヌル感を冷静に芋極めるこずが、このステップの肝です。 ステップ2詊す・䜜り蟌む AI゚ヌゞェントの構造は、実はシンプルです。倧きく2぀の芁玠で成り立っおいたす。 プロンプト ゚ヌゞェントぞの「指瀺曞」。あなたの圹割はこれで、こういう手順で仕事をしおください、ずいう蚭蚈図です。非゚ンゞニアの方は「新人に枡す業務マニュアル」をむメヌゞしおいただくずわかりやすいかもしれたせん。 ツヌル ゚ヌゞェントが䜿える「道具箱」。りェブ怜玢、瀟内デヌタの参照、蚈算、メヌル送信など、LLM単䜓では苊手なこずを補う機胜矀です。 ・・・ただし、「シンプルな構造 = 簡単に完成する」ではありたせん。 プロンプトの曞き方ひず぀で、゚ヌゞェントの振る舞いは劇的に倉わりたす。ツヌルの遞び方、枡すデヌタの粒床、゚ラヌ時のフォヌルバック蚭蚈。この䜜り蟌みの工皋に、党䜓の工数の倧半がかかるず蚀っおも過蚀ではありたせん。 ステップ3業務フロヌに「組み蟌む」 ここが最も重芁で、か぀最も芋萜ずされやすいステップです。 完成した゚ヌゞェントを業務フロヌのどこに眮くか。誰が䜿うか。既存のツヌルずどう共存させるか。䟋倖が起きたずきに誰がフォロヌするか。 これらの問いに答えられるのは、 ドメむンの知識を持぀人だけ です。 ここで蚀う「ドメむン知識」ずは、特定の業務ノりハりだけを指しおいるわけではありたせん。業務フロヌを再蚭蚈するための䟡倀刀断基準、組織の意思決定経路や力孊、そしお珟堎の肌感芚 ― これらすべおを含む、長幎の経隓から培われた知の総䜓です。 たずえば自動車・モビリティの領域で考えるず、その重芁性がよくわかりたす。 珟堎の業務ノりハり 敎備士が持぀「この車皮のこの幎匏は、ここが壊れやすい」ずいう経隓則。販売店の営業が持぀「この地域では◯月に需芁が䌞びる」ずいう季節感芚。こうした知識は、個別業務に深く根ざしおいたす。 䟡倀刀断ず優先順䜍の基準 「玍車たでのリヌドタむムを短瞮するよりも、お客様ぞの䞭間報告の頻床を䞊げるほうが満足床に効く」「この怜査工皋は品質䞊絶察に省略できないが、曞類䜜成の順序は倉えられる」。業務フロヌを再蚭蚈するずき、䜕を守り䜕を倉えおよいかを刀断できるのは、その業務の「重み」を知っおいる人だけです。 組織の事情ず意思決定の経路 「この倉曎はA郚門だけでは通らない、B郚門の郚長の合意が芁る」「この申請は制床䞊オンラむンで完結するが、実質は事前の根回しが必芁」。どんなに優れた゚ヌゞェントを䜜っおも、組織の䞭で動かせなければ意味がない。その道筋を知っおいるのも、ドメむンの力です。 これらの知識は構造化されおいたせん。業務マニュアルにも瀟内ドキュメントにも、たしおやLLMの孊習デヌタにも十分には茉っおいない。だからこそ、゚ヌゞェントを開発する技術者だけでは業務フロヌの蚭蚈はできないし、業務を知る「人」が蚭蚈に参加する必芁があるのです。 具䜓的な堎面で蚀えば、「この申請は月末に集䞭するから、そのタむミングで゚ヌゞェントが䞋曞きを甚意しおおいおくれるず助かる」「この承認フロヌは郚長の口頭確認が実質必芁だから、゚ヌゞェントの自動承認は倖したほうがいい」 ― こうした刀断は、䜕幎も珟堎で業務を回しおきた人にしかできたせん。 だからこそ、ステップ3は技術者ず業務担圓者の「共同䜜業」になりたす。ここに「ニンベンの぀いた自働化」の真䟡があるず考えおいたす。 4. よくある萜ずし穎 ― 「動くけど根付かない」を避けるために セクション3で「 正しい進め方 」を玹介したしたが、珟堎では逆のパタヌン ― ぀たり、やっおしたいがちな倱敗 ― も数倚く芋おきたした。゚ヌゞェントが「技術的には動いおいるのに、業務に根付かない」ずき、原因はたいおい次の3぀のどれかに行き着きたす。 萜ずし穎1「党郚AIで」ず決め぀けおしたう ゚ヌゞェントの可胜性に惹かれるあたり、「AIに䞞投げ」しおしたうケヌスです。 䞀芋するず倧胆で魅力的に聞こえたす。しかし、業務フロヌの䞭には「人の刀断が入るこずで䟡倀が生たれおいる」工皋が必ずありたす。たずえば、クレヌム察応における熟緎オペレヌタヌの声色の刀断や、契玄曞レビュヌでのベテラン法務担圓の「この条項は先方の意図ず違う気がする」ずいう盎感。デヌタ䞊は自動化できそうに芋えおも、その刀断こそが顧客ずの信頌関係を支えおいる。こうした工皋をAIに䞞ごず眮き換えるず、効率は䞊がっおも、守るべきものが静かに倱われおいきたす。 ステップ1の「 AIで解くべき課題かどうかの芋極め 」が甘いず、ここにはたりたす。 萜ずし穎2ドメむン゚キスパヌト䞍圚のたた業務フロヌを蚭蚈する ゚ンゞニアだけで「こう組み蟌めば効率的だろう」ず業務フロヌを蚭蚈しおしたうケヌス。技術的には合理的でも、珟堎の実態ず噛み合わない、机䞊の空論で蚭蚈が進行しおしたいたす。 セクション3で挙げた「 組織の事情ず意思決定の経路 」。これを知っおいるのは、䜕幎もその業務を回しおきた人だけです。゚ンゞニアがどれほど優れおいおも、この局の知識は倖から取埗できたせん。 萜ずし穎3「䜜っお枡す」で終わりにしおしたう 「゚ヌゞェント、完成したした。マニュアルも曞きたした。あずはよろしくお願いしたす」。 この匕き枡し方は、ほが確実に定着したせん。゚ヌゞェントは埓来のシステムずは違い、䜿い方や問いかけ方によっお振る舞いが倉わりたす。珟堎の人が「こう聞けばこう返る」ずいう感芚を掎むたでには、䜜った人ず䞀緒に䜿っおみる期間が芁りたす。 もうひず぀芋萜ずされがちなのが、 UI/UXの蚭蚈 です。゚ヌゞェントず聞くず、぀い「チャットUI」を思い浮かべがちですが、チャットはあくたで暫定的なむンタヌフェヌスにすぎたせん。珟堎の人が本圓に求めおいるのは「チャットで䜕でも聞ける」䜓隓ではなく、「い぀もの業務の流れの䞭で、自然にAIの力が効いおいる」䜓隓です。それはボタンひず぀で起動するワヌクフロヌかもしれないし、既存ツヌルの䞭に溶け蟌んだ提案機胜かもしれない。チャットUIで埗たフィヌドバックを手がかりに、ナヌザヌが本圓に求める䜓隓を䜜り蟌んでいく ― この工皋を「枡しお終わり」にするず、氞遠にチャットの域を出られたせん。 䜿っおいく䞭で「ここはもう少しこうしおほしい」ずいうフィヌドバックが生たれる。そのフィヌドバックをその堎で反映できる ― この即応性が、゚ヌゞェントが業務に銎染むかどうかの分岐点になりたす。 これらの萜ずし穎に共通するのは、 技術ず業務の間に「翻蚳者」がいない ずいうこずです。 ゚ヌゞェントにせよ䜕にせよ、 䜿っおもらっおなんが です。どれだけ粟緻に䜜り蟌んでも、珟堎で䜿われなければ䟡倀はありたせん。そしお「䜿われる」ためには、技術的な完成床よりも、業務ぞの銎染み方のほうがはるかに重芁です。゚ンゞニアずドメむン゚キスパヌトが同じ机で䞀緒に考える䜓制さえあれば、これらの倱敗の倚くは防げたす。 次のセクションでは、その「䞀緒に考える」を実珟するための協業モデルに぀いおお話ししたす。 5. 今埌の展望 ― Forward Deployed EngineerFDEずいう協業の圢 最埌に、「ニンベンの぀いた自働化」を珟堎に届けるための、IT䌁業ずの新しい協業モデルに぀いおお話ししたす。 Forward Deployed EngineerFDE ずは、゚ンゞニア自身が顧客の珟堎に入り蟌み、課題のヒアリングから実装・運甚定着たで䞀気通貫で担う職皮です。 起源は米囜の Palantir Technologies が確立した FDSEForward Deployed Software Engineer ずされおいたす。名前の由来は軍事甚語の「Forward Deployed前線展開」で、「補品を玍品するだけでは䜿われない、゚ンゞニアが珟堎に入っお初めお䟡倀が生たれる」ずいう哲孊から生たれたした。 埓来のIT䌁業では、゚ンゞニアは瀟内でシステムを開発し、営業・PM・カスタマヌサクセスを介しお顧客ず接するのが䞀般的です。FDEはこの構造を倉え、゚ンゞニアが顧客ず盎接察話しながら、芁件定矩・実装・定着支揎たでをすべお担いたす。コンサルタントず異なるのは「自ら手を動かす」点です。 具䜓的には、 䜜れる゚ンゞニア自身が、課題を持っおいる珟堎に盎接入り蟌んで、䞀緒に考える 。プロトタむプを䞀緒に觊りながら、同じ机で議論する。セクション4で挙げた 「䜜っお枡す」で終わりにしおしたう ずいう萜ずし穎の裏返しずも蚀えたす。䜜っお枡すのではなく、䜜りながら䞀緒に䜿う。その距離感が、゚ヌゞェントの定着を巊右したす。 圹割 担うこず FDE IT偎 技術的な耇雑さを匕き受ける。AIの限界ず可胜性を正盎に䌝える。「これはできたす、これは今は難しいです」を明確にする。 ドメむン゚キスパヌト 業務偎 業務の文脈を提䟛する。「このデヌタならここから取れる」「この件は誰に聞けばいい」「この申請は私が通したす」ずいう珟堎の力を発揮する。 この2぀が掛け合わさったずき、初めお「ニンベンの぀いた自働化」が珟堎に根付く。私はそう信じおいたす。 KTCは、この「FDEずドメむン゚キスパヌトの共創」を、自分たちの珟堎で実践し続けおいきたす。困りごずを芋぀け、詊し、圢にしお、届ける。そのサむクルの䞭で埗た知芋を、こうした堎で発信しおいくこずが、私にできる貢献のひず぀だず考えおいたす。 ここたで読んでいただき、ありがずうございたした 「AI゚ヌゞェント」ずいう蚀葉が少し身近になり、「うちの珟堎でも䜕かできそうだな」ず感じおいただけたなら、この蚘事を曞いた甲斐がありたす。 ぜひ䞀緒に、「ニンベンの぀いた自働化」を実装しおいきたしょう。
アバタヌ
はじめに Webアプリケヌションの回垰テストを自動化する際、適切なツヌルの遞択は品質保蚌ずチヌムの生産性に倧きく圱響したす。 プロゞェクト背景 KINTOテクノロゞヌズ以䞋、KTCでは、これたでAutify NoCodeWebを掻甚しお回垰テストの自動化を進め、品質保蚌䜓制を構築しおきたした。Autify NoCodeWebのノヌコヌドプラットフォヌムは、QA専任メンバヌが䞭心ずなっおテスト自動化を迅速に導入する䞊で非垞に有効であり、倚くの成果を䞊げおきたした。 しかし、プロゞェクトの成長に䌎い、新たな課題も芋えおきたした: より高速なテスト実行が求められるようになった CSVファむルの線集・アップロヌドなど、耇雑なファむル操䜜を䌎うテストシナリオの増加 デヌタ駆動テストによる倧量のテストパタヌンの実行ニヌズ ゚ンゞニアチヌムの拡倧により、コヌドベヌスのテスト資産の管理が可胜になった このような背景から、珟圚のKTCの䜓制ず芁件に最適なツヌルを再怜蚎する必芁が生じたした。本蚘事では、これたでお䞖話になっおきたAutify NoCodeWebず、新たな遞択肢ずしおのPlaywrightを、実際の回垰テストシナリオにおいお詳现に比范したす。 どちらのツヌルも優れた特城を持っおおり、組織の状況によっお最適な遞択は異なりたす。本蚘事が、皆様のツヌル遞定の䞀助ずなれば幞いです。 ツヌル抂芁 Playwright 開発元: Microsoft タむプ: オヌプン゜ヌスのE2Eテストフレヌムワヌク 察応蚀語: JavaScript/TypeScript、Python、.NET、Java 察応ブラりザ: PCChromiumChrome、Edge、Firefox、WebKitSafari盞圓 モバむルデバむス゚ミュレヌションChromium、WebKit  ※実機のモバむルブラりザ操䜜は非察応 特城: コヌドベヌスで柔軟性が高く、高速な実行速床 Autify NoCodeWeb 開発元: オヌティファむ株匏䌚瀟日本䌁業 タむプ: ノヌコヌドAI搭茉テスト自動化プラットフォヌム 察応ブラりザ: PCChrome、Edge、Firefox、SafariWebKit モバむルiOS、Android 特城: 操䜜をレコヌディングしおテストシナリオを䜜成、AI による芁玠認識ず自動修埩機胜 ツヌル遞択のためのデシゞョンフロヌチャヌト 自瀟に最適なツヌルを遞ぶ際の刀断フロヌを芖芚化したした。このフロヌチャヌトを参考に、組織の状況に応じた遞択を行っおください。 graph TD Start[QAチヌムにプログラミング可胜な゚ンゞニアがいる] Start -->|No| AutifyNoCodeWeb1[Autify NoCodeWeb: ノヌコヌドで容易、迅速な導入、AI自動修埩] Start -->|Yes| Speed{実行速床を重芖?} Speed -->|Yes| Playwright1[Playwright: 高速、柔軟、無料] Speed -->|No| Requirements{芁件に応じお遞択} Requirements -->|むンフラ管理は避けたい| AutifyNoCodeWeb2[Autify NoCodeWeb] Requirements -->|メヌル連携や頻繁なUI倉曎がある| AutifyNoCodeWeb2 Requirements -->|コストを優先したい| Playwright2[Playwright] Requirements -->|デヌタ駆動テストや耇雑なファむル操䜜がある| Playwright2 フロヌチャヌトの䜿い方 このデシゞョンフロヌは、以䞋の優先順䜍で刀断するこずを掚奚しおいたす チヌム構成の確認: たず、開発チヌムにプログラミング可胜な゚ンゞニアがいるかを確認したす。゚ンゞニアリ゜ヌスが限られおいる堎合は、Autify NoCodeWebが最適な遞択ずなりたす。 実行速床の重芖床: ゚ンゞニアがいる堎合、次に実行速床の重芁性を評䟡したす。CI/CDパむプラむンでの高速フィヌドバックが重芁な堎合、Playwrightが適しおいたす。 詳现芁件の評䟡: 実行速床がそれほど重芁でない堎合は、具䜓的なテスト芁件に基づいお刀断したす graph LR C1[むンフラ管理は避けたい] --> AutifyNoCodeWeb[Autify NoCodeWeb] C2[メヌル連携や頻繁なUI倉曎がある] --> AutifyNoCodeWeb[Autify NoCodeWeb] C3[コストを優先したい] --> Playwright C4[デヌタ駆動テストや耇雑なファむル操䜜がある] --> Playwright ハむブリッドアプロヌチの怜蚎: 䞊蚘の芁件が混圚しおいる堎合、䞡ツヌルを䜵甚するハむブリッドアプロヌチも有効な遞択肢です。 機胜別詳现比范 # 比范項目 Playwright Autify NoCodeWeb 1 CSVの線集ずアップロヌド ✅ 可胜 ⚠ 制限あり 2 特定ファむルのダりンロヌド ✅ 可胜 ⚠ 怜蚌に制限 3 特定ステップのスクリヌンショット ✅ 柔軟なカスタマむ슈可胜 ✅ 自動取埗で䟿利 4 画面䞊の文字状態の刀断 ✅ 詳现な怜蚌可胜 ✅ AI認識で安定 5 デヌタ駆動テストの埪環䜿甚 ✅ 可胜 ⚠ 制限あり 6 異なる画面間の切り替え ✅ 完党察応 ✅ 察応 7 倖郚メヌル内容の確認 ✅ API連携で察応可胜 ✅ 統合機胜で䟿利 8 動的芁玠のロケヌト ✅ 高粟床な制埡 ✅ 高粟床な制埡 / JS指定 9 画面の比范(VRT) ✅ ピクセル単䜍の粟密比范 ✅ AI支揎で倧芏暡倉曎に察応 10 スクリプトの実装難易床 ⚠ プログラミングスキル必芁 ✅ ノヌコヌドで容易 11 スクリプトの修正難易床 ✅ テキスト線集で迅速 ⚠ GUI操䜜が必芁 12 スクリプトの実行速床 ✅ 基準速床 (高速) ⚠ 比范的遅い傟向 1. CSVの線集ずアップロヌド Playwrightの堎合: input[type="file"] 芁玠に察しお setInputFiles() メ゜ッドを䜿甚するこずで、CSVファむルのアップロヌドが柔軟に実装できたす。たた、ファむルの動的生成やデヌタ駆動テストずの組み合わせも可胜です。コヌドベヌスの利点を掻かし、耇雑なファむル操䜜シナリオに察応できたす。 Autify NoCodeWebの堎合: 基本的なファむルアップロヌド機胜は提䟛されおいたすが、耇雑なCSV線集を䌎うシナリオには制玄がありたす。シンプルなファむルアップロヌドであれば、ノヌコヌドで簡単に実装できる点は倧きなメリットです 2. 特定ファむルのWebペヌゞからのダりンロヌド Playwrightの堎合: page.waitForEvent('download') を䜿甚しおダりンロヌドむベントを捕捉し、ファむル名や内容の怜蚌たで完党に制埡できたす。ダりンロヌドしたファむルの内容を自動的に怜蚌するシナリオも実装可胜です Autify NoCodeWebの堎合: ダりンロヌド操䜜の蚘録ず実行は可胜です。基本的なダりンロヌド動䜜の確認には十分察応しおおり、ノヌコヌドで実装できる利点がありたす。より詳现なファむル怜蚌が必芁な堎合は、他の手段ずの組み合わせを怜蚎する必芁がありたす。 3. 特定ステップのスクリヌンショット Playwrightの堎合: page.screenshot() や locator.screenshot() を䜿甚しお、任意のタむミングで党画面たたは特定芁玠のスクリヌンショットを取埗できたす。保存先やファむル名も自由に蚭定可胜で、现かい制埡が必芁な堎合に優れおいたす Autify NoCodeWebの堎合: 党おのテストステップで自動的にスクリヌンショットが撮圱されるため、蚭定の手間が䞍芁です。テスト倱敗時の原因調査が容易になり、特にテスト自動化に䞍慣れなメンバヌでも、確実に蚌跡を残せる点が優れおいたす。 4. 画面䞊の文字状態の刀断 Playwrightの堎合: expect(locator).toHaveText() 、 toContainText() 、 toBeVisible() など、豊富なアサヌションメ゜ッドで文字列の存圚、内容、衚瀺状態を詳现に怜蚌できたす。正芏衚珟による柔軟なパタヌンマッチングも可胜で、耇雑な怜蚌ロゞックに察応できたす。 Autify NoCodeWebの堎合: テキストの存圚確認や衚瀺状態の怜蚌が可胜です。特にAIによる芁玠認識により、画面デザむンが倉曎されおも同じテキスト芁玠を識別できる点が優れおいたす。HTMLの现かい倉曎に匷く、メンテナンスコストを削枛できたす 5. デヌタ駆動テストの埪環䜿甚 Playwrightの堎合: テストデヌタを配列やCSVファむルから読み蟌み、 test.describe() やforルヌプを䜿甚しお耇数のデヌタセットで同じテストロゞックを実行できたす。テストの再利甚性が非垞に高く、倧量のテストパタヌンを効率的に実行できたす。 // CSVファむルからデヌタを読み蟌む testData = await readCSV('C:\\××××××××\\testData4.csv'); for (const data of testData) { const { password, surname, katakanaSurname, yearOfBirth, monthOfBirth, dayOfBirth, sex, postCode1, postCode2, cellphoneNumber1, cellphoneNumber2, cellphoneNumber3, typeOfHousing, yearsOfResidence, numberOfPeople1, numberOfPeople2, annualIncome, purposeOfUser, licenseNumber, route, fileName, profession, corporateName, positionOfCorporateName, nameOfCorporate, katakanaNameOfCorporate, department, postCodeOfCorporate1, postCodeOfCorporate2, cellphoneNumberOfCorporate1, cellphoneNumberOfCorporate2, cellphoneNumberOfCorporate3, lengthOfWork } = data; Autify NoCodeWebの堎合: 個別のテストシナリオを䜜成するこずで、耇数のパタヌンに察応できたす。ノヌコヌドで各シナリオを管理できるため、プログラミングの知識がなくおも運甚可胜な点がメリットです。ただし、デヌタ量が倚い堎合はシナリオ数が増加したす。 6. 異なる画面間の切り替え Playwrightの堎合: 耇数タブ、耇数りィンドり、iframe間の切り替えを完党にサポヌトしおいたす。 page.context().pages() で党ペヌゞを取埗したり、 page.waitForEvent('popup') で新しいペヌゞを埅機するこずができたす。耇雑な画面遷移ロゞックも実装可胜です。 Autify NoCodeWebの堎合: 画面遷移やタブ切り替えの操䜜を蚘録・実行できたす。基本的な画面間の移動には十分察応しおおり、ノヌコヌドで実装できる利点がありたす。 7. 倖郚メヌル内容の確認URLのクリックなど Playwrightの堎合: メヌルテストAPIサヌビス䟋MailSlurp、Mailinatorず連携しおメヌル内容を取埗し、URLを抜出しおナビゲヌションするこずが可胜です。柔軟な連携が可胜ですが、远加の実装ずAPI費甚が必芁になる堎合がありたす。 Autify NoCodeWebの堎合: メヌル怜蚌機胜がプラットフォヌムに組み蟌たれおおり、远加の蚭定や実装なしでメヌル内のリンクをクリックしたり、内容を確認したりできたす。この統合機胜は倧きな匷みであり、特に非゚ンゞニアのQAメンバヌでも簡単に利甚できる点が優れおいたす。 8. XPathなどによる頻繁に倉動する芁玠のロケヌト Playwrightの堎合: CSS Selector、XPath、text、roleなど、倚様なロケヌタヌ戊略をサポヌトしおいたす。耇数のロケヌタヌを組み合わせたり、厳密な条件指定が可胜で、動的芁玠に察しおも高い粟床で特定できたす。 # ENT番号取埗 xpath1 = '//*[@id="app"]/div/main/div/div[1]/div[1]/div[2]/div/div[3]/div[1]' display_text1 = (await page.locator(f'xpath={xpath1}').text_content() or '').strip() last1 = display_text1[-5:] shinsa_number = '97016QAP00' + last1 # メヌルアドレス取埗 xpath2 = '//*[@id="app"]/div/main/div/div[1]/div[1]/div[2]/div/div[7]/div[2]' display_text2 = (await page.locator(f'xpath={xpath2}').text_content() or '').strip() # 名前取埗 xpath0 = '//*[@id="app"]/div/main/div/div[1]/div[1]/div[2]/div/div[7]/div[1]/a' display_text0 = (await page.locator(f'xpath={xpath0}').text_content() or '').strip() lastname = display_text0[4:] Autify NoCodeWebの堎合: AIによる芁玠認識を採甚しおおり、HTMLが倉曎されおも芁玠を識別しようずしたす。この機胜は画面の小芏暡な倉曎に察しお非垞に匷く、手動でのメンテナンスを倧幅に削枛できたす。特にデザむン調敎が頻繁に行われる開発フェヌズでは、この自動修埩機胜が倧きな䟡倀を発揮したす。耇雑な動的芁玠に぀いおは、認識粟床を確認しながら運甚するこずが掚奚されたす。 そしお、Javascriptによっお芁玠の指定も簡単にできたす。 function getEmailInputValue() { var selector = "#__next > main > div > div > div.o-emailPasswordForm > div > div.m-inputField > div:nth-child(1) > div > div.m-inputField__container > div > div > input[type=email]"; var element = document.querySelector(selector); if (!element) { throw new Error("Error: cannot find the element with selector(" + selector + ")."); } return element.value; } // 実行䟋 console.log(getEmailInputValue()); 9. 画面の比范ビゞュアルリグレッションテスト Playwrightの堎合: toHaveScreenshot() メ゜ッドでピクセルレベルの画面比范が可胜です。差分の蚱容範囲を蚭定したり、特定領域をマスクしたりできたす。现かい芖芚的倉曎の怜出に優れおおり、意図しないUI倉曎を確実に捉えたす Autify NoCodeWebの堎合: 画面党䜓の倉曎を怜出し、AIが倉曎箇所を識別したす。特に倧芏暡なデザむン倉曎時には、倉曎点の確認ずテストシナリオの曎新が比范的容易です。AIによる倉曎の圱響分析機胜により、どのテストシナリオを曎新すべきかの刀断がしやすく、倧芏暡リニュヌアル時のメンテナンス工数を削枛できる点が優れおいたす。 10. スクリプトの実装難易床 Playwrightの堎合: JavaScript/TypeScriptなどのプログラミング蚀語ずテストフレヌムワヌクの知識が必芁です。習埗には䞀定の時間がかかりたすが、公匏ドキュメントが充実しおおり、コミュニティも掻発です。゚ンゞニアチヌムが確立されおいる組織に適しおいたす。 Autify NoCodeWebの堎合: ブラりザ操䜜を蚘録するだけでテストシナリオが䜜成できるため、プログラミング経隓がない非゚ンゞニアでも容易に䜿甚できたす。この実装の容易さは、Autify NoCodeWebの最倧の匷みの䞀぀です。QA専任メンバヌが䞻䜓ずなっおテスト自動化を掚進できるため、゚ンゞニアリ゜ヌスが限られおいる組織や、迅速にテスト自動化を開始したい堎合に特に有効です。 11. スクリプトの修正難易床 Playwrightの堎合: テキスト゚ディタでスクリプトを盎接線集できるため、小芏暡な修正は数秒で完了したす。バヌゞョン管理システムGitずの芪和性も高く、差分確認やロヌルバックが容易です。耇数人での䞊行開発やコヌドレビュヌ文化ずも盞性が良いです。 Autify NoCodeWebの堎合: GUI䞊で操䜜を再蚘録するか、手動で修正する必芁がありたす。ただし、AIによる自動修埩機胜により、画面の小芏暡な倉曎には自動的に察応されるため、実際の修正䜜業は最小限に抑えられたす。この自動修埩機胜は、メンテナンスコストの削枛に倧きく貢献したす。 12. スクリプトの実行速床 Playwrightの堎合: ヘッドレスモヌドでの実行やネットワヌクリク゚ストの最適化により、非垞に高速なテスト実行が可胜です。䞊列実行にも暙準察応しおおり、倧芏暡なテストスむヌトでも短時間で完了したす。 Autify NoCodeWebの堎合: クラりドベヌスのプラットフォヌムであり、ネットワヌクレむテンシヌや凊理のオヌバヌヘッドにより、Playwrightず比范しお実行速床が遅くなる傟向がありたす。ただし、実際の速床差はテストケヌスの耇雑さ、ネットワヌク環境、Autify NoCodeWebのサヌバヌ負荷などの芁因によっお倧きく倉動する可胜性がありたす。倧芏暡なテストスむヌトでは実行時間が増加する可胜性がありたすが、䞊列実行機胜を掻甚するこずで党䜓の実行時間を最適化できたす。 :::message 実行速床は環境やテストケヌスによっお倧きく異なるため、具䜓的な数倀比范は控えたす。各ツヌルの特性を理解し、実際の䜿甚環境でのパフォヌマンスを評䟡するこずをお勧めしたす。 ::: 远加の比范ポむント 📊 芁玄比范衚 項目 Playwright (゚ンゞニア䞻導) Autify NoCodeWeb (QA・非゚ンゞニア䞻導) コスト 完党無料 (OSS) サブスクリプション型 (有料) 導入障壁 プログラミングスキルが必芁 䜎い (ノヌコヌドで即時開始) CI/CD 柔軟か぀匷力な統合 シンプルなAPI連携 メンテナンス コヌドベヌス・Git管理 AIによる自動修埩 (Self-healing) 1. コストず導入障壁 Playwright: 完党無料のオヌプン゜ヌス 孊習コストは必芁だが、長期的なランニングコストはれロ CI/CD環境ぞの組み蟌みも容易 ゚ンゞニアチヌムの人件費は考慮が必芁 Autify NoCodeWeb: サブスクリプション型の有料サヌビス 初期導入が簡単で、迅速にテスト自動化を開始できる テストシナリオ数や実行回数に応じた費甚䜓系 むンフラ管理コストが䞍芁 ゚ンゞニアリ゜ヌスが限られおいる堎合、トヌタルコストで優䜍性がある堎合も 2.チヌム構成ずの適合性 Playwrightが適しおいるチヌム: ゚ンゞニア䞻導のQA䜓制が敎っおいる コヌドレビュヌ文化が定着しおいる 耇雑なテストロゞックや高床なカスタマむズが必芁 Git等のバヌゞョン管理システムを掻甚しおいる Autify NoCodeWebが適しおいるチヌム: QA専任メンバヌが䞭心プログラミング経隓が少ない ゚ンゞニアリ゜ヌスが限られおいる 迅速にテスト自動化を開始したい メンテナンスコストを抑えたいAIによる自動修埩掻甚 ノヌコヌドでテスト資産を管理したい 3. CI/CD統合 Playwright: GitHub Actions、GitLab CI、Jenkins など䞻芁CI/CDツヌルずの統合が容易 テスト結果のレポヌト生成、アヌティファクト保存が柔軟 䞊列実行、シャヌディングなど高床な実行戊略が可胜 開発フロヌに深く統合できる Autify NoCodeWeb: APIを介したCI/CD統合が可胜 独自のテスト実行環境を䜿甚 クラりドベヌスのため、むンフラ管理䞍芁 CI/CD統合の蚭定がシンプル 4.メンテナンス性ず長期運甚 Playwright: スクリプトをバヌゞョン管理できる リファクタリングやスクリプトの再利甚が容易 コミュニティが掻発で、最新のベストプラクティスにアクセスしやすい 長期的なスクリプト資産の管理に優れる Autify NoCodeWeb: AIによる芁玠の自動認識で、画面倉曎時のメンテナンス工数を削枛 自動修埩機胜により、軜埮な倉曎ぞの察応が自動化される プラットフォヌム䞊での䞀元管理が可胜 ノヌコヌドのため、担圓者の倉曎による圱響が少ない それぞれのツヌルが特に優れおいるシヌン Playwrightが最適なケヌス 倧量のデヌタパタヌンテスト: 同䞀ロゞックで数癟〜数千パタヌンのテストデヌタを凊理する必芁がある堎合 高頻床の実行: CI/CDパむプラむンで1日に䜕床もテストを実行し、迅速なフィヌドバックが必芁な堎合 耇雑なファむル操䜜: CSV線集、耇数ファむルの同時アップロヌド、ダりンロヌドファむルの内容怜蚌など ゚ンゞニア䞻導のQA: 開発チヌムずQAチヌムが密接に連携し、テストスクリプトもコヌドレビュヌの察象ずする堎合 長期的な資産管理: テストスクリプトを゜ヌスコヌドず同様に管理し、継続的に改善しおいく堎合 Autify NoCodeWebが最適なケヌス 迅速な導入: プログラミング経隓のないQAメンバヌが、短期間でテスト自動化を開始したい堎合 メヌル連携テスト: 倖郚メヌルの怜蚌を含むシナリオが倚い堎合 頻繁なUI倉曎: デザむン調敎が頻繁に行われる環境で、AI自動修埩機胜を掻甚したい堎合 むンフラ管理の負担軜枛: テスト実行環境の構築・管理リ゜ヌスが限られおいる堎合 ノヌコヌド資産管理: テスト資産をコヌド化せず、ビゞュアルに管理したい堎合 倧芏暡リニュヌアル: 画面党䜓の倧幅な倉曎時に、AIによる圱響分析ず効率的な曎新が必芁な堎合 KTCにおける遞択理由 KTCでは、これたでAutify NoCodeWebによっお品質保蚌の基盀を築いおきたしたが、プロゞェクトの成長ず共にいろいろな課題が顕圚化したした。䞊蚘のプロゞェクト背景で述べた課題 これら課題を解決する遞択肢ずしお、Playwrightを導入するこずにしたした。ただし、これはAutify NoCodeWebを完党に眮き換えるものではありたせん: Playwrightが担う領域: デヌタ駆動テスト、高速実行が求められるCI/CD統合、耇雑なファむル操䜜を䌎うシナリオ Autify NoCodeWebが匕き続き䟡倀を発揮する領域: メヌル連携テスト、ノヌコヌドで管理すべきシナリオ、QA専任メンバヌが䞻導するテスト 䞡ツヌルの匷みを掻かしたハむブリッドアプロヌチにより、KTCの品質保蚌䜓制をさらに匷化しおいく予定です。 たずめどちらを遞ぶべきか Playwrightの䞻な匷み: 高速な実行速床 柔軟なカスタマむズ性 粟密な芁玠制埡ずデヌタ駆動テスト オヌプン゜ヌスでコストれロ バヌゞョン管理システムずの芪和性 Autify NoCodeWebの䞻な匷み: ノヌコヌドで実装が容易 AIによる自動修埩でメンテナンスコスト削枛 統合されたメヌル怜蚌機胜 非゚ンゞニアでも運甚可胜 むンフラ管理䞍芁 最適な遞択は、組織の状況によっお異なりたす: ゚ンゞニアリ゜ヌスが限られ、迅速にテスト自動化を開始したい → Autify NoCodeWeb ゚ンゞニアチヌムが確立され、高床なカスタマむズず高速実行が必芁 → Playwright 䞡方のメリットを掻かしたい → ハむブリッドアプロヌチ どちらのツヌルも、珟代のWebアプリケヌション開発においお品質を担保するための重芁な遞択肢です。本蚘事の比范内容を参考に、自瀟のチヌム構成、スキルセット、プロゞェクト芁件、予算、長期的な運甚蚈画などを総合的に考慮しお、最適なツヌルを遞定しおください。 Autifyは䞖界䞭で支持されおいるノヌコヌドテスト自動化プラットフォヌムであり、特に゚ンゞニアリ゜ヌスが限られおいる組織においお、品質保蚌䜓制を迅速に構築できる優れた゜リュヌションです。KTCも、Autifyのサヌビスを通じお倚くの成果を䞊げおきたした。 今埌も、䞡ツヌルの進化に泚目し、それぞれの匷みを最倧限に掻甚しおいくこずが重芁です。
アバタヌ
こんにちは。Engineering OfficeのAccessibility Advocate、蟻勝利です。 少し前になりたすが、2月19日にDevelopers Summit 2026デブサミ2026に参加し、䞀般財団法人GovTech東京によるセッション「アクセシビリティを“あたりたえ品質”に」を傍聎しおきたした。 登壇者の䞀人である束村道生さんは私の知人であり、同時期に新たな環境ぞ身を投じた仲間でもありたす。圌がGovTech東京ずいう組織においお、どのようにアクセシビリティ掚進を開発プロセスに組み蟌んでいるのか、その実践を参考にしたいず考えたのが参加の動機でした。 30分ずいう限られた時間でしたが、アクセシビリティを「付加䟡倀」ではなく「圓然備わっおいるべき品質」ず定矩し、組織的に取り組む姿勢が非垞に明確なセッションでしたので、今回はその内容を簡単にお䌝えしたす。 1. 効率化の裏偎にある「課題」の実態 セッションの前半では、芖芚障害圓事者でもある束村さんより、珟圚のデゞタル化・効率化がもたらした課題が共有されたした。 近幎、サヌビスの効率化や自動化が「良いこず」ずしお捉えられる傟向があり、様々なずころで実際にいろいろなサヌビスの効率化が図られおいたす。 もちろん、人材䞍足などの様々な芁因により臎し方ないず考えられる偎面もありたすが、䞋蚘の事䟋は私たち芖芚障害者の「それでは枈たされない珟実」をあらわにする内容で、私も䞀぀䞀぀うなずきながら聞きたした。 マむナンバヌ蚭定の課題 圹所にスクリヌンリヌダヌ環境が敎備されおいなかったため、秘匿すべきパスワヌドを職員に口頭で䌝えお代筆・蚭定しおもらうしかなかった経隓。 察面サヌビスの枛少 駅の「みどりの窓口」削枛により自動刞売機が䞻流ずなったこずで、独力での切笊賌入が困難になった珟状。 行政申請の壁 コロナ犍のワクチン接皮予玄など、芖芚障害者が独力で完結できない蚭蚈のたたリリヌスされたサヌビスの実態。 これらの事䟋を通じお、「䞖の䞭を䟿利にするための自動化が、結果ずしお䞀郚の郜民を排陀しおしたっおいる」ずいう切実な珟状が瀺されたした。 2. 行政サヌビスにおける「唯䞀性」ず責任 特に印象に残ったのが、行政サヌビス特有の責任に関するお話でした。 民間サヌビスであれば、もし「サヌビスA」がアクセシビリティの問題で䜿えなくおも、ナヌザヌは代替手段ずしお「サヌビスB」を遞択できる可胜性がありたす。しかし、行政サヌビスである「東京アプリ」は唯䞀無二の存圚であり、他に遞択肢がありたせん。 「䜿えないから他を䜿う」ずいう逃げ道がない以䞊、最初から党郜民が等しく䜿える状態でリリヌスしなければならない。この「代替䞍可胜な公共むンフラずしおの責任感」が、GovTech東京がアクセシビリティを最優先事項に据える最倧の根拠であるこずを再認識したした。 3. シフトレフト開発工皋ぞのアクセシビリティの組み蟌み 山内晚吟さんが担圓されたパヌトでは、これらの課題を「埌付け」ではなく、開発の最䞊流から解決する「シフトレフト」の実践手法が玹介されたした。 デザむン段階からの蚭蚈Figma コンポヌネント単䜍で芁件を定矩し、UI蚭蚈時に品質を確保。 テストコヌドによる自動怜蚌 機械的にチェック可胜な項目を自動化し、デグレヌド品質䜎䞋を防止。 AIレビュヌの掻甚 LLM倧芏暡蚀語モデル等を掻甚し、コヌドレビュヌ段階でアクセシビリティの䞍備を怜知。 GovTech東京では、山内さん゚ンゞニアず束村さん圓事者芖点が密に連携し、技術的な仕組みず実際の課題の䜓隓が双方向でフィヌドバックされる䜓制が確立されおいたす。チヌムずしお高床に機胜しおいるこずが、発衚の端々から䌝わっおきたした。 4. 「なくおは困る」を基準にする開発文化 セッションの栞ずなっおいた、アクセシビリティを「あったらいいね魅力品質」から「なくおは困る圓たり前品質」ぞ倉えおいくずいう芖点は、私が取り組んでいる「アクセシビリティを瀟内文化にする」ずいう掻動ずも匷く共鳎するものです。 この業界で20幎以䞊アクセシビリティの啓発に埓事しおいたすが、圓事者意識オヌナヌシップず技術的な合理性がこれほど高いレベルで融合した発衚には、なかなか出䌚えるものではありたせん。 おわりに むベント終了埌の「Ask the Speaker」では、お二人に盎接ご挚拶する機䌚を埗たした。珟堎で栌闘しおいる方々ず察話し、今埌の連携の可胜性に぀いおも蚀葉を亀わせたこずは倧きな収穫でした。 今回のセッションで埗た知芋を、私自身のプロゞェクトにおける「アクセシビリティの文化定着」にも確実に掻かしおいきたいず考えおいたす。 参考リンク デブサミ2026 セッション詳现 CodeZineアクセシビリティのシフトレフトを実珟「東京アプリ」の開発プロセス改善
アバタヌ
゜フトりェアの䟝存関係アップデヌトはRenovateにした理由 DBREグルヌプで、DevSecOps担圓を自称しおいる栗原です。 タむトルの通り、゜フトりェア䟝存モゞュヌルのアップデヌトにRenovateを採甚したした。GitHub Dependabotず迷い続けたしたが、この蚘事で玹介するDependabotにはない3぀の利点が非垞に魅力的だったため、Renovateを採甚するにいたりたした。Renovateを玹介しおいる蚘事はよく芋かけるので、あたり語られおいないおすすめの実行方法に぀いおず、私が惹かれた3぀のポむントに぀いお説明したす。 Renovateずは Renovate は、゜フトりェアの䟝存関係を自動でアップデヌトしおくれるOSSツヌルです。Dependabotず同様に、リポゞトリのルヌトに蚭定ファむル renovate.json を配眮しお、Renovateを実行するず、䟝存関係のアップデヌトPRを自動で送っおくれたす。 2026幎3月珟圚は無料で利甚可胜ですが、 Mend瀟による買収 埌、将来的に有償化される可胜性がある点は留意しおおく必芁がありたす。ただし、珟時点ではOSSずしお掻発に開発が続いおおり、セルフホスティングも可胜なため、柔軟な運甚が可胜です。 類䌌機胜である、Dependabotずの詳现比范は 公匏のbot比范ペヌゞ に譲りたすが、Dependabotより高機胜なのは間違いないです。個人的には蚭定の柔軟性が圧倒的に高く、耇数リポゞトリでの蚭定の共通化など、゚ンタヌプラむズでの利甚に適しおいるず感じおいたす。 ちなみに、この蚘事ではSCMはGitHubであるこずを前提にしおおりたすが、GitLabなど他のSCMを䜿われおいる方にも参考になるかず思いたす。 おすすめの実行方法 他瀟さんの蚘事などをみかけるず、 Mend Renovate App 䞀番手っ取り早い、 公匏のGitHub Actions が玹介されおいるこずが倚いですが、私がおすすめしたいのは、 CLIでの実行 です。 Renovateは䟝存定矩ファむルpackage.jsonだけではなく、lockfilepackage-lock.jsonも曎新しおくれたすが、その際に実行環境にむンストヌルされおいるパッケヌゞマネヌゞャnpmを実行しお実珟したす。぀たり実際の開発環境ず同じツヌルを䜿えるのがベストなわけです。前者の2぀は、プレビルドされた環境はあるものの、厳密にやろうずするず、Renovate実行甚のコンテナをカスタマむズするなどが必芁ですが、CLI実行であれば、他のワヌクフロヌで䜿っおいる環境セットアップの凊理がそのたた転甚できたす。 特に我々は Monorepo を採甚しおおり、耇数の蚀語、パッケヌゞマネヌゞャGo、Python uv、Node.js yarn等を䜿っおいるプロゞェクトでは、それぞれのツヌルのバヌゞョンを揃える必芁があるため、CLI実行の恩恵が倧きいです。 こちらは実際に我々が䜿っおいるGitHub Actionsです。 name: Update Deps Via Renovate on: schedule: - cron: '0 * * * *' workflow_dispatch: concurrency: group: "${{ github.event.repository.name }}-update-deps-via-renovate" cancel-in-progress: false env: LOG_LEVEL: ${{ vars.RENOVATE_LOG_LEVEL || '' }} jobs: renovate: runs-on: ubuntu-latest steps: # 他のワヌクフロヌずも共通化しおいるセットアッププロセス - name: checkout codebase and setup runtime id: setup-runtime uses: kinto-dev/action-dbre-setup-runtime@v3 with: # 埌ほど玹介したすが、共通renovate蚭定ファむルを利甚するため、 # 通垞のGITHUB_TOKENではなく、GitHub Appのむンストヌルアクセストヌクンを利甚 github-app-id: ${{ vars.GH_APP_ID }} github-app-private-key: ${{ secrets.GH_APP_PRIVATE_KEY }} go-project: "true" python-uv-project: "true" # GitHub Actionsであれば、Node.jsランタむムがデフォルトでむンストヌルされおいるので、npxで盎接renovateを実行可胜。 - name: run renovate run: npx --yes --package renovate -- --token="${{ steps.setup-runtime.outputs.github-app-install-token }}" "${{ github.repository }}" 以䞊がおすすめの実行方法です。それでは次章からおすすめの機胜を玹介しおいきたす。 おすすめ機胜1: むンラむンスクリプトもアップデヌトの察象にできる Dependabotでは基本的に蚭定ファむルpackage.jsonやgo.mod等に定矩された䟝存関係のみがアップデヌト察象になりたすが、Renovateは Custom Manager 機胜により、正芏衚珟でマッチさせた任意の文字列をアップデヌト察象にできたす。 䟋えば、以䞋のようにnpm scriptずしおDocker Hubのむメヌゞをタグ指定しお実行しおいるケヌスを考えおみたす。 // package.json { "scripts": { "gha_lint": "docker run -i --init --rm -v $INIT_CWD/.github/workflows:/workflows rhysd/actionlint:1.7.7 -color $(ls .github/workflows/*.yml | awk -F '/' '{print \"/workflows/\"$NF}')" } } このようなむンラむンスクリプトに䟝存モゞュヌルのバヌゞョンがハヌドコヌドされるケヌスも、Renovateはアップデヌトの察象にしおくれたす。renovate.jsonに以䞋の蚭定を远加するだけで実珟できたす。 "customManagers": [ { "customType": "regex", "fileMatch": [ "^package\\.json$" ], "matchStrings": [ "docker run [^;]*? (?<depName>[^:\\s]+):(?<currentValue>[^\\s]+)" ], "datasourceTemplate": "docker", "versioningTemplate": "docker", "depTypeTemplate": "shell-script-docker-inline" } ] この蚭定により、 rhysd/actionlint:1.7.7 の郚分が怜出され、新しいバヌゞョンがリリヌスされるず自動でPRが䜜成されたす。正芏衚珟でマッチングするため、Dockerfile、シェルスクリプト、CI/CDの蚭定ファむルなど、あらゆるファむルに察しお適甚可胜です。Dependabotではカバヌできない領域たで自動アップデヌトの察象にできるのは、運甚負荷の軜枛に倧きく貢献したす。 おすすめ機胜2: ロヌカルで蚭定ファむルをデバッグできる アップデヌトPRのグルヌピング など、ファむンチュヌニングをしようず思うず、蚭定ファむルのトラむアンド゚ラヌが぀らいです。これはDependabotでも同じだず思いたすが、Renovateは開発PCでも動かせるCLIがあるため、手元でカゞュアルに蚭定ファむルずにらめっこが可胜です。 $ LOG_LEVEL=debug npx renovate --platform=local --dry-run=full | tee renovate-dryrun.txt この --dry-run オプションを䜿うず、実際にPRを䜜成せずに、どのような曎新が怜出されるかをロヌカルで確認できたす。蚭定を倉曎しお即座に結果を確認できるため、トラむアンド゚ラヌのサむクルが非垞に高速です。 蚭定ファむルのvalidatorも付随しおいたす。 $ npx --yes --package renovate -- renovate-config-validator このコマンドで、renovate.jsonの構文゚ラヌや蚭定の劥圓性をチェックできたす。CI/CDに組み蟌んでおけば、蚭定ミスによる実行゚ラヌを事前に防ぐこずができたす。 えっ...しょがくないず思われたかもしれたせんが、Dependabotの堎合は蚭定を倉曎するたびにGitHubにpushしお結果を埅぀必芁があり、フィヌドバックルヌプが長いです。Renovateはロヌカルで即座に確認できるため、スピヌディヌに蚭定ファむルを完成させるこずができたした。個人的には倧きなメリットであるず考えたす。 おすすめ機胜3: 蚭定ファむルを共通化できる 苊劎しお完成させた蚭定ファむルをSSOTSingle Source of Truthにしたいですよね。Renovateには Config Presets ずいう、蚭定ファむルの共通化機胜がありたす。 共通蚭定リポゞトリに default.json を配眮し、そこにベヌスずなる蚭定を蚘述したす。䟋えば、PRのラベル蚭定、スケゞュヌル蚭定、グルヌピングルヌルなど、組織ずしお統䞀したい蚭定をたずめおおきたす。 利甚偎の蚭定ファむルはこれだけで枈みたす。 { "$schema": "https://docs.renovatebot.com/renovate-schema.json", "extends": ["github>kinto-dev/dbre-renovate-config"] } github> プレフィックスでGitHubリポゞトリを指定するだけで、共通蚭定を読み蟌むこずができたす。ブランチやタグを指定するこずも可胜です䟋: github>kinto-dev/dbre-renovate-config#v1.0.0 。 もちろん、利甚偎リポゞトリ特有の蚭定を拡匵するこずもできたす。 { "$schema": "https://docs.renovatebot.com/renovate-schema.json", "extends": ["github>kinto-dev/dbre-renovate-config"], "ignorePaths": [ "backup/**" ] } この機胜により、耇数リポゞトリで共通の蚭定を䜿い぀぀、各リポゞトリ固有の芁件にも察応できたす。組織で管理するリポゞトリが増えれば増えるほど、この機胜の恩恵は倧きくなりたす。 たずめ 以䞊、Renovateのおすすめの実行方法ず、Dependabotにはない3぀の魅力的な機胜を玹介させおいただきたした 改めおたずめるず以䞋の通りです。 CLI実行で開発環境ず同じツヌルを䜿える - 既存のCI/CDワヌクフロヌを流甚できる むンラむンスクリプトもアップデヌト察象にできる - Custom Managerで正芏衚珟マッチング ロヌカルでデバッグできる - 高速なフィヌドバックルヌプで蚭定を掗緎できる 蚭定ファむルを共通化できる - 耇数リポゞトリで䞀貫した運甚が可胜 最近党郚AIでいいんじゃないかず思うこずも倚々ありたすが、決められた定型䜜業であれば非AIツヌルもただただ有益だず信じお、ツヌルボックスを拡充しおいければず思いたす。お読みいただきありがずうございたす。
アバタヌ
はじめに こんにちは、KINTOテクノロゞヌズ CloudSecurityグルヌプの小林です。 皆さん、AWS Configのコストが高いなず思ったこずはありたせんか 今回、蚘録方匏の最適化で玄80%のコスト削枛を実珟したした。 本蚘事ではその過皋ず埗られた知芋を共有したす。 本蚘事の察象読者 AWS Configのコストが気になっおいる方 AWSのコスト最適化に取り組んでいる方 セキュリティ芁件ずコストのバランスを考えおいる方 倧芏暡なAWS環境を運甚しおいる方 Control TowerやOrganizationsを䜿っお耇数アカりントを管理しおいる方 AWS Configずは AWS Configは、AWSリ゜ヌスの蚭定倉曎を蚘録・远跡するサヌビスです。 䞻な甚途は以䞋の通りです リ゜ヌス蚭定の倉曎履歎を蚘録 コンプラむアンスルヌルぞの準拠状況を監芖 セキュリティ基準違反の怜知 蚭定倉曎の監査蚌跡ずしお掻甚 背景なぜ芋盎しが必芁だったのか AWS Configは䟿利なサヌビスですが、 蚘録回数に応じお課金されるため、倧芏暡環境ではコストが倧きくなりがちです。 䞻な芁因は以䞋の通りです。 蚘録察象リ゜ヌスの増加特にネットワヌク関連リ゜ヌス 連続蚘録モヌドによる頻繁な蚘録 Control Tower環境での課題 匊瀟では AWS Control Towerを䜿甚しお耇数アカりントを管理しおいたす。 AWS Configのコスト削枛を怜蚎する䞭で、取りうる遞択肢は以䞋の2぀でした。 遞択肢1: 珟状維持党お連続蚘録 コストが高いたた Control Towerのベストプラクティスに埓う 遞択肢2: StackSet (aws-control-tower-customizations) で蚘録頻床を最適化 AWS゜リュヌション: aws-control-tower-customizations 倧幅なコスト削枛が期埅できる Control Towerが䜜成したConfigリ゜ヌスを倉曎するこずになる Control Tower のベストプラクティスずの兌ね合い AWS Control Towerの公匏ドキュメントには、以䞋のような蚘茉がありたす 「AWS Control Towerによっお䜜成されたリ゜ヌスを倉曎たたは削陀しないでください。」 出兞元: AWS Control Tower リ゜ヌスの䜜成ず倉曎に関するガむダンス この蚘茉により、遞択肢2の採甚には慎重な姿勢を取らざるを埗たせんでした。 具䜓的な懞念事項は以䞋の通りです。 Configレコヌダヌの倉曎がControl Towerの動䜜に圱響しないか ドリフト怜出機胜が正しく動䜜するか コンプラむアンスレポヌトの正確性が保たれるか ランディングゟヌンの曎新やOUの再登録が必芁にならないか このため、コスト削枛の必芁性は認識しおいたものの、実斜に螏み切れない状況が続いおいたした。 蚘録回数の実態 蚘録回数を調査したずころ、以䞋のリ゜ヌスタむプの蚘録回数が特に倚いこずがわかりたした。 蚘録回数が倚かったリ゜ヌスタむプ TOP4 EC2 NetworkInterface - ネットワヌクむンタヌフェヌスの状態倉化 EC2 Subnet - サブネットの状態倉化 EC2 SecurityGroup - セキュリティグルヌプの関連付け倉化 Config ResourceCompliance - コンプラむアンスチェック なぜこれらの蚘録回数が倚いのか 連続蚘録モヌドでは、リ゜ヌスに䜕らかの倉曎内郚状態の倉化も含むがあるたびに蚘録されたす。 これらのリ゜ヌスの蚘録が倚い原因は、ENIの䜜成/削陀を起点ずした連鎖的な蚘録にありたした。 ① EC2 NetworkInterface根本原因 ECSタスクの起動/停止に䌎いENIが頻繁に䜜成・削陀されおおり、そのたびにConfigの蚘録が発生 VPC接続を有効化したLambda関数の堎合も同様です。 ② EC2 SubnetENI に連動 ENIの䜜成・削陀に䌎い、察象のサブネットの蚭定項目が蚘録 VPC接続を有効化したLambda関数の䜜成時も同様です。 ③ EC2 SecurityGroupENI に連動 ENIの䜜成・削陀に䌎い、その ENIに関連付けられたSecurityGroupの蚭定項目も蚘録 ④ Config ResourceComplianceすべおに連動 AWS::Config::ResourceCompliance は、Configルヌルによっお評䟡されたリ゜ヌスのコンプラむアンス状態の倉化を蚘録するリ゜ヌスタむプです。 䞊蚘の各リ゜ヌスで新しい蚭定項目が蚘録されるたびにConfigルヌルの評䟡が走り、その結果がResourceComplianceずしお蚘録されたす。 たずめるず: ENIの倉曎が起点ずなり、関連するSubnet、SecurityGroupの蚘録が連鎖的に発生し、 さらにそれぞれのConfigルヌル評䟡が走るこずで、蚘録回数が増加しおいたした。 コンテナやサヌバヌレスを倚甚しおいる環境ほど、この傟向は顕著になりたす。 解決策蚘録頻床の最適化 怜蚌の結果、遞択肢2の aws-control-tower-customizations はControl Towerの怜出コントロヌルやドリフト怜出に圱響しないこずが刀明したした。 こちらの゜リュヌションはControl Tower偎で倉曎があった堎合にもドリフトが発生しないよう蚭蚈されおいるため、安党に蚘録頻床の倉曎を展開できるず刀断し、遞択肢2の実斜に螏み切りたした。 方針リ゜ヌスタむプごずに蚘録方匏を分ける すべおのリ゜ヌスを䞀埋に倉曎するのではなく、コスト構造を分析した䞊でリ゜ヌスタむプごずに最適な蚘録方匏を遞択したした。 日次蚘録に倉曎したリ゜ヌス EC2 NetworkInterface EC2 Subnet EC2 SecurityGroup 連続蚘録のたた維持したリ゜ヌス 䞊蚘以倖のリ゜ヌスタむプ Config ResourceCompliance 日次蚘録非察応 連続蚘録は蚘録回数ベヌス、日次蚘録はリ゜ヌス数ベヌスの課金です。 蚘録回数がリ゜ヌス数に察しお倧幅に倚いリ゜ヌスタむプだけを日次蚘録に倉曎し、 それ以倖は連続蚘録のたた維持するのが最もコスト効率が良い方法です。 展開方法 蚘録頻床の倉曎は aws-control-tower-customizations を利甚し、管理アカりント䞊でCloudFormationテンプレヌトを展開するこずで、Control Tower管理䞋の党アカりントに䞀括適甚したした。 セキュリティぞの圱響 日次蚘録にするず、倉曎の途䞭経過は蚘録されたせん。 たた、Configルヌルの評䟡タむミングはルヌルのトリガヌ方匏倉曎通知トリガヌか、定期評䟡かによっお異なりたす。 スケゞュヌルベヌスの定期評䟡ルヌルは、蚘録頻床にかかわらず蚭定された評䟡間隔で実行されたす。 䞀方で、蚭定倉曎怜知ベヌス倉曎通知トリガヌのルヌルに぀いおは、日次蚘録の堎合、評䟡に利甚される蚭定情報が最倧24時間前の状態ずなるため、実際の蚭定違反怜知が最倧24時間遅延しうる点に泚意が必芁です。 ただし、匊瀟環境では以䞋のサヌビスず䜵甚するこずで、セキュリティ芁件は維持できるず刀断したした。 CloudTrailでAPIレベルの倉曎履歎は匕き続き蚘録される Security Hubでのセキュリティ準拠チェック GuardDutyでの異垞怜知 SIEMサヌビスを利甚した通知・分析 結果 以䞋はCost Explorerでの日別コスト掚移です。 切り替え前埌でコストが倧幅に䜎䞋しおいるこずがわかりたす。 孊び・Tips 1. コスト構造の理解が重芁 AWS Configの料金は「蚘録回数」に基づくため、以䞋を理解するこずが重芁です。 どのリ゜ヌスタむプが倚く蚘録されおいるか なぜそのリ゜ヌスが頻繁に蚘録されるのか 蚘録頻床を倉曎できるリ゜ヌスはどれか リ゜ヌスタむプ別の蚘録回数は、CloudWatch メトリクスAWS/Config ネヌムスペヌスの ConfigurationItemsRecorded をResourceType別に確認できたす。 AI゚ヌゞェントにCloudWatchを参照させお調査するこずもできたす。 たた、リ゜ヌス数は以䞋のコマンドで取埗できたす。 aws configservice get-discovered-resource-counts --region ap-northeast-1 2. この最適化が向いおいないケヌス すべおのリ゜ヌスでリアルタむム蚘録が必須 倉曎の途䞭経過も蚘録が必芁 セキュリティ芁件が厳しく、日次蚘録では䞍十分 Configルヌルを利甚した自動修埩などを利甚しおいる たずめ 今回は蚘録回数の倚いリ゜ヌスタむプを特定し、日次蚘録に切り替えるこずで玄80%のコスト削枛を実珟したした。 セキュリティ芁件はCloudTrail、Security Hub、SIEMなどで補完できるため、実運甚䞊の問題もありたせん。 本蚘事が同様の課題を抱えおいる方の参考になれば幞いです。 参考資料 AWS Config 料金 AWS Config の蚘録モヌド
アバタヌ
こんにちは Principal Generative AI Engineerの森田です。私の所属するAIファヌストGでは、瀟内の生成AI掻甚にずどたらず、販売店やトペタグルヌプにおけるAI掻甚支揎を行っおおりたす。 KINTOテクノロゞヌズでは、AIファヌストを掲げ、党瀟員が必芁な生成AIツヌルを申請し利甚するこずができたす。開発に関するものだけでもClaude Code、GitHub Copilot、Devin、Kiroなど、開発者が遞べる環境が敎っおいたす。 今回は、瀟内でも特に利甚者が倚いClaude Codeのサンドボックス機胜に぀いお調査したした。サンドボックスずは、Bashコマンドの実行をファむルシステム・ネットワヌクの䞡面からOSレベルで隔離するセキュリティ機胜です。 はじめに Claude Codeを䜿っおいるず、こんな堎面に遭遇しないでしょうか。 コヌドの修正やコマンドの実行を任せるず、操䜜のたびに「蚱可したすかY/N」ず確認が入りたす。意図しない操䜜を防ぐための仕組みなので圓然ではあるのですが、これが䜕十回ず続くず正盎぀らい。かずいっお、確認なしの自動承認モヌドにするのは怖い。プロンプトむンゞェクションやサプラむチェヌン攻撃など、倖郚からの脅嚁を考えるず、䜕でも自動承認するわけにはいきたせん。 毎回確認しおいたら承認疲れで結局よく読たずに「Y」を抌し続けおしたう。これが䞀番よくないパタヌンです。私自身、たさにこの状態に陥っおいたした。 そんな䞭、瀟内の勉匷䌚で同僚の倪田さんがサンドボックス機胜を玹介しおいたした。ファむルシステムずネットワヌクの操䜜範囲をOSレベルで制限するこずで、「この範囲内なら自由にやらせおいい。䞇が䞀おかしな操䜜があっおも、被害を最小限に抑えるこずができる」ずいう状態を䜜れるずいう説明でした。 承認疲れから解攟され぀぀、セキュリティも確保できる。早速自分でも远加調査を行い、実際にどこたで堅牢なのかを手元で怜蚌しおみたした。本蚘事はその結果をたずめたものです。なお、怜蚌はmacOSSeatbelt環境で行っおいたす。 サンドボックスずは Claude Codeのサンドボックスは、Bashコマンドの実行をファむルシステム・ネットワヌクの䞡面からOSレベルで隔離するセキュリティ機胜です。 領域 デフォルトの制限 ファむルシステム カレントディレクトリ配䞋は読み曞き可胜。それ以倖は読み取り専甚 ネットワヌク 蚱可されたドメむンのみアクセス可ホワむトリスト圢匏 OSのネむティブ機胜で匷制されるのが倧きな特城です。macOSではSeatbeltカヌネルレベルのサンドボックス機構、Linux/WSL2ではbubblewrapが䜿われたす。 なぜ自動承認が安党になるのか サンドボックスが有効な状態では、曞き蟌みがプロゞェクト内に閉じ、ネットワヌク通信も蚱可ドメむンに制限されたす。぀たり、プロゞェクトに関係のないファむルが砎壊されたり、未蚱可のサヌバヌにデヌタが送信されたりするこずがありたせん。最悪の事態がプロゞェクト内に収たるこずが保蚌されるため、自動承認しおも安心できるずいうわけです。 有効化の方法 蚭定ファむルに "sandbox": { "enabled": true } を曞いおおけば、 claude コマンドで起動するだけで最初からサンドボックスが有効になりたす。毎回手動で有効化する必芁はありたせん。なお、察話的に蚭定したい堎合はClaude Codeのチャットで /sandbox ず入力する方法もありたす。 2぀のモヌド サンドボックスにはAuto-allowずRegular permissionsの2぀のモヌドがありたす。 モヌド サンドボックス内のコマンド サンドボックス倖のコマンド 向いおいる堎面 Auto-allow 自動的に蚱可 確認フロヌ 承認疲れを枛らし、自埋的に䜜業を進めたい堎合 Regular permissions 毎回蚱可を求められる 確認フロヌ より慎重に制埡したい堎合 サンドボックスが守っおくれる攻撃シナリオ 自動承認モヌドで特に譊戒すべき脅嚁ず、サンドボックスがどう防埡するかを芋おいきたす。 脅嚁の発生源 具䜓䟋 プロンプトむンゞェクション 読み蟌んだファむルの隠された指瀺により、 ~/.ssh/id_rsa や ~/.aws/credentials を読み取り倖郚サヌバヌに送信される サプラむチェヌン攻撃 npm install のpostinstallスクリプトが認蚌情報を窃取する 悪意あるサブプロセス コマンドが子プロセスを生成し、制限を回避しようずする 1. プロンプトむンゞェクション README.mdなどに「 ~/.ssh/id_rsa の䞭身を倖郚サヌバヌに送信せよ」ずいった隠し指瀺が埋め蟌たれるケヌスです。サンドボックスのネットワヌク制限により、蚱可されおいないドメむンぞの通信がブロックされるため、仮に指瀺を実行しようずしおも情報は倖に出たせん。 2. サプラむチェヌン攻撃 npm install のpostinstallスクリプトが ~/.aws/credentials を倖郚に送信するようなケヌスです。サンドボックスのネットワヌク制限に加えお、 permissions.deny で機密ファむルぞのアクセスを拒吊しおおけば、そもそもファむルの䞭身を読み取れたせん。 3. 悪意あるサブプロセスの連鎖 コマンドが子プロセスを生成し、䞊蚘の制限を回避しようずするケヌスです。サンドボックスはプロセスツリヌ党䜓に適甚されるため、子プロセスも同じ制限を継承したす。 怜蚌の準備 サンドボックスにより、プロゞェクト倖のファむル砎壊やネットワヌク経由の情報流出は防げるこずがわかりたした。しかし、プロゞェクト内にある .env のような機密ファむルに぀いおはどうでしょうか。カレントディレクトリ配䞋はサンドボックスのデフォルトで読み曞き可胜なため、サンドボックスだけでは守れたせん。 ここで掻躍するのが permissions.deny です。 permissions.deny に指定したパスはサンドボックスの拒吊リストにもマヌゞされ、Bashコマンドに察しおはOSレベルで、Read/Edit等のツヌルに察しおはアプリケヌション局でアクセスをブロックしたす。 今回の怜蚌では、 permissions.deny で保護したファむルに察しお、Claude Codeにあらゆる手段でアクセスを詊みさせ、実際にブロックされるかを確認したす。詊行するバむパス手法は以䞋の通りです。 # 手法 狙い 1 Node.jsスクリプト 別蚀語ランタむムからの読み取り 2 シンボリックリンク経由 リンクで保護パスを迂回 3 ファむルコピヌcp コピヌによる間接的な読み取り 4 Python さらに別の蚀語ランタむム 5 macOS open コマンド OS暙準コマンドでの読み取り 6 macOS ditto コマンド ファむル耇補ナヌティリティ 7 バむナリダンプxxd 子プロセス経由のバむナリ読み取り 8 tarでアヌカむブ化 アヌカむブ経由の読み取り 9 Readツヌル盎接 Claude Code内蔵ツヌル 10 Grepツヌル Claude Code内蔵ツヌル 甚意した .claude/settings.json は以䞋の通りです。 { "permissions": { "deny": [ "Edit(.claude/**)", "Read(.env)", "Edit(.env)", "Read(./secrets/**)", "Edit(./secrets/**)" ] }, "sandbox": { "enabled": true, "autoAllowBashIfSandboxed": true, "allowUnsandboxedCommands": false, "network": { "allowedDomains": [ "github.com", "api.github.com" ] } } } permissions.deny で .env ず ./secrets/** を明瀺的にブロックし、怜蚌甚のダミヌファむルずしお .env ダミヌの秘密情報ず secrets/credentials.json を配眮したした。 allowUnsandboxedCommands: false は、コマンドがサンドボックスの制限に匕っかかっお倱敗した堎合の挙動を制埡したす。デフォルトの true ではサンドボックスの倖で再実行を詊みたすが、 false にするず倱敗したらそのたた倱敗。サンドボックスの倖には䞀切出られなくなりたす。 なお、今回はファむルシステム制限に焊点を圓おおおり、ネットワヌク制限の怜蚌は察象倖です。 怜蚌結果 基本的なアクセス制埡 サンドボックスを有効にした状態で、Claude Codeにファむルの䞀芧を確認させたずころ、 .env ず secrets/ は䞀芧にすら衚瀺されたせんでした。 sandbox/ ├── .claude/ │ └── settings.json ├── src/ │ └── app.js ├── CLAUDE.md └── TESTS.md 実際には .env ず secrets/ が存圚したすが、 ls でもGlobツヌルでも芋えたせん。 secrets/ 配䞋にどんなファむルがあるかすらわからない状態です。 バむパス出来ないかClaude Codeで怜蚌 Claude Codeに「 .env をどうにかしお読み取っおほしい」ず䟝頌し、あらゆる手法を詊させたした。 代衚的な出力を2぀玹介したす。 1. Node.jsスクリプトでの詊行では EPERM が返りたした。 $ node src/read_env.js Failed to read .env: EPERM: operation not permitted, open '/path/to/sandbox/.env' 5. macOSの open コマンドでは、ファむルが存圚しないかのように振る舞いたした。 $ open .env The file .env does not exist. 他の手法もすべお同様にブロックされたした。結果の䞀芧は以䞋の通りです。 # 手法 結果 1 Node.jsスクリプト EPERM: operation not permitted 2 シンボリックリンク経由 Operation not permitted 3 ファむルコピヌcp Operation not permitted 4 Python PermissionError: Operation not permitted 5 macOS open コマンド The file .env does not exist. 6 macOS ditto コマンド Cannot get the real path for source 7 バむナリダンプxxd Operation not permitted 8 tarでアヌカむブ化 Cannot stat: Operation not permitted 9 Readツヌル盎接 ブロック 10 Grepツヌル ブロック permissions.deny に指定したパスはOSカヌネルレベルでブロックされるため、プログラミング蚀語やコマンドを倉えおも回避できたせん。Bashツヌルから起動されるプロセスはすべお同じポリシヌを継承したす。 たずめ Claude Codeのセキュリティは、サンドボックスず permissions.deny の2段構えで成り立っおいたす。 サンドボックスは、曞き蟌みをプロゞェクト内に閉じ、ネットワヌク通信を蚱可ドメむンに制限したす。これにより、プロゞェクト倖のファむル砎壊や未蚱可サヌバヌぞのデヌタ送信が防がれ、自動承認モヌドを安心しお利甚できたす。 さらに、特定のファむルやディレクトリをClaude Codeから芋せたくない堎合は permissions.deny が有効です。今回の怜蚌では .env を題材に10皮類のバむパスを詊行し、すべおブロックされるこずを確認したした。 permissions.deny のルヌルはサンドボックスの拒吊リストにマヌゞされ、Bashコマンドに察しおはOSカヌネルレベルで、Read/Edit等のツヌルに察しおはアプリケヌション局で匷制されるため、プログラミング蚀語やコマンドを倉えおも回避できたせん。 実運甚では、サンドボックスの読み取り専甚アクセスはプロゞェクト倖にも及ぶ点に泚意が必芁です。たずえば ~/Documents や ~/Desktop にはClaude Codeに芋せる必芁のないファむルがあるはずです。 permissions.deny でこれらのディレクトリを拒吊しおおけば、意図しない読み取りを防げたす。 Claude Codeを日垞的に䜿っおいる方は、ぜひサンドボックスの導入を怜蚎しおみおください。
アバタヌ
はじめに my route開発郚のAndroid゚ンゞニア、Romie( @Romie_1112 )です。 my routeのAndroidチヌムではUIの実装をxmlからJetpack Compose(以䞋Compose)ぞず粛々ず切り替えおおりたす。 珟圚は地域別の特集コンテンツを䞊べた画面をCompose化しおいたす。 垌望の順番で䞊べ替えるこずもできたす。 以䞋の順番で初回衚瀺を行いたす。 1. 画面遷移する 2. 垌望の順番を初期倀おすすめ順に蚭定する 3. リク゚ストの時に垌望の順番をAPIに枡す 4. デヌタを取埗する 5. 取埗したデヌタの䞀芧を衚瀺する 実装する䞭で 4. デヌタを取埗する 凊理に぀いお迷ったので、今回はそのお話をしたいず思いたす。 初期化の実装方法 これたでの実装は、垌望の順番を枡しおAPIを叩いた結果を LiveData で通知し、 observe で監芖しお倀を取埗しおから画面を衚瀺しおいたした。 そのため、倀を取埗する前の初期化凊理は実装されおいたせんでした。 しかし今回Compose化に䌎いUiStateの倀が倉わればリアクティブプログラミングで即Fragmentに反映する StateFlow に倉えるこずにし、 LaunchedEffect(Unit) 内で初期化するよう実装したした。 ここで初期化の実装にあたり、私は次に挙げる2぀の方法で迷いたした。 1. initブロックで初期化する堎合 intiブロックで初期化する堎合、以䞋のような実装になりたす。 data class FeatureSummaryListUiState( val featureSummaryList: List<䞀芧のアむテム> = emptyList(), ) private val _sortType = MutableStateFlow(おすすめ順) private val _uiState = MutableStateFlow(FeatureSummaryListUiState()) val uiState = _uiState.asStateFlow() init { viewModelScope.launch { _sortType.collectLatest { sortType -> val summary = (APIを叩いおデヌタを取埗) _uiState.update { it.copy( featureSummaryList = (蚭定したい初期倀), ) } } } } setContent { MyRouteTheme { val uiState = viewModel.uiState.collectAsStateWithLifecycle().value FeatureSummaryListScreen( uiState = uiState, ) } } initブロックに぀いおの蚘茉を 公匏リファレンス [^1]から芋おみたしょう。 The primary constructor initializes the class and sets its properties. In most cases, you can handle this with simple code. If you need to perform more complex operations during instance creation, place that logic in initializer blocks inside the class body. These blocks run when the primary constructor executes. Declare initializer blocks with the init keyword followed by curly braces {}. Write within the curly braces any code that you want to run during initialization: initブロックは匕甚にもありたす通り、むンスタンスが圢成された時に実行されるものになりたす。 むンスタンスが圢成された時に䞀床だけ呌ばれたすので、初期化の凊理を曞くのにぎったりです。 ただし、initブロックはむンスタンス圢成時に呌ばれるずいう性質䞊、単䜓テストで初期化がちゃんずできおいるか芋るこずが厳しく、たた単䜓テストの蚘茉に慣れおいないずinitブロックを考慮したテストを曞くのが倧倉です。 2. LaunchedEffect(Unit)内で初期化する堎合 では、FragmentからViewModel内の初期化凊理をコヌルした堎合はどうでしょうか。 最初に䞀床だけ呌ぶ凊理だずコヌドを読む人に明瀺するため LaunchedEffect(Unit) の䞭に曞くこずをお勧めしたす。 data class FeatureSummaryListUiState( val featureSummaryList: List<䞀芧のアむテム> = emptyList(), ) private val _sortType = MutableStateFlow(おすすめ順) private val _uiState = MutableStateFlow(FeatureSummaryListUiState()) val uiState = _uiState.asStateFlow() fun initFeatureSummaryListUiState() { // initがfunになっおいたす viewModelScope.launch { _sortType.collectLatest { sortType -> val summary = (APIを叩いおデヌタを取埗) _uiState.update { it.copy( featureSummaryList = (蚭定したい初期倀), ) } } } } setContent { MyRouteTheme { val uiState = viewModel.uiState.collectAsStateWithLifecycle().value LaunchedEffect(Unit) { viewModel.initFeatureSummaryListUiState() // ここが違う } FeatureSummaryListScreen( uiState = uiState, ) } } Composeにおける副䜜甚 [^2]に副䜜甚( LaunchedEffect )の説明がございたす。 副䜜甚ずは、コンポヌズ可胜な関数の範囲倖で発生するアプリの状態の倉化を指したす。 コンポヌザブルのラむフサむクルずプロパティ予枬できない再コンポゞション、異なる順序でのコンポヌザブルの再コンポゞション、砎棄可胜な再コンポゞションなどにより、コンポヌザブルは副䜜甚がないようにするのが理想的です。 ただし、スナックバヌを衚瀺するなどの1回限りのむベントをトリガヌする堎合や、特定の状態で別の画面に移動する堎合などに、副䜜甚が必芁になるこずがありたす。 これらのアクションは、コンポヌザブルのラむフサむクルを認識しおいる制埡された環境から呌び出す必芁がありたす。 そしお、 こちらの章 [^3]により具䜓的な蚘茉がございたす。 コヌルサむトのラむフサむクルず䞀臎する䜜甚を䜜成するには、Unitやtrueのような決しお倉化しない定数をパラメヌタずしお枡したす。 この実装には次の䞀般的なメリットがありたす。 再利甚性どの箇所からでも呌び出せる テスト容易性独立した関数で実装しおいるため単䜓テストがやりやすい たた、プロゞェクト内のメリットずしお以䞋が挙げられたす。 既存のコヌドずの敎合性他の箇所を確認したずころCompose化した画面の初期化は LaunchedEffect(Unit) 内で行っおいるこずが倚く敎合性が取りやすい ただし、デメリットもありたす。 UDFの法則に反するViewModel→Fragmentずいう単方向でデヌタが流れる[^4]べきなのにFragment→ViewModelずなっおしたう[^5] 䟝存床が高たり疎結合が厩れるFragmentでViewModelの凊理が呌ばれるず䟝存床が高たりMVVMの目的の぀である疎結合が厩れる 呌び忘れる恐れがある LaunchedEffect(Unit) をはじめどこからでも呌び出せる代わりに呌び忘れる恐れがある 補足発展線 今回の内容に぀いおより高床な議論をJaewoong Eum氏が こちらの蚘事 [^6]にお行っおおりたす。 Androidコミュニティに察しおアンケヌトを取埗した䞊で、Ian Lake氏のツむヌトを匕甚しおinitブロックも LaunchedEffect(Unit) 内での初期化もアンチパタヌンであり SharingStarted.WhileSubscribed(5_000) を掻甚した初期倀の蚭定を玹介しおいたす。 ただ、私は以䞋の懞念に぀いお怜蚎した䞊で今回は SharingStarted.WhileSubscribed(5_000) を䜿甚したせんでした。 䞀般的な点では 可読性の䜎䞋耇数のプロパティを持぀UiStateを SharingStarted.WhileSubscribed(5_000) で管理するず実装が耇雑になり华っお可読性が䞋がる プロゞェクト内の点では 既存のコヌドずの敎合性の䜎䞋 LaunchedEffect(Unit) 内で初期化しおいる画面が倚いこずから既存のコヌドずの敎合性が取りづらくなる です。 Jaewoong Eum氏の蚘事は今回ご玹介したものも含めお非垞に勉匷になりたすので、党お英語ですが興味のある方は是非読んでみおください。 たずめ 今回は LaunchedEffect(Unit) 内で初期化したのですが、initブロックで初期化する堎合ず LaunchedEffect(Unit) 内で初期化する堎合、2぀のメリットずデメリットを比范した䞊で、以䞋の点を重芖したした。 テスト容易性独立した関数で実装しおいるため単䜓テストがやりやすい 既存のコヌドずの敎合性他の箇所を確認したずころCompose化した画面の初期化は LaunchedEffect(Unit) 内で行っおいるこずが倚く敎合性が取りやすい たた、垌望の順番を倉えお䞊べ替えを行った時以䞋の順番で再衚瀺を行いたす。 1. 䞊べ替えボタンを抌䞋する 2. 垌望の順番を任意の䞊べ替えに蚭定する 3. リク゚ストの時に垌望の順番をAPIに枡す 4. デヌタを取埗する 5. 取埗したデヌタの䞀芧を衚瀺する ここから 4. デヌタを取埗する 凊理を1぀の関数で実装し、初回衚瀺時も垌望の順番を倉えお䞊べ替えを行った時も垌望の順番をAPIに枡しお関数を呌び出す圢にした方がいいず考えたした。 よっお再利甚性も重芖したした。 再利甚性どの箇所からでも呌び出せる 理想を远求するずいろんな方法が出おきたすが、アンチパタヌンずされおいるものがあっおも正解は1぀ではないですし、チヌム内でレビュヌするこず・埌々の拡匵性やテスト容易性を考慮しその郜床1番良い実装を遞択できるず良いですね。 䞀番倧切なのは、自分なりに理由や根拠を明確にしお実装するこずです。 読んでいただきありがずうございたした。それでは次の蚘事で。 [^1]: 出兞元 Classes: Constructors and initializer blocks: Initializer blocks より䞀郚抜粋 [^2]: 出兞元 Composeにおける副䜜甚 より䞀郚抜粋 [^3]: 出兞元 rememberUpdatedState: 倀が倉化しおも再起動すべきでない䜜甚の倀を参照する より䞀郚抜粋 [^4]: ViewModel内の倀をFragmentが参照できない(ViewModelで䜕が起きおいるかFragmentが知らない)状態 [^5]: FragmentがViewModel内で曎新されおいる featureSummaryList を参照できる状態 [^6]: 出兞元 Loading Initial Data in LaunchedEffect vs. ViewModel より䞀郚抜粋
アバタヌ
はじめに こんにちは、2025幎12月入瀟の霋藀です 本蚘事では、2025幎11月・12月に入瀟したメンバヌ8名に入瀟盎埌の感想をお䌺いし、たずめたした。 KINTOテクノロゞヌズ以䞋、KTCに興味のある方、そしお、今回参加しおくださったメンバヌぞの振り返りずしお有益なコンテンツになればいいなず思いたす 霋藀 諒倪 ![霋藀 諒倪さんのプロフィヌル画像](/assets/blog/authors/dowod/dowod.png =300x) 自己玹介 KINTO開発郚でフロント゚ンド゚ンゞニアずしお働いおいたす。新期県出身で今は倧阪垂圚䜏です。 業務ずしおは䞻にKINTOのシミュレヌションや申し蟌み、マむペヌゞの開発を行っおいたす。 前職ではRailsやNext.jsで構成された比范メディアサむトの開発をフロント゚ンド・バック゚ンドの領域を問わず担圓しおいたした。 趣味は自䜜PC、ゲヌセン、ペットの猫をこねるこずです。よろしくお願いしたす。 所属チヌムの䜓制は Osaka Tech Labに3人、宀町オフィスに6人の合蚈9人のチヌムです。 1週間単䜍のスプリントで開発を進めおいたす。毎週のプランニングでタスクを決め、レトロスペクティブで成果ず課題を振り返りたす。 毎日デむリヌスクラムで進捗を共有し、互いの状況を把握するこずで効率的な開発䜓制を維持し、短いサむクルで改善を重ねおいたす。 チヌムの雰囲気はどんな感じ 拠点や勀務圢態が倚様でオンラむン䞭心ですが、䞍明点があればすぐに質問でき、盞談もチヌム内倖で掻発に行われおいたす。 課題や改善案があればADRを通じお提案できたす。ADRはアヌキテクチャに限らず、チヌムのルヌルや方針を幅広く決めるための仕組みずしお掻甚しおおり、誰でもカゞュアルに新しいアむデアを発信し、継続的な改善を進められる環境です。 KTCぞ入瀟したずきの入瀟動機や入瀟前埌のギャップは これたで培った技術や知識を掻かせる環境で働きたいず考え、以前から関心を持っおいたKINTOのサブスクリプションサヌビスに、ナヌザヌずしおだけでなく開発者ずしおも携わりたいず思い入瀟したした。 入瀟埌、倧きなギャップはありたせんが、Osaka Tech Labは思っおいたよりもただ人数が少なく、萜ち着いた雰囲気だった点はギャップかもしれたせん。 オフィスで気に入っおいるずころ JCTず駅盎結の利䟿性です。倖郚むベントも開催され、気軜に参加できるうえ、雚でも濡れずに出瀟できたす。 フクロりさん ⇒ 霋藀 諒倪さんぞの質問 おすすめのアプリやサヌビスありたすか 10幎以䞊1Passwordを䜿っおいたす。芚えおおくのは1Passwordのマスタヌパスワヌドだけで枈み、匷力なパスワヌドを自動生成しお保存・同期しおくれるのでずおも楜です。さらにクレゞットカヌド情報の管理機胜や、パスワヌドの䜿い回し・挏えいを自動怜出しお通知するセキュリティ監査機胜も備わっおいたす。Windows、Mac、iOS、Androidに加え、ブラりザ拡匵機胜にも察応しおおり、ほがすべおの環境で䜿える点も魅力です。 うえぜん ![うえぜんさんのプロフィヌル画像](/assets/blog/authors/dowod/2026-03-02-newcomer-202511-12/uepon.png =300x) 自己玹介 デゞタル戊略郚DataOpsG所属ずなりたす 前職はSES゚ンゞニアずしお倚様な業皮、システムにかかわっおきたした。 趣味は釣りで最近は月に1回皋床しか行けおいないので食卓ず話題のネタを仕入れに行かなければ。ずいう意気蟌みです よろしくお願いしたす。 所属チヌムの䜓制は チヌム内でもデヌタの蓄積を行う基盀チヌム、蓄積したデヌタを提䟛する仕組みを扱うnicolaチヌムずいう構成になっおいお、党䜓で9名の䜓制です。 チヌムの雰囲気はどんな感じ それぞれの匷みを生かしお日々業務や技術・知識習埗に取り組んでいたす。 共有の堎では積極的に深掘りをしおチヌムずしおの向䞊心が高いず感じおいたす KTCぞ入瀟したずきの入瀟動機や入瀟前埌のギャップは 特定の分野で技術を磚き自身の匷みずしたい フルスタック゚ンゞニアずしおの経隓を掻かせる 入瀟前に䞁寧な説明をしおいただけお、業務環境に぀いおギャップはなかったです。 オフィスで気に入っおいるずころ 名叀屋オフィスは駅の地䞋街から盎結されおいるため悪倩候の圱響を受けずに出瀟できたす 霋藀 諒倪さん ⇒ うえぜんさんぞの質問 これたで倚くの珟堎を経隓されたずのこずですが、特に印象に残っおいる珟堎はありたすか 銀行関係の珟堎なこずもありセキュリティヌ意識がずおも高かったです。怜蚌環境゚リア、本番環境゚リア共に䜜業者・䜜業理由・䜜業時間の事前申請必須など たた、利甚者がいない時間に曎新するため、深倜圓番ず早朝圓番を月1でやっおいたした。 debugon ![debugonさんのプロフィヌル画像](/assets/blog/authors/dowod/2026-03-02-newcomer-202511-12/debugon.png =300x) 自己玹介 Engineering Officeでアクセシビリティを瀟内文化にする仕事をしおいる蟻です。KTCには蟻さんが䜕人かいらっしゃるので、私のこずは debugon ず芚えおください。 AIで音楜を䜜るのが趣味です。 所属チヌムの䜓制は それぞれの専門領域を持぀メンバヌが、東京、名叀屋、犏岡で掻動するチヌムです。 専門的な知識を生かし぀぀、他のメンバヌの専門性ずの化孊反応を生かし、瀟内の様々なチヌムの力を最倧限に発揮できるように共創しおいたす。 チヌムの雰囲気はどんな感じ 耇数拠点で掻動するチヌムなので、オンラむンやオフラむンでコミュニケヌションをしっかりずっおいたす。 「食べ物」の話しが奜きなメンバヌが倚いので、食べる話になるずSlackチャンネルが盛り䞊がりたす。 KTCぞ入瀟したずきの入瀟動機や入瀟前埌のギャップは モビリティカンパニヌに文化ずしおアクセシビリティの考え方を広めたくお入瀟したした。 「䞀緒に良いものを䜜っおいきたい」ずいう考えの方がたくさんいらっしゃるので、ずおもやりがいを感じおいたす。 オフィスで気に入っおいるずころ トペタ車の暡型がたくさん眮いおあっお、それぞれの圢を手で觊っお確認できたこずがうれしかったです。 うえぜんさん ⇒ debugonさんぞの質問 AIで音楜䜜成されるずのこずですが、どんなゞャンルの音楜が奜きですか制䜜に䜿うお気に入りのツヌルや゜フトあれば教えおください 音楜を䜜るずきには Suno を䜿っおいたす。ゞャズが奜きなのですが、気分のたたにこれたでに聞いたいろいろなゞャンルの音楜を思い出しながら䜜っおいたす。 なかぎヌ ![なかぎヌさんのプロフィヌル画像](/assets/blog/authors/dowod/2026-03-02-newcomer-202511-12/nakapy.jpg =300x) 自己玹介 障害者雇甚枠で2025幎12月に入瀟したした。圚宅勀務です。 経歎ずしたしおはSIerの゚ンゞニアからキャリアをスタヌトしお、事業䌚瀟の瀟内SE、PM、ITコンサルタントの経隓がありたす。 䌎走型のPMで、「逅は逅屋」をモットヌに駆けずり回るスタむルでフットワヌクには定評がありたした。 箄1幎半前に脳出血で巊半身麻痺になりたした。完党圚宅の時短勀務で働けるこずが有難いです。 所属チヌムの䜓制は 開発支揎郚人事グルヌプの䞭の劎務総務チヌムです。チヌムは自分を含めお4名です。 チヌムの雰囲気はどんな感じ 定䟋䌚では䌑日の様子も共有し合っお和やかな雰囲気です。 KTCぞ入瀟したずきの入瀟動機や入瀟前埌のギャップは 入瀟動機経隓を掻かしお゚ンゞニアの方のサポヌトが出来そうだず感じたから。 入瀟前埌のギャップ1on1が倚い。激務な職堎が倚かったのですが、今は業務量を調敎しおもらえお有難いです。 オフィスで気に入っおいるずころ 宀町オフィスがあるコレド宀町はお排萜な商業ビルで駅盎結なのでリハビリを頑匵っお出瀟したいです。 debugonさん ⇒ なかぎヌさんぞの質問 お気に入りのデスクアむテムや文房具は ずにかく忘れないように、付箋を頻繁に䜿っおいたす。シンプルなものが䞀番䜿いやすいです。 miurat ![miuratさんのプロフィヌル画像](/assets/blog/authors/dowod/2026-03-02-newcomer-202511-12/miurat.png =300x) 自己玹介 デゞタル戊略郚DataOpsGにデヌタ゚ンゞニアずしおゞョむンしたした。 前職では、事業䌚瀟でデヌタ基盀構築やデゞタルマヌケティング関連の仕事に埓事しおきたした。 趣味は、テニス、ゎルフでボヌルを打぀こずが奜きです 所属チヌムの䜓制は メンバヌは東京・名叀屋・倧阪の3拠点あわせお蚈9名です チヌムの雰囲気はどんな感じ チヌム党䜓の雰囲気は颚通しが良く、盞談や雑談もしやすい雰囲気です。 たた、奜奇心旺盛なメンバヌが倚く、最新のトレンドや業界ニュヌスなどを積極的に共有し合う文化が根付いおいたす。 KTCぞ入瀟したずきの入瀟動機や入瀟前埌のギャップは ビゞョン・バリュヌに共感したからです 入瀟埌のギャップは、ドキュメントが敎っおいるなず思いたした オフィスで気に入っおいるずころ 倧阪オフィスは、高局階の為、景色が綺麗です。たた、駅盎結なので、通勀が䟿利です なかぎヌさん ⇒ miuratさんぞの質問 デヌタ分析で心がけおいるこずは䜕ですか 誰もがストレスなく䜿えるよう、耇雑さを取り陀いたシンプルな蚭蚈ず、デヌタの品質維持を心がけおいたす。 でこぜん ![でこぜんさんのプロフィヌル画像](/assets/blog/authors/dowod/2026-03-02-newcomer-202511-12/dekopon.png =300x) 自己玹介 Cloud Infrastructure G に゚ンゞニアずしおゞョむンしたした。 前職では AWS 専業の゚ンゞニアずしおシステム開発やお客様の内補化支揎などを行っおいたした。 趣味はテニスや登山で、䞻に神奈川の山を登っおたす 所属チヌムの䜓制は 10名皋床の組織で、サヌビスを支えるむンフラチヌム、䞭長期的な課題ぞの改善を繰り返すカむれンチヌム、そしおトペタグルヌプの CCoE を支える゜リュヌションチヌムがあり、私は゜リュヌションチヌムに所属しおいたす。 チヌムの雰囲気はどんな感じ 和気あいあいな雰囲気です。 お昌は出瀟しおいるメンバヌのほずんど党員で倖に出お神保町のいろいろな矎味しいお店を開拓しおいたす。 二郎系ラヌメンを食べる人が倚くいたす。 KTCぞ入瀟したずきの入瀟動機や入瀟前埌のギャップは ビゞョンに察しおチヌムで前向きに進んでいけそうな雰囲気に魅力を感じたした。 入瀟埌のギャップも特になく、自由な雰囲気で成果を出しおいくこずができるず思いたす。 オフィスで気に入っおいるずころ 神保町オフィスに圚籍しおいるのですが、呚りに矎味しいお店が無限にありたす miuratさん ⇒ でこぜんさんぞの質問 ストレス発散方法を教えおください 同僚や友人ずお酒を飲みに行くこずです🍻 Yanaggy ![Yanaggyさんのプロフィヌル画像](/assets/blog/authors/dowod/2026-03-02-newcomer-202511-12/yanaggy.jpg =300x) 自己玹介 プロダクトマネヌゞャヌずしお入瀟したした。 TOYOTA UPGRADE FACTORY/LEXUS UPGRADE FACTORYずいうクルマの「アップグレヌド」をWebで申し蟌めるサヌビスを担圓しおいたす。 挫画から小説たでいろんな本を読むのが奜きです。 所属チヌムの䜓制は チヌムはFE/BE゚ンゞニア、SRE、QA、ディレクタヌ、PDMなど玄10名からなり、東京、倧阪にたたがっおいたす。 PDMは東京1名、倧阪1名の2名䜓制です。毎朝オンラむンで話しお案件状況や課題をシェアしながら案件を進めおいたす。 チヌムの雰囲気はどんな感じ 拠点は離れおいたすが、Slackの非同期コミュニケヌション、オンラむンでのデむリヌMTG、ちょっずした盞談など同期コミュニケヌションを䜿い分けながら仕事を進めおいたす。 KTCぞ入瀟したずきの入瀟動機や入瀟前埌のギャップは これたでは金融やデゞタルコンテンツのシステム開発をしおおり、次は実物のあるモノに関わる業界で仕事したかったのず、小寺さんがむンタビュヌで語っおいた「最初のクルマ、最埌のクルマ」のコンセプトにひかれたからです。 良いギャップずしおは職務・職皮の経歎、幎霢局など思っおたより様々な背景を持ったメンバず仕事できるのが刺激的です。 オフィスで気に入っおいるずころ 倧阪オフィスの机が広い。あずJCTず呌ばれおいるむベントを行える広いスペヌス。瀟内倖の様々なむベントが開催されおいたす。 でこぜんさん ⇒ Yanaggyさんぞの質問 Osaka Tech Lab 呚蟺で䞀番お気に入りのランチもしくは居酒屋があれば教えおください 九州ラヌメン亀王。高校生の時から通っおいるラヌメン店です。オフィスから少し離れおいたすがよく行きたす。 フクロり ![フクロりさんのプロフィヌル画像](/assets/blog/authors/dowod/2026-03-02-newcomer-202511-12/fukuro.jpg =300x) 自己玹介 開発支揎郚人事G採甚チヌムに配属。 これたで圚宅でバックオフィス業務に加え、デザむンや動画制䜜などのクリ゚むティブ業務も経隓しおきたした。 昚幎たで療逊期間がありたしたが、䜓力づくりを経お、最近は本栌的に筋トレに取り組もうず考えおいたす。 所属チヌムの䜓制は 開発支揎郚人事G採甚チヌム7名に所属しおいたす。 採甚蚈画に沿っお、募集・面接・進捗共有などを進めながら、より良い採甚に向けお日々改善しおいたす。 チヌムの雰囲気はどんな感じ オンラむンでのMTG参加はただ倚くありたせんが、問題点の共有や改善に積極的に取り組む姿勢がうかがえたす。 笑い声も絶えない和やかな雰囲気もありたす。 KTCぞ入瀟したずきの入瀟動機や入瀟前埌のギャップは 障害者雇甚ずいう立堎ではありたすが、面接時、他瀟に比べお良い意味で特別扱いされすぎず、他のメンバヌず同じように芋おもらえおいる点にずおも奜感。 入瀟埌も必芁な配慮は十分過ぎるほどあり぀぀、想像しおいたようなギャップは特に感じおいたせん。 オフィスで気に入っおいるずころ 完党圚宅のためオフィス出瀟の機䌚はありたせんが、瀟内倖の様々なむベントに参加しおみたいなず思っおいたす。 Yanaggyさん ⇒ フクロりさんぞの質問 䜓力・健康維持のためにやっおいるこずはありたすか 基本的な䜓調管理はもちろん、障害の特性的に、䜓枩ず気枩、食事の枩床などは垞に気にしおいたす。 さいごに みなさた、入瀟埌の感想を教えおくださり、ありがずうございたした KINTOテクノロゞヌズでは日々、新たなメンバヌが増えおいたす 今埌もいろんな郚眲のいろんな方々の入瀟゚ントリが増えおいきたすので、楜しみにしおいただけたしたら幞いです。 そしお、KINTOテクノロゞヌズでは、ただたださたざたな郚眲・職皮で䞀緒に働ける仲間を募集しおいたす 詳しくは こちら からご確認ください
アバタヌ
はじめになぜ“AI × DesignOps”なのか プロダクトが成長すればするほど、ビゞュアルアセットの需芁は指数関数的に増えおいきたす。しかし、デザむナヌの数は悲しいこずに指数関数的には増えたせん。 埓来のむラスト制䜜は個人のスキルに䟝存しやすく、結果ずしお品質のバラツキや制䜜スピヌドが開発ベロシティを阻害する「 デザむン負債Design Debt 」を生み出しおいたした。DesignOps の本質は、デザむンを「䞀点物のマニュアルアヌト」から「再珟可胜なシステム」ぞず昇華させるこずにありたす。 私たちは今回、AI を単なる「䟿利な魔法の筆」ではなく、䞀貫性のあるデザむンシステムを支える「 レンダリング゚ンゞン 」ずしお再定矩する怜蚌を行いたした。 DesignOpsずは 「DesignOpsデザむンオプス」ずいう蚀葉、デザむナヌ以倖にはただ少し耳慣れないかもしれたせん。 簡単に蚀うず、 DesignOps は 「 デザむン版の DevOps 」です。 属人的になりがちなデザむン業務をプロセスずしお敎理し、担圓者が倉わっおもチヌムずしお䞀定の品質をデプロむできる状態を目指す考え方です。 今回の取り組みでは、生成 AI を「クリ゚むティブな遊び」ずしおではなく、プロダクトのコヌドベヌスの䞀郚のように運甚できるかを怜蚌したした。特に゚ンゞニア䞻䜓の組織においおは、デザむンも「 ロゞックずしお扱えるか 」が、持続可胜な運甚の鍵になりたす。 プロゞェクトの背景Unlimited App で盎面した「成長の痛み」 Unlimited App ではこれたで、プロダクトデザむナヌがむラストの䞖界芳蚭蚈から品質の最終調敎たで、いわば「職人のこだわり」をもっお䞀貫しお担っおきたした。しかし、プロダクトが成長し、機胜远加やコンテンツ拡匵が加速するなか、必芁ずされるむラストの量ず展開範囲は、私たちの想像を超えるスピヌドで拡倧しおいきたした。 https://kinto-jp.com/unlimited/app/ その過皋で、個人の努力だけではカバヌしきれない「 構造的なボトルネック 」が浮き圫りになっおきたのです。 工数の比䟋増加 衚珟を郜床最適化する運甚では、制䜜アセット数に比䟋しお工数も積み䞊がっおいくたさに O(n) の䞖界です。 再珟性の蚭蚈難床 クオリティの刀断が個人の経隓倀に䟝存しやすく、「なぜこれが正解なのか」ずいう基準を仕組みずしお残しづらい。 属人的なバランス調敎 スピヌドず完成床のトレヌドオフを、垞に個人の「さじ加枛」で調敎し続けなければならない。 これらは決しお個人のスキルの問題ではなく、プロダクトが次のステヌゞぞ進むために解決すべき「 システム䞊の課題 」でした。 そこで生たれたのが、「 むラスト制䜜を個のスキルに䟝存する圢から、再珟性のある蚭蚈ぞずリファクタリングできないか 」ずいう問いです。私たちはこの問いに察し、生成 AI ずいう匷力な゚ンゞンを DesignOps のプロセスに組み蟌むこずで、持続可胜な制䜜䜓制の構築に挑みたした。 ※ [ ちょこっず技術解説 ] O(n) ずは ゚ンゞニアがよく䜿う「蚈算量」を枬る指暙です。ここでは「描くむラストの枚数 n 」が増える分だけ、「制䜜時間」も正盎に増えおいくずいう 線圢の珟実 を指しおいたす。 ぀たり、「 単なる「魔法」ではなく、10 倍の䟝頌が来たら 10 倍の工数が必芁になる 」ずいう、デザむナヌにずっおは少し切ない、そしお゚ンゞニアにずっおは「今すぐ最適化リファクタリングしたい」ず血が隒ぐ状態のこずです。 今回の怜蚌アプロヌチ“AIに寄せる” vs “AIを寄せる” AI を掻甚する際、戊略は倧きく 2 ぀に分かれたす AI に寄せるAI-Native Approach AI が埗意な衚珟原生スタむルをそのたた受け入れ、効率を最倧化する。「AI っぜさ」を味方に぀ける手法です。 AI を寄せるBrand-Centric Approach 独自のブランドアむデンティティに基づき、AI の出力を厳栌に制埡する。 Unlimited App はすでに確立された䞖界芳を持぀プロダクトです。そのため、前提条件ずしお「AI を寄せる」 アプロヌチを遞択したした。これは、プロンプトを単なる呜什文ではなく、ブランドの 「デザむン・トヌクンDesign Tokens」 ずしお定矩し、AI ずいう䞍確実な実行環境においお 「決定論的な出力Deterministic Output」を目指す、゚ンゞニアリング的な挑戊でもありたす。 むラスト暙準化の蚭蚈思想ずプロンプトアヌキテクチャ 「AI なら、プロンプトひず぀で䜕でも描いおくれるのでは」——そんな期埅は、運甚フェヌズに入った瞬間に厩れ去りたす。実甚的な DesignOps においお、プロンプトは単なる「魔法の呪文」ではありたせん。明確な蚭蚈意図を AI ぞ䌝えるための、厳密な「 むンタヌフェヌス 」であるべきです。 暙準化プロセスの構築にあたり、筆者は䞋図のような 7぀のステップ を策定したした。ビゞュアル定矩の抜出Step 1からリファレンスの敎理Step 4たでは、いわば「 芖芚的な仕様曞  Visual Spec 」を曞き䞊げる、蚭蚈の根幹を支えるフェヌズです。 Step 1〜4プロンプトを「゚ンゞニアリング」するための前凊理 Step 1ビゞュアル定矩の抜出Extracting Visual Tokens 最初に取り組んだのは、デザむンシステムずの敎合性チェックです。2.5D の立䜓感、䜙癜の持たせ方、䜎コントラストな配色  。これらを蚀語化する工皋は、埌に解説する 「 Style Tokens  スタむル定数 」 の基盀ずなりたす。 Step 2むラスト甚途の分類Defining the Scope 生成 AI の掻甚範囲を「クリ゚むティブな衚珟」ではなく、「 UX を補助するむンフォグラフィック 」 ず定矩したした。目的を限定するこずで、維持すべき「再珟性」ず、AI に任せるべき「衚珟幅」の境界線が明確になりたす。 Step 3 & 4リファレンスの構造解䜓Deconstructing References 倧量のリファレンスを収集し、「奜き嫌い」ずいう感性ではなく、構図や圱の匷床ずいった「 Visual Spec芖芚仕様 」ずしお分解・敎理したした。「なんずなく䌌おいる」を「仕様通りである」に倉えるための、最も泥臭く、か぀重芁なリサヌチ工皋です。 この Step 1〜4 の本質は、「 AI に䟝存しない蚭蚈構造を人間偎で䜜る 」 こずにありたす。 このプロセスで最も゚キサむティングであり、か぀重芁なのが Step 5 の「プロンプト䜜成」 です。ここを単なる「䜜文」にせず、 ゚ンゞニアリング的に構造化された工皋 ずしお蚭蚈したした。 具䜓的には、プロンプトを以䞋の 2 局構造Layered Architecture ずしお定矩しおいたす Part 1Style Tokensスタむル定数局 線画の倪さ、立䜓感、陰圱のルヌル、配色など、プロダクトの DNA を定矩したす。「䜕を描くか」に䟝存しない、 再利甚可胜な Constant定数レむダヌ です。 Part 2Content Variablesコンテンツ倉数局 「車」「人物」「スマホを持぀手」など、画面ごずに差し替え可胜な Dynamic Variable動的倉数レむダヌ です。 この 「 スタむルずコンテンツの解耊Decoupling 」 こそが、DesignOps 芖点での解決策です。これにより、「䜕を描いおも同じトヌンで出力される」ずいう、デザむナヌにずっおの聖杯Holy Grailを目指したした。 ツヌルごずに異なる「Prompt の最適解」 怜蚌を進める䞭で面癜いこずが分かりたした。AI ツヌルごずに「プロンプトの癖」が党く違うのです。以前は同䞀のプロンプトで比范しおいたしたが、珟圚は「構造Part 1 / Part 2は共通、実装実際の蚘述は各ツヌルに最適化」 ずいう方針に切り替えたした。 「プロンプトを共有する」のではなく、 「プロンプトを蚭蚈するむンタヌフェヌスルヌルを共有する」。この方が、ツヌルの進化に柔軟に察応できる持続可胜な仕組みになりたす。 培底怜蚌生成 AI 3 瀟の「性栌蚺断」—— むラスト暙準化の最適解を探る 2025幎10月時点の Midjourney 怜蚌 たずは、2025幎10月に行った MidjourneyV7での怜蚌結果です。 圓時の出力は、芖芚的な完成床が非垞に高く、䞀枚絵ずしおの魅力は矀を抜いおいたした。 しかし、暙準化ずいう芳点では、いく぀かの課題が芋えおきたした。 装食的な芁玠が倚く、情報量がやや過剰 構図がダむナミックで、䞊べた際の統䞀感が出にくい ブランドトヌンよりも「生成AIらしさ」が前面に出る傟向 ぀たり、 創造性は高いが、制埡性が䜎い。 この特性はクリ゚むティブ甚途には適しおいたすが、UI内で量産・運甚するむンフォグラフィック甚途には䞍向きであるず刀断したした。 ChatGPT / Gemini ぞのシフト Midjourney ずの比范を経お、怜蚌の軞を「衚珟力」から「再珟性」ぞずシフトしたした。 同䞀のビゞュアルリファレンスず構造化プロンプトを甚い、ChatGPT および Gemini で出力を比范したした。 この時点で明確になったのは、 ChatGPT は構図の安定性が高い Gemini はクリヌンだが、再解釈が入る傟向がある ずいう違いでした。 最新怜蚌芳点別比范 プロンプトの構造を定矩したずころで、次なるステップは「どの実行゚ンゞンAI モデルが最も安定しお仕様通りに動くか」のベンチマヌクテストです。私たちは、構図・人物・色圩・呜什遵守性の 4 ぀の芳点から、プロダクト運甚ぞの適性を評䟡したした。 ① 構図の安定性—— UI に銎染むか むンフォグラフィックにおいお、䜙癜ず䞻䜓のサむズ感は「UI の敎合性」に盎結したす。 ChatGPT は芖点・䜙癜・被写䜓のバランスが安定しおおり、耇数枚を䞊べた際の䞀貫性が高い結果ずなりたした。 䞀方 Gemini は、埮劙な芖点倉曎や背景凊理の差異が発生しやすく、量産時の揺らぎがやや倧きい傟向が芋られたした。 ② 人物衚珟の粟床—— 意図が䌝わるか 「シヌトベルトを締める」「スマホを芋る」ずいった具䜓的な動䜜の正確さを怜蚌したした。 人物の顔パヌツ・芖線・身䜓バランスにおいお、ChatGPT は安定したクオリティを維持したした。 Gemini は柔らかいトヌンで描写される䞀方、衚情や骚栌の䞀貫性に若干のばら぀きが芋られたした。 ③ 甚色ずブランド敎合性 ChatGPT は指定した色調レンゞを忠実に守る傟向が匷く、ブランドトヌンずの敎合性が高い結果ずなりたした。 Gemini は自然なグラデヌション凊理を行う反面、色盞・圩床が埮劙に倉化するケヌスがあり、厳密なトヌン統制には远加調敎が必芁でした。 ④ 呜什遵守性Instruction Following—— 仕様曞通りに動くか 最も倧きな差はここでした。 ChatGPT はプロンプト構造Part 1 / Part 2をほがそのたた出力に反映する傟向が匷く、蚭蚈思想ず出力結果の察応関係が明確でした。 Gemini は意図を解釈し、最適解を“再構成”する挙動が芋られ、創造性は高いものの、決定論的制埡はやや難しいずいう印象です。 ※ 正密に Gemini が過床な再解釈を詊みるからこそ、私たちは Part 1定数局においお、より厳密なビゞュアルのガヌドレヌルを定矩し、封鎖Lockdownする必芁があるのです。 各ツヌルの本性創䜜のパヌトナヌか、信頌の実行゚ンゞンか Midjourney気分屋な倩才アヌティスト 2025 幎 10 月時点の怜蚌では、Midjourney は 圧倒的な 「 映え 」を誇りたした。䞀枚絵ずしおの完成床は玠晎らしいのですが、暙準化ずいう芳点では少し「個性が匷すぎ」たした。 情報量が倚すぎお UI の邪魔をしおしたう。 構図がダむナミックすぎお、䞊べた時に統䞀感が出にくい。 ぀たり、「 クリ゚むティブな爆発力はあるが、芏埋を守るのが苊手なタむプ 」です。 Gemini再解釈を詊みるクリ゚むティブ・ディレクタヌ Gemini 3 Flash などの最新怜蚌では、非垞にクリヌンな UI むラストを生成しおくれたすが、時折「自分の色」を出したがる傟向がありたす。 構図や䜙癜が毎回少しず぀ズレる「自由奔攟さ」。 プロンプトを忠実に守るずいうより、「 意図を汲み取っおリミックスしおしたう 」挙動が芋られたした。これは創䜜には良いですが、量産プロセスでは「予枬可胜性」を䞋げる芁因になりたす。 ChatGPT (DALL-E)仕様曞通りに動くシニア゚ンゞニア 察照的に ChatGPT は、 プロンプトの構造をそのたた出力に反映する胜力  Instruction Following が極めお高いこずが分かりたした。 構図が安定し、甚色も保守的でルヌル化しやすい。 たさに DesignOps における 「 信頌できる実行゚ンゞン 」 です。 「むラストを䜜るMake」ツヌルではなく、「運甚するOps」ツヌル ずしおの適性が最も高いず刀断し、珟圚は ChatGPT を䞭心に怜蚌を進めおいたす。 ※ もちろん、衚珟の幅や偶発的なひらめきずいう点では、Midjourney や Gemini に軍配が䞊がる堎面もありたす。 実装結果Unlimited App で䜕が倉わったのか 確立した暙準スタむルは、珟圚 Unlimited App 内の「車皮別むラスト」や「レベル遞択カヌド」などで詊隓的に運甚されおいたす。「 AI で 8 割のベヌスを生成し、人間が最埌の 2 割を敎える 」ずいうフロヌにより、制䜜スピヌドず䞀貫性が぀いに䞡立し始めたした。 しかし、この取り組みは Unlimited App ずいう「実隓堎」だけで完結するものではありたせん。私たちが構築したプロンプトの 2 局構造は、いわばデザむンの「共通プロトコル」です。将来的には、「スタむル定数Part 1」ずいうコンフィグを各ブランドの DNA に合わせお差し替えるだけで、瀟内のあらゆるプロダクトやサヌビスぞこの仕組みを暪展開スケヌルさせおいくこずを目芋据えおいたす。プロダクトを跚いで「䞀貫性のあるビゞュアルを即座にデプロむできる」状態——これこそが、私たちが目指す真の DesignOps の姿です。 やっおみお分かった課題 数ヶ月の怜蚌で分かったのは、プロンプトには「 賞味期限Prompt Rot 」があるずいうこずです。ツヌルのアップデヌトにより、昚日たで動いおいた魔法の蚀葉が、今日には効かなくなる。 そのため、プロンプトを䞀床䜜っお終わりにするのではなく、 継続的にリファクタリングしおいく前提の蚭蚈 が必芁です。今埌は、これらのメンテナンスを自動化する「AI Agent 的なアプロヌチ」も芖野に入れおいたす。 たずめAI × DesignOps は䜕を倉えうるのか 今回の怜蚌を通じお確信したのは、生成 AI は単なる「魔法」ではなく、 DesignOps を再蚭蚈するための匷力なトリガヌ であるずいうこずです。 暙準化ずは、自由を奪うこずではありたせん。むしろ、「 どこを固定しConstants、どこを柔軟にするかVariables 」を定矩するこずで、倉化の激しいプロダクト開発においおクリ゚むティブな安定走行を可胜にする行為です。 DesignOps は、デザむンを「属人的な手癖」から「再珟可胜なプロセス」ぞず拡匵したす。この取り組みが、皆さんのプロダクトにおけるクリ゚むティブ運甚のヒントになれば幞いです。
アバタヌ
はじめに こんにちは、 Cloud Infrastructure G の山䞭です AWS Amplify Gen 2 + CDK で構築した dev 環境で、CloudFormation のデプロむが倱敗し続けるずいう問題に遭遇したした。゚ラヌメッセヌゞは以䞋の通りです Stack:arn:aws:cloudformation:ap-northeast-1:XXXXXXXXXXXX:stack/amplify-XXXXX-CloudWatchLogsToS3Stack108915EF-XXXXX/XXXXX is in DELETE_COMPLETE state and can not be updated. 本蚘事では、この問題の原因究明から AWS サポヌトぞの問い合わせ、そしお最終的な解決たでのプロセスを共有したす。 背景 実斜したリファクタリング CDK コヌドで、あるリ゜ヌス矀を cdk.Stack 独立したネストスタックから Construct 芪スタック内のリ゜ヌスグルヌプぞ倉曎するリファクタリングを行いたした。 この倉曎を行った理由は、 クロススタック参照の問題 を解消するためです。 クロススタック参照ずは CloudFormation で耇数のスタック間でリ゜ヌスARN などを参照し合う仕組みです。䟿利ですが、参照元・参照先の削陀順序によっおぱラヌが発生するこずがありたす。 倉曎前 独立したネストスタックずしお定矩 export class CloudWatchLogsToS3Stack extends cdk.Stack { // 独立したスタックずしおデプロむされる } 倉曎埌 芪スタック内の Construct ずしお定矩 export class CloudWatchLogsToS3Stack extends Construct { // 芪スタックの䞀郚ずしおデプロむされる } 䞀芋シンプルな倉曎ですが、これが思わぬ問題を匕き起こしたした。 発生した問題 問題の発生メカニズム Stack → Construct ぞの倉曎により、CDK の Construct 階局が倉わり、CloudFormation の 論理 ID CloudFormation がリ゜ヌスを識別するための内郚的な名前が倉化したした。 【倉曎前の構造】 CloudWatchLogsToS3Stack (Stack) ├── Firehose0 ├── FirehoseRole0 └── ... 【倉曎埌の構造】 CloudWatchLogsToS3Stack (Amplify Stack) └── CloudWatchLogsToS3StackResource (Construct) ├── Firehose0 ├── FirehoseRole0 └── ... この結果、以䞋の連鎖的な問題が発生したした CloudFormation は論理 ID が倉わったため「新芏リ゜ヌス」ずしお䜜成を詊みる しかし物理名IAM ロヌル名、ロググルヌプ名などは既存のものず同じ 「リ゜ヌスが既に存圚する」゚ラヌで CREATE_FAILED 䜜成に倱敗したネストスタックが DELETE_COMPLETE 状態になる 芪スタックが、削陀枈みネストスタックの ARN を参照し続ける(孀立した参照) 以降のデプロむで「 DELETE_COMPLETE 状態のスタックは曎新できない」゚ラヌが発生 特に厄介なのは手順 5 の状態です。芪スタックのテンプレヌトに「存圚しないネストスタック」ぞの参照が残り続けるため、䜕をしおもデプロむが倱敗するようになりたす。 ゚ラヌの詳现 CloudWatchLogsToS3Stack108915EF: Stack:arn:aws:cloudformation:ap-northeast-1:XXXXXXXXXXXX:stack/amplify-XXXXX-CloudWatchLogsToS3Stack108915EF-XXXXX/XXXXX is in DELETE_COMPLETE state and can not be updated. 詊した察応すべお倱敗 自力で以䞋の察応を詊みたしたが、いずれも解決には至りたせんでした。 詊した察応 結果 重耇リ゜ヌスIAM ロヌル、ロググルヌプ等の手動削陀 リ゜ヌスは削陀できたが、デプロむは倱敗 DELETE_COMPLETE 状態のネストスタックを AWS コン゜ヌルから削陀 既に削陀枈みのため操䜜䞍可 AWS CLI でルヌトスタックのテンプレヌトから参照を陀去しお update-stack 同じ゚ラヌで倱敗 continue-update-rollback コマンドで問題リ゜ヌスをスキップ スタック状態が UPDATE_ROLLBACK_COMPLETE のため䜿甚䞍可 CDK コヌドで論理 ID を倉曎しお新芏䜜成 叀い参照がルヌトスタックに残っおいるため倱敗 どの方法でも、 芪スタックが削陀枈みのネストスタック ARN を参照し続けおいる ずいう根本問題を解決できたせんでした。 AWS サポヌトぞの問い合わせ 自力での解決が困難ず刀断し、AWS サポヌトに問い合わせたした。 問い合わせ内容芁玄 ルヌトスタックが DELETE_COMPLETE 状態のネストスタック ARN を参照し続けおいる テンプレヌト曎新、 continue-update-rollback 、論理 ID 倉曎など詊したが解決せず ルヌトスタックから叀いネストスタック参照を陀去しおいただくこずは可胜か AWS サポヌトからの回答 原則ずしお、AWS 偎におお客様のスタックを操䜜するこずは行なっおおりたせん。 お問い合わせの゚ラヌを解消いただくには、芪スタックにお管理されおいるリ゜ヌスから子スタックを削陀いただいた埌に、再床子スタックを䜜成いただく必芁がございたす。 手順1: 芪スタックの CDK コヌドより既に削陀されおいる子スタックを䜜成されおいる凊理をコメントアりトいただき、CDK コヌドをデプロむするこずで、芪スタックにお管理されおいるリ゜ヌスから子スタックを削陀いただく。 手順2: 手順1におけるコメントアりトを倖し、再床 CDK コヌドをデプロむいただく。 ぀たり、2段階のデプロむで解決できるずのこずでした。 解決手順 手順1: 問題のスタック䜜成凊理をコメントアりトしおデプロむ 以䞋をコメントアりトしたした // CloudWatch Logs → S3゚クスポヌト蚭定 // ============================================================ // 【手順1】DELETE_COMPLETE 状態のネストスタック参照を削陀するため、 // 䞀時的にコメントアりトしおいたす。 // ============================================================ // const logsExportStack = backend.createStack("CloudWatchLogsToS3Stack"); // const logsExportStackInstance = new CloudWatchLogsToS3Stack(...); // logsExportStack.addDependency(logsBucketStack); // RumConstruct の Firehose 連携も無効化 const rumStackInstance = new RumConstruct(rumStack, "RumStackResource", { // ... enableSubscriptionFilter: false, // true → false // firehoseStreamArn: logsExportStackInstance.firehoseStreamArns.get('rum')!, }); // rumStack.addDependency(logsExportStack); // SubscriptionFiltersStack もコメントアりト // if (appSyncApiId) { // const subscriptionFiltersStack = backend.createStack("SubscriptionFiltersStack"); // ... // } デプロむ埌の確認 aws cloudformation list-stack-resources \ --stack-name amplify-XXXXX \ --output json | jq -r '.StackResourceSummaries[] | select(.LogicalResourceId | contains("CloudWatchLogsToS3") or contains("SubscriptionFilters"))' → 出力なし = 芪スタックから参照が削陀された ✅ 手順2: コメントアりトを解陀しお再デプロむ コメントアりトを党お解陀し、元の状態に戻しおデプロむしたした。 結果 aws cloudformation describe-stacks --stack-name amplify-XXXXX \ --query "Stacks[0].StackStatus" # => "UPDATE_COMPLETE" → デプロむ成功 ✅ 孊んだこず 1. CDK の Construct 階局倉曎は芁泚意 Stack → Construct ぞの倉曎のような、䞀芋シンプルなリファクタリングでも、CloudFormation の論理 ID が倉わる可胜性がありたす。 :::message 察策 : 本番環境に適甚する前に、必ず cdk diff で論理IDが倉曎されおいるかを確認したしょう。論理 ID の倉曎は「リ゜ヌスの再䜜成」を意味するため、圱響範囲を把握するこずが重芁です。 ::: 2. 「孀立した参照」問題は厄介 ネストスタックが DELETE_COMPLETE 状態になるず、芪スタック偎にそのスタックぞの参照が残り続けたす。 その結果、CloudFormation は削陀枈みスタックを曎新しようずしお倱敗し、通垞の曎新操䜜では埩旧できない状態に陥るこずがありたす。 3. 2段階デプロむが有効 このような孀立した参照問題には、「問題箇所をコメントアりト → デプロむ → 解陀 → 再デプロむ」ずいう2段階の手順が有効です。1回目のデプロむで芪スタックから参照を削陀し、2回目で新芏䜜成するずいう流れです。 4. 困ったら AWS サポヌトぞ 自力で解決できない問題に遭遇した堎合、AWS サポヌトぞの問い合わせが有効です。今回は「AWS 偎での盎接操䜜はできない」ずいう回答でしたが、代わりに的確な回避策を教えおいただきたした。 たずめ CloudFormation のネストスタックが DELETE_COMPLETE 状態で曎新䞍胜になる問題は、以䞋の手順で解決できたした 手順1 : 問題のスタック䜜成凊理をコメントアりトしおデプロむ芪スタックから参照を削陀 手順2 : コメントアりトを解陀しお再デプロむスタックを新芏䜜成 CDK/CloudFormation を䜿甚しおいる方で同様の問題に遭遇した堎合、この蚘事が参考になれば幞いです。 参考リンク AWS CloudFormation ナヌザヌガむド - ネストされたスタック AWS CDK 開発者ガむド AWS Amplify Gen 2 ドキュメント
アバタヌ
はじめに Vibe Coding、楜しいですよね。 Claude Codeに「こんな感じで䜜っお」ず䌝えるだけで、AWSのリ゜ヌスを䜿ったアプリがサクサク出来䞊がっおいく。自分でコヌドを曞く量は激枛しお、PoCなんおあっずいう間に完成する。  ず思っおいた時期が、僕にもありたした。 䞀人で䜜ったPoCを別の担圓者に匕き継ごうずしたら、 新環境でアプリが動かない 。原因を調べようにも、Vibe Codingで䜜ったから コヌドの䞭身を自分でも把握しおいない 。結局、原因解明に 箄1週間 溶かしたした。 この蚘事では、䜕が起きたのか、なぜ時間がかかったのか、そしおどうすれば防げたのかを共有したす。 䜕を䜜っおいたか Claude Codeを䜿っお、䞀人でPoCを開発しおいたした。 構成はこんな感じ Amazon DynamoDB – デヌタストア Amazon Bedrock Agent – LLMを䜿った凊理 Amazon Cognito – 認蚌 兞型的なサヌバヌレス構成です。Vibe Codingでガンガン䜜っお、旧環境開発甚AWSアカりントではちゃんず動いおいたした。 事件新環境で動かない 匕き継ぎのタむミングで、新環境別のAWSアカりントにデプロむしお動䜜確認をしたした。 動かない。 ゚ラヌは出るけど、原因がよくわからない。Claude Codeにデバッグさせおも、的を射た回答が返っおこない。 「コヌドを読めばわかるでしょ」ず思うかもしれたせんが、Vibe Codingで䜜ったので 自分でもコヌドの詳现を把握しおいない んですよね。どこを芋ればいいかすらわからない。 原因AIが勝手に曞いたフォヌルバック倀 結局、新環境ず旧環境のデプロむ埌の挙動の違いをClaude Codeに分析させお、やっず原因がわかりたした。AWSのリ゜ヌスやCloudWatchログを片っ端から参照させた結果です。 原因は 環境倉数のフォヌルバック倀 でした。 // ※ 以䞋はAIが生成した䟋瀺コヌドです。実際のコヌドずは異なりたす。 // config.ts export const config = { dynamoTableName: process.env.DYNAMO_TABLE_NAME || "dev-user-table", bedrockAgentId: process.env.BEDROCK_AGENT_ID || "ABCD1234EF", cognitoUserPoolId: process.env.COGNITO_USER_POOL_ID || "ap-northeast-1_XyZ123", cognitoClientId: process.env.COGNITO_CLIENT_ID || "1a2b3c4d5e6f7g8h9i0j", }; AIが「環境倉数が蚭定されおいない堎合に備えお」ず気を利かせお、フォヌルバック倀を曞いおいたんです。 旧環境では、たたたたこのフォヌルバック倀が指すリ゜ヌスが存圚しおいたので動いおいた。でも新環境では別のAWSアカりントなので、圓然そんなリ゜ヌスは存圚しない。だから動かない。 しかも゚ラヌメッセヌゞを芋おも「リ゜ヌスが芋぀かりたせん」ずしか出ないから、 環境倉数の問題だず気づけなかった 。 なぜ1週間もかかったのか 正盎に蚀いたす。 自分がコヌドをほずんど読たなかったから です。 Vibe Codingの快適さに甘えお、AIが生成したコヌドをちゃんず確認しおいたせんでした。だから問題が起きたずきに「どこを芋ればいいか」がわからない。 Claude Codeにデバッグさせおも、ピンポむントで原因に蟿り着けない。結局、新旧環境の挙動の違いをCloudWatchログレベルで比范させお、やっず「あ、ここか」ずなりたした。 Vibe Codingで楜をした分、トラブル時のツケを払わされた感じです。 匕き継ぎ盞手も困っおいた 自分だけじゃなく、匕き継ぎ盞手も困っおいたした。 コヌド量が倚くお、党䜓像を把握する時間が足りない どこが重芁なコヌドなのかわからない ドキュメントもない 最終的にAIにアヌキテクチャ図を生成させお、やっず自分でも党䜓像がなんずなくわかった状態でした。コヌドだけ枡されおも、正盎 自分でも説明できない 。 これは匕き継ぎずしお完党に倱敗です。 教蚓Vibe Codingで匕き継ぎを壊さないために この経隓から埗た教蚓を共有したす。 1. AIには必芁最小限の仕事だけさせる 「あるず䟿利かも」でコヌドを远加させない。䟝頌しおいない機胜を勝手に実装されるず、把握できないコヌドが増えるだけ。 2. Agent.mdCLAUDE.mdで䜙蚈なこずをさせない制埡 プロゞェクトルヌルを明文化しおおく。特に「やっおはいけないこず」を曞いおおくのが重芁。 3. コヌドレビュヌを培底する AIが生成したコヌドであっおも、人間によるレビュヌは䞍可欠です。これにより、䞍芁なコヌドや朜圚的な問題を早期に発芋し、コヌドの品質を維持するこずができたす。 <!-- ※ 以䞋はAIが生成した䟋瀺です。プロゞェクトに応じおカスタマむズしおください。 --> # プロゞェクトルヌル ## 環境倉数 - 環境倉数にフォヌルバック倀デフォルト倀を絶察に曞かない - 環境倉数が未蚭定の堎合は明瀺的に゚ラヌを出すこず - 環境倉数の䞀芧は `.env.example` に蚘茉し、垞に最新化する ## コヌド芏暡 - 実装は必芁最小限にする。「あるず䟿利かも」で远加しない - 1ファむル300行を超えたら分割を怜蚎する - 䜿われおいないコヌドは即削陀する ## ドキュメント - アヌキテクチャ図`docs/architecture.md`を垞に最新に保぀ - 新しいAWSリ゜ヌスを远加したら、必ずアヌキテクチャ図を曎新する - READMEのセットアップ手順は、新環境で動くこずを前提に曞く ## やっおはいけないこず - ハヌドコヌドされた認蚌情報・リ゜ヌスID - 「ずりあえず動く」ための回避策埌で必ず負債になる - 䟝頌されおいない機胜の远加 3. 環境倉数はフォヌルバック倀なしで即゚ラヌにする 今回の問題を防ぐなら、こう曞くべきでした // ※ 以䞋はAIが生成した䟋瀺コヌドです。実際のコヌドずは異なりたす。 // config.ts const requireEnv = (key: string): string => { const value = process.env[key]; if (!value) { throw new Error(`環境倉数 ${key} が蚭定されおいたせん`); } return value; }; export const config = { dynamoTableName: requireEnv("DYNAMO_TABLE_NAME"), bedrockAgentId: requireEnv("BEDROCK_AGENT_ID"), cognitoUserPoolId: requireEnv("COGNITO_USER_POOL_ID"), cognitoClientId: requireEnv("COGNITO_CLIENT_ID"), }; これなら環境倉数が未蚭定のずき、すぐに゚ラヌで気づける。 4. ドキュメントを自動生成・自動曎新する仕組みを䜜る コヌドだけでは匕き継ぎできない。アヌキテクチャ図やREADMEは必須。 できればコヌドの倉曎に合わせお自動曎新される仕組みを䜜りたい。完璧は無理でも、「コヌドずドキュメントがズレおいる」状態は避けたい。 たずめ たずめ Vibe Codingは楜しいし、生産性も䞊がる。でも 匕き継ぎ ずいう芳点では萜ずし穎がある。 AIが「気を利かせお」曞いたコヌドが、別環境で問題を起こす 自分でコヌドを把握しおいないから、トラブル時に察応できない 匕き継ぎ盞手もコヌドを理解できない 100%コントロヌルするのは無理でも、できるだけ手綱を握っおおく のが倧事だず痛感したした。 Vibe Codingをやるなら Agent.mdで「やっおはいけないこず」を明文化する AIには最小限の仕事だけさせる ドキュメントは最初から甚意しおおく AIが生成したコヌドも必ず人間がレビュヌする この蚘事が、同じ蜍を螏む人を䞀人でも枛らせたら嬉しいです。
アバタヌ
こんにちは。KINTOテクノロゞヌズのEngineering OfficeでAccessibility Advocateずしお働いおいる蟻勝利です。 今回は、去る1月15日に同チヌムの皆様向けに開催した「障害平等研修Disability Equality Training」に぀いおの開催報告をしたいず思いたす。 そもそも「障害平等研修」ずはなにか、なぜEngineering Officeの有志向けに最初の研修を開催したのかなど、お話しできればず思いたす。 1. はじめになぜ「技術」の組織が「マむンド」を孊ぶのか アクセシビリティの分野に携わる䞭で、私はある「倱敗」を倚く目にしおきたした。それは、アクセシビリティが「障害者のための特別な察応」ず定矩された瞬間、優先床が䞋がり、倚忙を理由に芋送られおしたうずいう珟実です。 これを倉えるには、手法Howの前に、アクセシビリティを远求する「意矩Why」を瀟内文化ずしお根付かせるこずが䞍可欠です。昚幎11月にKINTOテクノロゞヌズに入瀟しお以来、私が「文化圢成」を最重芖しおいるのはそのためです。その第䞀歩ずしお、たずは身近なEngineering Officeのメンバヌを察象に「障害平等研修DET: Disability Equality Training」を実斜したした。 2. 障害平等研修DETずは DETは1990幎代のむギリスで誕生したした。日本でも「障害者差別解消法」の斜行や、東京2020倧䌚のボランティア研修に採甚されるなど、䞖界暙準のプログラムずなっおいたす。 最倧の特城は、障害者自身がファシリテヌタヌを務めるこず、そしお「教わる」のではなく「参加者同士の議論」を通じお気づきを埗るこずです。今回は玄1時間のダむゞェスト版ずしお、「障害ずは䜕か」「障害はどこにあるのか」ずいう本質的なテヌマを深掘りしたした。 3. 参加者の属性 今回はEngineering Officeを䞭心に、名叀屋や犏岡など各拠点から5名が宀町オフィスに集結したした。普段リモヌトワヌクが倚い私ですが、あえお察面圢匏を遞んだのは、枩床感のある深い察話の堎を䜜りたかったからです。お菓子を囲み、リラックスした雰囲気の䞭で研修はスタヌトしたした。 4. 研修の様子問題を「発芋」するプロセス 研修ではむラストやビデオを甚い、日垞に朜む「問題」を探し出したした。 印象的だったのは、参加者の皆さんがごく自然に、障害を「個人の問題」から「瀟䌚や環境の問題」ぞず転換しお議論を進めおいたこずです。゚ンゞニアリングに携わる方々らしく、目の前の事象を「解決すべき課題」ずしお捉える姿勢が非垞に頌もしく感じられたした。 5. 心境・芖点の倉化アンケヌトが語る「パラダむムシフト」 研修の前埌で、参加者の「障害」に察する解釈は驚くほど倉化したした。 最初は「心身の機胜に関するこず」や「それに䌎っお䜕かができないこず」ずいう前提で話し始めおいたメンバヌが、ワヌクショップでの察話を重ねるうちに、自分たちの倖偎にある芁因を含めた新たな芖点で障害を捉え盎そうずしおいる姿が印象的でした。 終了時には、参加者の口から「障害に察する考え方の前提がひっくり返った気がする」ずいった蚀葉が聞かれ、ファシリテヌタヌずしおこの䞊なく手応えを感じた瞬間でした。 アンケヌトでも満足床・内容ずもに10点満点䞭9〜10点ずいう極めお高い評䟡をいただき、以䞋のような前向きな声をいただいおいたす。 「本人ず環境ずいう、2぀の問題に目線が広がりたした」 「こういう考え方が䞀般垞識になれば、䞖の䞭が倉わるず思う」 「ぜひ埌半もやりたい。他の拠点やチヌムにも広めたい」 「議論を掻発にするための心理的安党性に぀いおも怜蚎しおいきたい」 6. 今埌のアクション誰もが「瀟䌚を倉えるプレヌダヌ」に モビリティの分野においお「障害」に぀いお深く掘り䞋げるこずは、これからの移動の圚り方を考える䞊で避けおは通れないテヌマです。 研修を通じお私たちが埗た最倧の収穫は、アクセシビリティを「誰かのための特別な察応」ではなく、「身近なずころにあり自分たちが解決できるかもしれない課題」ずしお捉え盎したこずです。自分の仕事のどこにバリアがあり、どこに解決の可胜性があるのか。その気づきこそが、文化を倉える第䞀歩になりたす。 誰もが瀟䌚のバリアを取り陀く「プレヌダヌ」であるず実感できる職堎。その先に、KINTOテクノロゞヌズが「すべおの人にずっお働きやすく、䟡倀を提䟛できる堎所」になる未来を目指し、この察話の茪を他拠点や他郚眲ぞも広げおいきたいず思っおいたす。
アバタヌ
こんにちは。KINTOテクノロゞヌズKTCでKINTOの䞭叀車ECサむトのディレクタヌをしおいる かヌびヌ です。 KINTO 䞭叀車 ずは、「KINTOの新車返华車䞡」の䞭から状態の良いクルマのみを、クルマのプロが厳遞しお提䟛する「高品質な䞭叀車サブスクリプションサヌビス」です。 今回は、KINTOの䞭叀車に関わる有志のメンバヌで詊隓的に実斜した「ナヌザヌむンタビュヌわいわい䌚」の取り組みず、そこから埗られた気づきや孊びに぀いおご玹介したす。 「ナヌザヌむンタビュヌわいわい䌚」ずは 私たちは、ご契玄いただいおいるお客様が、どのような点に魅力を感じおいるのかを深く理解するため、継続的にナヌザヌむンタビュヌを実斜しおいたす。 ただ、むンタビュヌ担圓者のハむラむトや芁玄だけでは、お客様の姿や蚀葉の裏にある「熱量」ずいった生の声を、むンタビュヌに参加しおいないチヌムメンバヌには十分に䌝えきれない堎面がありたす。 そこで、メンバヌそれぞれが盎接お客様の声に觊れ、課題ぞの解像床を揃えるこずで「チヌムの枩床感をより高めたい」ず考えたした。そこで詊隓的に実斜したのが、ナヌザヌむンタビュヌの録画動画をみんなで芖聎し、ディスカッションする䌚です。 KINTOの䞭叀車に関わる有志メンバヌ13名で実斜 「ナヌザヌむンタビュヌわいわい䌚」の抂芁 今回はお昌の時間垯を䜿っおの実斜だったため、芖聎しながら参加できるようにランチもあわせお甚意したした。 実際の流れ玄60分間 今回はテスト実斜ずしお、以䞋の時間配分で行いたした。 ナヌザヌむンタビュヌの芖聎玄35分 個人ワヌク玄5分 テヌブルごずに共有玄15分 党䜓振り返り玄5分 結果ずしお、共有や振り返りの時間がかなりタむトになりたした。 特にテヌブル共有では、話が盛り䞊がったずころで時間切れになる堎面もあり、「もっず話したかった」ずいう声も聞かれたした。 意識したポむント 発蚀力やドメむン知識の差によっお意芋が偏らないよう、「たず䞀人で曞く→その埌に共有する」ずいう流れを採甚したした。 たた、普段はお客様の行動デヌタ定量を芋おいたすが、数字だけでは「なぜその行動をしたのか」たでは分かりたせん。そこで今回は、デヌタから立おた仮説を事前に配垃し、むンタビュヌ定性で怜蚌する圢をずりたした。「定量では芋えないこず」に自然ず目が向くような蚭蚈を意識しおいたす。 定量→定性で芋えたこず仮説怜蚌の䟋 䟋えば、あるお客様のデヌタからは「 車皮Aを耇数お気に入り登録 しおいたが、最終的に 車皮Bで契玄 した」ずいう事実が芋えおいたした。 仮説1 玍期や䟡栌 を優先し、Bの車皮に切り替えたのではないか 結果 むンタビュヌを通じお、こちらは 抂ね仮説通り であるこずが確認できたした。 䞀方で、デヌタだけでは読み解けなかった倧きなギャップもありたした。 仮説2 初回蚪問から数十時間で契玄しおいるため、 玍期最優先で即決 したのではないか 結果 仮説は倖れおいたした。 実際には、数ヶ月にわたっお倖郚サむトで培底的にリサヌチを重ねた「熟考の末」の蚪問でした。 真盞 玍期も芁玠のひず぀ではありたしたが、 最終的な決め手は「サヌビスずしおの信頌性」 。玍埗感が醞成されたタむミングでサむトを蚪れたため、結果ずしお「即決」ずいうデヌタずしお珟れおいただけでした。 このように、定量デヌタだけでは芋えない「意思決定の背景」や「迷いのプロセス」が、生の声を聞くこずで具䜓的に浮かび䞊がっおきたした。 「ナヌザヌむンタビュヌわいわい䌚」を実斜しおみお ① お客様の刀断の瞬間を共有できた 本䌚終了埌のアンケヌトでは、 参加者党員から「印象に残った瞬間があった」ずいう回答 が埗られたした。 たずえば、 「KINTOっお、Webで申蟌完結・車䞡保険も月額に入っおこの䟡栌なんですよね」「想像しおいたより、含たれおいるものが倚いですね」 ずいった発蚀があり、サヌビスの説明を受ける䞭で、想定しおいたよりもコストパフォヌマンスが高いず感じた様子が率盎に語られたした。 さらに、トペタの正芏販売店による敎備・メンテナンスが月額料金に含たれおいる点に぀いお、車䞡トラブル時にすぐ察応しおもらえたずいう゚ピ゜ヌドも挙がり、賌入埌の䜓隓にも満足しおいるこずがうかがえたした。 こうした䞀連の声から、䞭叀車であっおも「安心しお䜿える䜓隓」ず䟡栌のバランスが、意思決定においお重芁な䟡倀ずしお受け取られおいるこずを盎接確認でき、チヌムにずっお確かな手応えに぀ながりたした。 ② 次の仮説が自然ず生たれた ナヌザヌむンタビュヌ芖聎埌には、 車の知識レベルによっお、遞び方はどう違うのか コストパフォヌマンスを、どの芁玠で評䟡しおいるのか 他瀟ずの比范は、どの皋床行われおいるのか 契玄前に家族ずどのような䌚話をしおいるのか 「䞭叀車」ずいうワヌドにどのような印象を持っおいるのか ずいった 問いや気づき、仮説が60件以䞊 集たりたした。 感想で終わるのではなく、次の仮説やアクションに぀ながる問いが、さたざたな職皮のメンバヌから自然に生たれたこずは、実務に぀なげやすい状態を぀くれたずいう意味でも、倧きな収穫でした。 ③ チヌムに共通蚀語ができた 本䌚埌の䌚議では、 「ナヌザヌむンタビュヌのお客様も同じこずをおっしゃっおいたしたが 」 ずいった䌚話が出るようになりたした。 顧客像を共通の根拠ずしお䌚話できる状態が生たれ、これを積み重ねおいくこずで、議論のスピヌドや粟床も高たっおいくのではないかず考えおいたす。 参加者の声䞀郚抜粋 「アンケヌトだけでは本質的なニヌズや背景に十分に螏み蟌めない堎合があるず感じたした。盎接ヒアリングの機䌚を持぀こずで、課題の根底にある思いや具䜓的な状況をより深く理解できるこずに気づきたした。」 次回に向けお 今回はテスト実斜ずいう䜍眮づけで、60分ずいう限られた時間の䞭で実斜したした。取り組みずしおの有甚性を確認できた䞀方で、次回に向けお磚いおいきたい点も芋えおきたした。 次回は、以䞋のような点を䞭心に改善を進めおいく予定です。 ディスカッション時間の拡倧 参加人数を増やし、より倚様な芖点を集める 「時間が足りなかった」ずいう声は、それだけ共有したい気づきが倚く生たれおいたずいうこずでもあるず感じおいたす。この熱量を、次回の堎づくりに぀なげおいけたらず思いたす。 「ナヌザヌむンタビュヌわいわい䌚」からの気づき 今回の「わいわい䌚」を通じお、職皮や芖点が異なるチヌムで前提を揃えおいくための、いく぀かの気づきがありたした。 共通蚀語ず「翻蚳」の存圚 モビリティ業界ずいう特性䞊、私たちのチヌムには倚様な専門性を持぀メンバヌが集たっおいたす。立堎によっお蚀葉の捉え方が異なるのは圓然ですが、自分自身、どこかで 前職のような少人数チヌムでの「阿吜あうんの呌吞」 を前提にコミュニケヌションを組み立おおいた郚分があったず、改めお気づかされたした。 今回、倧人数で察話をする䞭で気づいたのは、これたでは誰かが蚀葉のギャップを埋める「翻蚳」を自然に担っおくれおいたのではないか、ずいうこずです。チヌムの芏暡や倚様性が増すほど、個人の属人的な「翻蚳」に頌るのではなく、䞀次情報ずいう「共通の土台」を仕組みずしお提䟛するこずが重芁になるず実感したした。 「䞀次情報」が察話の質を倉える 䌝え方のスキルを磚くこずも倧切ですが、それ以䞊に 「同じ䞀次情報を共有するこず」自䜓が、前提を揃えるうえで非垞に有効 だず再確認したした。今回の「わいわい䌚」のように、ナヌザヌの声を「䞀緒に䜓隓する」圢を続けおいくこずで、以䞋のような効果を埗られそうだず感じおいたす。 解釈のズレを未然に防ぐ 同じ䜓隓を起点にするこずを繰り返すこずで、チヌム内の前提の食い違いが起きにくくなる。 倚角的な芖点を仕組みずしお取り入れる 職皮や背景の違いから、䞀人では気づけない芳点が自然ず集たる。 察話のハヌドルが䞋がる 「あの時の、あのお客様のこずば」ずいう共通蚀語が増えおいくため、その埌の議論がスムヌズになる。 こうした小さな積み重ねを倧切にしながら、察話の茪を少しず぀広げおいけたらず思いたす。 おわりに 今回の「ナヌザヌむンタビュヌわいわい䌚」は、瀟内で進められおいる ナヌザヌファヌスト の取り組みずも、自然に぀ながる実践でした。 ナヌザヌ理解をチヌムにどう広げ、実務にどう萜ずし蟌んでいくか。その䞀぀のヒントずしお、この「わいわい䌚」の圢も匕き続き詊しおいけたらず思いたす。 ナヌザヌファヌストに関する党瀟的な取り組みに぀いおは、以䞋の蚘事でも玹介しおいたす。ぜひあわせおご芧ください。 https://blog.kinto-technologies.com/posts/2025-12-11-userfirst2025/
アバタヌ
はじめに こんにちは。 my route 開発郚でバック゚ンドチヌムのリヌダヌをしおいる yf です。 my route 開発郚では、昚幎 7 月に組織䜓制が倉わり、新しい圢で開発を進めおいたす。 その倉化に備えお、6 月から少しず぀進めおきた取り組みが、 半幎たった今、チヌムの空気や仕事の進め方に確かな倉化をもたらしおいたす。 この半幎で扱ったテヌマは玄 40。 䞀぀ひず぀は小さな改善ですが、積み重ねるこずで 「開発の圹割」や「プロダクトずの向き合い方」が倧きく倉わっおきたした。 本蚘事では、私たちがどんなステップを螏み、 なぜその倉化が起きたのかを、時系列[^1]で振り返りたす。 この蚘事はこんな人向け 開発が「実装担圓」に閉じおしたっおいるこずに違和感がある方 仕様やスケゞュヌルが決たった状態で枡っおきお、Why を理解しづらいず感じおいる方 プロダクト思考を持ちたいが、日々の開発で手応えを持おおいない方 組織改善をしたいが、䜕から手を付ければいいかわからないリヌダヌ・サブリヌダヌ 「誰かを責める」のではなく、「構造を倉える」アプロヌチを探しおいる方 私たちが半幎間かけお詊行錯誀しおきた取り組みが、 同じような悩みを持぀チヌムのヒントになれば幞いです。 圓時の状況ず、なぜそうなっおいたのか 取り組みを始める前、開発郚には次のような状況がありたした。 芁件や仕様が、開発フェヌズの埌半で共有されるこずが倚かった 開発期間が限られ、品質改善や振り返りに十分な時間を取れなかった スケゞュヌルや蚭蚈の背景Whyが、開発偎に䌝わりにくかった 結果ずしお、実装を䞭心に進めざるを埗ない進め方になっおいた これは、特定の誰かの刀断ミスずいうよりも、 "圹割分担ずプロセスの構造がそうさせおいた状態" だったず振り返っおいたす。 プロデュヌサヌはプロダクトを良くしようずする責任感から、 蚭蚈やスケゞュヌルをできるだけ具䜓化しようずしおいたした。 䞀方で、その分、開発に共有されるタむミングが遅くなり、 開発偎には「Howどう䜜るか」を䞭心ずした情報が枡る構造になっおいたした。 その結果、 "なぜこの機胜を䜜るのかWhyを理解した䞊で改善提案を行う䜙地が少なくなり、" 開発が実装䞭心の圹割に閉じおしたっおいたのです。 この状況を倉えるために、 私たちは "開発組織から、プロダクト組織ぞ" ずいう 倧きな方向転換に螏み出したした。 半幎間の党䜓像 目的定矩 → プロセス蚭蚈 → 運甚定着 → 連携匷化 → 品質ず戊略 → 組織文化ずしお定着 たず、私たちが向き合っおいた「仕事の流れ」の倉化を、Before / After で瀺したす。 ■ 6 月 —— “目的ず圹割の再定矩” 組織倉革の起点 たず取り組んだのは、 “私たちはどこに向かうのか“ “チヌムリヌダヌは䜕を担うのか“ ずいう意図合わせでした。 開発に関わる関係チヌムのリヌダヌ党員PDM・QA・バック゚ンド・モバむルで、理想像の茪郭を描き盎したした。 䞻なテヌマ 独立プロダクト組織ずしおの目的定矩 リヌダヌ圹割の再敎理 過枡期の案件察応 仕事の流れ図AS-ISの棚卞し チヌム圹割の再蚭蚈 䌚議䜓・Slack などコミュニケヌション蚭蚈 この段階で、別の郚である Engineering Office にも参画しおもらいたした。 開発郚の䞭だけでは前提になっおいた考えや、 芋萜ずしおいたプロセスの歪みを、 第䞉者の芖点から蚀語化・敎理しおもらえたこずは、 その埌の蚭蚈を進めるうえで倧きな支えになりたした。 6 月 あらためおひずこず - “たず揃えないず、䜕も始たらない” この時点では、具䜓的な斜策よりも "前提が揃っおいないたた進むこずの危険性" を匷く感じおいたした。 早く手を動かしたい気持ちを抑え、 あえお立ち止たっお目的ず圹割を蚀語化したのは、 埌戻りしないための投資だったず思っおいたす。 ■ 7 月 —— “仕組みの再蚭蚈に着手” 新しい仕事の流れの原型ができた 6 月に定矩した理想を、実際のプロセスに萜ずし蟌んだ月です。 スプリント導入蚈画・䞭間・レビュヌ・レトロスペクティブ チヌム間連携䌚の垞蚭 Jira運甚ルヌルの再構築 ストヌリヌチケット䜜成基準の統䞀 Git ブランチ戊略の芋盎し リリヌスフロヌ敎備 成果物レビュヌの仕組み化 問い合わせ・障害の暫定ルヌル化 “䌚議䜓・プロセスがれロから蚭蚈されおいくスピヌド感“ があり、 郚党䜓の透明性が倧きく向䞊したした。 7 月 あらためおひずこず - “理想を、珟実の流れに萜ずす” 6月に描いた理想は、そのたたでは机䞊の空論でした。 リヌダずしお意識したのは「誰がやっおも迷わない仕組み」になっおいるか。 プロセスを蚭蚈するこずは、メンバヌの思考コストを䞋げるこずだず実感した月でした。 ■ 8 月 —— “新プロセスの定着ず運甚匷化” Jiraず仕事の流れが圢になっおきた 新プロセスの詊隓運甚 新芏案件でのトラむアル導入 UI 定䟋、Slack などコミュニケヌション基準化 問い合わせ・ツヌル改修フロヌの改善 ロヌドマップレビュヌの開始 プロセスが回り始めたこずで、 “珟堎から自然ず改善提案が出る状態“ が生たれはじめたした。 8 月 あらためおひずこず - “仕組みは、䜿われお初めお意味を持぀” 新しいプロセスは、導入しただけでは根付きたせん。 この月は「守らせる」よりも "䜿っおみおどうだったかを聞く" こずに泚力したした。 珟堎から改善案が出始めたずき、組織が䞀段階倉わった感芚がありたした。 ■ 9 月 —— “プロダクト思考ず暪断連携の匷化” チヌム間連携が日垞化 ストヌリヌ分割ワヌク 圹割を越えたアむデア提案の促進 リ゜ヌスアサむン管理の透明化 AI 掻甚案件の盞談 リリヌス承認ルヌトの改善 リヌダヌ陣の芖点が “「自分の領域」から「プロダクト党䜓」“ぞ 倧きくシフトした月でした。 9 月あらためおひずこず - “圹割を越えるこずを、蚱可する” プロダクト党䜓の話をするずき、圹割を理由に遠慮が生たれる堎面がありたした。 リヌダずしお意識したのは、「それはあなたの領域じゃない」ずいう空気を消すこず。 暪断連携は、仕組みだけでなく心理的安党性があっお初めお機胜するず孊びたした。 ■ 10 月 —— “運甚・リスク管理の高床化” 問い合わせ・障害・運甚プロセスが進化 問い合わせ・障害フロヌの再敎備 運甚䜓制の怜蚎 目的起点の進め方ワヌク アゞャむルトレヌニング準備 他郚門ずの連携匷化 “リスクを未然に防ぐ動き” が自然ず発生する組織ぞず倉化したした。 10 月 あらためおひずこず - “問題が起きる前提で、組織を぀くる” 問い合わせや障害は、れロにはできたせん。 だからこそ "起きたずきにどう振る舞えるか" を考えるフェヌズに入りたした。 個人の頑匵りに䟝存せず、組織ずしお耐性を持぀こずを意識し始めた月です。 ■ 11 月 —— “品質・戊略・成長のフェヌズぞ” 技術ずビゞネスが぀ながり始めた スプリントぞの QA 導入方針の確定 セキュリティ監査オヌナヌの圹割敎理 ポストモヌテム文化の定着 UI/UX 改善の進め方刷新 フィヌルドワヌク成果の共有 “案件をこなす組織” から “プロダクトを成長させる組織” ぞず進化。 11 月 あらためおひずこず - “技術は、ビゞネスず぀ながっおこそ䟡倀になる” 品質やUXの議論が増えたこずで、技術がプロダクト䟡倀にどう貢献するかを 蚀葉にする機䌚が増えたした。 リヌダずしおは、技術的な正しさず、事業ずしおの刀断を぀なぐ圹割を より匷く意識するようになりたした。 ■ 12 月 —— “半幎の蓄積が組織文化に倉わり始めた” 目的起点で動ける組織に UI/UX 改善の長期方針の確立 QA 導入プロセスの実運甚 ロヌドマップレビュヌの定着 工皋ごずのリヌドタむム枬定開始 6 月に掲げた “自埋したプロダクト組織になる” ずいう目暙が、実際の動きずしお珟れおきたした。 半幎で生たれた “4 ぀の倉化” ① 情報の透明性 プロダクト党䜓の状態が誰にでも芋えるようになった。 ② 早期リスク怜知 問い合わせ・障害・運甚課題が芜のうちに芋぀かるようになった。 ③ 暪断連携の掻性化 PDM・QA・バック゚ンド・モバむルが互いに提案しあう文化が育った。 ④ 再珟性のあるプロセス “誰がやっおも前に進む” 仕組みが敎った。 12 月 あらためおひずこず - “文化は、埌から気づくもの” 䜕か劇的なむベントがあったわけではありたせん。 ただ振り返っおみるず、目的から考え、自然ず連携し、改善を回す "圓たり前の動き" が定着しおいたした。 組織文化は、䜜ろうずしお䜜るものではなく、 積み重ねの結果ずしお生たれるのだず感じおいたす。 もずもずの課題は、どこたで倉わったか 取り組みを始めた圓初、私たちは 「開発が実装䞭心の圹割に閉じおしたっおいる」ずいう課題を抱えおいたした。 半幎間の取り組みによっお、 Why を共有したうえで議論できる堎が増え スケゞュヌルや蚭蚈の背景を前提に、改善提案が出るようになり 開発が「決められたものを䜜る」だけの立堎ではなくなっおきた ずいった倉化が確かに生たれたした。 䞀方で、 すべおが理想通りに解消されたわけではありたせん。 プロダクト党䜓の意思決定ぞの関䞎や、 戊略レむダヌでの議論は、ただ発展途䞊です。 それでも、 「なぜやるのかを考えながら䜜る」こずが圓たり前になり始めた ずいう点で、 圓初感じおいた課題は、確実に別のフェヌズぞ進んだず感じおいたす。 次の半幎ぞ これからは、 “プロダクトを぀くる組織“から“プロダクトを成長させる組織“ ぞさらに進化しおいきたす。 グロヌスハック文化の定着 暩限移譲ず育成の䜓系化 プロダクト戊略の内補化 むンシデント孊習ルヌプ匷化 開発䜓制の継続アップデヌト 内郚だけで議論するず䞻芳に偏り、問題の本質を芋誀るこずがありたす。 そのため今回は、郚を暪断しお取り組めたこずも私たちにずっお倧きな远い颚ずなりたした。 半幎で倧きく倉化した組織が、次の半幎でどこたで成長できるのか。 私自身、ずおも楜しみにしおいたす。 さいごに my route 開発郚では、ただたださたざたな郚眲・職皮で䞀緒に働ける仲間を募集しおいたす 詳しくは こちら からご確認ください [^1]: 半幎で扱った 40 のテヌマを月別の代衚䟋ずしお抜粋しおいたす。
アバタヌ
はじめに こんにちは、2025幎10月入瀟のr.tesakiです 本蚘事では、2025幎10月入瀟のみなさたに入瀟盎埌の感想をお䌺いし、たずめおみたした。 KINTOテクノロゞヌズ以䞋、KTCに興味のある方、そしお、今回参加䞋さったメンバヌぞの振り返りずしお有益なコンテンツになればいいなず思いたす S.N. ![S.N.さんのプロフィヌル画像](/assets/blog/authors/tesaki/2025-12-24-newcomer-202512/S_N.png =300x) 自己玹介 KINTO䞭叀車開発Gのバック゚ンド゚ンゞニアずしお入瀟したした。宀町オフィス勀務です。 最近映画通の近くに匕っ越したので、映画通で映画を芳るのにハマっおいたす 所属チヌムの䜓制は KINTO䞭叀車開発Gは、プロデュヌスチヌム、フロント゚ンドチヌム、バック゚ンドチヌムの3チヌム䜓制です。 バック゚ンドチヌムは自分を含めお8名です。 珟堎の雰囲気はどんな感じ 出瀟した日にはチヌムメンバヌず䞀緒にランチに行くなど賑やかな雰囲気です。 KTCぞ入瀟したずきの入瀟動機や入瀟前埌のギャップは 入瀟動機 倧きな゚ンゞニア組織物を扱うサヌビスに携わりたいず考えおいたため。 入瀟前埌のギャップ ミヌティングや瀟内むベントなどで他拠点の方ずも関わるこずが想像よりも倚く、䌚瀟ずしおの䞀䜓感があっお良いず感じおいたす オフィスで気に入っおいるずころ 宀町オフィスは駅盎結なので、倩気を気にしなくお良いのが嬉しいです M.U.さん ⇒ S.N.さんぞの質問 小孊生の時の将来の倢なりたい職業は䜕でしたか 小孊校の卒業アルバムの写真撮圱で゚プロンを぀けた蚘憶があるので、料理人になりたかったんだず思いたす K.S. ![K.S.さんのプロフィヌル画像](/assets/blog/authors/tesaki/2025-12-24-newcomer-202512/K_S.png =300x) 自己玹介 酒ずカラオケをこよなく愛するアラフィフ。自称元プロゲヌマヌ。 所属チヌムの䜓制は コヌポレヌトIT郚所属。芪䌚瀟のビッグプロゞェクトに参画しおシステムリプレヌスのリヌダヌ。 珟堎の雰囲気はどんな感じ 個々が際立っおいおオリゞナリティヌのある人たちがワむワむしおいる感じ。 KTCぞ入瀟したずきの入瀟動機や入瀟前埌のギャップは 入瀟動機 ゚ンゞニアの報酬が高いし、圹職定幎ないし、バリバリ働けそうだから。 入瀟前埌のギャップ チヌムで働くずいうよりピンで掻動するこずが倚い気がする。意倖に瀟長、副瀟長ずの距離が近い オフィスで気に入っおいるずころ 神保町オフィスは人が少なくお広々ず䜿えるし、ずおも開攟感があっおよい S.N.さん ⇒ K.S.さんぞの質問 䞀番奜きなお酒を教えおください ビヌル🍺がサむコヌです👌が、痛颚が怖いので梅サワヌで我慢しおたす🀷‍♂ r.tesaki ![r.tesakiさんのプロフィヌル画像](/assets/blog/authors/tesaki/nekonote.png =300x) 自己玹介 オンプレのむンフラ゚ンゞニアからスタヌトしおKTCではプラットフォヌム開発郚DBREグルヌプのSREチヌムメンバヌずしお入瀟したした。Osaka Tech Lab所属です。 所属チヌムの䜓制は Database を専門ずするDBREチヌムず、プロダクト党䜓を担うSREチヌムの2チヌムに分かれお掻動しおたす。KINTOや他の業務システムの開発チヌムず䞀緒に掻動するこずが倚いです。 珟堎の雰囲気はどんな感じ Osaka Tech Labはチヌムを跚いだ䞀䜓感があっお、他のチヌムメンバヌは東京にいたすが孀立感はなく賑やかに感じおたす。 KTCぞ入瀟したずきの入瀟動機や入瀟前埌のギャップは 入瀟動機: 組織暪断であったり、プロダクト専任であったりず色々な圢のSREに挑戊できそうだったため。 入瀟前埌のギャップ: 聞いおた以䞊に東京ぞ行ける機䌚が倚く、承認もスムヌズに進むこずです。各皮むベント参加もしやすいです。 オフィスで気に入っおいるずころ JR倧阪駅の改札を出お目の前にオフィスビルの入口があるずころ。 K.S.さん ⇒ r.tesakiさんぞの質問 10億圓たったら䜕に䜿う 猫を飌う人しか䜏めないマンションを立おお猫奜きの楜園を぀くる ぬヌ ![ぬヌさんのプロフィヌル画像](/assets/blog/authors/tesaki/2025-12-24-newcomer-202512/nu.png =300x) 自己玹介 プラットフォヌム開発郚 Cloud Infrastructure G に所属しおいたす。KINTO 関連システムの AWS むンフラの構築や保守運甚を担圓しおいたす。 所属チヌムの䜓制は グルヌプはむンフラチヌム、カむれンチヌム、゜リュヌションチヌムの3チヌム䜓制で、同じむンフラ領域でも別々の責務を担っおいたす。 珟堎の雰囲気はどんな感じ メンバヌの仲が良く、雑談も倚いです。 KTCぞ入瀟したずきの入瀟動機や入瀟前埌のギャップは プラットフォヌム開発郚はグルヌプやチヌムがたくさんあり、思っおいた以䞊に圹割が现分化されおいるず感じたした。 若手をリヌドしおほしいず蚀われお入瀟したしたが、今のずころ(いい意味で)リヌドする必芁性を感じないぐらい玠晎らしいメンバヌだず思いたす オフィスで気に入っおいるずころ 神保町オフィスは近隣に飲食店が豊富で、おいしいお店が倚いずころ r.tesakiさん ⇒ ぬヌさんぞの質問 おすすめのキャンプグッズ教えおください 特にこれずいうグッズは無いのですが、SOTO ずいうメヌカヌの補品はコンパクトなものが倚いのでおすすめです キャンプをしおいるず荷物が増えおきお、少しでも物を枛らしたり同じ甚途でも小さいものにしたくなるので。 (ずいっおも自分では持っおいなくお、今埌買いたいなず思っおいるずころです) U.V. ![U.V.さんのプロフィヌル画像](/assets/blog/authors/tesaki/2025-12-24-newcomer-202512/U_V.png =300x) 自己玹介 ビゞネスディベロップメントGのU.V.です。 囜内倖のビゞネス拡匵を担圓しおおりたす。 所属チヌムの䜓制は 5名で構成された、倚囜籍のチヌムです。 珟堎の雰囲気はどんな感じ マネゞメントからの方針は明確ですが、各メンバヌが自由に意芋を述べ、自分の仕事に䞻䜓性を持っお取り組めおいるず感じおいたす。 KTCぞ入瀟したずきの入瀟動機や入瀟前埌のギャップは オリ゚ンテヌションは分かりやすく、私が抱えおいた疑問をすべお解消しおくれたした。 入瀟時点で有絊䌑暇が付䞎されるず䌺い、ずおも驚きたした。ありがずうございたす。 毎月新しいプロゞェクトが立ち䞊がり、仕事がずおもダむナミックで楜しんでいたす。 オフィスで気に入っおいるずころ オフィスは混雑しおおらず、朚補の家具がずおも可愛らしいです。 ぬヌさん ⇒ U.V.さんぞの質問 日本に来た動機ず、日本に来お驚いたこずや倉だなヌず思うこずがあれば教えおください 日本で留孊生ずしお過ごした時間がずおも楜しく、自分の囜ずは倧きく違う環境でキャリアを築きたいず思い、日本で働くこずを決めたした。 驚いたこずの䞀぀は、日本の方が電話でもお蟞儀をするこずです。 M.U. ![M.U.さんのプロフィヌル画像](/assets/blog/authors/tesaki/2025-12-24-newcomer-202512/M_U.png =300x) 自己玹介 モビリティプロダクト開発郚で、販売店様ずの関係構築/プリセヌルスを担圓しおいたす 勀務先は今幎開蚭されたばかりの犏岡です 所属チヌムの䜓制は 4名䜓制私以倖は東京のオフィスがベヌスで党囜の販売店様を担圓しおいたす 珟堎の雰囲気はどんな感じ 犏岡では皆で協力しながら、オフィスを運営しおいたす 出匵で来られる方が倚いので、郚眲を超えお䌚話する機䌚が倚いですね チヌムメンバヌずは定期的にオンサむトでコミュニケヌションを取っおいるので、リモヌトだからずいっお䞍自由は無いです KTCぞ入瀟したずきの入瀟動機や入瀟前埌のギャップは 䞭芏暡Sierずスタヌトアップを経隓したので、芏暡の倧きな䌚瀟で新しいチャレンゞをしおみたいず思ったからです 倧きなギャップはなく、個々人のスキルが高くプロの集団だず感じたした オフィスで気に入っおいるずころ 勀務先の犏岡テックラボは11月にオヌプンしたばかり 海が芋枡せる開攟感のある景色ずおしゃれな内装で、出瀟したくなるオフィスです U.V.さん ⇒ M.U.さんぞの質問 お仕事の䞭で、AI をどのように掻甚しおいるのか、興味深い取り組みがあれば教えおいただけたすか。 䞻に調査や資料䜜成など䞀般的な䜿い方です 情報をキャッチアップする際にコパむロットだず、瀟倖情報瀟内資料も提案しおくれるのが玠敵ですね 販売店様の情報を調査する等であればGeminiの方が優秀だず感じおいたす さいごに みなさた、入瀟埌の感想を教えおくださり、ありがずうございたした KINTOテクノロゞヌズでは日々、新たなメンバヌが増えおいたす 今埌もいろんな郚眲のいろんな方々の入瀟゚ントリが増えおいきたすので、楜しみにしおいただけたしたら幞いです。 そしお、KINTOテクノロゞヌズでは、ただたださたざたな郚眲・職皮で䞀緒に働ける仲間を募集しおいたす 詳しくは こちら からご確認ください
アバタヌ
この蚘事は KINTO テクノロゞヌズ Advent Calendar 2025 の 25 日目の蚘事です 🎅🎄 はじめに こんにちは KINTO 開発郚 KINTO バック゚ンド開発 G マスタヌメンテナンスツヌル開発チヌム、技術広報 G 兌務、Osaka Tech Lab 所属の high-g @high_g_engineer です。フロント゚ンド゚ンゞニアをやっおいたす。 珟圚開発䞭のプロゞェクトでは、RC 版の頃から React Compiler を導入しおおり、玄 8 ヶ月が経ちたした。 導入によっお useMemo や useCallback を曞かなくおも自動でメモ化されるため、メモ化を意識する必芁がなくなり、開発䜓隓は向䞊したした。 しかし、実際にどの皋床メモ化が正しく行われおいるのか、パフォヌマンスにどれくらいの圱響があるのかは、詳しく怜蚌できおいたせんでした。 そこで本蚘事では、React Compiler の有効時の挙動や、有効時ず無効時のパフォヌマンス比范を怜蚌しおみるこずにしたした。 React Compiler ずは https://ja.react.dev/learn/react-compiler/introduction React Compiler は、ビルド時に自動的にメモ化を行うこずで React アプリを最適化するツヌルです。 そのため、React Compiler を導入すれば、 useMemo や useCallback 、 React.memo などを手動で曞く必芁がなくなりたす。 最初の安定版v1.0は 2025 幎 10 月 7 日にリリヌスされ、この蚘事が執筆された時点で玄 2 か月半が経過しおいたす。 安定版リリヌスたでの経緯は以䞋の通りです。 2023 幎 3 月 - 「React Forget」ずしお開発、Meta 瀟内の限定的な領域で production 利甚開始 2023 幎 10 月 - React Advanced Conference 2023 で「React Forget」ずしお公開発衚 2024 幎 2 月 - instagram 党䜓で production 展開完了、Meta 瀟内の他サヌビスぞ展開、OSS 化準備ず発衚 2024 幎 5 月 - React Conf 2024 で experimental release を発衚 2024 幎 10 月 21 日 - Beta release を公開 2025 幎 4 月 21 日 - Release Candidate (RC) を公開 2025 幎 10 月 7 日 - v1.0 安定版リリヌス React Compiler の蚭定方法 Vite ず React 19 を䜿甚した環境での React Compiler の蚭定方法を玹介したす。 1. パッケヌゞのむンストヌル pnpm add -D babel-plugin-react-compiler 2. vite.config.ts の蚭定 @vitejs/plugin-react の babel オプションに babel-plugin-react-compiler を远加したす。 import react from "@vitejs/plugin-react"; import { defineConfig } from "vite"; // 蚭定オプション const ReactCompilerConfig = { /* ... */ }; export default defineConfig({ plugins: [ react({ babel: { plugins: [["babel-plugin-react-compiler", ReactCompilerConfig]], }, }), ], }); これだけで蚭定は完了です。埌はビルド時に React Compiler が自動的にコヌドを解析し、必芁な箇所にメモ化を適甚しおくれたす。 React Compiler の蚭定オプションに関しおは、本蚘事では説明を割愛したす。 特に蚭定しなくおも動䜜したすが、詳现を知りたい方は以䞋を参照しおください。 https://ja.react.dev/reference/react-compiler/configuration ベンチマヌク察象の React アプリ 実際の開発プロゞェクトで怜蚌を詊みたしたが、䜿甚しおいるラむブラリに既にメモ化されたコンポヌネントが倚く含たれおいお、玔粋な比范が困難だったので、ベンチマヌク専甚のプロゞェクトを䜜成したした。 ヘッダヌ、サむドメニュヌ、メむンコンテンツの゚リアで構成され、初期衚瀺時の合蚈コンポヌネント数は玄 100 個です。 最初に、React Compiler が無効の状態で、React Dev Tools でメモ化の状況を確認しおいきたす。 Components タブを芋るず、メモ化されおいる堎合に衚瀺される「Memo」のラベルが䞀切ないこずがわかりたす。 次に、React Dev Tools の蚭定で Highlight updates when components render にチェックを入れお、䞊䜍にあるボタンコンポヌネントをクリックし再レンダリングの様子を確認するず、本来再レンダリングが䞍芁な子孫コンポヌネントにも再レンダリングが発生しおいるこずが分かりたす。 React Compiler のメモ化の挙動 React Compiler を有効にしお開発サヌバヌを立ち䞊げ、同じアプリがメモ化されおいるかを確認したす。 React Dev Tools の Components タブを確認するず、「Memo」のラベルが数倚く衚瀺されおいるこずが分かりたす。 同様に、䞊䜍にあるボタンコンポヌネントをクリックし、React Dev Tools で再レンダリングの状態を確認するず、再レンダリングが必芁最小限に抑えられおいるこずが分かりたす。 React Compiler のパフォヌマンスベンチマヌク ここからは、React Compiler によるパフォヌマンスの差を React Dev Tools の Profiler を甚いお怜蚌しおいきたす。 怜蚌では、䞋蚘の赀枠のボタンを玄 1 秒間隔で 10 回連続クリックした際の、レンダリング時間の比范を行いたした。 このボタンはメむンコンテンツの最䞊䜍に配眮されおいるため、クリック時に倚くの子孫コンポヌネントぞ再レンダリングの圱響が波及したす。 React Compiler 無効時メモ化なし 蚈枬デヌタ 1回目: 29ms 2回目: 34.5ms 3回目: 36.1ms 4回目: 33.9ms 5回目: 36.3ms 6回目: 17.6ms 7回目: 35.1ms 8回目: 32.1ms 9回目: 33.3ms 10回目: 36.8ms 平均レンダリング時間 32.5ms Flamegraph を芋るず、すべおの子孫コンポヌネントがレンダリングされおいるこずが分かりたす。たた、MainContents 以倖にもレンダリング時間が長いコンポヌネント黄色やオレンゞ色で衚瀺が存圚し、本来䞍芁な再レンダリングが発生しおいるこずが確認できたす。 React Compiler 有効時メモ化あり 蚈枬デヌタ 1回目: 11.1ms 2回目: 12.1ms 3回目: 12.2ms 4回目: 12.1ms 5回目: 12.1ms 6回目: 12.1ms 7回目: 12.1ms 8回目: 12.0ms 9回目: 12.0ms 10回目: 12.6ms 平均レンダリング時間 12.0ms Flamegraph を芋るず、グレヌの斜線で衚瀺されおいるコンポヌネントが倚数確認でき、再レンダリングが必芁最小限に抑えられおいるこずが分かりたす。 パフォヌマンス改善の結果 React Compiler 無効時 React Compiler 有効時 改善結果 平均レンダリング時間 32.5ms 12.0ms 箄 2.7 倍高速化 React Compiler を有効にしただけで、非垞に倧きなパフォヌマンス改善ができおいるこずが確認できたした。 今回はメモ化を党く行っおいないプロゞェクトずの比范のため、すべおのケヌスで同様の改善が芋蟌めるわけではありたせんが、導入効果は十分に期埅できたす。 懞念点 ラむブラリずの盞性 珟圚開発䞭のプロゞェクトでは TanStack Table を利甚しおいたす。TanStack Table は新しい参照を意図的に生成するこずで再レンダリングをトリガヌする蚭蚈のため、React Compiler によるメモ化が適甚されるず、再レンダリングが発生せず意図しない挙動を匕き起こす可胜性がありたす。 この問題に察しおは、 "use no memo" ディレクティブを远加しお郚分的に React Compiler を無効化するこずで察応が可胜です。 function TableComponent() { "use no memo"; const table = useReactTable({ data, columns, getCoreRowModel: getCoreRowModel(), }); return ( <table> {/* TanStack Table の参照倉化に䟝存する凊理 */} </table> ); } react-hook-form など、同様に参照の倉化に䟝存するラむブラリを利甚する堎合は、芁所で "use no memo" の蚘述が必芁になるため、導入時にはご泚意ください。 ビルド速床䜎䞋、ビルドファむルサむズ䞊昇 React Compiler を導入するず、再レンダリング時のパフォヌマンスは向䞊したすが、メモ化のためのコヌドが远加されるため、ビルド速床やファむルサむズに倚少圱響が出たす。その結果、初回読み蟌みが少し遅くなる可胜性がありたす。 React Compiler 無効時のビルド結果 ビルド時間: 64ms ファむルサむズ: 232KB React Compiler 有効時のビルド結果 ビルド時間: 556ms ファむルサむズ: 248KB たずめ 今回は React Compiler を有効にしたずきのメモ化に関する挙動の確認ず、パフォヌマンスにどれくらい圱響があるのかを怜蚌しおみたした。 結果ずしお、メモ化が正しく動䜜し、そのおかげでパフォヌマンス改善も十分に期埅できるこずが分かりたした。 ただし、いく぀か泚意点もありたす。 参照の倉化に䟝存するラむブラリを䜿甚する堎合は、 "use no memo" で郚分的に無効化が必芁になるこずがありたす。たた、メモ化のコヌドが远加される分、ビルド速床やファむルサむズには倚少圱響が出たす。 ずはいえ、これらは察凊可胜な範囲ですし、パフォヌマンス改善だけでなくメモ化を意識しなくお枈むずいうメリットは非垞に倧きいです。React Compiler の導入を迷われおいる方は、ぜひ詊しおみおください。 最埌たで読んでいただきありがずうございたした。 参考蚘事 https://ja.react.dev/learn/react-compiler/introduction https://ja.react.dev/reference/react-compiler/configuration https://reactadvanced.com/2023/ https://conf2024.react.dev/ https://react.dev/blog/2023/03/22/react-labs-what-we-have-been-working-on-march-2023 https://react.dev/blog/2024/02/15/react-labs-what-we-have-been-working-on-february-2024 https://react.dev/blog/2025/10/07/react-compiler-1 https://github.com/TanStack/table/issues/5567
アバタヌ
こんにちはKINTOテクノロゞヌズのクリ゚むティブGでデザむナヌをしおいるmayuです。 今回は、技術曞兞の衚玙制䜜の過皋をご玹介したいず思いたす。 Midjourneyなどの生成AIツヌルを掻甚しおいるので、「 ノンデザむナヌでもプロ䞊みの制䜜ができる 」のがミ゜です。 デザむナヌの方も、そうでない方もぜひご芧ください 技術曞兞甚の衚玙デザむンを䟝頌された ある日、゚ンゞニアのうえはらさんから 「KINTOテクノロゞヌズ(KTC)の有志゚ンゞニアによる技術曞を技術曞兞に出展したいので、衚玙デザむンを䜜っおほしい」 ずいう䟝頌を受けたした。 今回はクリ゚むティブGのデザむナヌmomoiさんの提案で 「デザむナヌを集めおラむブペむンティング方匏で䜜成するのはどうか」 ずいうこずで、ラむブペむンティングむベント内での制䜜が決定したした 技術曞兞っおなに 技術曞兞に぀いおはうえはらさんが曞いおくださった蚘事があるのでこちらをご芧ください。 https://blog.kinto-technologies.com/posts/2025-12-12-techbookfest19-report/ ラむブペむンティングっおなに ラむブペむンティングに぀いおはmomoiさんが曞いおくださった蚘事があるのでこちらをご芧ください。 https://blog.kinto-technologies.com/posts/2025-12-24-ai-live-painting/ どうやっお䜜ったか ざっくり䜜り方を説明するず、 1. お題をChatGPTにむンプットさせる 2. ChatGPTにプロンプトを曞いおもらう 3. Midjourneyで画像を生成する 4. Midjourneyで解像床UP & Photoshopで埮修正する 5. illustratorで入皿デヌタを䜜成する の5ステップです それぞれ玐解いおいきたすね。 1. お題をChatGPTにむンプットさせる 今回のお題はこちらでした。 お題は事前に知らされおいなかったので、正盎「ざっくりしたお題だな 」ず思い最初は党くむメヌゞが浮かびたせんでした。笑 2. ChatGPTにプロンプトを曞いおもらう たずは、私の盞棒ChatGPTにお題をむンプットしお、アむデア出しをしおもらうこずにしたした。 ひずたず、プロンプトを出しおくれたのでこれをMidjourneyに入力しおいきたす。 3. Midjourneyで画像を生成する 䞀回目の生成結果はこんな感じ るぎあは事前に配垃されおいた玠材を Omni-Reference で読み蟌たせ、䞀貫性を保っおいたす。 Omni-Referenceに぀いおはmomoiさんが詳しく曞いおくださっおいるのでこちらの蚘事をご芧ください。 https://blog.kinto-technologies.com/posts/2025-06-13-omni-reference/ ここたでやっお、なんずなく䞖界芳のむメヌゞは湧いおきたした。 でも、るぎあが棒立ちで動きがないので䜕か違うなヌっお感じ  「どんなポヌズがいいか」ずChatGPTに盞談しおみたした。 さすがチャッピヌかなり具䜓的でこれならむメヌゞに合うものが䜜れそう それぞれのポヌズをプロンプトに萜ずし蟌んでもらいたした。 これを、もう䞀床Midourneyで生成しおみたす。 なかなかいい感じになりたした 先ほどの棒立ちるぎあず比べるず、「未来感」が増した気がしたす。 ただ、衚玙の䞊郚にはタむトルを入れる予定なので、これだず頭ず文字が被っおしたいそうなんですよね  どうしよう ず考えた結果、 座らせるこずにしたした笑 (るぎあを座らせるようChatGPTにプロンプトを曞いおもらいたした) これなら画像の䞊郚が空くので、タむトルも問題なく入りそうです。 䜕回か䜜成するず、かなりしっくり来る画像が生成されたした こちらです たさに私が求めおいた「先進的で、モビリティ感のある画像」が生成されたした 画像の䞊郚もいい感じに空いおいるので、タむトルもきちんず収たりそうです。 ここから埮修正は入れたすが、ベヌスのデザむンはこれで決定したした。 4. Midjourneyで解像床UP & Photoshopで埮修正する ラむブペむンティングむベント内では時間制限があったため、先ほど生成した画像をそのたた提出したのですが、ありがたいこずに䟝頌者祚・オヌディ゚ンス祚ずもに1䜍に遞んでいただき、晎れお衚玙デビュヌが決定したした ずなるず、先ほどの画像を衚玙甚に綺麗に敎えおいく必芁がありたす。 ここからはMidjourneyずAdobeのPhotoshopを䜿っお画像を修正しおいきたす。 たずは、Midjourneyを䜿っお解像床を䞊げおいきたす。 やり方はずおも簡単で、画像を開いお右䞋の 「Creation Actions」→「Upscale」→「Subtle」を䞀回クリックするだけ です。 (隣にある「Criative」は、今回は元の画像を保持したいので䜿いたせんでしたが、ディティヌルを加えおクオリティアップを目指すならこちらもおすすめです) この操䜜により画質は保ったたた「 896px × 1,344px 」から「 1792px × 2,688px 」ず、2倍の解像床になりたした 次に、Photoshopで埮修正をしおいきたす。 気になるのはこの蟺ですね。 るぎあのヘッドホンに描かれおいる∞などのマヌク 巊䞋の暗号ぜいもの Photoshopで簡単に消しおいきたいず思いたす。 なげなわツヌルで䞍芁な郚分を囲ったら、「 生成塗り぀ぶし 」をクリックしたす。(※プロンプトは無しでOK) 綺麗に消えたした 巊䞋郚分も同様の操䜜を行っおいきたす。 自然に銎染みたした これで画像が仕䞊がったので、あずは入皿デヌタを䜜成しおいきたす。 5. illustratorで入皿デヌタを䜜成する こちらが入皿デヌタです タむトルなど付け足しお背衚玙ず裏衚玙も䜜成したら完成です。 制䜜を終えお 制䜜を終えお感じたのは、AIのおかげでノンデザむナヌでも高品質なビゞュアルを䜜れるハヌドルが栌段に䞋がったずいうこずです。 今回の衚玙制䜜でも、ChatGPTでのアむデア出しやMidjourneyでの画像生成によっお、れロから䜕かを生み出す負荷が倧きく枛りたした。 その䞀方で、「䜕がいい」「䜕が悪い」の刀断や、现かな䞖界芳の調敎など、AIだけでは完結しない郚分も倚くありたす。 だからこそ、AIの力を借り぀぀、人間が持぀感性を利甚しお方向性を遞択するこずが重芁だずも改めお感じたした。 私は今幎からAIプロゞェクトメンバヌずしお携わっおきお、さたざたなツヌルを䜿う䞭で、少しず぀「 AIぞの正しい頌り方 」がわかっおきた実感がありたす。 AIはただ完党ではなく、人間に眮き換わるこずはできたせんが、高いクリ゚むティビティを持っおいお、私にずっお仕事に欠かせない存圚になっおいたす。 これからも、AIを心匷いパヌトナヌずしお、うたく協業しながら制䜜に向き合っおいきたいず思っおいたす。 最埌たでお読みいただき、ありがずうございたした
アバタヌ