TECH PLAY

株式会社ラクス

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

941

はじめに 請求書の明細表を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を読んで頂き当社ラクスのプロダクト部に興味を持っていただけたデザイナーやプロダクトマネージャーの方はカジュアル面談からでも構いませんで、ご応募頂ければと思っています。
2025年、AI技術は新たなフェーズに突入しました。特に、自律的にタスクを計画・実行する「AIエージェント」の登場は、ソフトウェア開発の世界に大きなインパクトを与えています。私たちラクスでも、この技術革新の波を捉え、自社サービスを進化させるべく、社内のR&D活動「技術推進プロジェクト」にて「垂直型AIエージェント」の調査・研究に取り組みました。 申し遅れました、普段は技術広報を担当しているkawa3です。今回は久々にR&D活動を通じてエンジニア業務を担当しました。楽しかったです! 本記事では、その成果発表の内容をもとに、AIエージェントの基本からSaaSへの応用可能性、そしてPoC(概念実証)を通じて見えてきたリアルな課題と解決策までを簡潔にご紹介します。 この記事を通して、垂直型AIエージェントの技術的な面白さをお伝えするとともに、ラクスがどのように技術のキャッチアップと社内へのナレッジ展開に挑戦しているか、その一端を感じていただければ幸いです。 なぜ今「垂直型AIエージェント」なのか? AIエージェントの基本:従来のAIとの違いと得意なこと 実装への道筋:自律レベルによる6つのパターン分類 SaaS業界の最前線:競合他社のAIエージェント活用事例 AIエージェントを構成する8つのコア技術モジュール ラクス製品への反映アイデア やってみて分かったこと:AIエージェント開発フレームワークを用いたPoCのリアルな手応え 本番導入を阻む「3つの壁」と、その乗り越え方 知識を組織の力に:「垂直型AIエージェント実装ナレッジベース」 まとめと今後の展望 なぜ今「垂直型AIエージェント」なのか? AIエージェントには、分野を問わず汎用的に使える「水平型」と、特定の業界や業務(ドメイン)に特化した「垂直型」が存在します。私たちが今回「垂直型」に焦点を当てた理由は、ラクスが提供する多様なSaaSサービスへのAI導入を考えた際に、より現実的で高い価値を提供できると考えたからです。 プロジェクトの目標は以下の3つに設定しました。 国内外のAIエージェント活用パターンやユースケースの調査 ラクスが提供するサービスへの適用候補機能の洗い出し PoCによる実現可能性の判断 AIエージェントの基本:従来のAIとの違いと得意なこと まず、「AIエージェント」そのものについて整理しましょう。 AIエージェント : 自律的に計画・意思決定を行いながら作業を実行するAIです。タスク遂行に必要な情報を自ら収集し、状況に応じて最適な行動を判断・実行します。開発支援AI「Devin」などがその代表例です。 従来の生成AI・AIアシスタント : ユーザーの指示に基づき、コンテンツ出力や支援を行うAIです。対話や補助的な作業が主な役割となります。 そして、垂直型AIエージェントは、その高い専門性を活かして、特に以下の3つの領域を得意としています。 専門知識が必要な、高度な分析や判断支援 ルールに基づいた定型業務の自動化と効率化 大量のデータに基づく予測と最適化 医療の画像診断支援から金融の不正利用検知、法務の契約書レビューまで、その応用範囲は多岐にわたります。 実装への道筋:自律レベルによる6つのパターン分類 一口にAIエージェントと言っても、その自律レベルは様々です。私たちは、人間がどの程度関与するかに応じて、自律レベルを弱い方から Assist(支援) 、 Copilot(副操縦士) 、 Autonomous(自律型) の3段階に分けました。 さらに、これを具体的な機能パターンとして6つに分類しました。これにより、AIエージェント導入の難易度やステップをより明確にイメージできます。 パターン分類 自律レベル ①リサーチ&要約アシスト アシスト ②ドラフティング・ジェネレーター アシスト〜コパイロット ③意思決定コパイロット コパイロット ④業務フロー・オートメーター コパイロット〜自律 ⑤自律オペレーター 自律 ⑥モニタリング&ガーディアン 自律(単機能) SaaS業界の最前線:競合他社のAIエージェント活用事例 SaaS業界では、まさに「AIエージェント元年」とも言える状況で、各社が次々と新機能をリリースしています。 本記事では割愛しますが、社内向けの成果発表では各社のAIエージェント機能の事例を紹介しました。 各社とも、具体的な業務プロセスにAIを組み込み、「完全自動運転」を目指す動きが加速していることがわかりました。 AIエージェントを構成する8つのコア技術モジュール 私たちは、AIエージェントを構成する技術要素を8つのコアモジュールとして整理しました。 成果発表では、これらのコアモジュールの役割や技術例について解説を行いました。 LLM Core(GPT/Claude/Gemini等) プロンプト・推論エンジン(タスク分解・計画・自己修正) メモリ管理(短期/長期) RAG(幻覚抑制・ドメイン知識注入) 外部ツール連携(API/MCP/関数呼出) マルチモーダル(音声/画像/動画) 安全性・ガバナンス(Moderation/Guardrails/ルールエンジン) モニタリング・分析(Langfuse/LangSmith/OTel等) ラクス製品への反映アイデア ここでは、ラクスが展開する「楽楽明細」「楽楽販売」「メールディーラー」などの9製品を対象にAIエージェント機能の候補を洗い出しました。 9製品×6種の自律レベル = 合計54機能の実装案を検討しました。 これら案のうち、「楽楽勤怠」でのシフト自動作成機能をPoCで実施することが決まりました。 やってみて分かったこと:AIエージェント開発フレームワークを用いたPoCのリアルな手応え 私たちは、AIエージェント開発フレームワークを用いて、簡単なシングルエージェントを実装し、シフト作成の自動化を試みるPoCを実施しました。 【PoCの概要】 目的 : 従業員のスキルや希望勤務時間、各時間帯に必要な人数といった要件から、最適なシフトを自動生成する。 流れ : シフト要件を登録 従業員の勤怠情報(スキル、希望シフト等)を登録 AIエージェントにシフト作成をリクエスト AIエージェントが推論やRAG、外部ツールなどを使用しシフト案を作成 生成されたシフト案と充足状況を確認 【PoCから得られた知見】 良かった点 : AIエージェント開発フレームワークを用いることで、簡単なワークフローであれば容易に実装可能であることが確認できました。 気になった点(課題) : 処理速度 : 入力データが増えるほどレスポンスが遅くなり、タイムアウトのリスクがありました。単純なシフト作成であれば、専門の最適化ツール(例:ORTools)の方が適している可能性も感じました。 マルチエージェント化の必要性 : シフトを「作成するエージェント」「評価するエージェント」「修正するエージェント」のように役割分担させるマルチエージェント構成の方が、より真価を発揮できると感じました。 セキュリティ・保守性 : 今回のPoCでは簡単な検証に留まりましたが、本番運用を見据えると重要な課題が浮き彫りとなりました。 本番導入を阻む「3つの壁」と、その乗り越え方 PoCを通じて、AIエージェントのワークフロー自動化へのポテンシャルを実感する一方で、本番導入にはいくつかの大きな壁があることも明らかになりました。 本番導入を困難にする三大要因: 性能 : 処理が遅い、精度が低い。 コスト : API利用料などが高額になり、赤字になる可能性がある。 セキュリティ : プロンプトインジェクションのような攻撃への対処や、不適切な出力内容の精査など、企業としての責任が問われる。 これらの課題は決して低くありませんが、乗り越えるための技術やノウハウも存在します。 性能改善 : モデルの最適化、RAG(Retrieval-Augmented Generation)の精度向上、マルチエージェントによる並列化など。 コスト圧縮 : 軽量モデルの活用、推論キャッシュ、ライセンスの最適化など。 セキュリティ強化 : ガードレール(不適切な入出力を防ぐ仕組み)、ヒューマン・イン・ザ・ループ(人間の確認・介入)、モデレーションAPIの活用など。 今後は、これらの技術要素の研究やナレッジを組織として蓄積していくことが、競争力の源泉になると考えています。 知識を組織の力に:「垂直型AIエージェント実装ナレッジベース」 今回のプロジェクトの最終成果物として、私たちは調査・研究で得た知見を「垂直型AIエージェント実装ナレッジベース」としてGitHub Wikiにまとめ、社内に公開しました。 これは、AIエージェントを本番実装するための、設計から運用、評価までの実務知識を集約したものです。 ナレッジベースの主な構成 1. 基本概念 : 垂直型AIエージェントの定義や価値、ユースケースを整理。 2. 開発フレームワーク : LangChainやGoogle ADKなど、主要なフレームワークを比較。 3. 観測・分析 : Langfuseなど、トレーシングやデバッグを支えるツール群を紹介。 4. フルマネージド統合AI開発プラットフォーム : Azure, AWS, GoogleのPaaSを比較。 5. 本番運用・実践ガイド : パフォーマンス、コスト、セキュリティの観点からタスクを体系化。 6. 評価 (Evaluation) : 品質保証のための指標や評価フローを整理。 7. LLMOps : プロンプト管理や継続的改善のサイクルについて紹介。 8. 実装基盤 : アーキテクチャ設計やUX、組織体制など実装を支える土台を整理。 8-1. アーキテクチャ設計 - エージェント構成パターン / フェイルオーバ / 設計チェックリスト 8-2. ナレッジ&データ運用 - ナレッジライフサイクル / データ契約 / ドリフト監視 8-3. CI/CD & プラットフォーム自動化 - 環境分離 / パイプライン / Secrets管理 8-4. 責任あるAIとコンプライアンス - 規制マッピング / バイアス評価 / 透明性 8-5. プロダクト体験とUX - 会話設計 / 失敗UX / KPI 8-6. テストと信頼性 - 負荷/カオス/DRテスト / 演習テンプレ 8-7. 外部連携パターン - ツール連携 / Function Calling設計 / 失敗緩和 8-8. 組織と運用モデル - 役割/RACI / オンボーディング / 定例運用 このようなナレッジをオープンに共有し、誰でもアクセスできる状態にすることで、各プロダクトへのAIエージェント導入を加速させ、組織全体の技術力を底上げすることが狙いです。 まとめと今後の展望 今回の技術推進プロジェクトを通じて、私たちは垂直型AIエージェントがSaaSビジネスに大きな変革をもたらすポテンシャルを秘めていることを再確認しました。定型業務の自動化から高度な意思決定支援まで、その応用範囲は無限大です。 一方で、PoCを通じて明らかになったように、性能、コスト、セキュリティといった本番導入への壁は決して低くありません。しかし、それらを乗り越えるための技術やアプローチも着実に進化しています。 私たちラクスは、今後もこのようなR&D活動を積極的に続け、最新技術を迅速にキャッチアップし、実践的なノウハウを蓄積していきます。そして、その成果を「楽楽シリーズ」をはじめとする自社サービスに反映させ、お客様に新たな価値を提供し続けることを目指します。 AIエージェントが当たり前になる未来は、もうすぐそこまで来ています。このエキサイティングな技術革新の旅に、これからもご期待ください。
こんにちは、開発推進部 SRE課のimamotoです。 SRE課ではSlackを使ってアラートを通知しているのですが、 今回はそのアラートを確認する運用を自動化してGitHub上で運用を完結させた話をしたいと思います。 これまでのアラート確認運用について 運用の流れ 解決したかった困りごと ①見落とし・対応漏れのリスク ②手順書作成コスト ③見るべきツールが多い ④横展開の必要性 改善方針:GitHub Actionsを活用したアラート確認運用の自動化 1. GitHub ActionsによるSlackメッセージの自動分類 Slack Alert Analyzerの機能 作成されたIssue例 2. 未知のアラートのRunbookを自動作成 Issueテンプレート Pull Request 3. 対応完了処理 Slack Alert Resolverの機能 他チームへの横展開:Reusable workflowとTemplate Repositoryを利用 Template Repositoryについて フォルダ構成 README 効果 おわりに これまでのアラート確認運用について まず、今回改善した運用について簡単に説明します。 運用の流れ 毎朝Slackのチャンネル(対象:7チャンネル)を目視して、アラートの見落としが無いか確認 アラート内容の分析・判断 必要に応じて対応の実施・手順書の作成 対応状況を記録(チェックボックス) 解決したかった困りごと ①見落とし・対応漏れのリスク Slackチャンネルを日次で目視確認し、「その日の運用を実施したか」のチェックボックスをチェックする運用にしていました この方法だと「どのアラートまで確認済みか」の管理まではできないため、アラートの見落としリスクがありました。 ②手順書作成コスト 新しいアラートが発生するたびに手順書を作成する際、作成のコストがありました。 また、「一時的に無視しても良いアラート」についてはあまり手順化されておらず、アラート対応の属人化につながっていました。 ③見るべきツールが多い 7つのSlackチャンネルを目視確認し、必要に応じて適切なGrafanaダッシュボードを確認し、各所に分散した手順書を参照するので、運用が面倒でした ④横展開の必要性 SRE課以外でスプレッドシートでアラート情報を管理しているという事例がありました。 何らかの仕組みで管理を楽にして横展開したいと考えていました。 改善方針:GitHub Actionsを活用したアラート確認運用の自動化 前述した課題を解決するため、GitHub Actionsを活用してSlackアラートの確認を自動化しました。 運用は以下のような手順になりました。 毎朝GitHub Actionsをスケジュール起動して、Slackメッセージの収集・分類・GitHub Issueの作成を自動化 分類されたアラートに対応したRunbookリンクがGitHub Issue上に記載されるので、それを元に運用を実施 Runbookがない場合は、GitHubのIssueテンプレートからIssueを起票するとRunbookのマークダウンファイルを自動生成 GitHub Issueに確認終了のラベルを付与すると、Slackに対応済みである旨を記録 1. GitHub ActionsによるSlackメッセージの自動分類 Slackチャンネルの目視によるアラート分類の判断やRunbookの存在確認が非常に面倒だったため、 Slack Alert Analyzer というツールを作成してGitHub Actionsから日次で実行する形にしました。 Slack Alert Analyzerの機能 Slackアラートメッセージの収集・分類・フィルタリング GitHub Issueを起票して、分類したアラートの概要や対応するRunbook、メッセージ本文等をIssueに記載 作成されたIssue例 Slack Alert Analyzerを実行すると、以下のようなIssueが起票されます。 Issue本文:その日のアラート内容のサマリを記載 過去1週間分のアラートを収集(対応済みのアラートを除く) Issueコメント:グルーピングされたアラート情報を記載 正規表現ベースでグルーピング アラート件数、発生元チャンネル、Runbookリンク等 Slackメッセージ本文もIssueコメント上から確認可能 対応が完了したアラートのチェックボックスにチェックを入れる✅️ 2. 未知のアラートのRunbookを自動作成 Slack Alert Analyzerの設定ファイルで「既知のアラート」として登録されていないメッセージの場合、GitHub Issue上にRunbookが表示されません。 既知のアラート登録用のIssueテンプレートを使用してIssueを作成すると、以下の2つの変更を行うPull Requestが作成されるようになっています。 Slack Alert Analyzerの設定ファイルに既知のアラートとして追加 Runbookとなるマークダウンファイルを作成 Issueテンプレート こんな感じのIssueテンプレートを使っています。 Issueに add-known-alert ラベルが付与されます。 Pull Request add-known-alert ラベルがついたIssue作成をトリガーにPull Requestが作成されます。 knowledge/known-alerts.yaml に既知のアラートとして情報を追記 runbooks フォルダに新しいRunbookファイルが作成される 3. 対応完了処理 一通り確認が完了したら resolved-alerts ラベルをGitHub Issueに付与すると Slack Alert Resolver というツールがGitHub Actionsで自動実行されます。 Slack Alert Resolverの機能 Issueコメント上でチェックが付いているSlackメッセージに対して「✅️」リアクションを付与 ✅️リアクションを付与すると、次回以降に確認対象として拾われなくなる Issueを自動クローズ 他チームへの横展開:Reusable workflowとTemplate Repositoryを利用 元々SREチームでのみ使っていたツールだったのですが、 他チームにツールを展開するにあたって以下の対応を実施しました。 これによって、Template Repositoryから作成したリポジトリから迅速にセットアップして利用できるようになりました。 また、Reusable workflowにすることで、バグフィックス等の迅速な横展開も可能となりました。 Reusable workflow : Slack Alert Analyzer, Slack Alert Resolverの実行用ワークフローを再利用可能な共通ワークフローとして展開 Template Repository : Reusable workflowを呼び出すワークフローや、必要な設定ファイル・フォルダが準備された雛形のリポジトリを作成 必要なセットアップ方法も、READMEに記載 Template Repositoryについて フォルダ構成 必要なワークフローやIssueテンプレート、設定ファイルが含まれています。 README こんな感じでREADMEにセットアップ方法を記載しています。 効果 定常的な運用の動線を減らして運用を楽にすると、運用者の負荷を下げるだけでなく、品質も向上しました。 特にRunbook作成へのモチベーションが上がりました。 他チームへの横展開も迅速に開始することができました。 おわりに 今回のツールはチームの為に作ったという建付けなのですが、私自身も本当に運用作業が苦手でして、、 実は自分が一番このツールの存在を喜んでいるかもしれません。 また、今回のツール作成はGitHub CopilotのAgentモードを使って行いましたが、要件の壁打ちも含めて初版は2時間以内に作成することができました。 ちょっとした自作ツールの作成ハードルが生成AIの活用によって本当に低くなっていると感じるので、 「運用つれぇ…」 と思ったら何か作ってみるのもオススメです。 (適材適所で、生成物の品質やメンテナンスについては責任を持つ前提で) それでは、ブログをご覧いただきありがとうございました!
はじめに こんにちは、 @rs_tukki です。 ラクスの開発部では、これまで社内で利用していなかった技術要素を自社の開発に適合するか検証し、ビジネス要求に対して迅速に応えられるようにそなえる 「技術推進プロジェクト」 というプロジェクトがあります。 今回、このプロジェクトで「Passkey」に関する検証を行なったので、その結果を報告させていただきます。 はじめに Passkeyとは何か 基本概念 対応環境 ブラウザ要件 OS要件 技術的な仕組み FIDO2規格の構成 1. Web Authentication (WebAuthn) 2. Client to Authenticator Protocol (CTAP) 登録フロー 認証フロー フィッシング攻撃への耐性 リプレイ攻撃への耐性 他の認証方式との比較 多要素認証(MFA)との違い FIDO1との違い 1. UAF(Universal Authentication Framework) 2. U2F(Universal 2nd Factor) Spring Bootでの実装 システム構成 実装のポイント 1. データベース設計 2. ドメイン設定の制約 3. Passkeyの削除 BtoB SaaSへの導入に向けて Passkey導入のメリット/デメリット メリット デメリット まとめ 参考リンク Passkeyとは何か 基本概念 まず、具体的な検証内容の説明に入る前に、Passkeyについて軽く説明します。 PasskeyとはFIDOアライアンスとW3Cが共同で策定した新しい認証技術です。 従来のIDとパスワードを入力する認証方式とは異なり、ユーザはデバイスのロック解除に使う方法(生体認証やPINコードなど)を使ってWebアプリにログインすることができます。 Passkeyを利用することによるメリットは2点。 ユーザ体験を損なわず2要素認証を実現できる 点と、 複数のデバイス間で認証情報を共有できる 点です。 これにより、従来の認証方式と比較して、一定のセキュリティを担保しつつ、ユーザ体験を向上させることが可能になります。 対応環境 Passkeyを利用するには、ブラウザとOSでそれぞれ異なるバージョン要件が必要になります。 バージョンは以下の通りですが、近年の環境であればそれほど意識せずともPasskeyを利用できるかと思います。 ブラウザ要件 Chrome : バージョン109以上(Windows/Mac/Android/iOS/iPadOS) Safari : バージョン16以上(Mac/iOS/iPadOS) Edge : バージョン109以上(Chromiumベース) Firefox : バージョン122以上 OS要件 Windows : 10以上 macOS : 13(Ventura)以上 iOS/iPadOS : 16以上 Android : 9以上(Google Play開発者サービス搭載端末) 技術的な仕組み FIDO2規格の構成 実は、「Passkey」という言葉を定義する場合、 広義のPasskey と 狭義のPasskey という2種類の定義方法があります。 まずは広義のPasskeyについてですが、これは以下2つの技術仕様をまとめた、 FIDO2 を基盤として構成した認証技術です。 1. Web Authentication (WebAuthn) W3Cによって標準化された、ブラウザ上で公開鍵認証方式を利用するためのJavaScript APIです。開発者が直接操作するのは主にこのAPIになります。 2. Client to Authenticator Protocol (CTAP) FIDOアライアンスによって定められた、ブラウザと認証器(デバイスの生体認証センサーやセキュリティキーなど)との間で通信を行うための規格です。WebAuthnが内部で利用しており、開発者が直接意識することは少ないです。 この「広義のPasskey」では、認証情報を認証器(PCやスマホ端末)そのものが保持していました。 そのため、たとえばPCに対してPasskeyを登録していても、同じユーザがスマホ端末からログインしたい場合、また別の端末にPasskeyを登録し直すところから始める必要があります。 一方で「狭義のPasskey」では、上記のFIDO2仕様に加え、これらの情報を クラウド上のパスワードマネージャーに保管する ことを前提としています。 これにより、複数の端末を利用していても、パスワードマネージャーを共有することで、再登録の手間なく認証を行うことができます。 本記事では、単にPasskeyと呼ぶ場合、この「狭義のPasskey」を指して説明しています。 また、狭義のPasskeyはその特性から、 MDC(Multi-Device FIDO Credential) とも呼ばれることもあります。 登録フロー Passkeyによる認証は、「登録」と「認証」の2つのフローから成り立ちます。 登録のフローは下記の通りです。 チャレンジの生成 : サーバーが一意のチャレンジ(乱数)を生成 ユーザー検証 : デバイスのスクリーンロック解除(生体認証、PIN等)でユーザーを認証 鍵ペアの生成 : デバイスがドメインに紐づいた秘密鍵と公開鍵のペアを生成 秘密鍵の保存 : パスワードマネージャー(Google Password Manager、iCloudキーチェーンなど)に暗号化して保存 公開鍵の送信 : 公開鍵をサーバーに送信し、データベースに保存 ここで重要なのは、ブラウザとサーバの間でやりとりしている情報が チャレンジ(乱数) 秘密鍵で署名したチャレンジ 公開鍵 認証器に関するメタデータ など、 機密性の低い情報に限られる ことです。 従来のパスワード認証におけるIDやパスワード、またユーザ認証に必要な生体情報やPINコードなど、機密性の高い情報は一切やり取りされていません。 これによって、Passkeyではセキュリティを担保しているというわけです。 認証フロー Passkeyを登録した後は、以下のフローでユーザの認証を行います。 チャレンジの発行 : サーバーが一意のチャレンジを生成 ユーザー検証 : デバイスのロック解除でユーザーを認証 署名の生成 : 秘密鍵でチャレンジに署名 署名の検証 : サーバーが公開鍵で署名を検証 認証の場合も、登録時のフローと同様、秘密鍵や生の認証情報など機密性の高い情報はやり取りされていません。 また、加えて以下の仕様によってセキュリティを担保しています。 フィッシング攻撃への耐性 認証器が作成した秘密鍵は、その鍵を作成したサイトのドメイン(=RPID)と紐づいています。 これにより、偽サイトでPasskeyを利用させようとしてもRPIDが異なるため署名することができません。 リプレイ攻撃への耐性 一度サーバが生成したチャレンジは、次回以降の認証に使用することができません。 そのため、認証に成功したリクエストを再現するリプレイ攻撃へも耐性を持っています。 他の認証方式との比較 ここまでPasskeyの仕様について説明してきました。 続いては、他の認証方式とPasskeyとの違いを説明していきます。 多要素認証(MFA)との違い 多要素認証とは、認証に使われる以下の3要素のうち、2種類以上の要素を利用して認証することです。 知識情報 :パスワードやPINコードなど 所有情報 :PCやスマートフォンなどの端末そのもの、もしくはクライアント証明書など 生体情報 :指紋認証や顔認証、虹彩認証など Passkeyによる認証は、認証器を利用して照合を行うため、認証器という所有情報と、ロック解除に使用する生体/知識情報を 同時に利用して認証 しています。 二要素認証というと、よくあるパターンはワンタイムパスワードや「ログインしようとしていますか?」といったプッシュ通知を利用する二段階認証ですが、Passkeyでは認証情報を2回入力する手間を省きつつ、二要素認証によってセキュリティを担保できているわけです。 また、先述の通り、認証情報そのものを送信せず、RPIDが異なると認証できないことから中間者攻撃やフィッシング攻撃に耐性がある他、 攻撃者が大量に認証を試行することでユーザのデバイスに通知が大量に送られる、いわゆるMFA疲労攻撃に対しても耐性を持っています。 FIDO1との違い 先ほど、広義のPasskeyはFIDO2仕様を基盤にしていると説明しました。 一方で、認証方式にはFIDO1という仕様もあります。これには UAF と U2F の2つの規格があります。 1. UAF(Universal Authentication Framework) 専用のセキュリティキーで生体認証を行うパスワードレス認証です。 公開鍵と秘密鍵を利用して署名を検証する点はPasskeyと同様ですが、PCそのものでは認証ができず、外部機器が必要となります。 2. U2F(Universal 2nd Factor) 上記のUAFに2段階認証の仕組みを加えたものです。 まず最初に通常のパスワードで認証を行ったあと、セキュリティキーを用いた二要素認証を行います。 記載の通り、FIDO1では専用の外部機器が必要なことに対し、PasskeyではOSとブラウザのバージョン要件を満たしていれば PCやスマホそのものを認証器として利用できるのが大きなメリットです。 Spring Bootでの実装 さて、ここからはWebアプリに実際にPasskeyによる認証を組み込む実装を見ていきます。 システム構成 今回の検証では、以下の技術スタックを使用しました。 - AlmaLinux8 - Apache 2.4.37 - Spring Boot 3.4.5 - spring-boot-starter-security - spring-security-web - webauthn4j-core:0.29.2.RELEASE - PostgreSQL 16.8 - SimpleWebAuthn - 証明書を備えたHTTPS環境 バックエンドの実装に関しては、各言語にPasskey認証を実現するためのフレームワークがあるかと思いますが、 今回は一番手軽な、Javaの spring-security-web + webauthn4j-core の組み合わせを使用します。 フロントエンドでは、 SimpleWebAuthn を利用して、バックエンドと認証器の繋ぎ込みを行います。 実装のポイント 今回の構成では、チャレンジの作成やCredentialの検証など基本的なフローはフレームワークが担ってくれます。 そのため細かい実装内容の解説は他の記事に譲りますが、ここでは特に注意すべきポイントをいくつか解説します。 1. データベース設計 先述のフロー図で、公開鍵等のサーバが保持する情報はDBに保存すると記載しました。 Credentialを作成しDBに保存する処理は自前でinterfaceを実装する必要があるため、以下のようなテーブルを作成しておきます。 Table " public.m_passkey_credential " Column | Type | Collation | Nullable | Default -------------------------------+---------+-----------+----------+---------------------------------- id | integer | | not null | generated by default as identity credential_id | bytea | | not null | user_id | text | | not null | pubkey | bytea | | | attested_credential | bytea | | | attestation_object | bytea | | | Indexes: " m_passkey_credential_pkey " PRIMARY KEY, btree (id) " m_passkey_credential_credential_id_key " UNIQUE CONSTRAINT, btree (credential_id) それぞれのカラムに格納する内容は以下の通りです。 id :DB管理用の主キー credential_id :各認証器が生成する一意のID user_id :Credentialが紐づくユーザのID pubkey :認証器が生成した公開鍵 attested_credential :メタデータを含む、認証器の登録時にクライアントが生成したデータ attestation_object :認証器の製造元情報、証明書チェーンなどを含む、認証器の信頼性を証明するデータ 2. ドメイン設定の制約 Spring Securityを用いたWebアプリでは、以下のようなSecurityFilterChainを実装することでPasskeyの仕組みを有効化することができます。 @Bean public SecurityFilterChain securityFilterChain( final HttpSecurity http) throws Exception { http.authorizeHttpRequests(authorizeHttpRequests -> { // リクエスト許可設定(ログイン用URLとwebauthnフレームワークの関連URLは認証を不要とする) authorizeHttpRequests .requestMatchers( "/login/**" , "/webauthn/**" ).permitAll() .anyRequest().authenticated(); }) // ログインフォームの設定(デフォルト) .formLogin(formLogin -> {}) // Passkeyに関する設定 .webAuthn(webauthn -> { webauthn .rpName( "Passkey" ) // Passkeyのサービス名。任意の名称でOK .rpId( "localhost" ) // サービスのドメイン名 .allowedOrigins(Set.of( // Passkeyを利用可能なURL(完全一致) "https://localhost:8443" )); }); return http.build(); } ここで重要な設定が、 rpId です。こちらは先ほど説明した通り、Passkeyを紐づけるドメイン情報です。 指定したドメイン(もしくはそのサブドメイン)以外から認証をしようとした場合、不正な操作としてエラーになります。 そして、このRpIdの指定ですが、以下のような制約があります。 単一ドメインのみ : 1つのドメインしか指定できない IPアドレス不可 : IPアドレスでは動作しない HTTPS必須 : localhost以外では正式な証明書が必要 そのため、ローカル環境以外では、 正式な証明書が発行され、DNSで関連づけられた正式なドメインでしか検証できない ということになります。 検証用にサーバを構築している方は注意が必要です。 3. Passkeyの削除 Passkeyはパスワードマネージャーとサーバ上のDBの両方でデータを管理していますが、 このうちパスワードマネージャ上に保存されたデータは、 webauthnのAPIで削除することができません。 ブラウザ上の操作で削除可能ものはサーバ側のデータのみであるため、Passkeyを完全に削除したい場合、パスワードマネージャーから手動で操作を行う必要があります。 二段階に分けて削除を行う必要があるため登録時より手間がかかります。ユーザには予め二段階の削除が必要な旨を案内しておくのが良いでしょう。 BtoB SaaSへの導入に向けて ここまでPasskeyという技術について説明しましたが、ラクスが提供しているようなBtoB SaaSの場合、Passkeyによる認証の需要はまだ少ないです。 Amazon等BtoCのサービスでは徐々に普及しつつあるものの、BtoBでは採用されているサービスはほとんどないのが現状です。 理由としては、ユーザ側がシングルサインオンやSSLクライアント認証などの認証方式を利用しているためそれらで十分というケースが挙げられます。 また、前提として一人当たり1端末(認証器)の利用を前提としているPasskeyは、例えば複数社員で一つの端末を共有している場合などでは相性が悪かったりもします。 しかし、今後ユーザーニーズが変わり、生体認証を含めた二要素認証への理解と需要が高まってきた時には、Passkeyを導入することも検討できるのではないかと思います。 Passkey導入のメリット/デメリット 最後に、Passkeyのメリットとデメリットをそれぞれまとめておきます。 メリット ユーザビリティの向上 パスワード記憶が不要 (指紋認証や顔認証であれば)ワンタッチでログイン可能 デバイス間での同期が可能 セキュリティの強化 フィッシング攻撃への耐性 総当たり攻撃への耐性 認証情報の窃取リスクの排除 運用コストの削減 パスワードリセットの対応がほぼ不要になる (適切に実装されていれば)セキュリティインシデントの軽減に繋がる デメリット 技術的ハードル フレームワークである程度カバーできるとはいえ、セキュリティリスクも考慮すると実装の難易度は高い CredentialIDの重複による乗っ取りの可能性 originやRPIDの適切な設定が欠けていることによるフィッシングの可能性 ユーザ検証の不備によるなりすましの可能性 etc... ユーザー教育 そもそも「Passkey」という認証方法に馴染みがないユーザもいる マニュアル等で適切なサポートを行わないと、かえってユーザ体験を損ねてしまう可能性がある 互換性の課題 非対応環境の存在も考慮しなければいけない 特にスマホ端末で、MDM(Mobile Device Management)を利用している場合は互換性がない可能性も まとめ ここまで、Passkeyを使った認証方式のメリットと実装方法、またBtoB SaaSでのPasskeyの需要について説明してきました。 Passkeyによる認証は、従来のID/パスワードによるログインと同等かそれ以上のユーザ体験の向上に加え、セキュリティ面でも向上が見込める新時代の認証方式です。 現状のBtoB SaaSにおいてはまだそこまで需要の高い認証方式ではありませんが、 今後、二要素認証に対する理解が深まり、需要が高まってきた時に備え、仕組みや実装について理解しておくとよいでしょう。 参考リンク FIDO Alliance W3C WebAuthn Specification webauthn4j Documentation Spring Security WebAuthn SimpleWebAuthn パスワードはおしまい! 認証はパスキーでやろう Spring Security 6.4.0-RC1 でパスキー認証を実装してみる Passkey認証の実装ミスに起因する脆弱性・セキュリティリスク
ラクスでメールディーラーのUIUXデザインを担当しているたけしまです。 AIを活用した製品づくりに向け、上流工程から参画し、日々業務に取り組んでいます。最近では、社内でも業務効率化やナレッジの蓄積、雑務の処理などにAIを活用するようになってきました。 顧客ヒアリングの情報を収集・分析する際にもAIを活用していますが、顧客の声が蓄積されるにつれ、顧客から見たAIがどんな存在で、何を期待しているのかが少しずつ見えてきました。今回は、その気づきをデザイナー視点のAIの価値と併せてご紹介したいと思います。 顧客視点 業務変革のパートナー 5つの価値的変化 6つの役割イメージ デザイナー視点 新たなUX設計の可能性 1. 製品のUX向上 2. 広く深い顧客理解 3. UI設計と業務効率化 顧客視点とデザイナー視点の比較 まとめ 最後に 顧客視点 業務変革のパートナー 顧客企業にとってAIは、単なる便利な機能ではなく「自社や仕事をどう変えてくれるか」という価値や役割として認識されています。彼らにとってのAIは、仮想的な同僚や参謀のような存在です。 これまで手間がかかっていた作業を自動化し、属人化していた業務を解消することで、企業の能力が高まり、エンドユーザーからの評価や信頼の向上が期待されます。さらに、活用次第では市場でのポジション拡大へとつながる可能性もあります。 5つの価値的変化 業務負荷の軽減  ➡ 手を動かす時間が減り、対応漏れも防げる 判断のサポート  ➡ 優先順位や次の一手が明確になる スピードと確実性 ➡ 即レスできて、内容の抜け漏れも防げる 質の安定     ➡ 誰が対応しても一定以上のクオリティが保たれる 学習と成長の支援 ➡ 過去のやり取りやナレッジから学べる 6つの役割イメージ アシスタント  : 面倒な作業を代行 ナビゲーター  : 対応の優先度や進め方を案内 品質管理者   : 誤字・不適切表現をチェック アナリスト   : 顧客傾向を分析し提案材料を提供 記録係/図書係 : 過去データを即座に検索 コーチ     : 成功事例や改善案を提示 デザイナー視点 新たなUX設計の可能性 UI/UXデザイナーにとってAIは、業務効率化とデータ活用の両面で価値を発揮し、利用者の体験全体を "気づかないレベル" で滑らかにすることが実現できる可能性を秘めた存在です。 1. 製品のUX向上 メールディーラーを例に挙げると、エンドユーザからのお問い合わせに対し、返信文案を生成できるAIが実装されています。文章の内容をチェックしたあと、本文に挿入するだけで対応の大部分が完了するという操作フローを実現。スタッフのスキルに関わらず、一定のレベルでカスタマーサポートを実現できます。 また、メールディーラーに関してのお問い合わせに対しても、お問い合わせフォームにAIを組み込むことにより、先回り型のサジェストで顧客自身が解決しやすい環境を構築するなど、業務効率化やコミュニケーションコストの軽減により、顧客体験の改善に繋げています。 2. 広く深い顧客理解 AIを活用することで、顧客との接点や行動データを集めて整理・分析が簡単になり、定性的な情報を定量化しやすい仕組みが作れます。これにより、より精度の高いニーズの抽出やペルソナ設計、ユーザージャーニー最適化が可能になります。 3. UI設計と業務効率化 UI設計や運用に必要なルール・ガイドライン、スタイル情報などをAIに学習させることで、定型的な対応や運用の一部を任せられるようになります。
 その結果、担当者はより創造的な業務に集中でき、全体の運用もスムーズに進められます。 顧客視点とデザイナー視点の比較 顧客視点とデザイナー視点の比較 まとめ AIが当たり前になった今、顧客は業務効率化や信頼性向上といった成果を重視し、デザイナーはユーザー体験の滑らかさを重視しています。 それぞれの期待や価値を理解したうえでUI/UX設計を進めることが、効果的なAI活用につながるポイントになりそうです。 今回は、顧客理解を深める中で得られた気づきを共有しました。 顧客が価値を感じられる開発を行うことで、より魅力的な製品を生み出すことができ、営業としても自信を持って提案しやすくなるはずです。 最後に ラクスでは、現在新しいデザイナーやエンジニアを積極的に募集しています!少しでも興味を持っていただけた方は、ぜひお気軽にご連絡ください。まずはカジュアルにお話ししましょう。 みなさまからのご連絡をお待ちしています。 career-recruit.rakus.co.jp career-recruit.rakus.co.jp
はじめに こんにちは!楽楽勤怠開発チームのoo_yoshiです。 勤怠管理システムは「打刻して残業時間や休暇を計算すれば終わり」と思われがちです。しかし、実際にシステムを開発・運用してみると、その裏には複雑なルールと例外が山ほど存在します。 勤務体系は企業ごとに違い、法律や就業規則も定期的に改正されます。有休の付与や消化ルール、代休や振休の扱い、残業の丸め処理など、ひとつひとつのルールが微妙に違い、組み合わせると膨大なパターンになります。 私たちのチームでは、そうした複雑さに対応するために9年前にDDD(ドメイン駆動設計)を採用し、勤怠システムをリニューアルしました。本記事では、その9年間で感じたこと、分かったことを振り返りたいと思います。 はじめに 旧勤怠管理システムで直面した課題 リニューアル時にDDDを導入して変わったこと 属人化の解消 9年経って実感したDDDの価値 まとめ 旧勤怠管理システムで直面した課題 リニューアル前の勤怠システムは、自作フレームワークをベースに作られていました。 そのため「どこにどんな処理があるのか」が一目で分からず、長く在籍しているメンバーが「知っているからなんとかなる」という属人化した仕組みになっていました。結果として「この処理の正解は◯◯さんしか知らない」という状況も珍しくありませんでした。 新しく入ったメンバーにとってもハードルは高く、普段は残業や休暇を申請していても、システムがどう計算しているかを理解できない。用語として「休暇残数」「振休」「代休」を知っていても、コードを読んでもピンと来ない。結果として教育コストは大きく膨らみました。 私自身も新卒2年目の頃から旧勤怠システムに関わらせてもらい、数えきれないほどの失敗を経験しました。。。振り返れば大きな糧になりましたが、正直に言えば「他の人にはあまりおすすめできない環境」だったと今では思います。 リニューアル時にDDDを導入して変わったこと 旧勤怠管理システムで一番困っていたのは「何をどこで処理しているのかが不明確」という点でした。 そこで新システムではDDDを採用。まず「勤怠ドメインを整理してモデルに落とし込む」ことから始めました。 要するに「現実の勤怠の仕組みを、チーム全員が同じ言葉で説明できるようにする」というアプローチです。 モデルの分け方の例 労働パターン 勤務区分(固定、フレックス、管理監督者など)や勤務カレンダーなど勤怠計算に必要な設定を定義します。 打刻 出勤・退勤・休憩といった「事実」だけを表す。ここには「遅刻」や「残業」といった解釈は入れず、純粋に「いつ押したか」だけを残す。 勤務実績 打刻で登録された値や勤怠計算で計上された、その日の「働いた結果」を表現。ユーザーに見せるのはここからだけにした。 休暇履歴 有休の付与・取得・消滅をすべて履歴として積み上げる。残日数は履歴をたどれば自動的に導けるようにして、「この値は正しいのか?」と悩む必要をなくした。 ドメインを整理してモデルに落とし込むことで、「どの処理がどこにあるのか」が明確になり、コードを追いやすくなりました。 ※DDDを導入する際に整理した代表的なモデルを、簡単ではありますが役割とドメインルールとあわせてまとめると以下のようになります。 属人化の解消 もう一つ大きな効果は、ユビキタス言語によるチームの共通理解です。 「労働パターン」「打刻」「勤務実績」「休暇履歴」といった言葉をチーム全体で使うようにしました。以前は「ロジック名」や「○○画面の処理」といった曖昧な表現をしていましたが、今では具体的なモデル名を指して会話できるようになり、仕様確認やレビューがスムーズになりました。 その結果、属人化は大きく解消されました。知識が特定のメンバーに偏るのではなく、モデルに閉じ込めたドメイン知識をチーム全体で共有できるようになったのです。 9年経って実感したDDDの価値 9年間システムを運用してきて実感したのは、DDDが「複雑な業務知識をチーム全体で維持し続ける仕組み」としてとてもよく機能しているということです。 新メンバーの立ち上がりが速くなった 「休暇履歴」「勤務実績」といった用語をベースに理解できるようになった 制度変更にも柔軟に対応できるようになった(該当モデルにルールを追加・修正するだけで済む) 旧システムのように「勤怠ドメインの理解に数カ月」かかることはなくなりました。 まとめ 勤怠管理システムは、一見シンプルに見えて実は非常に複雑です。その複雑さは、エンジニアがドメイン知識を理解するだけでも大きな負担になります。 9年前にDDDを導入してから、私たちは「休暇履歴」や「勤務実績」といったドメインを整理し、モデルに落とし込むことで属人化を解消し、新規メンバーでも理解しやすく、制度変更にも柔軟に対応できるシステムへと進化させることができました。 振り返ってみると、DDDって単なる設計手法じゃなくて、「複雑な勤怠ドメインをチームみんなで理解し続けるための心強い道具」だったなと思います。 そして9年経った今、「あのときDDDを選んでよかった」と胸を張って言えるのは本当に嬉しいことです。