TECH PLAY

株式会社ラクス

株式会社ラクス の技術ブログ

926

こんにちは、プロダクト部 部長の稲垣です。(自己紹介やこれまでのキャリアについて↓をご覧ください。) tech-blog.rakus.co.jp 2025年12月4日(木)に当社ラクスの紀井が登壇し、『AI時代の「ジュニア不要論」に異議あり!未経験から戦力PdMを生み出すOJT戦略とは?』 2025.pmconf.jp というテーマで「PdM育成」について登壇しました。 そこで私も、現在、直下で1名のPdMを「再育成」していることもあり、 ラクスにおけるPdM育成のリアル を少しフィクションを交えつつお伝えします。 ■ はじめに メンバー概要 ラクスのプロダクトマネージャーの選考プロセス 採用時点の評価 ■ 入社後 → 再育成に至るまで ■ オンボーディングについて バディ体制 ■ PdM担当後に起きた課題 ■ 再育成の進め方 カリキュラム概要 1.課題図書 → レポート作成 → メンターと議論 2.社内e-learning受講 3.「自分のイシューは何か?」ワーク ■ 「自分のイシュー」課題の狙い チェックポイント(育成側) ■ 次の育成課題へ 最後に ■ はじめに メンバー概要 年齢:20代後半 PdM歴:約3年(ラクス入社前) 経歴: 新卒で大手IT企業のPdMとして入社。学生時代はベンチャーでエンジニアとして3年以上アルバイト経験。インバウンド向けのトラベル系プロダクトを担当。 ラクスのプロダクトマネージャーの選考プロセス 1. 書類選考 2. カジュアル面談 稲垣が15〜20分ほど会社と業務内容の説明 選考要素なし。その場で辞退してもOK 3. 一次面接(オンライン) 稲垣とリーダーPdMで実施 4.最終面接(対面) 部長が担当 このメンバーの採用時点での評価は以下です。 採用時点の評価 新卒PdMとして3年で一定成果を出していた ビジネス側・エンジニア側双方と連携経験あり 担当していた業務内容の整理・意義を高い解像度で説明できた (※言語化は今後の課題として認識) 行動力が非常に高く、インタビューでも多くのエピソードあり ラクスの開発組織が大事にする顧客志向で業務をしていた 複数のSaaS企業と比較した結果、 「サービスの成長性」「PdM組織の成熟度」「Biz/Dev バランス」 の3点を理由にラクスを選んでくれました。 ■ 入社後 → 再育成に至るまで 2024年夏 :入社(1か月オンボーディング) 2024年夏 :「楽楽明細」でPdM業務開始(当時は担当PdM 1名+本人) 2025年冬 :軽微な案件を担当開始。ステークホルダーとのコミュニケーション齟齬が発生  → 一部クレームもあり役割を縮小 2025年春 :リーダー判断で「一度プロダクト担当を外す」決定  → 再育成フェーズへ移行 2025年秋 :チーム規模拡大により、再育成担当者を私に変更 ラクスでは入社後1〜2ヶ月をオンボーディング期間としています。 入社半年以内に大きな成果を求めることはありません。特に入社1ヶ月目は 「会社の理解」「製品解像度の習得」 に集中してもらいます。 ■ オンボーディングについて ラクスでは「新入社員受入チェックシート(約50項目)」を進めてもらいます。 バディ体制 メインバディ :最初の業務フォローを担当 サブバディ :メイン不在時の相談先 また、1ヶ月間はマネージャーと週1〜2回の1on1を実施し、初期の6ヶ月目標もリーダー・メインバディで設定。 早期に「製品解像度」を上げる環境を整えます。 1〜2週目からはチャットや各種MTGにも参加し、 実務の情報もキャッチアップしてもらいます。多くのPdMは1ヶ月後半で 「そろそろ案件を担当したい」と意欲を見せる方が多いため、そこから軽微な案件をアサインする流れが一般的です。 今回のメンバーも同様でした。 ■ PdM担当後に起きた課題 担当後2〜3ヶ月は特に問題ありませんでしたが、3ヶ月目以降から以下のような課題が顕在化しました。 案件PRDの質 課題の解像度が粗い ステークホルダーとの認識齟齬が複数回発生 振り返ると、主因は以下の 「アサインミス」 だと判断しています。 それまでとは次元の違う難易度の案件を担当させてしまった その案件は、メインバディが担当しても難しかったレベルの内容だった PdMはステークホルダーとの信頼が生命線です。ここで信頼が揺らぐと、その後の業務が非常に進めづらくなります。そのため、本案件から外し、完全に再育成に入る決断をしました。 再育成を選んだ理由は以下です。 これまでの経験は「デリバリー寄り」で、「ディスカバリー」が弱かった 担当プロダクトは今後も高難易度案件が発生し続ける(OJTでは限界がある) ■ 再育成の進め方 ラクスでは、若手エンジニアをPdMへキャリアチェンジさせる際に 育成カリキュラム を作成しました。 今回はそれをベースに進めています。 カリキュラム概要 1.課題図書 → レポート作成 → メンターと議論 ■課題図書 『 問題解決――あらゆる課題を突破する ビジネスパーソン必須の仕事術 』 『 ロジカル・プレゼンテーション――自分の考えを効果的に伝える戦略コンサルタントの「提案の技術」 』 ■レポート内容 書籍を読んで印象に残ったことや気づき 自分ができている/できていない部分の整理 これまでの実務事例との紐付け※フォーマット自由 2.社内e-learning受講 ロジカルシンキング ラクスの事業理解 ラクスには豊富なe-learningコンテンツがあり、必須なものもあればそうでないものもあります。その中で、ピックアップしたものを受講してもらっています 3.「自分のイシューは何か?」ワーク ワーク:書籍『 イシューからはじめよ 』を読んだ上で「自分自身のイシューとは何か?」を提示せよ これは難易度が高く、平均して4〜5回のレビュー・議論を行います。 今回は当初リーダーがメンターとして実施しておりましたが、リソース逼迫により途中から私が直接担当しました。 ■ 「自分のイシュー」課題の狙い 狙いは以下の4点です。 1. ディスカバリーには「なぜ?」を問う力が重要 2. 多くの課題を見つけても「イシュー」を特定しないことにはディスカバリーできたとは言えない 3. 自分自身を対象にするため、他者への迷惑がかかりにくい 4. 成長の鍵である「メタ認知」を強化できる 育成側・育成される側双方に「評価基準」を最初から提示しています。  ※育成される側に徐々に開示している チェックポイント(育成側) 本人なりの「あるべき姿」が定義されている 単なる現状改善ではなく、自分の頭で考えた言語化になっている 「現状」と「あるべき姿」のギャップが構造化され、MECEになっている 課題と問題が区別できている 一次情報を元に事実と解釈を分離できている 最終的なイシューが以下を満たす 本質的な選択肢である(解決すれば価値が出る) 答えを出せる(解決策を示せる) イシューまでの流れがストーリーとして一貫している ここまで読んでお気づきの方もいると思いますが、 これはそのまま 「プロダクトマネジメント」 です。 つまり、 「自分自身」をプロダクトと見立てて、プロダクトマネジメントしてもらう というのが本課題の本質です。 ■ 次の育成課題へ このメンバーは10月に本課題をクリアしました。業務と並行しながら 約3ヶ月で完了 した点は素晴らしい進捗だと思います。 次に取り組んでもらっているのは—— 「PdM・デザイナーの業務をプロダクトマネジメントせよ」 具体的には、 PdM/デザイナー業務の中から課題を発見し、それを解決することでチームに貢献する というテーマです。 この課題の狙いは以下の3点です 1. 「自分のイシュー」より範囲が広くなり、難易度が格段に上がる 2. 成功すればチーム貢献となり、関係者からの信頼を獲得できる 3. チーム内でバラバラに取り組んでいたAI活用・生産性改善の棚卸しができる 私が育成を直接見ているため、難易度調整も可能で、成功確率を高められます。再育成を担当してまだ2ヶ月ほどですが、今の課題を確実にクリアし、2026年4月からは高いレベルで実案件に戻ってほしいなと思っています。 最後に 採用・オンボーディング・育成について紹介しましたが、 ラクスは「人への投資」を非常に大切 にしています。 また、記事を読んでラクスのプロダクト部に興味を持ってくださった デザイナー/PdM の方 は、ぜひカジュアル面談からご応募ください。 ●採用情報 デザイナー career-recruit.rakus.co.jp   └ デザインマネージャー career-recruit.rakus.co.jp /アシスタントマネージャー career-recruit.rakus.co.jp
アバター
この記事は ラクスアドベントカレンダー2025 17日目 の記事です。 はじめに こんにちは! エンジニア3年目のTKDSです! 今回はgo-gitについて紹介します。 はじめに go-gitとは 基本的な操作 応用的な操作 実例 差分があったファイルのみSQL実行 まとめ go-gitとは https://github.com/go-git/go-git goで書かれたgit操作用ライブラリです。 git操作とGoコードを組み合わせかけるので、非常に汎用性が高く便利です。 基本的な操作 まず基本的な操作を紹介します。 今回はPublicリポジトリなので、認証部分は省いてます。 一部抜粋して載せてきます。 全文は リポジトリ に載せてあるので、main.goにコピペして実行してください。 clone リモートリポジトリをcloneする操作は以下のとおりです。 r, err := git.PlainClone( "poc/" , &git.CloneOptions{ URL: "https://github.com/tkeshun/go-git-poc" , Progress: os.Stdout, // 進捗を表示したくなければ nil でOK }) これを使って、cloneしてからlogを表示するコードを実行すると以下のようになります。 add addしてステータス確認 if _, err := wt.Add(addpath); err != nil { slog.Error( "Add Error: " + err.Error()) return } st, _ := wt.Status() print (st.String()) addして取り消すコードを実行すると以下のようになります。 なぞの文字列とファイル名が表示されてますが、Aがadd, ??がステージング前を表しているようです。 commit commitする操作は以下のとおりです。 if _, err = wt.Commit( "test" , &git.CommitOptions{ Author: &object.Signature{ Name: "go-git-invalid" , Email: "" , When: time.Now(), }, }); err != nil { slog.Error( "commit Error: " + err.Error()) } commitするコードを実行するして git log でみるとcommitが追加されてるのがわかります。 このcommitを消したいときはheadを親commitに戻して、indexをリセットすれば良いです。 ※ Errorハンドリング書くのめんどくさくなって省略してますが、実際はだめです!!! headRef, _ := r.Head() headCommit, _ := r.CommitObject(headRef.Hash()) parent, _ := headCommit.Parent( 0 ) wt.Reset(&git.ResetOptions{ Commit: parent.Hash, Mode: git.MixedReset, }) さっきのcommitが消えて親commitに戻ってます。 ここまででよく使う操作は紹介できました。 push(※番外) 一応公式のexampleにPushもあります。 現状私があまり必要としてないため飛ばします。 興味がある人は 公式example みて試してみてください。 このように、goコード上からclone, add, commit, pushなどの基本の操作が可能です。 応用的な操作 次に応用的な使い方です。 指定したcommitハッシュ間の比較 Hash値を指定して比較することで差分の比較が可能です。 ファイル差分を単純に比較することや差分内容を取得することができます。 commitが隣合わせでなくても差分は出すことができ、1commitで複数のファイルをcommitしていたとしても1ファイルずつ差分を取り出せます。 t1, _ := r.CommitObject(commit1Hash) t2, _ := r.CommitObject(commit2Hash) p, _ := t1.Patch(t2) この3つの処理で差分を取り出せ、 p.FilePatches() に差分が入ってるので、それをループで回すとファイルごとに2点のcommit間の差分を取り出せます。 for _, fp := range p.FilePatches() { } 色々試したサンプルを載せおきます。 package main import ( "fmt" "log/slog" git "github.com/go-git/go-git/v6" "github.com/go-git/go-git/v6/plumbing" ) func main() { r, err := git.PlainOpen( "./poc" ) if err != nil { slog.Error(err.Error()) return } commit1Hash := plumbing.NewHash( "cacf82fd8a097b8266fb7a7c84f02a9a1a599a4c" ) commit2Hash := plumbing.NewHash( "b20da7389753009b3cd6be1ae0cc66e5551e8916" ) t1, _ := r.CommitObject(commit1Hash) t2, _ := r.CommitObject(commit2Hash) p, _ := t1.Patch(t2) print (p.String()) for _, fp := range p.FilePatches() { from, to := fp.Files() if from != nil { f := from.Path() fmt.Println(f) } if to != nil { t := to.Path() fmt.Println( "file: " + t) } for _, c := range fp.Chunks() { fmt.Println(c.Content()) } } } ブランチ間の比較 Reference関数でブランチとハッシュが取れるので、Reference関数が要求する plumbing.ReferenceName を plumbing.NewBranchReferenceName を作ります。 Reference関数を使うと返り値で *plumbing.Reference が取得できます。 *plumbing.Reference.Hashを使うとハッシュ値が取得できるので、あとは同じようにcommitハッシュの差分をとれば、ファイル差分の取得ができます。 r, err := git.PlainOpen( "./poc" ) if err != nil { slog.Error(err.Error()) return } ref1, err := r.Reference(plumbing.NewBranchReferenceName( "main" ), true ) if err != nil { slog.Error(err.Error()) return } fmt.Println(ref1) ref2, err := r.Reference(plumbing.NewBranchReferenceName( "test" ), true ) if err != nil { slog.Error(err.Error()) return } // あとは同じ 最新版と旧版の比較 fetchと組み合わせて使うことで、現在あるremoteの状態と最新のremoteの状態の比較が可能です。 コードは以下のようになってます。 package main import ( "fmt" "log/slog" git "github.com/go-git/go-git/v6" "github.com/go-git/go-git/v6/config" "github.com/go-git/go-git/v6/plumbing" ) func main() { r, err := git.PlainOpen( "./poc" ) if err != nil { slog.Error(err.Error()) return } remoteRefName := plumbing.NewRemoteReferenceName( "origin" , "test" ) beforeRef, err := r.Reference(remoteRefName, true ) if err != nil { slog.Error(err.Error()) return } beforeHash := beforeRef.Hash() err = r.Fetch(&git.FetchOptions{ RemoteName: "origin" , RefSpecs: []config.RefSpec{ "+refs/heads/test:refs/remotes/origin/test" , }, }) if err != nil && err != git.NoErrAlreadyUpToDate { slog.Error(err.Error()) return } afterRef, err := r.Reference(remoteRefName, true ) if err != nil { slog.Error(err.Error()) return } afterHash := afterRef.Hash() if beforeHash == afterHash { fmt.Println( "diff: no changes" ) return } beforeCommit, err := r.CommitObject(beforeHash) if err != nil { slog.Error(err.Error()) return } afterCommit, err := r.CommitObject(afterHash) if err != nil { slog.Error(err.Error()) return } patch, err := beforeCommit.Patch(afterCommit) if err != nil { slog.Error(err.Error()) return } for _, fp := range patch.FilePatches() { _, to := fp.Files() if to != nil { t := to.Path() fmt.Println( "file: " + t) } for _, c := range fp.Chunks() { fmt.Print(c.Content()) } } } 実行してみると下記画像のようになります。 2回目はもう更新済みなのでdiffがでません。 このように、単純なcommit間の差分、ブランチ間の差分、最新化した差分など様々な差分が取得できます。 実例 使用例を出してみました。 以前、登壇したことのある発表で出したツールの簡易版です。 差分があったファイルのみSQL実行 応用例で紹介したように、現状のHeadのcommit Hashを保持しておいてfetchをしたあとまたHeadのcommitを取得することで、更新差分が取得できます。 これを使うと、ブランチに新しく追加されたファイルを検知し、実行することができます。 コードは長いのでリポジトリをみてください。 差分検出にsql実行部分をくっつけます。 commitとpushして実行します。 init.sqlは以下のようになってます。 CREATE TABLE IF NOT EXISTS demo_items ( id bigserial PRIMARY KEY, name text NOT NULL UNIQUE , note text NOT NULL DEFAULT '' ); go run main.goで実行したあと、DBにつないで実行するとテーブルが作成されていることがわかります。 今回は単純な実行コードですが、もう少し作り込むならSQLファイルの内容チェックなどがあったほうがよいですね。 insertとselectも順番にやってみましょう 投入と検索もうまくいきました。 もし差分検知して自動実行したい場合は、これを定期起動すれば差分の自動実行もうまくいきそうです。 まとめ ここまでみていただきありがとうございました。 今回はgo-gitの紹介と簡単な実用例を紹介しました! 実際に社内用のプロダクトでも使われており非常に便利なライブラリです。 この記事でgo-gitに興味持った人は、ぜひgitを活かして色々やっててみてください!
アバター
こんにちは。株式会社ラクスで「楽楽債権管理」のPdMをしている柴、PMMの江良です。 「楽楽債権管理」は 請求(債権)データと入金データの照合・消込を自動化するクラウドサービスで、入金の過不足、まとめ入金、名義違いといった実務で頻発する複雑なケースにも対応します。消込後の仕訳データも自動生成し、手作業では時間のかかる債権管理業務を正確かつスピーディーに進められるようにします。 https://www.rakus.co.jp/rakurakucloud/saikenkanri/ 「楽楽債権管理」は2025年7月、「楽楽明細」のオプション機能からスピンアウトし、単独プロダクトとして販売を開始しました。単独化によって事業のポテンシャルは大きく広がりましたが同時に、ステークホルダーの増加や組織の拡大により、立ち上げ期のような少人数の阿吽の呼吸だけではスケールしなくなりました。 そこで必要になったのが、体系的で再現可能なプロダクトマネジメント、そしてチーム全員が「同じ地図」を持って進むための仕組みでした。この記事では、「楽楽債権管理」が新たなフェーズに向かう中で、どのようにその「地図」が整備され、プロダクトと組織が変わっていったのかをご紹介します。 このnoteは、プロダクトの立ち上げ期〜成長前夜にいるチームに向けて書いています。戦略や役割がまだ曖昧で、「自分たちはどこへ向かっているのか」「どうやって再現性のある組織を作るのか」に悩む方に、少しでも参考になれば幸いです。 立ち上げ期にあった課題感 役割を明確化し、組織の“ハブ”をつくる PdMは「開発・デザイン」のハブ PMMは「営業・CS」のハブ 戦略設計を「共通言語」に 顧客の声(VoC)の仕組みづくり データ活用による顧客行動の可視化 ロードマップを“見える化”する協働 おわりに 採用情報 立ち上げ期にあった課題感 単独化前後のチームには、次のような課題がありました。 データが整備されておらず、お客様の課題や利用状況を定量的に把握できない 戦略がなく、商談でよく出る要望を“積み上げ式”に対応していた チーム内の役割が曖昧で、意思決定の軸が人によって異なっていた こうした状況では、「プロダクトとしてどこへ向かうべきか」も「組織としてどう動くべきか」も不明瞭になります。ここから、再現性のある意思決定・役割分担・戦略共有に向けた取り組みを進めていきました。 役割を明確化し、組織の“ハブ”をつくる これらの課題に向き合ううえで、最初に取り組んだのが役割の整理でした。組織が拡大する中で、誰がどの領域をリードするのかを明確にすることも重要な課題でした。役割が曖昧なままでは情報が滞り、意思決定が遅くなってしまうためです。ラクスでは職能別組織体制を採用しており、それぞれが持つ専門性を最大限に活かしながらプロダクトを前に進めています。一方で、職能が分かれているからこそ、情報をつなぐためのコミュニケーションコストが一定かかるという側面もあります。そこで「楽楽精算」や「楽楽明細」と同様にPdMとPMMは役割を明確にし、“分断”ではなく“補完”として機能するよう再定義しました。 PdMは「開発・デザイン」のハブ エンジニアとの仕様検討 デザイナーとの構造・UI議論 技術的制約と顧客価値のバランス調整 PdMはプロダクトを「どう作るか」の中心に入りこみ、ビジネスの意図を開発に翻訳する橋渡し。 PMMは「営業・CS」のハブ 商談やデモからの学び CSが拾った利用実態や課題 市場動向・競合比較 PMMは顧客や市場のリアルをプロダクトへ返し、現場とプロダクトの温度差をなくす存在。 このハブ構造により、開発/デザイナー ←→ PdM ←→ PMM ←→ 営業/CSという情報の流れが生まれ、意思決定が早く、滞留しない組織へ変わりました。 戦略設計を「共通言語」に 最初に取り組んだのは PMF(Product-Market Fit)の定義 でした。当時は「PMFを目指す」という言葉だけが独り歩きし、何をもって達成と言えるのかチーム内で解釈がバラバラでした。そこで他プロダクトの状況や事業状況、プロダクトの利用データを整理し、いくつかの定量指標を設定。チーム全員が “PMFとは何か” を同じ言葉で語れる状態 にしました。さらに ICP(Ideal Customer Profile)を定義 し、「誰に価値を届けるのか」を明確化。業種、規模、利用システム、入金件数などの基準でターゲットを整理することで、ロードマップ、優先順位、マーケ施策の判断軸が一貫するようになりました。戦略を明文化したことで、議論のスタートラインが揃い、チームとして“同じ方向を向く”状態を作りました。 顧客の声(VoC)の仕組みづくり 次に取り組んだのが、顧客の声(VoC)を意思決定に活かす仕組み です。私たちはLookerによるデータ可視化に加え、VoCを毎月1回、PdMとPMMがあえて手動で整理する運用を取り入れています。自動集計ではなく全件に目を通すことで、数値化しづらいニュアンスや深層の課題を捉えられるためです。 VoCとPBIはすべて Notionで一元管理。PdM・PMMはもちろん、開発・営業・CSまで誰でもリアルタイムにアクセスできます。さらに、RICEスコアを参考にVoCを以下のような軸でスコアリングしています。 顧客規模 課題の頻度 代替手段の可否 その課題が事業成長に与える強さ(失注や解約につながる課題か) ICPとのマッチ度 定量的に整理することで、「大口顧客の1件の声」と「中堅顧客の複数の声」を公平に比較でき、単なる“要望リスト”ではなく戦略と一貫したロードマップに落とし込めるようにしています。 データ活用による顧客行動の可視化 VoCとは別に、実際の利用行動データから顧客の状態を捉える仕組みも構築しました。お客様ごとの利用ログを取得し、主要機能の利用状況を業務フロー単位で可視化。これによって、 主要業務がどれだけ実施されているか どの機能が活用されていないか どの工程で“詰まり”が生じているか といったプロダクトの実態が明確になりました。さらに、これらをスコアリングし利用が停滞しているお客様を自動検知。CSチームが能動的にフォローできる体制が生まれました。「ログの可視化 → スコアリング → CSアクション」の流れによって、プロダクトの価値をお客様の業務に定着させる循環を作りやすい仕組みにしています。 ロードマップを“見える化”する協働 ロードマップ策定は、PdM・PMMに限らず営業・CS・開発まで巻き込みながら進めています。 セグメントごとのニーズ整理 競合比較 商談だけでは見えにくい非定量な課題感の抽出 顧客価値の大きい領域を優先する判断 機能開発における規模や難易度 上記のような情報を現場から吸い上げ、プロセスを透明化することで、「このタイミングで、この顧客セグメントに、こういう価値を届ける」という共通理解が生まれ、プロダクトの方向性が揺らぎにくくなりました。 おわりに こうした取り組みの積み重ねにより、PdMとPMMが互いの領域に自然と“越境”しながら協働する文化が育ってきました。役割は分担しつつも、共通言語と共通の地図を持ち、チーム全体でプロダクトを育てる文化へと変化しました。 楽楽債権管理は今まさに成長フェーズへ踏み出しているプロダクトです。その中で積み重ねてきた仕組みと文化は、これからステークホルダーが増えても迷わず進んでいくための土台になると信じています。プロダクトが変わると組織が変わり、組織が変わるとまたプロダクトが変わる。この循環をこれからも回し続けていきたいと思います。 採用情報 career-recruit.rakus.co.jp
アバター
こんにちは、プロダクト部 部長の稲垣です。(自己紹介やこれまでのキャリアについて↓をご覧ください。) tech-blog.rakus.co.jp ■ 「Noを伝える技術」の感想 ■ イエスと言って「誠実に合意形成する」ための技術とは? ① まずは「強いイエス」を返す ② ただし、本当にやるのは「徹底的なリサーチ」 ③ そのまま“事実として”レポートする ④ 相手は自然と「今回はやめるか」と判断する ■この技術の良いところ 📝 まとめ:本気で向き合う姿勢が、結果的に“ノーを機能させる”あるいは“イエスのコミットメントをあげる” ■ 「Noを伝える技術」の感想 先日出版された 『 Noを伝える技術 プロダクトマネージャーが教える「敵を作らずに断れるようになる」作法 』 について触れたいと思います。 この書籍は、PdM界隈では知らない人はいないと言われる「Noを伝える技術 #pmconf2021」の登壇内容をもとにしています。 speakerdeck.com ただし登壇は20分、スライドは25枚ほど。 一方で書籍は、内容がより広く深く、そしてプロダクトマネージャーに寄り添った実践的な話が多く収録されています。 私は2021年8月にPdMを名乗り始め、pmconfを知ったのは2023年頃。登壇の存在もそれと同時でしたが、それだけ有名で、そして現場で刺さる内容です。本書で印象的だった一文があります。 『良かれと思ってやったこと』が積み重なった結果、まったく望まない方向に進んでしまうことがある 私はこれを何度も見てきましたし、自分自身も経験してきました。 だからこそ「Noを伝える」技術は、どの会社・どの立場でも必要で、多くの人が“心ではNO”と思っていることを言語化できるようになることは大きな価値があります。 ちなみに私は、読書の際に必ずメモを取るのですが、この書籍は2025年に読んだ約100冊の中でも、かなり上位のメモ量でした。 最近はこのメモをまとめて社内展開することで、書籍を読む文化を作ろうとしています。…と、思ったより書籍の話を書いてしまいましたが、ここからが本題です。 私自身が現場で使ってきた“イエスと言って「誠実に合意形成する」ための技術” を紹介します。 タイトルにもある通り、私がよく使うのは—— まずは「イエス」と言う。 そして、事実を積み上げることで"イエス”か"ノー"か相互に合意形成をしていく方法です。これを進めると自分から“ノー“と言う前に相手が“ノー“というケースもあります。 という方法です。 ■ イエスと言って「誠実に合意形成する」ための技術とは? 前職はわりとハードなベンチャーでは「イエスかハイかどっち?」と言われるような環境でした。ベンチャーでは珍しくない話ですが、この環境では「ノー」を直接言うと、話がややこしくなることがあります。 特に相手が強い自信を持っている提案や依頼に対して、正面からノーを言うのは得策ではありません。 ひどい場合、もしその後うまくいかないと「最初にノーと言ったせいだ」「本気でやっていなかった」とさえ言われかねません。 そこで生まれたのが、次の方法です。 ① まずは「強いイエス」を返す 相手が自信満々のときに正面からノーを言っても勝てません。なので私はまず、あえて 力強いイエス を返します。 ✔ 「いいですね、やりましょう」 ✔ 「確認します。まず真剣に調べます」 “乗り気である”姿勢を見せることで、相手はこちらを信頼し、前向きに期待してくれます。 ② ただし、本当にやるのは「徹底的なリサーチ」 イエスと言ったからには、最初に 本気でリサーチ します。 経営者の直感はまとはずれなことは少ないです。 調べてみると、想像以上に価値があることも多い。しかし、深掘りしていくと… 大きなリスク 想定外の障害 無謀さを示すエビデンス が出てきます。 ③ そのまま“事実として”レポートする ここが最重要ポイントです。私は、そのリサーチ結果を淡々と報告します。 ✔ 依頼を本気で実行しようとした際に見えてきたリスク ✔ プロジェクトを阻害する障害 ✔ 実行時の工数・コスト・競合状況 ✔ 成功確率が低い理由(エビデンス付き) “やらない理由”ではなく “本気でやるにはここが問題です” というスタンスで伝えるのが大事。 ④ 相手は自然と「今回はやめるか」と判断する ここまで来ると相手は、 「これは一度立ち止まったほうが良いかもしれない」 と 自分自身で判断 してくれます。つまり、私がノーと言うのではなく、 相手がノーと言ってくれる のです。 しかも、こちらは“最初にイエスと言っている”ので、関係性にマイナスが一切ありません。 むしろ信頼が高まります。また、仮にそれでもやるとなった場合には、最初に「ノー」と言わず進めるべきものだったのだと思います。 ■この技術の良いところ ① 相手との関係性が傷つかない 最初に前向きに受ける姿勢を示すので、否定の空気が残りません。 ② 事実ベースの議論になる 感情論ではなく、リスク・データ・実態という“事実”で判断できます。 ③ 意外な「価値の芽」にも出会える 本気でリサーチすると、 「これ、いけるじゃん」「思ったより価値あるな」というケースもあります。 ④ 結局は“やるべきこと”だけが残る 取り下げられなかったものは、本当にやる価値があるものだったと後からわかる。 📝 まとめ:本気で向き合う姿勢が、結果的に“ノーを機能させる”あるいは“イエスのコミットメントをあげる” 私はこの方法で、多くの場面を乗り切ってきました。 そして副産物として、依頼者からの信頼が下がることはありませんでした。 どんな提案でも本気で向き合う。そして事実で会話する。 この姿勢が、もっとも健全で、もっとも誠実な「ノーの伝え方」になると感じています。 ぜひ皆さんも、機会があれば試してみてください。 また、記事を読んでラクスのプロダクト部に興味を持ってくださった デザイナー/PdM の方 は、ぜひカジュアル面談からご応募ください。 ●採用情報 デザイナー career-recruit.rakus.co.jp   └ デザインマネージャー career-recruit.rakus.co.jp /アシスタントマネージャー career-recruit.rakus.co.jp
アバター
この記事は ラクス Advent Calendar 2025 12日目の記事です。 はじめに こんにちは。ラクス フロントエンド開発課のたぐちです。 今回は、私たちフロントエンド開発課で取り組んでいる 学習文化の醸成に関する取り組み をご紹介します。 はじめに 取り組み内容 情報共有会の良いところ 1. 学習のハードルが下がる 2. メンバーの価値観や思考を知る機会が増える 3. 気になる技術をその場で試せる 今後の改善ポイント 1. ファシリテーターが固定化している問題 2. 記事を投稿するメンバーが偏りがち おわりに 取り組み内容 私たちのチームでは Notion を活用し、メンバーが日頃気になった記事や情報を随時ストックしています。 その中から、他のメンバーも気になった記事に「マーク」が付いたものを選び、 週次の情報共有会(1時間) で内容を確認したり議論したりしています。 記事共有の様子 以前は隔週開催としていましたが、最近は AI をはじめ技術の変化が非常に速いため、 「隔週ではキャッチアップが追いつかない」という声を受け、 毎週開催 へと変更しました。 また、Notion に追加された記事は Notion と Gemini の API を活用し、チャットツールへ要約を通知しています。 記事要約の例 情報共有会の良いところ 1. 学習のハードルが下がる 「エンジニアは日々の勉強が大事」というのは多くの人が感じていることだと思いますが、常に最新情報を一人で追い続けるのは、慣れていないと負担が大きいものです。 特にフロントエンドは移り変わりが激しいと言われていますが、AI はそれをさらに上回る速度で変化しています。追従しようとすると目が回りそうになります(私だけでしょうか…?)。 そこで、チーム全体で学習を共有する場をつくることで、 個々がキャッチアップし続ける負荷を抑えながら学習を進められる ようになっています。 2. メンバーの価値観や思考を知る機会が増える 業務中にも相談や議論はありますが、 開発とビジネスの距離をどう縮めるか 不要な機能の削減(いわゆる「機能の引き算」)をどう進めるか プロダクトの本質的な価値をどう捉えるか といった根源的なテーマを語り合う機会は意外と多くありません。 情報共有会ではジャンルを限定していないため、記事によってはこうしたテーマに踏み込んだ 普段は出てこない深い議論 が生まれることもあります。メンバーの考えを知る貴重な場になっています。 3. 気になる技術をその場で試せる 記事の確認が早く終わった場合は、紹介された内容を実際に触ってみる時間にしています。 たとえば、 新しい MCP Claude の Skills 機能 Playwright Test Agents など、多岐にわたります。 記事を読むだけでなく、その場で手を動かすことで理解が深まり、議論もより活発になる と感じています。 今後の改善ポイント 1. ファシリテーターが固定化している問題 現在は言い出しっぺである私がずっとファシリテーターを担当していますが、 私が休むと運用が止まってしまう メンバーがファシリテーションを練習する良い機会になる という理由から、 今後はローテーション制にしたい と考えています。 2. 記事を投稿するメンバーが偏りがち フロントエンドや AI 関連など、全員が興味を持ちやすい領域では記事が被りやすく、結果として毎週ほぼ同じメンバーが投稿してしまいがちです。 解決策としては、たとえば その週に投稿していない人の意見をファシリテーターが優先して聞く 投稿されていないジャンルを意識的に拾う といった工夫が考えられ、より多様で活発な議論につながるのではないかと思っています。 おわりに 以上、私たちの学習文化の醸成に関する取り組みをご紹介しました。 「受験は団体戦」とよく言われますが、 エンジニアリングの学習もチームで取り組むことでハードルが下がり、継続しやすくなる と実感しています。 もし技術の移り変わりの速さにキャッチアップが追いつかないと感じている場合は、ぜひチーム内で試してみてください。
アバター
はじめに 請求書の明細表をOCRによって自動で読み取ることができると、経理業務自動化の実現に役立ちます。 ところが実際には、多様なフォーマットの存在や OCR の誤読が積み重なり、AIモデルとルールベース後処理だけでは思った以上に精度が出ない、という壁にぶつかることがあります。 AI モデルそのものの改修となると、学習データの追加やモデル更新など、時間もコストも必要になります。また、ルールベース後処理を増やし続けるのは、将来の保守を重くする心配がつきまといます。 そこで、「大規模言語モデル(LLM)を後処理に加えたら、より柔軟に・より構造的に・まるで人間が行うように誤りを補正できるのではないか」という発想のもと、既存処理に GPT による補正ステップを追加し、精度改善ができるか検証しました。 はじめに LLM による後処理の追加 追加した処理の流れ GPT に与えたプロンプト 検証結果 まとめ LLM による後処理の追加 今回の検証では、ルールベース処理の“あと”に GPT による補正ステップを入れています。 使うのは画像入力に対応した gpt-4.1。表画像と OCR 結果(CSV)を突き合わせ、表構造と内容の整合性を取る役目を担います。 追加した処理の流れ 具体的にGPT が担うのは次のような作業です。 明細表の画像と既存処理の OCR 結果(CSV)を受け取る 画像と CSV を突き合わせ、 行・列のズレ修正 分割/結合ミスの調整 欠損・誤認文字の補正 修正済み CSV を返却 座標情報の扱いは精度を安定させるのが難しく、今回は見送りましたが、将来的には実装したい部分です。 GPT に与えたプロンプト 今回の補正処理は、次のような指示文(抜粋)を与えて実施しました。 表構造の統一、セル内容の整理、誤認識文字の補正など、発生しやすいゆがみを吸収するよう工夫しています。 refine_table_prompt = """表のOCR結果が次のようにCSV形式のテキストで与えられています。 {} 同時にOCR対象となった表の画像も与えられています。 表の画像を参照しながら、CSV形式のテキストを修正して下さい。 その際、以下の条件に従って修正を行って下さい。 条件: 1. 画像内の表の構造に基づいてCSV形式の行や列の構造を修正して下さい。 2. すべての行で同じ列数になるように修正して下さい。 3. 「||」は改行箇所を示しています。セル内の改行は「||」で表現してください。 4. 誤って複数行が1つのセルに入っている場合は、適切に分割してください。 5. ~ """ 検証結果 検証データ 165 件 を使い、 既存処理のみ GPT 補正を追加した処理 の比較を行いました。 結果として、 38 件で明確な精度向上が確認されました。 特に目視では、 列境界の誤りが正しく補正される 1 件の明細データが複数行に分離される誤りの統合 誤った行分割の修復 など、「人が見たらこう直したい」という形にかなり近づく改善が見られました。 一方でデメリットもあり、 コスト:検証データでは 1 リクエストあたり0.4~0.6 円(明細表の内容による) 処理時間:1〜5 秒 程度の追加(これも明細表の内容に依存) 後処理ルールをメンテナンスし続けるよりは負担が軽い?ものの、低コストの明細表読み取り実現やリアルタイム処理には少し工夫が必要かと思われます。 まとめ LLM を既存の OCR パイプラインに組み合わせることで、“ルールで吸収しにくい構造的なズレ” を補正でき、一定の精度向上が確認できました。 特に、 多様な書式の請求書を扱う ルールのメンテが重くなっている といった課題に対して、相性の良い手法かと思います。 一方で、「コストと処理時間の増加」という課題もあるため、実運用にはもうひと工夫が要りそうです。 今後は、座標情報を扱えるように処理を改修したり、より高性能なモデル(gpt-5.1のような推論モデル)を利用したりすることで、明細表読み取り処理をより優れたものにしていければと考えています。
アバター
※この記事は ラクスアドベントカレンダー 2日目の記事です はじめに こんにちは! エンジニア3年目のTKDSです! 今回はEKSでOtel Collectorを用いたContainer Insightsメトリクスの取得についてご紹介します。 ぜひ最後まで見ていってください! はじめに Container Insights Otel Collectorによるメトリクスの収集 Otel Collectorのマニフェスト例 まとめ Container Insights Container Insightsを使うとEKSクラスタからnodeやPodなどからCPU、メモリ、ディスク、ネットワークなどさまざまなメトリクスが取得可能です。 ※詳しくは AWSのドキュメント をご覧ください。 ※収集されるメトリクスについて知りたい方は こちらのドキュメント を見てください。 Otel Collectorによるメトリクスの収集 色々なメトリクスが取れるContainer Insightメトリクスですが、実はOtel Collectorでも取得することが可能です。 さらに、Otel Colectornにあるprocesserを使うことができるので、不要なメトリクスを落としてCloudWatchに送信することが可能です。 取得する流れは以下の図のようになってます。 まずAWS Container Insights Receiver(awscontainerinsightreceiver)がcollection_intervalに従って、定期的にメトリクスを取得します。 そのメトリクスに対して、processorでfilterを使い不要なメトリクスを落とします。ここで不要なメトリクスを落としておくことでCloudWatchの課金を抑えられます。 最後にexportersでawsemfを使って、 埋め込みメトリクスフォーマット というCloudWatch logsにメトリクスを取得するように指示する形式に変換して送信します。 Otel Collectorのマニフェスト例 次に実際に使ってるマニフェストの一部を下記に示します。 このマニフェストでは、 nodeとpodのCPUとメモリを取るようにしてます。 同じことをしたい人はぜひ参考にしてください。 apiVersion : v1 data : collector.yaml : | receivers : awscontainerinsightreceiver : collection_interval : 300s exporters : awsemf : dimension_rollup_option : NoDimensionRollup log_group_name : /aws/containerinsights/{ClusterName}/performance log_stream_name : performance/{NodeName} metric_declarations : - dimensions : - - Namespace - ClusterName metric_name_selectors : - pod_cpu_utilization - pod_memory_utilization - dimensions : - - NodeName - ClusterName metric_name_selectors : - node_cpu_utilization - node_memory_utilization namespace : ContainerInsights parse_json_encoded_attr_values : - Sources - kubernetes resource_to_telemetry_conversion : enabled : true debug : {} processors : batch : {} filter/drop_unused : metrics : metric : - name != "pod_cpu_utilization" and name != "pod_memory_utilization" and name != "node_cpu_utilization" and name != "node_memory_utilization" service : telemetry : logs : encoding : json level : error metrics : readers : - pull : exporter : prometheus : host : 0.0.0.0 port : 8888 pipelines : metrics : exporters : - awsemf processors : - filter/drop_unused - batch receivers : - awscontainerinsightreceiver CloudWatchでの保存先は以下の部分で指定しています。 自動作成されるので、事前の作成は不要です。 {ClusterName}と{NodeName}は自動で埋めてくれます。 ただ、"{NodeName}"のように書くとエラーで自動で埋めるのが機能しなかったため、適当に performance/ とつけました。 最後のnamespaceで指定した名前で、CloudWatchMetricsのnamespaceが作成されます。 log_group_name: /aws/containerinsights/{ClusterName}/performance log_stream_name: performance/{NodeName} namespace: ContainerInsights この設定で動かすと、CloudWatchに保存されます。 レコードは以下のような形で記録されます。(見せられない部分は伏せてます) { "AutoScalingGroupName": "xxxx", "ClusterName": "xxxx", "InstanceId": "xxxx", "InstanceType": "xxxx", "NodeName": "xxxx", "Sources": [ "cadvisor", "/proc", "pod", "calculated" ], "Type": "Node", "Version": "1", "_aws": { "CloudWatchMetrics": [ { "Namespace": "ContainerInsights", "Dimensions": [ [ "ClusterName", "NodeName" ] ], "Metrics": [ { "Name": "node_memory_utilization", "Unit": "Percent", "StorageResolution": 60 } ] } ], "Timestamp": 1764157664000 }, "kubernetes": { "host": "xxxx" }, "node_memory_utilization": 31.46575974804524 } 絞り込んだメトリクスだけ取れてるのがわかります。 この形式でロググループに入るとCloudWatch logsが自動でメトリクスに転送してくれます。 CloudWatchのページに行きContainerInsights→指定したDimension→メトリクスを選んで表示してみるとメトリクスを観察することができます。 ちなみにメトリクスとして取り込んだあとはemf形式のログは消しても問題ありません。 まとめ ここまで読んでいただきありがとうございました! 今回はEKSにおけるContainer InsightsメトリクスのOtel Collectorでの収集についてご紹介しました! filterでの柔軟なメトリクス削減は需要が高いのではないでしょうか? ぜひ興味ある方はお試しください!
アバター
こんにちは、プロダクト部 部長の稲垣です。(自己紹介やこれまでのキャリアについて↓をご覧ください。) tech-blog.rakus.co.jp 2025年4月、ラクスではプロダクト部が新たに組成され、デザイナーとプロダクトマネージャーが同じ組織に加わりました。 そして2025年10月から、私はこの組織のマネジメントを担うことになりました。 実は7〜8年前にも、兼務という形でデザイナーのファーストラインマネージャーを経験しており、採用も含めて直接マネジメントをしていた時期があります。 その経験があるため、今回デザイン組織が含まれることに対する不安はありません。むしろ プロダクトマネージャーとデザイナーが同じ組織でコラボレーションできることにワクワクしている というのが今の正直な気持ちです。 この記事では、これまでの自分とデザイン/デザイナーとの関わり、そして今回のマネジメントに向き合うにあたって考えていることをまとめました。 ラクスでデザイナーとして働く未来を考えてくれる方に、少しでも私の考えが届けば嬉しいです。 目次 「デザイン」との出会い SI企業時代:管理画面の“画面設計”から始まった はじめて「デザイン」を意識した案件 デザイナー理解が一気に深まった転職先での経験 ●フラッシュセールサイト:国内にないコンセプトを形に ●ECプラットフォーム:UXとクリエイティブの両軸 デザイナーが入るだけで“世界が変わる”という実感 デザイナー採用への深い関与 エンジニア出身の自分がデザインを理解するためにやった2つのこと 1. デザインに関する本を“読みまくった” 2. デザイナーと“とにかく対話しまくった” 再びデザイン組織のマネジメントへ ― 私が今思っていること ― 「デザイン」の認識を変えたい 最後に:ラクスのデザイナー組織に興味を持ってくれた方へ 「デザイン」との出会い SI企業時代:管理画面の“画面設計”から始まった 新卒で入社したのはSI企業でした。案件の多くはWeb開発で、いわゆる管理画面のようなUIが中心。UI/UXの概念はほとんどなく、 『入力 → 確認 → 完了 』のような単純なフローが基本。 CSSやJavaScriptもほぼ使わず、デフォルトHTMLボタンさえ「その方がいい」と言われるような時代でした。 はじめて「デザイン」を意識した案件 転機となったのは、toC向け求人サイトのプロジェクト。大手メガベンチャーの案件で、お客様先に常駐し、自社チームで要件定義からリリースまで担当しました。 デザインはお客様側のデザイナーに依頼する形だったため、自分はHTMLベースの画面を紙芝居のように作成。それを見たデザイナーから絶賛されたのは今でも印象に残っています。 広告枠を削り、とにかくユーザーの機能に集中した“シンプルさ”を評価してくれた。 この時、 デザイナーは広告やノイズの少ない“純粋な体験”を好む傾向があるのだな と初めて理解しました。 デザイナー理解が一気に深まった転職先での経験 その後、toC系・ゲーム系の企業へ転職。ここでデザイナーとの連携は圧倒的に密になりました。私が関わったプロダクトは以下: ブログサービス フラッシュセールサイト ECプラットフォーム(ネイティブアプリあり) ここでは“当時も優秀だと思っていたが、今振り返ると本当に優秀だった”と思えるデザイナーたちと仕事をする幸運に恵まれました。 ●ブログサービス:感性と論理の狭間で学んだ スマホ・PC対応を進める中で、代表が細部までデザインにこだわるタイプだったため、私もデザイナーと代表の間に立ち大量のやりとりを経験しました。代表の感性的な指摘に対して、デザイナーはその意図を聞き出し、言葉にならないイメージを視覚に落とし込んでいく。 ヒアリング力・翻訳力・表現力のすべてを見せてくれました。 ●フラッシュセールサイト:国内にないコンセプトを形に 海外サイトを参考に、国内にはない体験をデザインするプロジェクト。 完成した UI は自分から見ても「これは素晴らしい」と感じられるものでした。 ●ECプラットフォーム:UXとクリエイティブの両軸 デザイナーは バナー・LPなどのクリエイティブデザイン EC購入導線のUI/UXデザインの双方を担当。 マーケやセールスの要望を視覚化する一方で、 「なぜこのデザインなのか?」 を 言語化し、理論で説明する姿 を見て、行動心理学、デザインパターン、言語化の重要性を強く理解しました。 デザイナーが入るだけで“世界が変わる”という実感 ブランド向け管理画面のリニューアルでは、機能は大きく変えていないのに、デザイナーが入ったことでブランド担当者の印象が一気に改善したことがあります。また、 ネイティブアプリ 国内でも未導入のオンライン決済の導入の体験 写真からサイズを測る機能 など、UX領域で共に多くの挑戦をしました。 デザイナー採用への深い関与 新卒・中途・マネージャー採用にも関わりました。 50名以上のデザイナーと話した 経験は、今考えても大きな財産です。 エンジニア出身の自分がデザインを理解するためにやった2つのこと 結局、自分がデザインやデザイナーを理解するためにやったことはシンプルです。 1. デザインに関する本を“読みまくった” エンジニアのための理論でわかるデザイン入門 デザイン思考が世界を変える〔アップデート版〕: イノベーションを導く新しい考え方 デザインのデザイン デザインはストーリーテリング 「体験」を生み出すためのデザインの道具箱 誰のためのデザイン? 増補・改訂版 ―認知科学者のデザイン原論 ジョナサン・アイブ 偉大な製品を生み出すアップルの天才デザイナ ピクサー流 創造するちから 小さな可能性から、大きな価値を生み出す方法 特に印象に残っている書籍は 「ピクサー流 創造するちから」はいまでも読み返す愛読書です。 プロダクト部のキックオフでも、この本に出てくる “ブレーン・トラスト” を組織に導入したいと話しました。 2. デザイナーと“とにかく対話しまくった” デザイナーが参加するMTGに同席 なぜその質問をしたのか、なぜその表現にしたのかをひたすら聞く ワークサンプルテストに参加して理解を深める 採用面談でキャリア観や課題感を聞き続ける 「多分、かなり鬱陶しかっただろうな」と思うほど聞きました。 でもこの対話の量が、デザイナー思考を理解することにつながりました。 再びデザイン組織のマネジメントへ ― 私が今思っていること ― 2025年、ラクスのデザイナー組織は再始動しました。 若く優秀なデザイナーが多く、プロダクトの成長に日々向き合っています。その中で、私がまず変えていきたいと思っていることがあります。 「デザイン」の認識を変えたい 多くの人にとって「デザイン」は 見た目を整える UI/UXの領域 といった“狭義”で認識されがちです。 しかし、本来デザインとは 「問題を解決するための設計・計画全般」 であると思っています。 ※本資料はプロダクト部の発足の時に「社内ラジオ」(毎月技術広報が取り組んでる開発組織内での定期イベント)でも紹介ししたスライドの抜粋 ※もともとのスライドを「Nano-Banana」で綺麗にしてもらった 私は職能をこう捉えています: デザイナー:人の体験をより良くするために課題を見つけ、形にする専門家 エンジニア:課題を仕組みで解決し、それを動かし続ける専門家 そして今はこうも思っています。 『デザイナー』『エンジニア』全員がプロダクトマネジメントのマインドを持てるなら、 プロダクトマネージャーは“1人いればいい”のかもしれない。 最後に:ラクスのデザイナー組織に興味を持ってくれた方へ ラクスのデザイナー組織は2025年に再始動しました。 これから人数も増え、 リードデザイナー デザイナーマネージャー といった役割も必要になっていきます。 もし少しでも興味があれば、ぜひ応募をご検討ください。 プロダクトの成長に本気で向き合い、『顧客志向』で一緒に良いものをつくれる仲間を心からお待ちしています。 ●採用情報 デザイナー career-recruit.rakus.co.jp   └ デザインマネージャー career-recruit.rakus.co.jp /アシスタントマネージャー career-recruit.rakus.co.jp
アバター
この記事は ラクス Advent Calendar 2025 1日目の記事です。 はじめに こんにちは! エンジニア3年目のTKDSです! 今回はCodex CLI SDKの入門記事を書きました! Codex CLI SDKはChatGPTの有料プランに契約していれば、特に追加費用不要で使用可能です。 そのため、さくっとMy AIエージェントを作るのには非常におすすめです。 では早速本題に入っていきたいと思います。 はじめに Codex CLIの概要 Codex CLI SDKについて 環境情報 基本的な操作 お天気エージェントを題材にした解説 シンプルなエージェント 最終版 まとめ Codex CLIの概要 Codex CLI is a coding agent from OpenAI that runs locally on your computer. 翻訳:OpenAIが提供するローカルコンピュータ上で動作するコーディングエージェント. Codex CLIはOpenAIの提供するモデルが使えるコーディングエージェントです。 Codex CLI SDKについて codex exec相当の処理をTypeScript(JavaScript)コード上から実行できるSDKです。 プログラムから使えるので、処理の流れを書きやすくなったり、TS(JS)ライブラリの使用・連携ができます。 今回このSDKを使ってエージェントを作ってみます。 環境情報 nodeは24.11.1を使いました。 $ node --version v24.11.1 codex、codex-sdkとmodelcontextprotocol/sdkを使いました。 細かいところは リポジトリ みてください。 mise install node@24.11.1 mise use -g node@24.11.1 npm i -g @openai/codex npm install @openai/codex-sdk npm install @modelcontextprotocol/sdk codexの設定は以下のようにしておきます。 今回用に余計なMCP設定は消してます。 [ sandbox_workspace_write ] network_access = true # 機能フラグ [ features ] web_search_request = true 事前に codex login しておいてください。 基本的な操作 // QuickStartにあるコード参考にしたコード import { Codex } from "@openai/codex-sdk" ; const codex = new Codex(); const thread = codex.startThread(); const turn = await thread.run( "東京の今日の天気は?" ); console . log (turn.finalResponse); console . log (turn.items); codexの操作関連について軽く解説します。 Codexとのやり取りをするオブジェクトを作成します new Codex() 1セッションを開始するのに相当する操作です codex.startThread() メッセージの送信操作です、これを繰り返すと同じセッションにメッセージを送信し続けられます thread.run() 逐次的にレスポンスを受け取りたい場合はこちらを使います。 codex.runStreamed() runStreamedを使う場合、 サンプルコード にあるようにawaitを使って非同期処理にすると良さそうです。 const { events } = await thread.runStreamed( "Diagnose the test failure and propose a fix" ); for await ( const event of events) { switch (event. type ) { case "item.completed" : console .log( "item" , event. item ); break ; case "turn.completed" : console .log( "usage" , event.usage); break ; } } お天気エージェントを題材にした解説 基本的な操作は説明したので、次にお天気エージェントを題材に実際にCodex CLI SDKを使ってみます。 追加のOpenAI API Keyの設定などは不要です。 codex login だけできてるか確認しておいてください。 シンプルなエージェント まずは単純にcodex cliをSDK経由で呼び出すエージェントを作ってみましょう。 シンプルにスレッドで天気を聞くだけです。 import { Codex } from "@openai/codex-sdk" ; const codex = new Codex(); const thread = codex.startThread(); const turn = await thread.run( "今日の東京の天気は?" ); console . log (turn.finalResponse) 何回か呼んでみると回答はぶれるものの大体ほしい回答を返してくれます。 $ npm run dev > codex-cli-sdk@1.0.0 dev > tsx src/index.ts **東京の天気 (2025年11月23日)** - 現在: 快晴で約11 °C。冷え込む朝なので薄手のコートやニットが安心。 - 朝~昼: 07時頃10 °C→正午前後で17 °C近くまで上昇。日中は日差しがあり比較的穏やか。 - 夜: 深夜に向けて再び10 °C前後まで下がる見込み。帰宅が遅くなるなら上着を忘れずに。 $ npm run dev > codex-cli-sdk@1.0.0 dev > tsx src/index.ts **東京の天気** - 現地時間2025年11月23日(日)の東京は晴れて気温11 °C前後。日中は次第に雲が増え、最高15 °C、最低9 °Cの予想です。 - 11月24日(月)は最高18 °C/最低9 °Cで晴れ間が広がり過ごしやすい見込み。 - 11月25日(火)は雲が多めで最高15 °C/最低9 °C、26日(水)は午後に風が強まるものの晴れて18 °Cまで上がる予報です。 $ npm run dev > codex-cli-sdk@1.0.0 dev > tsx src/index.ts 2025年11月23日現在の東京は快晴で、気温はおよそ11°C(51°F)です。 未明から早朝にかけては晴天が続き、気温は9~11°C程度まで下がる見込みです。 午前になると晴れをキープしつつ徐々に気温が上がり、正午前後には16~17°C付近まで昇る予報です。 ただ回答形式がブレブレなので、適当にシステムプロンプト作って添付してみましょう。プロンプトはChatGPTでさくっと作ったのをベースに結構いじりました。 コツはoutput_templateを最後に持ってくることです。 user_inputが最後になると出力形式がどうしても安定せず思い通りの出力が得られないことが多いです(体感7割失敗)。 import { Codex } from "@openai/codex-sdk" ; const codex = new Codex(); const thread = codex.startThread(); const system_prompt = ` <system-prompt> # システムプロンプト あなたは天気情報専用アシスタントです。 - 常に「いつ・どこ・どんな天気か」を明示して、簡潔な日本語で答えます。 - 最新かつ信頼できる情報に基づき、不確実な点はその旨を明示します。 - 危険な気象では、公式機関の情報確認と安全への注意を必ず促します。 - 天気と無関係な質問には、天気専門であることを伝えて簡潔に断ります。 # 調査内容 1. 詳細 * 降水: 降水確率 {{降水確率}}%、予想降水量 {{降水量}}mm(あれば) * 風: 風向 {{風向}}、風速 {{風速}}m/s(強風時はその旨) * 湿度・体感: 湿度 {{湿度}}% 程度、{{蒸し暑く感じる/乾燥しやすい/体感は気温どおり}} 2. 行動の目安 * 服装: {{長袖/半袖/上着の有無などの簡単な目安}} * 持ち物: {{折りたたみ傘/日傘/帽子/飲み物/防寒具 など}} 3. 注意事項 * {{大雨/雷/強風/猛暑/大雪 など}} のおそれ: {{あり/なし}} * 必要に応じて: 「最新の警報・注意報は気象庁など公式情報を確認してください」 * 時刻はJSTを基準に調査 4. 補足(任意) * 洗濯・外出・運転などの簡単な一言アドバイス: {{例: 洗濯物は外干しで問題なさそうです など}} </system-prompt> ` const output_template = ` ユーザーへの回答には参考リンクなどは不要です。 # 出力テンプレート <output_template> * 日時: {{日付・時間帯}} * 地域: {{地域名}} * 天気: {{天気の要約}}(例: 晴れ時々くもり、にわか雨の可能性あり) * 最高/最低気温: {{最高気温}}℃ / {{最低気温}}℃ * 服装等のアドバイス: {{行動のアドバイス}} </output_template> <output_template_error> 天気専門なので答えられません </output_template_error> # 作業手順 1. <user_input>が天気についてか判断し、違った場合<output_template_error>を出力して終了。天気についての場合2へ遷移 2. お天気エージェントとして動作。作業が完了したら3へ遷移 3. output_templateに従って回答 promptにしたがって、作業してください。 ` // const user_input = "今日の東京の天気を教えて" const user_input = "一発芸して" const prompt = [ system_prompt, "<user-input>" ,user_input, "</user-input>" ,output_template ] const turn = await thread.run( prompt . join ()); console . log (turn.finalResponse) 何回か試してみます。 $ npm run dev > codex-cli-sdk@1.0.0 dev > tsx src/index.ts * 日時: 2025-11-23(日) 終日(JST) * 地域: 東京都心 * 天気: 日中は晴れて夕方以降ゆっくり雲が広がる見込み。降水確率や降水量の公式値は未取得ですが現状は雨要素なしと見られます。風は弱い北寄りと推定、湿度も大きく変化せず体感は気温どおり * 最高/最低気温: 15℃ / 9℃ * 服装等のアドバイス: 長袖+薄手の上着で快適、朝晩は冷え込むため軽いコートがあると安心。日中は乾きやすいので飲み物でこまめに保湿。大きな荒天リスクはありませんが最新の警報・注意報は気象庁などでご確認ください $ npm run dev > codex-cli-sdk@1.0.0 dev > tsx src/index.ts * 日時: 2025年11月23日(日) 日中~夜(JST) * 地域: 東京都心 * 天気: 午前は穏やかな晴れ、午後は雲が増える見通しで大きな崩れは今のところ見込まれていません;降水確率・降水量、風向・風速、湿度の詳細は今回取得できなかったため、必要に応じて最新の公式情報を必ずご確認ください。 * 最高/最低気温: 15℃ / 9℃(日中も空気はひんやりで体感は気温どおり) * 服装等のアドバイス: 朝晩は冷えるので薄手ニット+コートなど長袖の重ね着が安心、日中も羽織り物を携帯すると快適;雨具は不要そうですが念のため折りたたみ傘の最新情報をチェックしてください。 $ npm run dev > codex-cli-sdk@1.0.0 dev > tsx src/index.ts * 日時: 2025-11-23(日) 日中(JST) * 地域: 東京都心 * 天気: 午前は快晴、午後は次第に薄雲が広がる見込み。降水: 降水確率データは取得できず、現状では雨の兆候なし・降水量情報なし。風: 風向風速データ未取得(体感的には穏やかな北寄りの風程度)。湿度・体感: データ不足だが朝はひんやり、日中は気温どおりのさわやかな体感になりそう。大きな警報級の現象は見込まれていませんが、念のため最新の注意報は気象庁公式で確認してください。 * 最高/最低気温: 15℃ / 9℃ * 服装等のアドバイス: 朝晩は冷えるので長袖+薄手アウター、日中はカットソー+カーディガン程度が快適。乾燥が進みやすいのでリップやハンドクリームと飲み物を持つと安心、日中の強い日差し対策に帽子もあると良いでしょう。 回答形式も安定し、良くなりました。 コメントアウトしてる部分を外して実行してみましょう // const user_input = "今日の東京の天気を教えて" const user_input = "一発芸して" $ npm run dev > codex-cli-sdk@1.0.0 dev > tsx src/index.ts 天気専門なので答えられません $ npm run dev > codex-cli-sdk@1.0.0 dev > tsx src/index.ts 天気専門なので答えられません しっかり断りを伝えられました。 ただ、実は問題点が残っており、記事執筆時、11/24(月)1:20なのですが、11/23(日)なってしまってます。これを修正してみましょう。 日付を作成して追加します。ついでに次の日の情報を聞くようにしましょう。 const ONE_DAY_MS = 24 * 60 * 60 * 1000; // 現在時刻から 1 日後の日時 const tomorrow = new Date(Date.now() + ONE_DAY_MS); // JST として日付部分だけを文字列にする const time_pormpt = tomorrow.toLocaleDateString('ja-JP', { timeZone: 'Asia/Tokyo', year: 'numeric', month: '2-digit', day: '2-digit', }); const prompt = [system_prompt, "<user-input>",time_pormpt,user_input,"</user-input>",output_template] 結果は以下のようになりました。 概ね思い通りの出力ができてます。 $ npm run dev > codex-cli-sdk@1.0.0 dev > tsx src/index.ts * 日時: 2025年11月25日(終日・JST) * 地域: 東京都心 * 天気: 明け方は9℃前後で晴れ、午前から午後はおおむねくもり、夕方以降は再び晴れ間が広がる見込み。提供データに降水確率・風向風速・湿度は含まれていませんが、雨要素は示されていません。 * 最高/最低気温: 15℃ / 9℃ * 服装等のアドバイス: 朝晩は冷えるので長袖+薄手アウターが安心、日中は薄手ニット程度で快適。折りたたみ傘は不要そうですが、公式の最新情報も念のためご確認ください。 $ npm run dev > codex-cli-sdk@1.0.0 dev > tsx src/index.ts * 日時: 2025/11/25(火) 0:00-24:00 JST * 地域: 東京都心 * 天気: 夜明けは晴れ、日中はくもり優勢で雨シグナルなし(降水確率データ未取得・不確実)/風は北寄りの弱風が中心で体感は気温どおり/湿度データ未取得 * 最高/最低気温: 15℃ / 9℃ * 服装等のアドバイス: 朝晩は薄手のコートやカーディガンがあると安心、日中は長袖シャツで十分/乾燥しやすいのでリップやハンドクリームと飲み物を 降水量の具体値や湿度は取得できませんでしたが、現状は大きな雨雲の兆候は見当たりません。強い気象リスクの情報はありませんが、最新の警報・注意報は気象庁など公式情報でご確認ください。 最終版 import { Codex } from "@openai/codex-sdk" ; const codex = new Codex(); const thread = codex.startThread(); const system_prompt = ` <system-prompt> # システムプロンプト あなたは天気情報専用アシスタントです。 - 常に「いつ・どこ・どんな天気か」を明示して、簡潔な日本語で答えます。 - 最新かつ信頼できる情報に基づき、不確実な点はその旨を明示します。 - 危険な気象では、公式機関の情報確認と安全への注意を必ず促します。 - 天気と無関係な質問には、天気専門であることを伝えて簡潔に断ります。 # 調査内容 1. 詳細 * 降水: 降水確率 {{降水確率}}%、予想降水量 {{降水量}}mm(あれば) * 風: 風向 {{風向}}、風速 {{風速}}m/s(強風時はその旨) * 湿度・体感: 湿度 {{湿度}}% 程度、{{蒸し暑く感じる/乾燥しやすい/体感は気温どおり}} 2. 行動の目安 * 服装: {{長袖/半袖/上着の有無などの簡単な目安}} * 持ち物: {{折りたたみ傘/日傘/帽子/飲み物/防寒具 など}} 3. 注意事項 * {{大雨/雷/強風/猛暑/大雪 など}} のおそれ: {{あり/なし}} * 必要に応じて: 「最新の警報・注意報は気象庁など公式情報を確認してください」 * 時刻はJSTを基準に調査 4. 補足(任意) * 洗濯・外出・運転などの簡単な一言アドバイス: {{例: 洗濯物は外干しで問題なさそうです など}} </system-prompt> ` const output_template = ` ユーザーへの回答には参考リンクなどは不要です。 # 出力テンプレート <output_template> * 日時: {{日付・時間帯}} * 地域: {{地域名}} * 天気: {{天気の要約}}(例: 晴れ時々くもり、にわか雨の可能性あり) * 最高/最低気温: {{最高気温}}度 / {{最低気温}}度 * 服装等のアドバイス: {{行動のアドバイス}} </output_template> <output_template_error> 天気専門なので答えられません </output_template_error> # 作業手順 1. <user_input>が天気についてか判断し、違った場合<output_template_error>を出力して終了。天気についての場合2へ遷移 2. お天気エージェントとして動作。作業が完了したら3へ遷移 3. output_templateに従って回答 promptにしたがって、作業してください。 ` const user_input = "東京の天気を教えて" // const user_input = "一発芸して" // 1日分のミリ秒 const ONE_DAY_MS = 24 * 60 * 60 * 1000 ; // 現在時刻から 1 日後の日時 const tomorrow = new Date ( Date . now () + ONE_DAY_MS); // JST として日付部分だけを文字列にする const time_pormpt = tomorrow. toLocaleDateString ( 'ja-JP' , { timeZone : 'Asia/Tokyo' , year : 'numeric' , month : '2-digit' , day : '2-digit' , } ); const prompt = [ system_prompt, "<user-input>" ,time_pormpt,user_input, "</user-input>" ,output_template ] const turn = await thread.run( prompt . join ()); console . log (turn.finalResponse) まとめ ここまで読んでいただきありがとうございました! 今回はお天気エージェントを題材にCodex CLI SDKを使ってみました。 今回はmcpや構造化出力を使わなかったので、いずれ使うものを作ってみたいと考えてます。 今回のお天気エージェントも上記を使ってないので、改良の余地はまだあります。 Codex CLI SDKは codex login しておけば、追加でAPI利用料を支払わずに使えるのが大きな魅力です。 みなさんもぜひMyエージェントを作ってみてください!
アバター
こんにちは、プロダクト部 部長の稲垣です。(自己紹介やこれまでのキャリアについて↓をご覧ください。) tech-blog.rakus.co.jp 先日、こんなイベントでモデレーターをしました。このイベントではプロダクトエンジニアをテーマに対談をしました。この『プロダクトエンジニア』という言葉はここ5年くらいででてきた名称です。 rakus.connpass.com プロダクト開発の現場では、 エンジニア・PdM・デザイナーという大きな分類だけでなく、 その内側でさらに細かな役割が生まれています。 グロースPdM / テクニカルPdM / AI PdM プロダクトデザイナー / UXデザイナー / サービスデザイナー フロントエンド / バックエンド / SRE / Platform / MLエンジニア こうした細分化は「仕事の複雑さに対応する進化」であり、 同時に「働く側の専門性の見える化」でもあります。しかし一方で、 細分化すればするほど“本当に良いことなのか?” という疑問も生まれます。 本記事では、これまで自分の経験やラクスの開発組織を例にしながら、以下のテーマを深掘りします。 職種内細分化のメリット・弊害 求職者と企業側、それぞれにとっての価値 「越境しなさい」という言葉への違和感の正体 ラクスは専門性と越境をどうバランスさせているのか 目次 ■なぜ職種は細分化されるのか?──良い面と本質的な価値 ■しかし細分化には“弊害”もある ① プロダクトごとの縦割りが強まる ② “越境しないと回らない”状況を生んでしまう ③ キャリアの固定化が起こりやすい ■では、ラクスはどちらのスタンスなのか? ラクスで活躍する人の共通点 ■まとめ:ラクスは「役割を尊重しつつ、越境も価値」と考える組織 最後に ■なぜ職種は細分化されるのか?──良い面と本質的な価値 専門性が深まり、プロダクト品質が上がる プロダクトは年々複雑化し、AI・データ基盤・クラウド・UX のように専門性が高度化しました。 1人がすべてを深く理解するのは不可能です。そのため、 AI PdM グロースPdM プラットフォームエンジニア UXリサーチャー など、 “深い専門領域”を担当するロールが自然発生 しています。 これは市場側から見ても、 専門性を言語化し、キャリア価値を高める良い流れ といえます。 自分の強みと合うポジションを見つけやすくなる 求職者にとっては、 「探索フェーズが得意」 「UI設計が強い」 「AI企画に興味がある」 といった“強み”と職種をマッチさせやすくなります。結果としてミスマッチが減り、 入社後の立ち上がりも速くなります。 組織側も「必要な人材」を明確にできる 採用・育成・配置の精度が上がるため、 中〜大規模の開発組織では特に細分化の恩恵は大きいです。 ラクスのように複数プロダクトが並行して走る企業では、    プロダクト固有の課題にフィットする役割を採用できる のは大きなメリットです。 ■しかし細分化には“弊害”もある 細分化は良いことばかりではありません。ラクスの文脈を踏まえると、特に以下の弊害が起こりやすいです。 ① プロダクトごとの縦割りが強まる 役割が細かくなるほど、「ここから先は担当外」という意識が生まれやすい。ラクスのプロダクトは独立性が高いため、役割の細分化がそのまま“壁”になるリスク があります。 ② “越境しないと回らない”状況を生んでしまう 人数が不足していたり、 立ち上げフェーズでロールが定まっていない場合、 PdMがUXもやる デザイナーが要件定義も見る エンジニアが仕様詰めも担当する という状況が発生します。これは本来、 マネジメント側が役割を設計しきれていない 場合に起こりがち。 ③ キャリアの固定化が起こりやすい 役割が明確になると、 「あなたはグロースPdMだから探索は任せない」 「UIの人だからサービスデザインは向いてない」 と“移動の壁”が生まれることもあります。ラクスは社内異動が比較的柔軟な組織だからこそ、 ここは課題になりやすいポイント。 「越境しなさい」が生む違和感の正体 求職者・現場メンバーの中には、「越境しろ」という言葉にモヤモヤを感じる人も多いです。その違和感の正体は、 ✔ 役割が曖昧なまま越境を強要されると、責任がぼやけるから ✔ 専門性を深めたい人からすると、広く浅くを求められるのは苦痛だから ✔ 越境できる人が“便利屋化”しがちだから 本来は、“越境”は役割を全うしたうえで自然に生まれる副産物 であるべきです。 専門性を深めるキャリアも、越境して幅を広げるキャリアも、 どちらも価値があり、どちらも正しい。 ■では、ラクスはどちらのスタンスなのか? ラクスは結論として、 「役割定義は進める」+「越境も推奨する」 ただし実態はプロダクトフェーズごとにバラつきがあるという “ハイブリッド型” の組織です。 役割定義は進めている ラクスでは近年、 PdMの役割整理 UXの期待値の明文化 エンジニア領域の Platform / SRE / アプリ の区分 AI PdM・データPdMのような新規ロール検討 など、「役割の明確化」が確実に進んでいます。 ただし越境が必要な場面もまだ多い 特に以下の領域は越境が自然に発生します: 新規プロダクト・AI領域 小規模プロダクト 立ち上げ直後のフェーズ UXリサーチのリソース不足領域 そのため、 役割があっても境界は柔らかい のが現状。 結果 ラクスの最適解は「専門性×越境」の両立型 ラクスは、 深い専門性を持ちつつ、必要があれば他領域にも関われるバランス型 を理想としていると言えます。そして、ラクスの開発組織としては、『顧客志向』を旨としているため、これを共通言語、見解として動くようにしています。 ラクスで活躍する人の共通点 職種に関わらず、ラクスで活躍しやすいのは次のタイプです。 ✔ 自分の専門性を持ち、それを武器にしている ✔ 他職種の視点を理解し、壁を作らず連携できる ✔ 必要なときは越境する柔軟性がある ✔ 役割定義が曖昧なら言語化し、組織に提案できる ✔ 利用するお客様を向いている “なんでも屋”ではなく、 専門性を軸にしながら、必要に応じて染み出すタイプ がもっともパフォーマンスを出しやすい環境です。 ■まとめ:ラクスは「役割を尊重しつつ、越境も価値」と考える組織 ラクスは、 役割をきっちり定義する 専門性を評価する 越境も歓迎する プロダクトごとに柔軟に運用する という、“いいとこ取りのハイブリッド型”のスタンスです。PdM・デザイナー・エンジニアのいずれにとっても、 専門性を磨きつつ、必要な範囲では越境できる柔らかな環境 といえます。 以前にイベントで以下のような話をしましたので合わせて見てもらえればと思います。 speakerdeck.com 最後に 職種の細分化も、越境も、どちらも本質的には プロダクトの価値を最大化するための手段 です。 ラクスはその両方をうまく取り入れながら、多様なスキルセットを持つ人たちが活躍できる組織づくりを進めています。 “専門性×越境” のバランスに興味がある方にとって、 ラクスはとても相性の良い環境になるはずです。 本記事を読んでラクスのプロダクト部に興味を持ってくださった デザイナー / PdM の方は、ぜひカジュアル面談からご応募ください。 ※プロダクトマネージャーのカジュアル面談は、基本的に私(稲垣)が担当します! ●採用情報 プロダクトマネージャー career-recruit.rakus.co.jp デザイナー career-recruit.rakus.co.jp   └ デザインマネージャー career-recruit.rakus.co.jp /アシスタントマネージャー career-recruit.rakus.co.jp
アバター
1. はじめに こんにちは、 id:rksbun です。私は40代の楽楽精算開発のPjMで、元エンジニアです。ラクスには今年2月に入社しました。 最近の開発案件で、通常よりもかなり短い期間でリリースできたので、PjMとしてやったことを書きたいと思います。この記事で、ラクスがただ言われた通りのプロジェクト管理だけでなく、考えたことに挑戦させてくれて、それを評価してくれる会社だということを伝えられたら嬉しいです。 1. はじめに 2. あったこと 3. 意識したこと 4. やったこと 1. DB設計は全員で重点的に 2. AIを使った効率化への挑戦 3. リスク管理 4. トラブル対応は迅速かつ大胆に 5. 結果 6. まとめ 2. あったこと PdMから、チャレンジングなスケジュールでのリリース打診がありました。通常の機能開発期間より大幅に短い期間でした。もちろん高品質は維持しなければならず、見るからに難易度の高い挑戦でしたが、チームと相談して、やることに決めました。 3. 意識したこと プロジェクト自体がチャレンジングだったこともあり、以下を特に意識していました。 自分の考えていることはいつも以上に意識して伝える チームのモチベーション高い協力は必要不可欠 目的とか何を考えているかは当たり前でも毎回伝える この意識を持っていても伝え漏れたりは全然あったと思います 設計には時間をかける 手戻りを最小限に なるべくシンプルな設計になるようにし、実装やテストを効率化する チームメンバーの「今」よりも、「少し先」を見て動く 障害になりそうなものを予め取り除いておく 他の部署との調整など時間がかかるものに早めに対処しておく その代わり、メンバーの今やっていることへの意識が薄くなりがちになるが、ポイントを絞って時間を使う メンバーを信頼し、時には勇気を持って任せる 4. やったこと 通常のプロジェクトマネジメント業務に加え、強化したり追加でトライしたことを書きます。今まで通りやっていては間に合わないことはわかっていたので、今までやったことのないものも積極的に取り入れました。なので当然ながら失敗もありました。 1. DB設計は全員で重点的に 要件が決まった後、テーブル設計の段階でかなり時間をかけました。AIも活用しながらチームのエンジニア5人全員で時間をかけて検討しました。ここで全員から意見を出し合い、認識を揃えられたことで、後の開発フェーズを安心して進めることができました。開発スピードを上げたいのに時間をかけるという、一見矛盾したアクションにも見えますが、結果的には時間をかけて良かったです。 2. AIを使った効率化への挑戦 やったことがなくても、効率化できそうな箇所は積極的にAI活用を試しました。結果的に成果があったのは一つだけでしたが、知見が得られたことや、今後も考えれば全部成功だし、やって良かったです。 実装 :いわゆるスペック駆動開発に近いもの(AIに設計書を読み込ませてソースコードをアウトプットさせる)を試しましたが、期待したほどの効果は出ませんでした。ベテランエンジニアと若手エンジニア+AIで同じ実装を先行調査してもらったところ、結果的にはベテランエンジニアがスピードも正確さも圧勝。既存コードが膨大な箇所のAI活用はまだ発展途上で、プロンプトの工夫が必要という結論になりました。 レビュー :Claude CodeとGitHub Actionsを使ったレビューの仕組みを作りたかったのですが、開発と並行しながらだったため実戦投入には間に合いませんでした。ただ、その後しっかり仕組み化できたので、今後の開発には活かせそうです。 テスト :これは大成功しました!PlaywrightMCPを活用し、テスト項目書からAIでテストコードを作成、テスト実施もAIがやってくれるように自動化しました。これにより、自動化できた箇所は50%の工数削減を実現できました。人間が苦手な繰り返しテストで特に効果が高かったです。 3. リスク管理 他プロジェクトとのコンフリクト対応 :同じ箇所を触っている別プロジェクトがあったので、コンフリクト対応を先回りしてスケジューリングしておきました。しかし諸事情でその別プロジェクトがリリースされないことになり、結局元に戻すことに。ただ、この可能性も事前に察知していたので、被害は最小限にできたと思います。 QA・CIグループとの調整 :遅延発生に備え、前もって調整することで、後続作業のチームからリカバリー期間を確保できました。調整は早めが鉄則ですね。とてもありがたかったです。 4. トラブル対応は迅速かつ大胆に 技術的な課題 :開発終盤でライブラリのバグを踏んで実装に遅延が発生しました。発覚したのは夜でしたが、その場にいたエンジニア全員で問題を整理し、必要な対応をリストアップ。バグを回避する実装の認識合わせと、その箇所の強化テストを整理できました。この時はチームに緊張感が走りましたが、すぐに対処できてよかったです。あの瞬間は若干ピリつきましたが、正直私は楽しかったです。(みんなで仕事するの大好きなので) 仕様レベルのバグ :結合テストで仕様レベルのバグが発覚した時は、すぐにエンジニアに調査を依頼して状況をまとめてPMMやPdMを緊急招集しました。判断しやすい状況を作れたおかげか、対応方針をすぐに決定できました。結果、結合テスト期間内で対応完了できました。緊急事態では臆せず関係者とコミュニケーションをとり、迅速かつ大胆に行動することが大事だと再認識しました。 5. 結果 要求通りのスケジュールでリリースできました。担当のPdMや効率化に挑戦してくれたエンジニアが部内のスピードアップ賞を受賞し、私やチームも上長から評価していただけました。上長からはもちろんFBもいただけましたので、次回以降の開発に活かせればと思っています。 6. まとめ 失敗もありつつ、色々挑戦したおかげで、最初は困難と思われたリリースまで無事漕ぎ着けることができました。私自身は難しい課題に挑戦してクリアするのはゲームのように楽しめるタイプで、この挑戦は楽しかったです。 ラクスでは、「失敗を許容する」という文化(他にも いっぱいある 。ちなみに冒頭で触れた「考えている事を言葉で伝える」とかもあります)がありますが、これは心の中の安心材料としつつも、「挑戦せずに失敗もないよな」と思い、色々挑戦させていただきました。結果的には評価もいただけてとても良かったです。 短期間でのリリースに協力してくれたエンジニア、デザイナー、QAチームの皆さん、その他ステークホルダーの皆さん、また、ここまでお読みいただいた方にはとても感謝しています。ありがとうございました。
アバター
はじめに こんにちは。楽楽勤怠のバックエンドを担当しているkoyaです。 約二年前、あるきっかけからQiitaに記事投稿を始めました。 最初は毎週書こうと決めていたわけではありませんが、 気づけば毎週投稿するようになり、いつの間にか100週が経っていました。 振り返ってみると、続けてきた中でいろんな気づきがあり、自分自身も少しずつ成長できたように感じます。 この記事では、その間のことを少し振り返りながら、 書くことを続ける中で感じたことをまとめてみようと思います。 はじめに 入社当初の焦り とりあえずで始めた記事投稿 毎週投稿の決意、そのためのルール 記事投稿をする中で得た気づき 1. アウトプットできるかどうかが理解度の物差しとなる 2. 書けない週はインプットが少ない 3. アウトプットを前提に学ぶことの大切さ 記事投稿を継続したいま、思うこと おわりに 入社当初の焦り 2023年7月、私はバックエンドエンジニアとしてラクスに中途入社しました。 入社して最初に感じたのは、周りのエンジニアが持つ知識や考え方の幅の広さです。 前職で担当していた領域にはある程度対応できましたが、 新しい環境では扱う技術の幅が一気に広がり、アーキテクチャの考え方や開発プロセスなど、これまで経験してこなかった領域に触れる機会が増えました。 最初のうちは、新しい概念や技術が次々に出てきて、ミーティングの内容を理解するのにも時間がかかるような状態でした。 当時メンターをしてくれていたのは、新卒2年目の社員の方でした。 分からないことを質問すると、どんな問いにもすぐに明確な答えが返ってきて、その知識量や理解の深さに驚くと同時に、 「このままではまずい」という焦りの気持ちが次第に強くなっていきました。 とりあえずで始めた記事投稿 焦った私は、とにかく何か行動しないとと思いました。 勉強はしていたと思います。技術書も読んでいたし、実際に手で動かすということもしていたつもりです。 ですが、“身についている実感”があまりなく、読んだ内容を翌日には半分忘れていて、いざ会話になると説明できない—— そんなことの繰り返しでした。 また、社内には、技術が好きで、実力のある方々がたくさんいます。 「このまま同じ勉強方法を続けても、たぶん今の差を埋めることはできない」 そんな感覚がありました。 そうした感情の中で始めたのが、Qiitaへの記事投稿です。 正直なところ、深い理由があったわけではありません。 「アウトプットは大事」とどこかで聞いたことがあって、 何か形に残ることをしていれば、少しは安心できるかもしれないと思ったというのが本音です。 今思うと、記事投稿は結果的に自分に合っていたのだと思います。 大きな苦もなく続けられたのは、書き終えたときの達成感や、反応をもらえたときのちょっとした喜び、そして少しずつ実力がついていく実感といったポジティブな要素が、アウトプットの負担を上回っていたからです。 楽しさが負担を超えていたからこそ、自然と継続することができました。 毎週投稿の決意、そのためのルール 書き始めて数週間が経った頃、投稿を週1で続けていることに気が付きました。 Qiitaには「バッジ」という機能があり、毎週連続で投稿すると、その週数に応じたバッジがもらえます。 当時は50週が上限だったので、「まずは50週連続を目指そう」と目標を立てました。 毎週投稿を続けるにあたって、自分の中でいくつかルールを決めました。 どんなに短くても書く 書き続けているうちは順調でも、一度手を止めてしまうと、そのまま書かなくなるかもしれないという不安がありました。 目的はあくまで「実力をつけること」ですが、書かなくなることが一番の遠回りだと思い、 とにかく手を止めない ことを最優先にしました。 そこで、「どんなに短くてもいいから、毎週必ず書く」というルールを設けました。 内容の深さよりも、“書き続けること”自体に価値を置きました。 会社のOrganizationには入らない QiitaにはラクスのOrganizationもありますが、私はそこに所属していません。 「どんなに短くてもいいから書く」というルールと、会社名が並ぶことへの責任の重さが相反しているように感じたためです。 「こんな内容で出して大丈夫だろうか」 「もし間違っていたら会社に迷惑をかけてしまうかも」 そんなことを考えると、気軽に投稿できなくなってしまいそうでした。 そこで、 プレッシャーを感じずに自由に書けるよう、個人として投稿する ことを選びました。 こうして決めたルールのもとで記事投稿を続けてきました。 途中でQiitaのバッジ上限が100週に引き上げられたこともあり、50週を達成したあともそのまま継続。 気づけば、今も習慣として続いています。 記事投稿をする中で得た気づき 投稿を続けたことでとで、以下のような気付きを得ました。 1. アウトプットできるかどうかが理解度の物差しとなる Qiitaを書き始めた当初は、とにかく一つの記事を書くのにすごく時間がかかりました。 「簡単な内容だからすぐ書けるだろう」と思っていても、実際に手を動かしてみるとまったく違います。 まずは知りたい内容を調査して、手元で検証して、それを整理してまとめる。 この一連の流れだけでも思っていた以上に大変で、特に理解が浅いとそもそも記事としてまとめられないということに気づきました。 逆に、何度も調べ直して試行錯誤しながら、ようやく一本の記事として書き上げられたときは、 そのテーマについて人に説明できるレベルまで理解できていることが実感できました。 この経験から、 「アウトプットできるかどうかが、自分の理解度を測るバローメーターになる」 ということを強く意識するようになりました。 書けないということは、まだ理解しきれていないというサイン。 書けるようになったら、それは確実に自分の力になっている証拠。 記事を書くという行為は、自分にとっての「理解の物差し」そのものになっていきました。 2. 書けない週はインプットが少ない 焦りから始めた記事投稿でしたが、最初の気持ちをずっと保ち続けるのは簡単ではありません。 モチベーションが上がらない時期もあり、そういうときは記事のネタがなかなか思いつきませんでした。 しかしある時、「書けないのはモチベーションが低いからではなく、インプットが少ないからだ」と気づきました。 定期的に記事を書くことをルールにしておくと、書きづらさそのものがインプットの少なさを示してくれます。 逆に、すらすら書けるときは、それだけ知識が新しく、理解が整理されている証拠です。 いつの間にか、 「記事を書くことはインプットの量を測る物差し」 としても機能し始め、 記事が書きづらいという感情から、インプットの不足を早めに察知できるようになり、結果として「気づけば最近全然勉強してないな」という状態を防ぐことができました。 3. アウトプットを前提に学ぶことの大切さ 毎週の記事投稿を続けているうちに、少しずつ記事を書くスピードが上がってきました。 最初の頃とは違い、一本の記事を書き上げるまでの時間が目に見えて短くなっていったのです。 その理由は、 「アウトプットを前提に学ぶという習慣が自然と身についていた」 からでした。 調査や学習の段階から、 「これをどう言語化しよう?」 「文章にするとき、どんな順番で説明すれば伝わりやすいだろう?」 といったことを意識するようになりました。 その結果、学びながら理解を整理するクセがつき、“分かっていない状態で書き始めて詰まる”ということが格段に減りました。 書き始める段階では、すでに頭の中で構成ができているため、筆をとったらそのまま最後まで書き切れることも多くなりました。 「書くために学ぶ」から「学びながら書く」へ。 このスタイルに自然と変わっていったことで、アウトプットの効率も質も大きく上がったと感じます。 さらに、この習慣は業務にも良い影響を与えました。 会話の中で内容を整理しながら聞き、理解したことをその場で言語化して確認することで、認識の齟齬が減り、コミュニケーションの精度が高まったと感じています。 これもまた、「アウトプットを前提に学ぶ」姿勢の成果だと思います。 記事投稿を継続したいま、思うこと あらためて自分の書いた記事の一覧を見ると、「たくさん書いたな」としみじみ感じます。 転職したばかりで自信を失いかけていた自分にとって、努力の軌跡が記事という形で残っていることは、大きな支えとなっています。 記事を書く過程では、思い通りにいかないことも多く、何度も試行錯誤を重ねました。 AIに質問したり、公式ドキュメントを読み込んだり、OSSのコードを追ったり—— 記事投稿を始める前にはほとんどやってこなかったことを、今では自然と行うようになりました。 そうした試行錯誤の中で身についた「トラブルシュートの力」は、今では業務でも確実に活きていると感じます。 焦りから始めた記事投稿は、いつの間にか日常になりました。 「ローマは一日にして成らず」 もちろん、まだ道半ばですが、小さな積み重ねが確かに今の自分を作ってくれていると感じます。 おわりに これまでたくさんの記事を書いてきましたが、こうした“ポエム系”の記事を書くのは今回が初めてでした。 なかなか筆が進まず、「記事投稿を続けてきて自分は何を得たのか」を、実はこれまできちんと整理できていなかったことにも気づきました。 書き終えたいま、日々の積み重ねが自分に与えた影響の大きさを、あらためて実感しています。 もちろん、万人に合うやり方ではないかもしれませんが、もし当時の自分と同じように悩んでいるエンジニアの方がいたら、この経験が少しでも参考になれば嬉しいです。 最後に、自分のQiitaアカウントを紹介します。 気になった記事などありましたら、ぜひご覧ください。 https://qiita.com/nnhkrnk ここまで読んでいただき、本当にありがとうございました!
アバター
こんにちは、稲垣です。 先日、こちらのイベント generative-ai-conf.connpass.com のLTで話しました内容についてnoteでもう少し詳しくまとめました。 イベントの登壇資料はこちら speakerdeck.com になります 「AIをどう使うか」ではなく、「どう溶け込ませるか」。 生成AIが当たり前になりつつある今、プロダクト開発においても「AIをどう取り入れるか」だけでなく、「どう文化として根づかせるか」が問われています。私たちラクスでは、このテーマに真正面から取り組み、「AIをプロダクトづくりに溶かす」挑戦を続けています。その過程で見えてきた“3つの壁”と、それを乗り越えるための工夫を紹介します。 🧩 AI浸透を阻む3つの壁 ① プロセスやプロダクトフェーズの違い ② 職種の役割の曖昧さ ③ AIに対するリテラシーや向き合い方の違い 🛠️ ラクス流・3つの壁との向き合い方 1. 最初から共通化や理想を追い求めない 2. 職種としての定義を決める 3. みんなが楽しく使う 🚀 おわりに ― AIを“当たり前”にするために 🧩 AI浸透を阻む3つの壁 ① プロセスやプロダクトフェーズの違い ラクスでは10以上のプロダクトを展開しており、開発フェーズも手法もさまざまです。成熟期の「楽楽精算」と、探索期の新製品では、スピード感も意思決定も全く異なります。結果として、AIを「一部業務」に取り入れることはできても、「プロセス全体」に溶け込ませるのは簡単ではありません。 ② 職種の役割の曖昧さ PdM、デザイナー、エンジニア。理想的な分担表は描けても、実際には職種間の境界はあいまいです。そのため、AI活用が“点的”な取り組みに留まり、組織全体としての成果につながりにくいという課題がありました。 ③ AIに対するリテラシーや向き合い方の違い AIとの関わり方には段階があります。 「AIを理解する」 「AIを使いこなす」 「AIと共創する」 多くの人が2段階目まで到達している一方で、3段階目――AIを“共創パートナー”とするレベルにはまだ届いていません。この差が、AIの価値を組織全体に広げるうえでの壁になっています。 🛠️ ラクス流・3つの壁との向き合い方 1. 最初から共通化や理想を追い求めない AI活用を一律に標準化しようとすると、議論や調整に時間がかかりすぎてスピードを失います。そこで私たちは、チーム単位で自由に試し、成功も失敗も共有する形をとりました。 チャットや勉強会、月次ミーティングで知見をオープンに蓄積。共通化は「後から考える」方針にすることで、むしろ現場主導の自走文化が生まれました。 「誰もが使えそうなものは、結局誰にも刺さらない。」だからまず、AI活用のトッププレイヤーを活かす環境をつくる。 2. 職種としての定義を決める ラクスでは、プロダクトごとに異なっていた役割定義を整理しました。「楽楽精算」ではDACIモデルを導入し、誰がDriver・Approver・Contributor・Informedなのかを明確化。また、PdMとPMMのデュアルエンジン体制を取り、「価値をつくる人」と「価値を届ける人」が連携できる仕組みを構築しています。 AIによって得られた余白の時間は、各職種が専門性を磨くために使う。役割を明確にするほど、AI活用の深さは増していきます。 3. みんなが楽しく使う AIを「業務目標」に入れるだけでは文化になりません。大事なのは、楽しそうに使う姿を見せることです。 「こう使ったらすごく便利だった」「これは失敗だった」――そんな小さな話を日々共有することで、自然と周囲にも火がつきます。AI活用を“義務”ではなく、“遊び心ある実験”として扱う。それが組織を動かす一番のエネルギーになります。 🚀 おわりに ― AIを“当たり前”にするために ラクスは今、「生成AIの標準搭載」と「統合型ベスト・オブ・ブリード戦略」という2つの進化に挑戦しています。AIを特別なものではなく、“当たり前の道具”にする。そして、AIによって生まれる余白を、人がよりクリエイティブな仕事に使えるようにする。 プロダクトづくりにAIを“溶かす”とは、単なる技術導入ではなく、 人とAIが共に学び、楽しみ、進化していく文化をつくる ことなのです。
アバター
こんにちは、 id:takaram です。 ラクスでは全社で GitHub を利用しており、大半のプロジェクトが GitHub Actions を CI として利用しています。 GitHub Actions は、テストやデプロイまでを自動化する強力な仕組みである一方、正しく使わなければ セキュリティホールとなる危険性 もはらんでいます。 今回は、GitHub Actions のセキュリティについて紹介していきます。 GitHub Actions のセキュリティ ありがちな侵害のパターンと対策 1. サードパーティアクションの侵害 問題 対策 2. 過剰な権限設定 問題 対策 3. run 内での OS コマンドインジェクション 問題 脆弱な例 対策 4. curl | bash 型の危険なスクリプト実行 問題 対策 追加の対策 1. actionlint で構文・展開の安全性をチェック 導入例 2. ghalint で権限設定やタグ指定を検査 導入例 まとめ GitHub Actions のセキュリティ プロダクトコードのセキュリティには皆さん気をつけていると思いますが、CI/CD のコードに気を配る必要性はあまり認識されていないかもしれません。 しかし、2025年に入ってからも CI/CD 基盤を狙ったサプライチェーン攻撃が相次いでいます。 3月: tj-actions/changed-files が改ざんされ、これを実行したリポジトリの GitHub Actions のビルドログにシークレット情報が出力された rocket-boys.co.jp 8月:npm パッケージ Nx の GitHub Actions の設定が悪用され、不正なコードが混入したパッケージをリリース(通称 "s1ngularity" 攻撃) blog.jxck.io これらはいずれも、CI/CD がアプリケーションと同じレベルで攻撃対象になっていることを示しています。 開発者自身が GitHub Actions のセキュリティを理解し、適切に守ることが重要です。 ありがちな侵害のパターンと対策 ここでは、よくある脆弱なパターンを4つ取り上げます。 それぞれのリスクと、すぐに実践できる対策をセットで紹介します。 1. サードパーティアクションの侵害 問題 GitHub Marketplace などで配布されている外部アクションは、メンテナーが乗っ取られたり、公開リポジトリが改ざんされると、攻撃者が不正なコードを仕込むことができます。 2025年3月に発生した tj-actions/changed-files 改ざん事件では、多数のリポジトリが影響を受けました。 タグ指定(例: @v3 や @v3.6.0 )では、タグは後から付け替え可能であり、改ざんの影響を受けてしまいます。 対策 commit SHA で固定するのが有効です。 uses : actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 ただし、この場合アクションの新バージョンがリリースされ、通常の機能追加やバグ修正が行われても自動では最新版が利用されないことになります。 Dependabot / Renovate を利用して適宜最新バージョンに更新するのがいいでしょう。 また、そもそもアクション自体が信頼できるものか、導入時点で確認することも重要です。アクションのコードを確認できればベストですが、せめてメンテナーや開発体制、利用実績などを確認するとよいでしょう。 2. 過剰な権限設定 問題 GITHUB_TOKEN に不要な権限が付与されていると、侵害時にリポジトリ改変やタグ作成・リリース改ざんなどの被害が発生する可能性があります。 また、secret に PAT (Personal Access Token) を設定している場合も、発行時に不要な権限を付与していると、漏洩時の被害が拡大します。 対策 ジョブごとに GITHUB_TOKEN の最小限の権限を明示します。 permissions : contents : read pull-requests : read # 指定していない権限は`none`になる また、上記の権限設定がされていない場合のデフォルトの権限が、リポジトリ設定から変更できます。 これはread onlyにしておきましょう。 Settings → Actions → General → Workflow permissions → 「Read repository contents and packages permissions」を選択 PAT を利用する際は、最低限の権限のみ与えます。 また、そもそも PAT を使わずに、 GITHUB_TOKEN や GitHub Apps トークンを利用できないか検討してください。 3. run 内での OS コマンドインジェクション 問題 run ステップ内で ${{ ... }} を直接展開すると、展開された値がシェルに渡されて解釈されます。 外部由来の値(PRタイトル、入力パラメータなど)に悪意のある文字列が含まれていた場合、意図しないコマンドが実行されるおそれがあります。 脆弱な例 - run : echo "${{ github.event.pull_request.title }}" PRタイトルが Hello"; rm -rf * # のように細工されていると、シェルがそれを区切って解釈し、 rm コマンドを実行してしまいます。 対策 以下のようにします。 1. 外部からの値を環境変数に設定する 2. シェルコマンド内で "" で囲って使用する - env : TITLE : ${{ github.event.pull_request.title }} run : echo "$TITLE" ${{ ... }} の直接展開は避け、必ず変数をダブルクオート付きで使いましょう。 これにより、シェルのワード分割やメタ文字解釈を防止できます。 4. curl | bash 型の危険なスクリプト実行 問題 curl https://example.com/foo.sh | bash のような形で外部スクリプトを直接実行すると、配布元サーバーや通信経路が侵害された場合に不正なスクリプトを実行させられる危険があります。 対策 一度ファイルとしてダウンロードし、チェックサム検証などを行ってから実行する。 可能な限り、公式パッケージマネージャ(apt, npm など)を利用する。 追加の対策 こうした安全な設定を、チーム内に浸透させ、全員が気をつけて実装するというのはなかなか難しいものです。 そこで、自動検出の仕組みが有効です。プロダクトコードに対して lint を実施するのと同様、ワークフローファイルも CI を利用して機械的にチェックしましょう。 ここでは、GitHub Actions の構成を lint できる代表的なツールを紹介します。 1. actionlint で構文・展開の安全性をチェック actionlint は、GitHub Actions のワークフローファイルの構文チェックをしてくれるリンターです。 基本的な構文チェックに加えて、上記で紹介した run: 内の危険な ${{ ... }} なども検出してくれます。 ShellCheck がインストールされている環境 1 であれば、 run: 内のシェルコマンドに対してもLintを実行してくれます。 変数をダブルクオートで囲んでいないなどの問題を検知可能です。 導入例 actionlint はビルド済みのバイナリが配布されているので、ダウンロードするだけで利用可能です。 ただし、ダウンロードしたバイナリが改ざんされていないか、チェックサムで確認しておきましょう。 env : ACTIONLINT_VERSION : "v1.7.8" ACTIONLINT_SHA256 : "be92c2652ab7b6d08425428797ceabeb16e31a781c07bc388456b4e592f3e36a" steps : - uses : actions/checkout@v5 - run : | gh release download "${ACTIONLINT_VERSION}" -R rhysd/actionlint \ -p 'actionlint_*_linux_amd64.tar.gz' -O actionlint.tar.gz echo "${ACTIONLINT_SHA256} actionlint.tar.gz" | sha256sum -c - tar -xzf actionlint.tar.gz actionlint - run : ./actionlint 2. ghalint で権限設定やタグ指定を検査 ghalint は、 permissions: の指定漏れやサードパーティアクションのタグ指定( @v3 など)を検出するツールです。 actionlint に比べて、よりセキュリティにフォーカスしたチェックを行ってくれます。 導入例 ghalint もビルド済みバイナリをダウンロードして利用可能です。 ダウンロードしたバイナリの検証はチェックサムでもいいですが、 アーティファクトの構成証明 も利用できます。 env : GHALINT_VERSION : "v1.5.3" steps : - uses : actions/checkout@v5 - run : | gh release download "${GHALINT_VERSION}" -R suzuki-shunsuke/ghalint \ -p "ghalint_*_linux_amd64.tar.gz" -O ghalint.tar.gz gh attestation verify ghalint.tar.gz \ -R suzuki-shunsuke/ghalint \ --signer-workflow suzuki-shunsuke/go-release-workflow/.github/workflows/release.yaml tar -xzf ghalint.tar.gz ghalint - run : ./ghalint run まとめ GitHub Actions は開発を支える強力な仕組みであり、現代の開発にはなくてはならないものです。しかし同時に、攻撃者にとってのターゲットにもなり得ます。 設定ミスや依存先の侵害が攻撃につながる以上、CI/CD もアプリケーションと同じように守る必要があります。 今回紹介した対策を徹底し、安全に CI/CD を実行していきましょう! GitHub-hosted runner の ubuntu-24.04 などには ShellCheck がデフォルトでインストールされています。 ↩
アバター
「開発が遅い」と嘆くのは簡単です。でも本当に遅いのは“人”ではなく、“見えない仕組み”かもしれません。 ラクスの開発組織が大切にしているのは、「顧客志向」です。 そして私たちは お客様に価値を速く・確実に届けるための基盤づくり として開発生産性の向上に重きを置いています。 そのため各チームは、プロダクトの性質やお客様のニーズに合わせて、プロダクトごとに合理的な開発スタイルを選択しています。 そして、開発生産性に関わるデータを活用し、スタイルに合った施策を日々検証することで、価値提供のスピードと確実性を高めています。 今回は、そうした多様な背景を持つ開発チームが行っている リアルな「生産性向上のための取り組み」 をチラっとご紹介します。 多様な技術スタックを持つチームが、それぞれの現場でどんな工夫をしているのか。 そこには  「開発生産性を科学する文化」  があります。 目次 データが語る、チームの「今」 チームによって違う、“スピードの壁”への取組 「数字」ではなく学びの共有に注目する文化 さいごに データが語る、チームの「今」 ラクスでは開発の現在地を見える化するために、  (1) チームごとの客観データ収集  (2) Findy Team+や社内ツールで可視化  (3) リーダーによる改善 というサイクルを継続しています。 可視化結果はメンバー層まで共有され、チーム全体でボトルネックを発見・議論できるようになっています。 (※ Findy Team+については先行記事 参照) 可視化されている値の例として、 全チームのPR(Pull Request)データをFindy Team+で分析し、 「オープンからレビューまでの平均時間」や「レビューコメント数」 といった指標を毎週~毎月追跡しています。 開発に要した時間だけではなく、レビュー待ち時間やレビュアーの偏りなど、 開発サイクルの“詰まりポイント”を見つけ出し、改善の余地をチーム単位で議論しています。 プルリク数と経過時間の可視化イメージ あるチームでは、オフショア開発体制ゆえにレビュー周りの時間が長引く課題がありました。 そこで AIを活用した一次コードレビューを併用し、ヒトの負荷を減らしつつ質とスピードの両立を実現 しました。 レビュアーの偏りがボトルネックになっていたチームでは、 1PRあたりの変更量を下げてレビュー負荷を分散 しやすくしました。 同様の他チームでは、レビュアーを育てる仕組みに意図的にシフトすることで、負荷分散を目指しています。 単体テスト工数が規模に対して大きく、コストが課題になっていたチームでは、 AIを使ったテストの自動化を進め、テスト工数の半減 を実現しました。 ラクスの開発チームでは、顧客ニーズの解決に直結するPR数の増加とその消化スピードを上げるため、 開発現場をよく知る 開発リーダーが直接GitHub統計や各種社内ツールを組み合わせて分析、 原因を深堀、改善施策を打つ ことで高速な改善サイクルを実現しています。 チームによって違う、“スピードの壁”への取組 開発スタイルは、前述した通りチームによってさまざまです。 WFで設計精度を高めるチーム、Agileで小さく早く試すチーム、両者を織り交ぜるハイブリッドがあり、 いずれも担当サービスのお客様に最短で価値を届けるために戦略的に選択しています。 全チームの共通事項として、 「4Keys指標(Googleが提唱するDevOps成功の4つの指標)」を意識しつつ より自律的に改善できる指標として 自チームのスタイルに合った指標 を置いています。 前項でも挙げたように、"管理される側"というよりも、自発的に“改善を設計する側”として指標を定めて動くことで、 ラクスのユニークネス「ゴールオリエンテッド」、「着実な継続」、「不確実性の排除」(※)を地についた形で実現しています。 ※ ラクスのユニークネスについては別記事 参照 開発スタイルに即した開発生産性向上の施策として興味深いものでは、オフショア開発の事例があります。 ベトナム開発課では、現地メンバーが主導して工程ごとの指摘数や本番バグ発生率を分析しています。 レビューコメント数の集計、内容確認を振り返り会に組み込み、テスト工程へのフィードバックに活かす など、 開発拠点間の距離を“データ”で埋めることでスピードUPに繋げています。 オフショア開発という開発スタイルならではの取組と思います。 なおラクスの海外拠点では、 “本社の指示を待つ”のではなく、“自分たちで課題を見つけ、仕組みを考える”思想が根付いています (もちろんコミュニケーションも密に行っています)。 そこに Findyなどの数値で見られる各種ツールや、翻訳が容易になるAIが加わることで、私たちは言語的、地理的な壁を越えた認識の共有を しています。 「数字」ではなく学びの共有に注目する文化 開発本部では、結果として起きた数字の変化に対して、 「数字」を共有して優劣を競わせるのではなく、 変化させるために行った施策で得た「ナレッジの共有」を促進しています。 これは、手探りになりがちな施策の検討にあたり、リーダー陣が闇雲に施策を試すのではなく、 数値をベースに過去事例の根拠を以て小さく試し、大きく育てることにより、 高効率で生産性の向上をするためです。 この分析サイクルとナレッジ共有が習慣化すれば、結果としてスピードも品質も向上します。 全チームの施策は経過に伴い当然アップデートされます。 各施策の進行途上で得た ナレッジは、3か月ごとに開発本部全体で共有され、次の一歩のヒントになります 。 あるチームの課題が、別のチームのアイデアで解決される、 「学びの連鎖」が生まれる仕組み となっています。 この仕組みの中で、チームリーダーたちは“数値を見る目”を磨いていきます。 単なるチームマネジメントではなく、「開発者として顧客へどうスピーディに価値を届けるか」を リーダークラスのメンバーが主体的に考え、実践しています。 ラクスの開発現場は、 コードを書く「だけじゃない」、言われたことをやる「だけじゃない」 データをもとに開発文化を進化させる、「だけじゃない」高次のスキルを磨ける環境です。 この環境で働くエンジニアは自然と、今後更に進化するAI駆動開発にも柔軟に対応していくものと思います。 さいごに 生産性向上の目的は、「顧客に価値を速く・確実に届ける」ための基盤づくりです。 今回は、顧客へ価値を届けるために、データを使って生産性向上に挑む私たちの取組を紹介させていただきました。 開発をもっと速く、もっと楽しく! ラクスは、開発の未来を作りたい仲間をお待ちしています!
アバター
はじめに こんにちは、楽楽精算開発チームの坂田です。 私は今年、楽楽精算における新機能追加プロジェクトにアサインされ、その中で新規アプリケーションの開発を担当する機会をいただきました。 アプリケーションの新規開発は様々な要件を考慮しながら進める必要があり、検討事項は多岐に渡ります。 今回は私自身の振り返りも兼ねて、アプリケーションを設計する際の流れや考え方を共有させていただきたいと思います。 内容はどちらかというと初歩的な物が多く、これから設計にチャレンジしようという方に向けたものとなっています。 この記事が皆さんのアプリケーション開発の一助となれば幸いです。 はじめに 今回の要件 システム構成を検討する リアルタイムデータ受信 DBは既存と共通 アプリのデプロイ先 アプリを設計する アプリケーションフレームワーク DBアクセスフレームワーク トランザクション制御 DBコネクション コネクションプール DB接続の上限 スレッドプール コードアーキテクチャ API I/F仕様 ビジネスロジック ログ、メトリクス、トレース まとめ 今回の要件 今回開発に取り組んだ機能の要件はおおよそ以下の通りです。 既存システムが外部から日次でファイル取り込みしているデータを、発生の都度リアルタイム取込できるようにしたい 取り扱うドメインは単一 開発中につき対象となるドメイン等の詳細は割愛 楽楽精算ではあるデータを外部から取り込むためのバッチが稼働しているのですが、日次起動という都合上、お客様の元にデータをお届けするタイミングは一日一回の決められたタイミングとなります。 このデータをよりタイムリーにお客様へお届けするため、データが発生するたびにリアルタイム取込を実現したいというのが今回の背景になります。 またデータのやりとりは B to B の限られたサーバー間でのみ行われます。 非機能要件は以下の通りです。 性能要件 想定される最大秒間処理回数:1 処理完了:3秒以内 通信は限られたサーバー間のみで発生し、頻度もそれほど多くないと言えます。 性能についてはあまり神経質になる必要はなさそうです。 (本当はセキュリティ要件とか運用・保守要件とか色々ありますが、このあたりは表に出せないので割愛) システム構成を検討する まずは要件の達成に向けてざっくりとした青写真を描いてみます。 今回のシステムの特徴は、おおよそ以下の通りまとめられそうです。 リアルタイムのデータ受信 DBは既存と共通 それぞれの特徴ごとに考えられることを列挙してみます。 リアルタイムデータ受信 どのプロトコルを採用するか 性能目標は? セキュリティは? DBは既存と共通 既存DB構成 既存DBの使用状況 順番に見ていきましょう。 リアルタイムデータ受信 今回は外部サーバーでデータが発生するたびに、こちらのサーバーでデータを受け取れるようにする必要があります。 パッと思いつくだけでも色々なやり方がありそうです。 HTTPで受信 どこかにファイルを置いてもらって、SFTPでポーリング どこかのキューに入れてもらって、それをサブスクライブ どれも一長一短あるかと思いますが、今回はHTTPを採用します。 データ送信元でもこちらの処理結果をトラッキングする必要があるため、非同期でデータのやりとりをするよりは、その場でこちら側のステータスを返却できる方が都合が良いからです。 (非同期でもできなくはないですが、ステータスをトラッキングするための仕組みを別で用意するといった一手間が必要になると思います) 今回は単純なデータ受信でセッションのような仕組みも必要ないことから、アプリ自体の構成も自然とREST-APIを採用することになりそうです。 また、性能については性能要件で記載した通りです。 DBは既存と共通 アプリ自体は新規で開発しますが、使用するDBは既存と共通です。 この場合、既存DBの使用状況、特にコネクション数には注意した方が良いと思います。 既存でコネクション上限すれすれの運用をしていた場合、追加のコネクションを貼れない可能性があります。 その際はDB側のコネクション上限を引き上げる等の対策が必要になります。 (DBが稼働しているマシンのスペックとの相談になるので、場合によっては単純に上限を引き上げるだけでは対応が難しいこともあると思います) 今回は幸い、対象DBのコネクションには余裕があるので、この点は問題にならないと考えて良さそうです。 また、DBの構成も重要です。 今回はアプリ一つに対して複数のDBが存在する構成になっており、アプリはデータの内容に応じて登録先となるDBを選択します。 このようにアプリ:DBが1:Nとなっている場合、アプリ側が保持するコネクション数にも注意を払う必要があります。 コネクションが多ければ多いほどアプリが稼働するサーバーのリソースを消費しますし、場合によってはアプリ側のコネクション上限に引っ掛かります。 そのあたりはDBと同様、サーバーのリソースと相談しつつ、コネクション上限を調節することになります。 さらに今回のシステムは少々特殊で、データを受け取った時点では、データを登録すべきDBをすぐに特定できない構成となっています。 このようなマルチテナント構成の場合、データ内部にテナント識別子のようなものがあって、それが直接DB名になっていたり、あるいはそれを元にどこかのデータストアにDB接続先を照会するといった仕組みが一般的かと思いますが、この既存システムは以下のようなアプローチが採用されています。 各DB内に保持しているテナント識別子を全て取得する アプリが受信した識別子と、1で取得した全識別子を突合する 2で合致した識別子を持つDBにデータを登録する 図で表すと概ね以下のようになります。 この構成は、「データ登録先を特定するために、一度すべてのDBに接続する必要がある」という点に特徴があります。 みなさんご存知かと思いますが、DB接続はコストの高い処理です。 これが一つや二つなら無視できる程度のオーバーヘッドかもしれませんが、数が増えていくにつれて無視できるものではなくなっていきます。 このシステムに含まれるDBは、現時点で100を超えています。 これはすなわち、100回を超えるDB接続処理がデータ取り込みのたびに実行されているということです。 これだけの回数になると、非常に大きなオーバーヘッドとなります。 既存システムはバッチ処理であり、多少時間がかかっても処理が完了すれば大きな問題にはなりません。 そのため、性能上の懸念はありつつもこの構成で運用されてきました。 しかし、今回作成するアプリはリアルタイムデータ受信用のAPIです。 データ受信頻度は既存システムと比較になりません。 データを受信するたびに100回以上のDB接続処理を繰り返していては、性能要件を達成することは到底不可能です。 そこで今回はDB側にも以下のような構成変更を行います。 新しく「テナント情報DB」を作成し、そこに各DBに散らばっているテナント識別子を全てコピーして集約します。 (テナント識別子を登録する別のアプリを改修し、各DBとテナント情報DBの情報が常に同期されるようにしています) 新しいアプリはテナント情報DBにテナント識別子を照会することで、全てのDBを参照することなく、最短ルートで適切なDBにデータを登録することができます。 少々回りくどいやり方ですが、今回は既存のデータ取り込みを変更することができないため、やむを得ずテナント識別子のコピーというやり方を選択しました。 (既存も併せて変更できる場合は、各DBのテナント識別子を廃し、テナント情報DBに一本化するのが最も適切だと思います) アプリのデプロイ先 アプリをデプロイするプラットフォームについても検討が必要です。 (オンプレ or クラウド、サーバーのOS、etc...) とはいえこのあたりはよほどド新規のサービスでない限りなんらかのプラットフォームがすでに存在していて、そこに載せるのが最善であることが少なくないと思います。 今回の場合は社内で利用可能なKubernetes(k8s)クラスタがすでに存在しているので、そちらにデプロイする方式を採用します。 アプリを設計する ここまででシステム構成を検討することができました。 あとはこれに当てはめてアプリを設計すればOKです。 これまでの情報をまとめると、アプリの特徴は概ね以下のとおりまとめることができそうです。 REST-API 複数のDBを取り扱う必要がある これを元に以下のような観点でアプリを設計していきます。 アプリケーションフレームワーク DBアクセスフレームワーク トランザクション制御 DBコネクション スレッドプール コードアーキテクチャ API I/F仕様 ビジネスロジック ログ、メトリクス、トレース アプリケーションフレームワーク アプリケーションフレームワークはアプリの基本的な構造となる重要な要素です。 最近だと Spring Boot が主流かと思いますが、Quarkus、Micronaut のようなマイクロサービス系も結構使われてたりすると思います。 弊社でも様々なプロダクトで Spring Boot が活用されています。 社内での普及状況も加味して、今回は Spring Boot を採用したいと思います。 現代のWebアプリケーションに必要な機能は大体カバーされていますし、世の中のナレッジも豊富です。 迷ったら Spring Boot でOKくらいのフレームワークと言えると思います。 REST-APIのフレームワークとしても優秀です。 一応、対抗馬として Quarkus の検討も行いました。 こちらはkube-native、コンテナファーストを謳うフレームワークで、GraalVMのネイティブイメージに早くから対応していた点にも特徴があります。 今回作成するアプリはk8sにデプロイすることになっているので、その点で親和性は高いと言えます。 またDBのコンテナなどを手軽に立ち上げることができるDev Serviceという機能が備わっており、開発環境の構築もかなり快適です。 個人的にはおすすめのフレームワークです。 Spring Boot と比較すると、それほど大きな機能差異はないと言えると思います。 Spring Boot もコンテナ運用は十分可能です。 こういった点と社内外に蓄積されたナレッジを考慮して、Spring Boot を採用することになりました。 この辺りはケースバイケースかと思いますが、今後もメンテナンスしていくことを考えると、ナレッジの有無は重要な判断要素だと思います。 DBアクセスフレームワーク Java の DBアクセスには JDBC を活用するのが一般的ですが、標準の JDBC API をそのまま業務アプリで採用するのは稀で、何らかのDBアクセスフレームワークを活用することが多いと思います。 これらを活用することで、DBのテーブル構造をJavaオブジェクトとして表現しやすくなり、より簡潔で可読性の高いDBアクセス処理の記述が可能になります。 多くの選択肢が存在しますが、Jakarta EE の仕様に組み込まれている JPA や、独自の仕様を持つ Mybatis、Doma、jOOQ といったものが選択肢としてあげられます。 JPA はDBとJavaオブジェクトの同期を可能にする仕組みで、Javaオブジェクトに対する作成、更新、削除が独自のメモリ空間に反映され、それらをDBと同期するためのSQLを自動で発行します。 (SQLを記述する仕組みもあります) SQLの記述なしでDBを変更することができるため、適切に設計すれば非常に簡潔で可読性の高いコードを記述することが可能です。 一方でオブジェクトの変更がDBに反映されるまでのメモリ空間上のライフサイクルを適切に把握する必要があり、場合によっては意図しないDB操作を発生させるリスクもあります。 この点で若干ハードルの高い選択肢と言えると思います。 JPA の実装としては、Spring Data JPA や Hibernate 等が挙げられます。 Mybatis、Doma、jOOQ 等は、JavaオブジェクトとDB間のマッピングや、SQL記述方法に独自の仕様を持っているライブラリです。 それぞれの特徴は、ざっくり以下の通りです。 Mybatis SQLをJavaコードやXMLファイルで記述し、それをJavaオブジェクトにマッピングする SQL記述の自由度が高い点が魅力で、特に複雑なSQLを必要とする場合に有用 Doma Mybatisと似たような機能に加え、SQL自動生成機能やコンパイル時のSQLチェックといった開発効率化機能を備える jOOQ SQLをJavaコード上でビルドすることにフォーカスしており、型安全を保ったままDB操作を記述することができる これらには使い勝手の違いこそありますが、SQLを何らかの方法で表現し、それをプログラム上で明示的に実行するという点で共通しており、ここがJPAとの大きな違いと言えます。 技術選定する際はJPAかどうかが一つの軸に挙げられると思います。 今回は以下のような点を加味して、Mybatisを採用します。 個人的に使い慣れている 楽楽精算開発チーム内での採用事例が多い SQLを柔軟に表現できる トランザクション制御 トランザクションの設計はDB操作に関連する重要な要素です。 ここではプログラムのどの単位をDBトランザクションの区切り(トランザクション境界)とするかを検討します。 例えばあるAPIの中に大きく分けてA、B、Cの三つの処理が含まれているとします。 これに対し、いくつかトランザクション境界のパターンを考えてみます。 すべて一つのトランザクションとする A、B、Cすべての処理が成功した場合のみコミットされる いずれか一つでも失敗すれば、すべてのDB操作がロールバックされる 「A、B」と「C」で分ける A、Bは両方成功しないとコミットされない Cが失敗しても、A、Bはロールバックされない すべて個別のトランザクションとする いずれかの処理が失敗しても、他のトランザクションはロールバックされない このように、どこにトランザクション境界を置くかによって、最終的なDB操作の結果が変わってきます。 特にいくつかの単位に分ける場合、何らかの処理が失敗しても、すでにコミットされたトランザクションはロールバックできないという点に注意が必要です。 もし全ての処理が常に同期している必要があるにも関わらず、Cの結果のみコミットされないといった場合、Cの結果が欠落した中途半端なデータが出来上がります。 またエラーが発生したトランザクションの後にも別のトランザクションを発行する処理が実装されている場合、エラーとなった時点で処理全体を止めるのか、それとも処理を継続して別のトランザクションを開始するのかといった判断も必要になります。 例えば処理の実行結果をDBに残すと言った場合、処理の成否に関わらず履歴が登録される必要があります。 この場合、先行するトランザクションが失敗した場合も、履歴登録処理は確実に実行されるよう設計されているべきです。 以上のようなことを踏まえて、今回のアプリケーションにおけるトランザクション設計を考えてみます。 システム構成でも述べた通り、一回の処理で二つのDBに接続する必要があります。 そのため、これらを一つのトランザクションとするか、それともDBごとにトランザクションを分離するかという判断が必要になってきます。 複数DBを一つのトランザクションとして扱う場合、2フェーズコミットのような仕組みが必要になります。 これは各DBに対する操作をコミット前の状態で待機させ、全てのDB操作が成功したタイミングでコミットされます。 (いずれかが失敗した場合はすべてロールバックされます) 複数DB間でデータの一貫性を保証できる一方、どこかの処理が遅延すればそれだけ多くのDBをロックすることになり、パフォーマンス上の影響が懸念されます。 こういった影響を最小限に抑えるための適切な設計が必要になるため、ハードルの高い選択肢と言えます。 まずはこれらに対するトランザクションを一つにまとめる必要があるか判断します。 今回の場合、「テナント情報DBからテナント情報を取得→取得した情報を元にいずれかのDBに登録」という流れで処理が行われます。 テナント情報DBへの接続は読み取り専用になるため、トランザクションについてはそれほど意識する必要はなさそうです。 これ以降の処理で何らかのエラーが発生したとしてもテナント情報DBの状態には一切影響がないため、パフォーマンス上の影響も加味して、2フェーズコミットを採用するメリットはあまりないと考えられます。 そのため、今回は各DBアクセス単位でトランザクション境界を作成する設計とします。 DBコネクション コネクションプール 先述の通り、DB接続は比較的コストの高い処理です。 あまりにも頻繁に行っていると、CPU使用率の増加でアプリケーション、ひいてはサーバー全体のパフォーマンスに悪影響を及ぼす恐れがあります。 それを避けるために一般的な手段がコネクションプールです。 これは一度開いたDB接続をプールしておき、次回以降の処理で使い回すというものです。 これによりDB接続の頻度を下げ、一回の処理あたりのオーバーヘッドも下げることができます。 Spring BootはデフォルトでHikariCPによるコネクションプールが備わっているので、特に意識しない限りこれを使うのが一般的かと思います。 一方、プールされたDB接続の個数が増えるにつれ、メモリ使用量も増えていきます。 アプリ:DBの数が1:1のような構成であればそれほど大きな問題になりませんが、これが1:Nとなるとどうでしょうか。 今回のシステム構成では一つのアプリケーションが100個を超えるDBにアクセスするため、コネクションプールも相当数確保する必要があります。 (一つのDBに対するコネクションは一つとは限らないので、これを二つ三つと増やすにつれて、全体のプール数も増加していきます) この場合、そもそもコネクションプールが必要かどうかという点を確認する必要があります。 その際の判断基準の一つが性能要件です。 冒頭を振り返ると、性能要件は以下のようになっていました。 性能要件 想定される最大秒間処理回数:1 処理完了:3秒以内 この程度であれば、コネクションプールがなくても性能要件は十分達成可能と言えます。 既存のように全DBにいちいち接続する必要がある場合はコネクションプールが必須と言えますが、今回はその点も改善されています。 以上のことから、今回コネクションプールは採用しない方針とします。 ここからさらに流量が増えてきた場合は、コネクションプールの導入を検討した方が良いと思います。 そのあたりはケースバイケースなので、早めにPoCを作って性能検証を行い、コネクションプールの有無でどの程度のパフォーマンスが出るか確認した上で判断するのが良いと思います。 DB接続の上限 コネクションプールを活用するかどうかに関わらず、同時に使用できるDB接続の上限を管理する必要があります。 この上限を超えるDB接続はその時点でペンディングとなり、別のDB接続が終了するまで待機することになります。 Spring Boot で Hikari CP を採用している場合、デフォルトの最大値は10です。 今回のアプリケーションでもこの値で性能検証の結果が良好だったことから、上限を10に設定しています。 もしここで性能劣化等の現象が発生した場合は、この値を調節する必要があります。 値が小さすぎるとDB接続待ちが発生しやすくなりますし、逆に大き過ぎれば、同時アクセス数が増えるにつれてメモリ使用量を圧迫すると同時に、接続の切り替えに伴うコンテキストスイッチも増えていきます。 いずれの場合も処理の遅延を招き、DB処理の待ち行列がどんどん長くなっていくことが予想されます。 値の決定には以下のようなことを考慮する必要があります。 性能要件(予想される流量) アプリケーションが稼働するサーバーのスペック DBが稼働するサーバーのスペック 明確な基準については諸説あると思いますが、サーバーのCPUコア数は代表的な判断基準と言えると思います。 一般的な同期処理アーキテクチャを採用するアプリケーションは、DB処理中にCPUコアを占有します。 そして、CPUはコア数を超える処理を同時に行うことはできません。 そのため、コネクション数を多めに設定したとしても、同時実行可能な処理数はコア数で頭打ちとなり、それを超える分はコアが解放されるまで待ち状態となります。 待ちが多くなればなるほどメモリ使用量増加と頻繁なコンテキストスイッチを誘発するので、コネクションの増やしすぎには特に注意した方が良いと思います。 実際の設定値については、CPUコア数を軸に据えて調節しながら、性能検証を重ねて適切な値を割り出すというアプローチが良いと思います。 スレッドプール コネクションプールはDB接続に対してのものですが、スレッドプールはサーブレットのスレッドをプールする仕組みです。 リアクティブなAPIを除いて、世の中で稼働するJavaベースのWebアプリケーションは、大部分がサーブレットです。 Spring Boot も例外ではありません(Web Fluxを採用した場合を除く)。 サーブレットはリクエストを受信するたびに、リクエスト専用のスレッドを確保します。 スレッド作成はDB接続と同様にコストの高い処理なので、リクエストのたびにスレッドを作成していては処理の遅延に繋がります。 それを避けるため、作成されたスレッドをプールしておき、リクエスト受信時に使い回す仕組みがスレッドプールです。 Spring Boot のデフォルト値は200です。 こちらも性能検証で問題がみられなかったことから、この値を採用しています。 もし問題が見つかった場合は、DB接続と同様、CPUコア数を軸に調整するのが良いと思います。 また Virtual Thread も選択肢の一つです。 これは Java21 で登場した新しいスレッドで、DB接続などのI/O中にCPUがブロッキングされないという点に特徴があります。 詳しい説明は省きますが、例えばDBサーバー側で処理に時間がかかっているような場合、従来のスレッドではCPUを占有し続けるため、他のスレッドはこれが解放されるまで待ち状態となります。 これが Virtual Thread に置き換わると、DB処理中にCPUの占有を解除し、他のスレッドがCPUを使用できる状態を作り出すことができます。 これにより、I/O待ちが多く発生するようなアプリケーションにおいてCPUの能力をより効率的に活用し、従来よりも多くのスレッドを同時に扱うことができるようになります。 従来のスレッドを置き換えるだけでリアクティブプログラミングのような恩恵を教授できるという点が画期的で、モダンJavaの中でも注目を集めている技術です。 (今回はパフォーマンス的にそれほどシビアなユースケースではなかったことから採用は見送りました) コードアーキテクチャ 例えばMVCという言葉はかなり一般的かと思いますが、それに類するものがコードアーキテクチャです。 ここではソースコードの構成(レイヤやクラス設計等)を検討します。 これの良し悪しがアプリケーションのメンテナンス性の良し悪しに直結すると言っても過言ではなく、開発速度の担保や安定的な運用に欠かせない重要な要素です。 最近はドメイン駆動設計(DDD)の考え方がずいぶん浸透してきたように感じます。 これはアーキテクチャの中心にドメインを据える考え方で、ドメインの振る舞いや状態に応じてユースケースを組み立てていきます。 それと同時に、DB接続のようなインフラ層の実装をドメインから分離することで、インフラ層の仕様に左右されることなく、ドメインの振る舞いに集中できるようになります。 詳細を語ると長くなるので省きますが、ドメインの振る舞いに集中する考え方は一度慣れると非常にわかりやすく、個人的にもおすすめの手法です。 アーキテクチャの決定には取り扱うドメインや業務要件が大きく関わってきますが、要件が単純な場合はMVCのような三層構造でも良いと思います。 ドメイン駆動設計を取り入れたアーキテクチャはMVCと比較すると複雑な傾向があるので、要件によっては過剰な設計となることも考えられます。 今回作成するアプリケーションは単一のドメインを扱う非常にシンプルな要件です。 この点だけ見るとMVCでも良さそうですが、既存のDB構造と今回取り扱うドメインの構造に微妙なギャップがあり、DB構造にドメインが引きずられることを避ける必要がありました。 ドメイン層とインフラ層を分離できるドメイン駆動の考え方はこの点で都合が良く、今回はこれをよく取り入れているオニオンアーキテクチャを採用しました。 (オニオンアーキテクチャはドメイン駆動設計を取り入れた設計手法の一つで、この他にクリーンアーキテクチャ等が存在します) API I/F仕様 Web-APIの場合、リクエストやレスポンスの形式を定める必要があります。 業務要件に応じて、以下のような観点で設計を行います。 リクエスト URL HTTPメソッド ヘッダ パラメータの種類や形式 レスポンス HTTPステータス ヘッダ ボディ 今回のアプリケーションでは、REST-APIを採用しています。 そのため、URLで操作対象のドメインを、HTTPメソッドで操作内容ををそれぞれ表現する必要があります。 例えば対象のドメインが「hoge」の場合、URLは http://xxx.yyy.zzz/hoge となります。 このドメインを取得する場合、HTTPメソッドは「GET」となります。 これが新規作成になるとHTTPメソッドが「POST」となり、更新では「PUT」、削除では「DELETE」となります。 URLの http://xxx.yyy.zzz/hoge は常に一定で、パスパラメータで操作対象データのユニークキーを指定したり、クエリパラメータで検索条件を設定する場合もあります。 またPOSTやPUTの場合、リクエストボディに登録または更新内容を設定することになります。 今回は要件が単一ドメインの登録のみのため、POSTメソッドに対するAPIエンドポイントを設計すればOKです。 こういったAPIではリクエストボディにJSON形式のデータを設定するのが一般的ですが、今回もそれに倣った設計とします。 Spring Boot ではJSON形式のリクエストボディをJavaオブジェクトにマッピングする仕組みがデフォルトで備わっており、その点でも親和性が高いです。 またREST-APIの仕様書についてはOpenAPIのフォーマットが一般的なので、特にこだわりがなければそちらを採用するのが良いと思います。 (共通言語なので社外とのやりとりもスムーズです) ビジネスロジック 業務要件をプログラムで直接表現するのがビジネスロジックです。 この部分は要件によってまちまちなのですが、少なくともアプリケーションフレームワークやトランザクション制御、コードアーキテクチャなどから逸脱した設計にならないよう注意する必要があります。 (今回の要件はあまり表に出せないため、詳細は割愛します。) ログ、メトリクス、トレース これらはアプリケーションの運用にあたって必要な要素です。 ログはアプリケーションに対するアクセス状況や処理結果等をテキストで出力することで、外部からこれらを確認することができます。 特にエラー発生時に出力されるスタックトレースといった情報は、本番環境のデバッグにおける重要な情報源となります。 また要件によっては機能の実行回数や利用者数を集計したいといった場合があり、それらをログで実現することもあります。 Spring Boot の場合はデフォルトで Logback が有効化されているため、特にこだわりがなければそちらを利用するのが良いと思います。 また Grafana Loki のようなログ集計システムを使用する場合、ログを JSON フォーマットで出力することでラベルごとの集計が容易になります。 メトリクスはサーバーのCPU使用率やメモリ使用率、Javaプロセスのヒープ使用率、GC発生状況等を監視するために取得する情報です。 これらを適切に取得し監視することで、サーバーそのものやプロセスの異常を検知することができます。 これを実現するツールとしては OSS の Prometheus が有名です。 Spring Boot では Micrometer の Prometheus 用エンドポイントを有効化することで、Prometheus が必要としている情報を簡単に取得することができます。 Prometheus が利用できる環境では、これを活用するのが良いと思います。 トレースは処理の流れを追跡するための仕組みです。 処理全体の開始から終了までをトレース、その中の任意のステップ(メソッド呼び出しやDBアクセス等)をスパンとして記録します。 スパンごとの処理時間を計測することでパフォーマンス上のボトルネックを特定したり、エラー発生までの処理内容を確認することで原因特定に役立てるといった活用方法が考えられます。 これはシステム間を跨ぐような処理でも一つのトレースとして扱うことができるため、複数のマイクロサービスが協調して動作する分散システムのような構成では特に有用です。 これを実現するための有名な OSS として OpenTelemetry があります。 Spring Boot には OpenTelemetry と連携する仕組みが用意されているので、これを活用するのが良いと思います。 今回作成したアプリケーションでは、以下の構成を採用します。 (収集および可視化ツールは社内で標準化されたプラットフォームが存在するので、そちらに合わせています) テレメトリー種別 出力 収集 可視化 ログ Logback (JSON形式出力には logstash-logback-encoder を使用) Grafana Loki Grafana メトリクス Micrometer Prometheus Prometheus Grafana トレース OpenTelemetry Java Agent Grafana Tempo Grafana まとめ 新規アプリケーション設計の流れと考え方を振り返ってみました。 ここに書かれているだけでも多くの検討事項がありますが、これ以外に書ききれなかった項目もありますし、書いてある内容もまだまだ掘り下げられると思います。 それだけアプリケーション設計は考えることが多く、奥が深い作業です。 今回のアプリケーションは比較的単純な構造でしたが、改めて振り返るとそれなりに時間のかかる作業だったと思います。 一方で大変なだけでなく、ゼロからモノを作り上げる楽しさもあります。 既存サービスの開発ではアプリケーションを新規で作成するような機会はそれほど多くないので、エンジニアとしては大変貴重な機会をいただけたと思います。 冒頭でも述べた通りですが、今回の投稿がこれから設計挑戦する皆さんの一助となれば幸いです。
アバター
目次 はじめに AI-Agentはインフラでどこまで使えるのか 実行環境とセットアップ 3日で進めたTerraform化のプロセス 使ってみて実感した効果 まとめ はじめに このブログの目的(と、ごあいさつ) こんにちは。SREの gumamon です! 昨今のAI Agentの進歩は目覚ましいものがありますね。 Vibe Coding という言葉も登場し、自然言語でAIに指示をすればアプリケーションが作れる時代になる──そんな話もちらほら聞きます。 しかし、Vibe(雰囲気)で作業をされると一瞬で崩壊してしまうのがインフラ領域です。 「AI Agentをどう使っていこう?」と悩まれている方も多いのではないでしょうか。 このブログでは、AI Agentの一種である ClaudeCode を使って、既存のAWS環境をTerraform化した過程をご紹介します。 この記事を読むことで、 インフラ領域におけるAI Agent活用のイメージ を掴んでいただければと思います。 対象読者と前提知識 本記事は、実務で Terraform を使用している技術者を対象としています。 また、以下については(本稿よりも圧倒的に良いブログやドキュメントがあるので)割愛します。 AI Agentについての基礎知識 ClaudeCode とは/使い方 免責 本稿の元となる作業は2025年7月に実施したものです。 執筆時点では、より良い選択肢や方法があるかもしれません (時の流れが速すぎて怖い・・・)。 AI-Agentはインフラでどこまで使えるのか 結論から言うと、現状では 「インフラ(リソース)の変更を伴わない作業」 に留めるのが良いと思います。 先日行われた PLATFORM ENGINEERING KAIGI 2025 のKeynoteで、こんな発言がありました。 AI is an angry intern(AIは怒れるインターン生) 少々言い過ぎですが、「確かにね!」と思うところがあります。 AI Agentに作業を任せる際、人間は「期待するふるまい」をコンテキストとして伝えます。 たとえば次のような指示です。 terraform plan は実行可、 terraform apply は禁止 既存のAWSリソース(ECSなど)をもとにTerraformコードを生成する 序盤はこれを忠実に守って動くのですが、作業が長引くにつれて次第に怪しい提案をしはじめ、最終的には terraform apply を実行してリソースを合わせにいく──そんなことも起こります(というか起こりました)。 現状のAI Agentは 長いコンテキストを保持するのが苦手 で、会話履歴が圧縮される過程で重要な指示が抜け落ちることがあります。 その結果、「やってはいけないこと」をやってしまう。 AIと人間は根本的に特性が異なります。 AIに任せるなら、ガードレール(制限・権限・監視)をきちんと整えることが必須 だと感じました。 実行環境とセットアップ AI Agentを逐一監視(提案されるコマンドのたびにEnter)していたのでは、人間側の作業効率が上がりません。 (諸説あると思いますが)私は AI Agentの実行環境をサンドボックス化し、インフラ構成を変更できない権限 を与えたうえで、自由に作業させることにしました。以下が実際の実行環境です。 sandbox 実行環境で工夫したポイントは以下です。 VirtualMachine(sandbox)環境では自由な振る舞いを許可 root権限を付与 必要なツールをインストール インターネット上の情報を参照可 AI Agentの社内環境アクセスを厳しく制限 Git:Featureブランチのみ操作可能 AWS:Terraform関連リソース以外はすべてReadOnly その他:不要なクレデンシャルは一切付与しない(例:AWS prod環境) AWSへのアクセス権限(IAM User/RoleにアタッチするIAM Policy)は以下の通りです。 ReadOnlyAccess (AWS管理/全リソースへのRead権限) custom-dynamodb-access-for-terraform (ユーザー管理/DynamoDB(lock)へのGet,Put,Delete権限) custom-s3-access-for-terraform (ユーザー管理/S3(tfstate)へのGet,Put,List権限) 3日で進めたTerraform化のプロセス ここからは、3日間で実際に行った作業と悩んだことを書いていきます。 Day1:ClaudeCodeのインストールとプロンプト整備 実行環境の作成 → ClaudeCodeの導入 クイックスタート を参考にインストール(Node.jsが必要) 対象リポジトリのルートで claude コマンドを起動し /init 実行 CLAUDE.md(プロジェクト用プロンプト)が生成される 内容が薄いとClaudeがうまく理解できないことに気づく Terraformを少しだけ書く サンプルとして軽くTerraformコードを追加(いわゆるワンショットプロンプト) 自分の構成が意外と曖昧なことに気づく README.mdにTerraformフォルダ構成を書く フォルダ構成と役割を整理しながらREADMEに記載 (構成ツリー) . ├── README.md # README └── terraform # Terraform Code ├── bootstrap # Bootstrap Code (初期化用コード: Terraform自体の初期設定を行う) │ ├── dev # Development Bootstrap Code (Terraformの実行ディレクトリ: dev環境用) │ │ ├── main.tf # Main Terraform file for dev bootstrap (Terraformのエントリーポイント) │ │ └── variables.tf # Variables for dev bootstrap (dev環境用変数) │ └── prod (WIP) # Production Bootstrap Code (Terraformの実行ディレクトリ: prod環境用) ├── environments # Environment Code (環境ごとのコード: dev,prodなど) │ ├── dev # Development Environment Code (Terraformの実行ディレクトリ: dev環境用) │ │ ├── main.tf # Main Terraform file for dev environment (Terraformのエントリーポイント) │ │ ├── variables_global.tf # Global variables (グローバル変数) │ │ ├── variables_platform.tf # Variables for platform module (プラットフォームモジュール用変数) │ │ ├── variables_gateway.tf # Variables for gateway module (ゲートウェイモジュール用変数) │ │ └── ... │ └── prod └── modules # Modules (モジュール: 再利用可能なコードの集まり) └── common # Common Modules (共通モジュール: 複数の環境で使用される共通のリソース) ├── platform # Platform Modules (プラットフォームモジュール: VPC, IAMなどの基盤となるリソース) │ ├── vpc.tf # VPC configuration (VPC設定) │ ├── xxx.tf # xxx configuration (任意のリソース設定: .tfファイルはリソースごとに準備する) │ ├── variables.tf # Variables for platform module (プラットフォームモジュール用変数) │ └── outputs.tf # Outputs for platform module (プラットフォームモジュールの出力) ├── gateway # Gateway Modules (ゲートウェイモジュール: API Gatewayなどの設定) │ ├── alb.tf # Application Load Balancer configuration (ALB設定) │ ├── xxx.tf # xxx configuration (任意のリソース設定) │ └── variables.tf # Variables for gateway module (ゲートウェイモジュール用変数) └── ... 一日目終了。 Day2:AWSリソースのTerraform化 ClaudeCodeのPJ初期化再実行 /init 実行 → より良いCLAUDE.mdが生成される 既存AWSのTerraform化を開始 Claudeに「既存AWS環境から1モジュールを作成」と依頼 想定外の提案も多く、しばらくペアプロ的に進行 成功したケースを要約してCLAUDE.mdに反映 試行錯誤の末、安定して出力できるようになり、2モジュールをTerraform化 (プロンプト例) # 目的 VPCのリソースをTerraformで管理したい - すでにAWS環境のリソースは存在しています (.aws/config の情報でアクセス可能) - AWSリソースを調査し、Terraformのコードを作成する必要があります - さらに、既存のリソースをTerraformで管理するために、 ` terraform import ` を使用する必要があります - 複雑なタスクです ` think ` して取り組んでください。調査ができ、**実行計画を立てることができたら一度私に確認させてください** # 追加するリソース - VPCに関するリソース # その他要件 - リソースはplatform moduleに追加してください - environments/dev から platform module を呼び出すコードを作成してください - moduleの変数は適宜設定してください - 構成や変数化の粒度については既存のコードを参照 二日目終了。 Day3:Terraformのリファクタリング リファクタリング方針を検討 Day2のコードではIAMをplatform moduleに含めていたが、 それではgateway moduleなどをスケールさせる際に柔軟性がないと気づく 各moduleで使うIAMをそれぞれに分離する方針へ変更 ClaudeCodeにリファクタを指示 想定通りに動かないため、再びペアプロモードへ 成功パターンを要約し、 additional_prompts/ 以下に保存 CLAUDE.mdからリンク参照させる方式を試す NOTE CLAUDE.mdが長くなってきたため、プロンプトを分割。 結果として「どの追加プロンプトを編集すべきか」が明確になり、体験が向上しました。 仕上げ Terraform全体をレビューさせ、 命名規則・タグのばらつき を指摘させ修正 人間による最終チェックを実施し、 #TODO コメントをClaudeに処理させて完了 使ってみて実感した効果 1. とにかく速い 序盤はClaudeCodeの動作を見守っていましたが、 プランニングもコーディングも人間の速度を遥かに超える 。 自力で1ヶ月かかる作業が、試行錯誤込みで3日で完了しました。 インフラ領域でも、今後仕事の進め方が根本的に変わると実感しました。 2. 想定以上に応用が効く 以前ならAWSリソースをTerraform化するには Terraformer が必須でした。 しかし、対応外リソースでもClaudeCodeは問題なくコードを生成。 ドキュメントを読んだり学習済み知識を活用したりしているようで、十分な精度を感じました。 3. 思い切った意思決定ができる Day3でIAM設計の問題に気づきリファクタに踏み切りましたが、手書きでTerraform化していたら費用対効果の面で諦めていたと思います。 Agentと協働することで、人間の業務をより抽象度の高い領域へシフトできると実感しました。 4. 思考整理の効果がある Day1でも触れましたが、 曖昧な要件では曖昧な出力しか得られません 。 Agentに読ませるプロンプトを練る過程で、自分の理解が不十分な部分が浮き彫りになり、思考が整理されていきました。 「自分がわからないことは指示できない」という制約が、結果的に品質を高めているように感じました。 まとめ 今回は、ClaudeCodeを使用した既存AWS環境のTerraform化の事例をご紹介させて頂きました! インフラ領域へのAI Agentの活用検討の一助となれていましたら幸いです。 以上、最後までお読み頂きありがとうございました!
アバター
202025年9月30日(火)、paiza株式会社と株式会社ラクスは、共同技術イベント「AI導入最前線!理想 vs 現実『AIドリブン開発』 〜エンジニア視点で語るリアル活用術〜」を開催しました。 「AIが自動でコードを書いてくれる」「開発効率が劇的に上がる」といった輝かしい「理想」の一方で、開発の現場では多くのエンジニアが現実的な課題に直面しています。 本イベントでは、AI開発の最前線で活躍する4名の登壇者が、実際に直面した困難や、それを乗り越えるために生み出したリアルな解決策を共有しました。 全てのセッションに共通するキーワードは 「コンテキスト(文脈)」 。AIの真価をいかに引き出すか、その実践的なヒントが満載のイベントの様子をレポートします! セッション1:属人化から「チームの力」へ。ラクスが挑んだ組織的なAI活用 セッション2:人とAIが共生する新しい開発フロー「AIエージェントを使った爆速デモアプリ作成」 セッション3:AIによる自律的並列処理でテストを効率化!「Claude Codeによる自律的並列分析の実践」 セッション4:コードを書かないマネージャーがつくる「コンテキストエンジニアリング」 セッション5:10年以上続くWebサービスのAIファースト時代への向き合い方 まとめ:AIドリブン開発は「魔法」ではなく、地に足の着いた「実践」 セッション1:属人化から「チームの力」へ。ラクスが挑んだ組織的なAI活用 登壇者:株式会社ラクス 石田 浩章 speakerdeck.com AI活用の第一歩は、個人のスキルや熱意といった「点」を、いかにして組織全体の「面」の強さに変えていくか、という課題にあります。 このセッションでは、ラクス社がAIツールの導入初期に直面した「活用レベルが個人の意欲に依存し、社員間の格差が生まれてしまう」という課題から、いかにして脱却したかが語られました。 取り組みのポイント 推進体制の構築: 各チームのリーダーによる「推進チーム」と、現場の旗振り役となる「推進役」を設置し、トップダウンとボトムアップを組み合わせた体制を構築。 「まず実践」の文化醸成: 完璧な計画を待つのではなく、「まずやってみよう」という文化を徹底し、実践から得られる学びを重視。 知見の共有サイクル: 各チームの成功・失敗事例をリーダーが集約し、汎用的な知見として全体に共有する学習サイクルを確立。 この4ヶ月間の取り組みの結果、AIツールの実務利用率は80%から100%に向上。さらに注目すべきは、 自発的な情報共有の活動量が34%も向上した 点です。これは単にツールが導入されただけでなく、AIを軸とした「学習する組織文化」が根付き始めたことを示しています。 AI活用を成功させる鍵は、ツール導入そのものよりも、チームで学び、成長し続ける文化をいかに育むかにある、という重要な示唆が得られました。 セッション2:人とAIが共生する新しい開発フロー「AIエージェントを使った爆速デモアプリ作成」 登壇者:株式会社ラクス 北嶋 初音 speakerdeck.com 「AIを開発プロセスにどう組み込むか?」この問いに対し、人とAIがそれぞれの得意な領域で力を発揮する、新しいワークフローが紹介されました。 新規プロダクトのPoC(概念実証)開発という、スピードが命のプロジェクトで、Miroのワイヤーフレームだけを元に「動くデモアプリ」を迅速に構築する必要がありました。そこで編み出されたのが、人とAIの役割を明確に分担した開発フローです。 人とAIの役割分担 【人】お手本の実装: 最初の1画面はあえて人が手動で実装。コーディング規約や設計パターンといった「お手本」をAIに示す。 【AI】土台の実装: 「お手本」コードとワイヤーフレームを元に、AIが2画面目以降の土台を高速で生成(完成度30〜60%)。 【人とAI】壁打ち修正: 人がAIに具体的な修正指示を出し、対話しながら完成度を80%まで高める。 【人】仕上げとレビュー: 細かなUI調整や動的な挙動の実装、最終的なコードレビューは人が担当。 このアプローチにより、 体感で30〜40%の工数削減 を実現しただけでなく、流動的な仕様変更にもスピーディに対応できるようになったとのこと。 結論は明快です。「0→1」の初期設計と「80→100」の最終品質担保は人が担い、その間の定型的な実装作業はAIに任せる。この賢い棲み分けこそが、AIドリブン開発を成功させる核心と言えるでしょう。 セッション3:AIによる自律的並列処理でテストを効率化!「Claude Codeによる自律的並列分析の実践」 登壇者:株式会社ラクス 大口 詩織 speakerdeck.com 大規模で長く運用されているシステムにおいて、品質を保証するためのリグレッションテストは、時に開発のボトルネックとなります。このセッションでは、膨大なテストケースの選定作業を、AIを用いて自動化した非常に高度な事例が紹介されました。 課題は、毎回手動で行っていたテストケースの選定作業の負担が大きいこと。そこで、「バグが起きやすい機能をデータから特定し、テストを優先順位付けする」という目標を立て、過去2年分・約1000件のGitコミットログの分析に挑みました。 この膨大かつ複雑な分析は、人手では現実的ではありません。そこで考案されたのが、AIによる独創的なアーキテクチャです。 "Manager-Worker"モデルによる自律処理 AIツールの使い分け: 方針決定の壁打ちにはChatGPT、具体的な分析作業にはClaude Codeと、役割に応じてAIを使い分け。 自律的な並列処理: 1体の「Manager」役AIが、複数の「Worker」役AIに分析タスクを割り振る構成を構築。これにより、AIチームが自律的に並列で作業を進める仕組みを実現。 この取り組みにより、 人間が介在せずとも処理が進む「手離れ」 を高いレベルで実現するという大きな成果を収めました。一方で、Workerが作業を停止してしまうなど、自律エージェントならではの新たな課題も見えてきたとのこと。ビジネスの根幹にある泥臭い課題に、革新的なアプローチで挑んだ好例です。 セッション4:コードを書かないマネージャーがつくる「コンテキストエンジニアリング」 登壇者:株式会社ラクス 石田 浩章 speakerdeck.com 長年開発されてきた複雑なシステムにAIを導入しようとすると、「過去の設計経緯が不明」「仕様書が整理されていない」「コード量が多すぎてAIが扱えない」といった壁に直面します 。なぜなら、既存の開発はチームに蓄積された「暗黙知(コンテキスト)」に支えられているからです。 このセッションでは、AIの真価を引き出す鍵となる 「コンテキストエンジニアリング」 というアプローチが紹介されました 。これは、AIが人間の意図を正確に理解するために必要な「情報(コンテキスト)」を、いかに設計し、構造化するかという技術です 。 マネージャーとして取り組むべき3つの解決策 ① コンテキストストリーム設計: ビジネスサイドも扱いやすいGoogleドキュメントで要求をまとめ、開発側が管理しやすいMarkdown形式でGitHubに連携させるなど、情報の流れを整えます 。 ② AIによる自動化と支援: ドキュメント形式の変換をAIで自動化したり、専門知識が必要な仕様の整合性をAIにチェックさせたりすることで、属人性を排除します。 ③ できる限りの情報を残す: なぜその技術を選んだのかという背景を「ADR(Architecture Decision Record)」として記録するなど、未来のチームとAIのために、意図的にコンテキストを残していくことが重要です。 重要なのは、より賢いモデルを待つことではなく、 「課題に最適なコンテキストを与えること」 。チーム、関係者、そしてAI自身がより良く開発していける環境を整えることこそ、マネージャーとしてのコンテキストエンジニアリングであると語られました 。 セッション5:10年以上続くWebサービスのAIファースト時代への向き合い方 登壇者:paiza株式会社 高村 宏幸 氏 speakerdeck.com 最後のセッションでは、これまでの具体例を俯瞰し、AI活用で真の競争優位性を生むための戦略的な視点が示されました。 高村氏は、AI活用には「光」と「闇」の2つの側面があると語ります。 光の側面 デモ映えする派手な活用法(例:0→1のアイデア創出) トレンドの進化が速く、追随しないと競合に劣後する 「守り」 の一手 闇の側面 地味で泥臭いが、ビジネスの根幹に関わる課題解決 自社特有の巨大なコンテキストが必要で、競合が真似しにくい 真の競争優位性を生み出す可能性を秘める 高村氏が強調するのは、 「目的はAIを使うことではなく、ビジネスの課題を解決することだ」 という原則です。たとえAIで実装が速くなっても、レビューやテストが新たなボトルネックとなり、全体のリリースサイクルが短縮されなければ意味がありません。 私たちは、流行りの「魅せ球(光)」を追いかけるだけでなく、自社の文脈に深く根ざした、競合が模倣困難な「決め球(闇)」を磨き続ける必要がある、という力強いメッセージでセッションは締めくくられました。 まとめ:AIドリブン開発は「魔法」ではなく、地に足の着いた「実践」 今回のイベントを通じて見えてきたのは、AIドリブン開発の成功は、単一のツールや魔法によってもたらされるものではない、という力強い現実でした。成功への道筋は、一つの成熟度モデルとして描くことができます。 まず、個人に依存せず、チームで学び成長する 組織的な基盤 を築きます。その上で、人とAIの得意領域を見極め、協業させる 戦術的な高速化 を実践する。さらに、既存システムの複雑さという壁を乗り越えるために、 戦略的にコンテキストを設計 し、AIに与える。そして、現場の真の痛みを解決するため、AIを 自律的なエージェント として活用し、価値の高い課題に挑む。これら全ての活動を、ビジネスの「本質的な課題解決」へと方向づける 戦略的思考 が、その羅針盤となるのです。 イベント全体を貫くテーマとして「コンテキスト」の重要性が繰り返し示されました。ラクスとpaiza社が共有したリアルな知見が、皆さまの開発現場をより良くする一助となれば幸いです。ご参加いただいた皆さま、誠にありがとうございました!
アバター
こんにちは、プロダクト部 部長の稲垣です。(自己紹介やこれまでのキャリアについて↓をご覧ください。) tech-blog.rakus.co.jp これまで「製品管理課」という名称で運営してきましたが、2025年10月より課を分割し、新しい名称と体制へと進化しました。本記事では、そのご紹介を兼ねてまとめています。 (上位組織である「プロダクト部」については先日まとめましたので、こちらもぜひご覧ください。) tech-blog.rakus.co.jp マルチプロダクトを展開し、かつ多様な製品フェーズを抱える企業において、プロダクトマネージャー組織をどのように設計・運営するかを考える上で、一つの参考になればと思います。また、ラクスのプロダクトマネージャーにご興味をお持ちいただいた方にとっても、その意義や背景を感じていただける内容にしていきたいと考えています。 第二進化の背景 当初12名で1つの組織「製品管理課」として活動していましたが、以下の理由から2つの組織に分割し、名称も「プロダクトマネジメント」へ変更しました。組織変更の背景と理由は以下の3点です スパン・オブ・コントロール(2ピザルール)の観点 リーダーPdMへの権限委譲によるプロダクト成長への寄与 名称の明確化と統一 それぞれについて解説します。 スパン・オブ・コントロール(2ピザルール)の観点 一般的に、マネージャー1人が効果的にマネジメントできる人数は 5~8名 と言われています。 また、2ピザルール(Amazon創業者のジェフ・ベゾス氏が提唱したルール)では「会議やチームは、2枚のピザでお腹いっぱいになる人数までがちょうど良い」とされています。アメリカのピザを基準にすると、2枚でおおよそ 6〜10人 が食べられる想定です。 ラクスにおいても、この考え方が推奨されており、実際の組織運営に適用されています。特にラクスでは 1on1 や 目標設定・管理 を非常に重視しているため、メンバー数が10名を超えるとチーム成果の最大化に影響が出る可能性があります。 つまり、組織が大きくなると意思決定や管理が複雑化するため、適切な規模に分割することで機動力を維持しやすくしました。 リーダーPdMへの権限委譲によるプロダクト成長への寄与 2024年度からは「楽楽精算」だけでなく、「楽楽明細」「楽楽電子保存」の2つも加わり、プロダクトマネジメントする対象が増えました。これにより、プロダクト部でマネジメントしているプロダクトの合計MRRは 250億円超 となり、相対する開発組織も 70名以上、さらにステークホルダーも 10組織以上 に一気に拡大しました。その結果、一人のマネージャーでは対応に限界が出てきました。 そのため、2024年度下期(10月)からは、リーダーPdMに「楽楽精算」のプロダクトマネジメントのリードを任せ、自分は支援に回る体制に移行しました。この結果、楽楽精算に関してはリーダーPdMが自分以上に高い製品解像度を持つようになり、同年10月にリーダーPdMからMGRへの昇格が決定しました。これを機に、組織を分割することとしました。 つまり、各プロダクトに専任のリーダーPdMを配置し、責任と裁量を持たせることで、よりスピーディーに成長へ貢献できると判断しました。 名称の明確化と統一 記載の通り、開発本部内には「開発管理課」という組織があり、「製品管理」という名称では「プロダクトマネジメント」との関連性が直感的に分かりにくい状況でした。そのため、2025年10月より名称を「プロダクトマネジメント」に変更しました。 もともとは開発本部の横断組織に所属しており、その時はすべて和名で統一されていたため違和感はありませんでした。しかし、プロダクト部に移り、さらに配下に「プロダクトデザイン課」が設置されたことで、和名と英名が混在し、違和感がより強くなっていたことも背景にあります。 第二進化の中身 分割については、製品単位で組織を分ける方針としています。また、対になる開発組織として第一開発統括部内に「楽楽精算開発部」「楽楽明細開発部」があるため、これらと連携を取りやすくする狙いもあります。 ※なお、「楽楽明細開発部」は 「楽楽明細」「楽楽電子保存」「楽楽債権管理」 のプロダクト開発を担っています。 プロダクトマネジメント1課  プロダクトマネジメント1課は 「楽楽精算」 を担当しています。役割分担は プロジェクト(PRJ/ミッション)単位 で行っており、1つのPRJは開発規模が大きく、期間も長期にわたるため、2名1チーム で担当する体制を取っています。 プロダクトマネジメント1課の特徴としては以下の4点が挙げられ、これらを踏まえたプロダクトマネジメントが求められます 「楽楽精算」は製品フェーズとして、成長期から成熟期へ移行している 「楽楽精算」は「楽楽シリーズ」の核となる製品である 「楽楽精算」はUXへの課題感があり、さらにシリーズで唯一、ネイティブアプリを有している 「楽楽精算」はシリーズの中で最も早く、AI・AIエージェントの取り組みを進めている プロダクトマネジメント2課 プロダクトマネジメント2課は 「楽楽明細」「楽楽電子保存」「楽楽債権管理」、および プロダクト部内の業務支援 を担当しています。「楽楽明細」は ARR が 100億円に迫る規模 となっており、3名(実質的には1名+0.5名+0.5名) で分担して担当しています。また、プロダクトマネジメント業務のプロセス効率化やAI活用推進 については、「業務支援」がマネージャーと共に担っています。 プロダクトマネジメント2課の特徴としては以下の4点が挙げられ、これらを踏まえたプロダクトマネジメントが求められます。 「楽楽明細」は楽楽シリーズの中でも成長著しいプロダクト(2025年3月期:対前年同期比 +45.7%) 「楽楽電子保存」は「楽楽明細」との連携が強く、製品特性上、他製品との連携ハブとなる製品である 「楽楽債権管理」は2025年7月に販売開始したばかりで、今後 PMF(プロダクト・マーケット・フィット)を目指す製品である ラクスのプロダクトマネジメント業務におけるAI活用は現状バラバラに行われており、ノウハウ共有にとどまっている 更なる進化へ 今後、更なる進化を模索していく中で、10月からのプロダクトマネジメント組織において見えている課題は以下の4点です。 プロダクトマネジメント2課は稲垣が部長と兼務でMGRを務めている デザイナー・PMMとの連携がまだ弱い 統合型ベスト・オブ・ブリード型の実現に向けたPdM体制が不十分 プロダクトマネージャーの製品貢献実感および実際の製品成長に大きな余地がある それぞれについて解説します。 プロダクトマネジメント2課は稲垣が部長と兼務でMGRを務めている プロダクトマネジメント1課では新しいMGRが誕生しましたが、2課については現在、稲垣が部長と兼務でMGRを担当しています。2課は複数のプロダクトを担当し、さらに業務支援も担うため、1課とは異なる難しさがあります。現状はリーダーPdMに一部を任せつつ伴走していますが、担う役割に対して人数が十分でない ため、新しいリーダーPdMの育成や採用が必要です。 また、今後人数を増やす場合には、スパン・オブ・コントロール(2ピザルール) の観点から、さらに組織を分割する必要が生じる可能性があります。 デザイナー・PMMとの連携がまだ弱い プロダクト部でプロダクトマネージャーが関わる場合、基本的にこのようなPdM-PMM体制、役割 としています。 両者の役割分担は明確になっていますが、今後はより高い解像度で顧客の課題に向き合い、製販一体 の動きを強化する必要があります。そのため、PdM自身がPMM領域の知識を学び、自ら情報をキャッチアップしていくことが求められます。 また、目指すべき姿をこのように定義していますが、デザイナーとの連携についても強化の余地が大きく、UXやデザインの知識に深く関与できるPdMが必要です。今後は、より多様な人材の登用 も視野に入れるべきと考えています。 統合型ベスト・オブ・ブリード型の実現に向けたPdM体制が不十分 現在、楽楽シリーズでは、これまでの 「ベスト・オブ・ブリード型」戦略 をアップデートし、「統合型ベスト・オブ・ブリード」 のプロダクトを目指しています。その実現に向けて、PMM側では 「マルチプロダクト戦略課」 を立ち上げ、戦略を前に進める取り組みを始めています。(詳細はこちら note.com へ) 一方で、PdM側ではまだ十分に呼応する体制が整っていません。今後、この戦略に対応したPdMを配置することで、より効果的に機能する可能性があると考えています。 現状では、連携の中心となるプロダクトが「楽楽精算」や「楽楽明細」であり、これらを担当するPdMがその役割を担っています。しかし、今後は 単独のドメインや個別プロダクトにとどまらず、より広い視野と先を見通す力を持つPdM が必要です。そのために、少しずつ準備を進めています。 プロダクトマネージャーの製品貢献実感および実際の製品成長に大きな余地がある 2024年度下期から、プロダクトマネージャーに対して 製品貢献実感 に関するアンケートを実施しています。※アンケート内容や詳細については「(2)製品貢献実感は、まだまだ伸びしろあり」を参照してください。 担当プロダクトは ARR規模が大きく、関わるステークホルダーも多いため、貢献実感を得にくい 側面があります。そのため、プロダクトマネージャーがしっかりと貢献実感を持てるような取り組みを進めつつ、実際の製品成長をさらに加速させること を目指していきます。 最後に 11月(大阪)、12月(東京)に開催される 「PM Conf 2025」 において、当社ラクスのPdMから2名が公募セッションに採択されました。ここでもご紹介しておきます。 大阪開催  植木遼太 (シニアPdM) 私とほぼ同期で入社し、一度退職後にラクスへ再入社していますシニアPdMとして多様な経験を積んできており、その知見を今回のセッションでお話しする予定です。 関連ブログ:ブーメラン転職ってどうなの?実体験から語る tech-blog.rakus.co.jp 東京開催  紀井 美里 (リーダーPdM) プロダクトマネジメント2課のリーダーPdMとして活躍中です新卒でラクスに入社して約10年、「楽楽精算」の開発・PdMを担当後、現在は別プロダクトを担当しています。さらにPdMの育成にも尽力しており、その取り組みを今回発表する予定です。 関連ブログ:AI時代のプロダクトマネージャー:組織と人材の変化から見る新しい価値創造 tech-blog.rakus.co.jp  / 個の限界が教えてくれたマネジメントへの道:葛藤を超えて形作る自分だけのキャリア tech-blog.rakus.co.jp 私の挑戦 私自身も昨年に続きプロポーザルを出しましたが、残念ながら今回は落選しました。まだ2回目の挑戦なので、来年もチャレンジするつもりです。ただし徐々にプロダクトマネジメントの現場から離れつつあるため、来年が最後のチャンスかもしれない と感じています。 今回応募したテーマは以下の通りで、今後どこかの機会でお話しできればと思っています。 組織戦略・キャリア・役割分担 意思決定とアライン 「2)次の進化にむけて」でも触れましたが、ラクスのプロダクト部では現在 プロダクトマネージャーを積極的に採用中 です。本noteを読んで当社プロダクト部に興味を持っていただいた デザイナーやプロダクトマネージャーの方 は、ぜひカジュアル面談からでもご応募ください。 ※プロダクトマネージャーのカジュアル面談は、基本、私(稲垣)が担当しています。 ●採用情報 プロダクトマネージャー career-recruit.rakus.co.jp デザイナー career-recruit.rakus.co.jp   └ デザインマネージャー career-recruit.rakus.co.jp /アシスタントマネージャー career-recruit.rakus.co.jp
アバター
こんにちは、 稲垣 です。 2025年4月から、プロダクトデザインの組織とプロダクトマネージャーの組織が、同じ「プロダクト部」という部門に統合されたのを受けて 「 プロダクト部はじめました 」を書きましたが、あれから半年経ちましたので、続編を書きます。 10月より副部長から部長となりました。 まずは改めて自己紹介です(キャリア変遷は コチラ へ) エンジニアを軸にこれまで20年以上製品ヅクリに携わってきました。PdMはラクスに入ってから名乗るようになり、デザイナーはファッションECサービスの時に一時的にマネージャー不在の時があり、その時に直接マネジメントをしていました。 (この時には新卒のデザイナー採用課題レビューやスカウトでデザイナーのマネージャーを採用してたりしました) 基本的なプロダクト部の紹介は「 プロダクト部はじめました 」に書きましたので、今回はスキップし、あれから6ヶ月に経って どう変化や進化をしているかについて書きます。 変化と進化 ■人が増えました ■楽楽シリーズのデザインガイドライン・システムが策定及び反映が進んでいます ■PdMとデザイナー合同でのお客様インタビュー等も順調に進められています 課題と今後取り組むべきこと ■UX改善は苦戦 ■製品貢献実感のまだまだ伸びしろあり ■デザイン・プロダクトマネジメント領域でのAI活用 最後に 変化と進化 ■人が増えました 2025年4月 25名 → 2025年10月 33名 デザイナー +6名 / PdM +2名 PdMはこれまでマネージャーは一人でしたが、新しいマネージャーが誕生し組織も2つに別れました 取り組むべきことは多いため、今後も増員はしていきます ■楽楽シリーズのデザインガイドライン・システムが策定及び反映が進んでいます 現在、楽楽シリーズの各製品においてのUIの刷新を徐々にしています( 詳細 ) 楽楽シリーズはご覧の通り、15年以上前に提供開始したプロダクトからつい、2025年7月から提供した「楽楽債権管理」まで規模含めて千差万別です。また、利用するお客様はバックオフィス部門の方が中心ものもあれば、一般の従業員の方も利用されるプロダクトもあり、これらに配慮しながらのUI刷新は非常に困難を極めます。 そのため、デザインガイドライン・システムについても既存のシステムやお客様に配慮しながらの策定で非常に難しいですが、デザイナーが中心にフロントエンドや各開発組織と連携を取り、概ね完成し、今は新しいプロダクトや既存のプロダクトのUI刷新を進めながら運用フェーズに入っています。 現在は上記のようなすみ分けをしています。 実際の改修にあたっては、一番改修規模の大きい楽楽精算を例にとると、経理の方向け、一般の申請者・承認者向け、管理者の方向けなど、利用するペルソナに応じたまとめた改修をすることでお客様に大きな不便がないような改修ステップを踏みながら進めています。 デザインガイドライン・システムによってデザインに関しての各ステークホルダーとの認識がそろいやすくなり、コミュニケーションコストが格段に減っている印象があります。また、新しいプロダクトやページ作成時のデザイン策定も効率的になっています。 デザインガイドライン・システムは完成はなく、しっかり定期的にブラッシュアップしていくことが大切だと思っています。 ●関連記事 ・ ラクスのプロダクトデザインチームとは? 〜「プロダクトデザイン3課」の役割と挑戦 ・ 【UIリニューアル】楽楽シリーズカラーパレット刷新の備忘録 ・ UIを変えたら、プロダクトもチームも、動き出した ■PdMとデザイナー合同でのお客様インタビュー等も順調に進められています 楽楽精算においてはUX改善PRJが立ち上がり、ここではほぼデザイナー主体でのお客様インタビューが進んでいます。 これまでこれもラクスのデザイナーは参画できていませんでしたが、ここは一気に2025年度から変わっています。 前回のブログでも出しましたが、中長期的には全てのプロダクトで以下のような状態をつくれるといいと思っています。 一番進んでいる「楽楽精算」でも以下のような取り組みはPdM主体で進んでいる状態なので、ここも徐々にできるようになるといいと思っています。    ・UX観点での広いディスカバリーをするためのインタビュー    ・ソリューションを検証のインタビュー(モックを作成して、しっかりあてていく) これはデザイナーのケイパビリティ的な課題もありますが、一番はリソース的な課題の原因もあるため、各プロダクトでしっかりリソース確保ができるようにする必要があると思っています。 課題と今後取り組むべきこと ここまで比較的ポジティブな振り返りをしてきましたが、ここからは進めてみたわかった課題や今後やっていくべきことについてお話します。 ■UX改善は苦戦 UIの刷新については進行していますが、UX改善については各プロダクトは時間が掛かっています。これには理由が2つあります。  1.UX課題のあるプロダクトは歴史あるプロダクトであり、この改善には多機能が故に難しさや    既存で長くご利用いただいてるお客様の体験が変わる可能性もあり慎重ならざるを得ない  2.AIを取り込んだUXとした方がよいケースが多く、ここの体験設計に時間がかかる   当社のように導入社数が多いと技術的な難易度も格段にあがる 現在、1と2を踏まえて各プロダクトでAIの搭載を見据えたロードマップを策定して、UX改善をしていく方針にしています。 AIエージェントを活用することで、現在のUXはそのままに新たな体験をツクっていくことができると考えています。 ●関連記事 ・AIエージェント開発課、始動の裏側 ・ AI開発の最前線!「RAKUS AI Meetup」開催レポート~3つの事例から見えたラクスの本気度~ ■製品貢献実感のまだまだ伸びしろあり 昨年度から「製品貢献度確認アンケート」というものをメンバーに取るようにしています。 ラクスでは事業が順調である一方で、どこまで各メンバーが事業や製品に対して貢献実感があるのかがわかりづらいため それを定点観測し、各メンバーの貢献実感を生み出したいと考えてやりだしています。 アンケート内容 はとても簡単な3つの問いです。 点数は公開しませんが、人が増えたこともあり、わずかに下がっていました。 定性情報のまとめは以下の通りです。自分の恣意的な情報が入らないようにChatGPTに定性情報の分析をしてもらった結果は以下です デザイナーとプロダクトマネージャーでは多少違うものの、こういった声が上がっていました。 今後は「製品への貢献実感をより感じること」を改善できるようにする必要があると感じています。 ■デザイン・プロダクトマネジメント領域でのAI活用 現在、ラクスでは全職種が業務において生成AIを積極的に活用しています。 プロダクト開発においてもエンジニアを中心に活用をしています。デザイナー、プロダクトマネージャーも活用していますが、まだまだ余地があると思っています。プロダクトによっては多少違いはでますが、以下ようなイメージや業務の置き換えを目標として進めていく予定です。 ここまで進めることができるとデザイナーはよりUXへ、プロダクトマネージャーはよりプロダクト戦略へ染み出すことができ、これまで以上にお客様のペインや課題理解に時間を充てることができる、開発組織全体がより『顧客志向』での開発を進められると思っています。 ●関連記事 ・ラクスの生成AI活用を加速させる、情シスAIチームの取り組み ・ ラクス、AI戦略を加速させる新ポジション「CAIO(最高AI責任者)」を新設 最後に プロダクト部は   「社内外の関係者と連携し、UX志向で製品価値を創出・提供し続けることでお客様の満足と利益を生み出す循環を担う」 を「責務」に以下の発足経緯と活動領域で業務をしています。 ! [image15]! [image16] そして、「UX志向」を元に、よりよいプロダクトの実現目指しています。 是非、本noteを読んで頂き当社ラクスのプロダクト部に興味を持っていただけたデザイナーやプロダクトマネージャーの方はカジュアル面談からでも構いませんで、ご応募頂ければと思っています。
アバター