有名テック企業の技術ブログを、ひとつのフィードで。
フィード
32件
はじめに カミナシでエンジニアをしている Shimmy です。今は新規プロダクト開発をしています。 0→1の開発設計では「コードベースの持続可能性」と「短期的なデリバリー速度」の両方が重要です。そのバランスを取りながら、AIの力を最大限活かせるアーキテクチャを考えてきました。 その過程で分かった設計原則というのは、AIを活用する前から変わらないものでした。 この記事では、AIの力を引き出す設計と、その設計を決定論的に守らせる仕組みついて話します。 補足: TanStack Start(フルスタックReactフレームワーク)を利用しており、フロントエンドとバックエンドが同一コードベースにあります。 AIの力を引き出す設計の3つの条件 自分のプロダクトの設計原則は次の3つです。 関心の分離: 関心事ごとにファイルをまとめる。AIのコンテキストに載せやすく、並列開発でもコンフリクトしにくい 価値の高いテスト: テストは数より質。振る舞い(Input→Output)を検証する出力値ベーステストと純粋関数の組み合わせで、モック不要でリファクタリングに強いテストが書ける 依存方向の決定: 層ごとに「何に依存してよいか」が決まっていれば、AIは迷わない。さらに静的解析で強制できる 上記の条件は、AIのために特別に取り入れた考えではありません。今まで良い設計とされていたものが、結果的にAIとの協働でさらに力を発揮するようになりました。 ここからは、各条件を深掘りして、採用した設計パターンと具体的な構成を見ていきます。 関心の分離 AIとの相性 関連ファイルが1つのディレクトリに集約されていると、AIのコンテキストに載せやすくなります。「このディレクトリを読んで、こう修正して」で済みます。散らばっていると、AIは修正箇所を探し回ってコンテキストウィンドウを無駄に消費します。 並列開発でもコンフリクトしにくいです。git worktree で複数のAIエージェントを同時に走らせても、関心事が分かれていれば触るファイルが重ならず、安全にマージできます。 Feature-Firstの構成 結合は悪ではありません。結合の強さと距離のバランスを取ることが大切です。結合が強いなら距離を短くし、距離が長いなら結合を弱くする。この考え方を Feature-First の構成に落とし込んでいます。 features/ ├── 関心事A/ │ ├── domain/ # Functional Core: 純粋関数のみ │ ├── infrastructure/ # Imperative Shell: DBアクセスなどI/O │ ├── server/ # API層: domainとinfrastructureを組み立てるエンドポイント │ ├── components/ # 複数ページで再利用するUI │ ├── hooks/ # カスタムフック │ └── index.ts # Public API ├── 関心事B/ │ ├── domain/ │ ├── infrastructure/ │ ├── server/ │ └── index.ts └── ... Feature内部 → 高凝集: 同じ関心事に関するコード(ビジネスロジック、DB操作、APIエンドポイント)が1つのディレクトリにまとまっています。統合強度は高いが、距離が短いので問題にならないです。 Feature間 → 疎結合: 各featureは index.ts を通じてPublic APIだけを公開し、domain/やinfrastructure/の内部構造は隠蔽する。外部からは index.ts 経由でのみアクセスするので、統合強度はコントラクト結合に留まる。距離が長い分、結合を最小限に抑えています。 domain、infrastructure、serverがそれぞれ1つのFeature内にあります。関心事Aに関するコードはすべてこのディレクトリに集約されているので、AIに「この機能を修正して」とfeatureを渡せば、そのディレクトリで完結します。 参考: 『ソフトウェア設計の結合バランス』(Vlad Khononov) Public API境界 各featureの index.ts は、外部に公開するものだけをexportします。 // features/xxx/index.ts // 外部から使う必要があるものだけを公開 export { calculateSomething, type Quantity } from "./domain/calculations"; export { useSaveRecord } from "./hooks/use-save-record"; export { recordsQueryOptions } from "./queries"; // 外部から使わないものは公開しない // domain/の内部ヘルパー、infrastructure/のDB操作詳細 など 実装の詳細は外部に公開していません。外部からはこの index.ts 経由でのみアクセスできます。featureの内部をどれだけリファクタリングしても、このPublic APIのシグネチャが変わらなければ外部のコードは影響を受けません。 featureを横断するケース Feature-Firstで分離したときに、最も考えるべきなのは複数のfeatureにまたがるケースについてです。横断が必要なケースは2つのパターンで対応しています。 パターン1: shared/ — 共通のビジネスロジックが必要な場合 複数のfeatureが使う計算ロジックは shared/lib/ に純粋関数として切り出します。 src/ ├── features/ │ ├── 関心事A/ │ ├── 関心事B/ └── shared/ └── lib/date.ts # 複数featureが使う共通の純粋関数 shared/ は features/ に依存しません。依存の方向は常に features/ → shared/ の一方向です。あくまで共通の純粋関数を提供するだけの層であり、shared/ が特定のfeatureの内部を知ることはありません。 パターン2: routes/ - 1つのページで複数featureが必要な場合 複数のfeatureのデータを組み合わせて1つのページを作るケースはどうするのか。ここで routes/ 層が登場します。TanStack Startの routes/ は、サーバーサイドでのデータ取得とUI描画の両方を1つのページとしてまとめる層です。各ページのコンポーネントやページ固有のロジックを持ちます。 (Next.jsの app/ ディレクトリでも同様の構成が取れるはずです。) src/ ├── features/ │ ├── 関心事A/ │ │ └── index.ts │ ├── 関心事B/ │ │ └── index.ts └── routes/ └── xxx/ └── $id/ ├── index.tsx # ページコンポーネント ├── -lib/ # このページのロジック ├── -components/ # このページのUI └── -hooks/ # このページのフック 先ほど話したように、各featureは index.ts を通じてPublic APIだけを公開し、互いに直接依存しません。 routes層でそれらを組み合わせます。ページコンポーネントが各featureからデータを取得し、組み合わせてUIを描画します。 // routes/xxx/$id/index.tsx // 各featureが公開するデータ取得関数を使って並行取得 const [recordsA, recordsB, recordsC] = await Promise.all([ fetchFeatureA(id, date), fetchFeatureB(id, date), fetchFeatureC(id), ]); // 複数featureのデータを組み合わせてUIを描画 const rows = buildRowData(recordsA, recordsB, recordsC); return <DataGrid rows={rows} ... />; 各featureは互いの存在を知りません。どのfeatureを組み合わせるかを決めるのはroutes層(ページ)の責務です。この構造により、Feature-Firstの疎結合を維持したまま、横断的なページを柔軟に構築できています。 価値の高いテスト 価値の高い単体テストとは ここでは単体テストに絞って話します。テストは数より質が重要です。 「単体テストの考え方/使い方」では価値の高い単体テストの条件として4つの柱が挙げられています。 退行(リグレッション)に対する保護 リファクタリングへの耐性 迅速なフィードバック 保守しやすさ 退行保護、リファクタリング耐性、迅速なフィードバックの3つはトレードオフの関係にあり、同時に最大化できません。ただしリファクタリング耐性は「あるかないか」の二値なので、まずこれを確保した上で残りのバランスを取ります。リファクタリング耐性がないテスト(偽陽性が多いテスト)はテストへの信頼を損ない、やがて無視されるようになるからです。 参考: 『単体テストの考え方/使い方』(Vladimir Khorikov) 出力値ベーステスト リファクタリング耐性を確保するために関数の内部実装ではなく振る舞い(Input→Output)を検証するテストを行っています。これが出力値ベーステストです。関数にInputを入れて、返ってきたOutputを検証する。テストが検証するのは「関数が内部でどう動いているか」ではなく「どんな入力に対してどんな出力を返すか」です。内部実装に依存しないので、振る舞いが変わらない限りリファクタリングしてもテストは通り続けます。 domain層の純粋関数(補足: コードは抽象/単純化しています // features/xxx/domain/calculations.ts /** 進捗率を計算する純粋関数 */ const progressRate = ( actualTotal: number, targetQuantity: number, ): ProgressRate | null => { if (targetQuantity === 0) return parseProgressRate(0); const ratio = actualTotal / targetQuantity; const percentage = roundToOneDecimal(ratio * 100); return parseProgressRate(percentage); }; この関数に対する出力値ベーステスト: describe("progressRate", () => { it("実績と目標から進捗率を返す", () => { expect(progressRate(75, 100)).toBe(75.0); }); it("100%を超える場合も正しく計算する", () => { expect(progressRate(120, 100)).toBe(120.0); }); it("目標が0のとき0を返す", () => { expect(progressRate(50, 0)).toBe(0); }); <span class="synI
こんにちは、ソフトウェアエンジニアのいちび (@itiB_S144) です。 2026年1月28日 (水) に「カミナシ Tech Night #1 - AWS re:Invent 2025 Recap Special」を開催しました!カミナシのエンジニアチームとしては初めての外部の方も参加可能なイベントの開催で、準備段階からドキドキしていましたが、当日は大盛況で無事に終えることができました。 今回のテーマは AWS re:Invent 2025 の recap (復習) イベントということで、実際にカミナシから現地参加したエンジニア 5 名と豪華なゲストの方々がそれぞれの視点でセッションレポートをお届けしました。イベントには社外からも 13 名ほど参加いただき、会場は熱気に包まれていました! 本ブログではイベントのレポートをお伝えします。 カミナシ Tech Night とは カミナシのエンジニアを中心に業務や趣味で触れた技術についてわいわい発表するイベントを企画しています。今回は #1 としており、今後も継続して開催していく予定です。 イベント概要 日時: 2026年1月28日(水) 19:00〜21:00 (開場時間:18:45~) 会場: 株式会社カミナシオフィス 5F (神田駅徒歩5分) kaminashi.connpass.com 時間 内容 登壇者 18:45 - 開場・受付 19:00 - オープニング 19:05 - AWS 上での脅威と向き合うために 西川 彰 19:15 - みんなだいすき ALB、NLB の仕組みから最新機能まで総おさらい 古屋 啓介 19:25 - なんとなく知っていた Cache を学ぶ いちび 19:35 - 休憩 19:45 - re:Invent 2025を振り返る 【ゲスト】Noritaka Sekiyama 19:55 - カミナシの re:Invent 補助事情 Tori Hara 20:00 - やっぱり EC2 / JAM の勝ち方 [検索] 【ゲスト】星 北斗 20:10 - re:Invent Lv.500 セッションの歩き方 LLM の未知の未知を知る 高井 真人 20:20 - クロージング 20:25 - 懇親会 ゲスト紹介 re:Invent の現地でカミナシメンバーと交流のあった方々にもゲストとしてご登壇いただきました。 ご登壇くださりありがとうございました🙌 星 北斗 様 (@kani_b) 株式会社LayerX 執行役員 CISO 兼 バクラク事業部 VPoE 2024年1月に株式会社 LayerX に入社。コーポレートエンジニアリング室 室長、バクラク事業部 PlatformEngineering部 SRE グループマネージャーを務め、2025年10月より現職。クラウドとセキュリティと料理が好き。 Noritaka Sekiyama 様 (@moomindani) 通りすがりのData Professional。 セッションレポート AWS 上での脅威と向き合うために - カミナシ 西川 彰 (@nishikawaakira) トップバッターは西川さん。脅威モデリングについてのお話でした。 リスクマネジメントで用いられる脅威モデリングについてのアプローチ手法の変化について紹介してくださいました。 昨今は LLM の進歩もあり開発者がより脅威モデリングをしやすくなっています。LLM フレンドリーなドキュメントを書くことでより実りある脅威モデリングやリスク分析ができるものの、開発者がレビューするのも難しく LLM の扱い方を検討する必要が今後来そうと考えているとのことでした。 みんなだいすき ALB、NLB の仕組みから最新機能まで総おさらい - カミナシ 古屋 啓介 (@saramune) 古屋さんは「ALB/NLB の内部実装から最新機能まで」について学んだセッションを紹介してくださいました。ALB がどのように AWS の裏側で実現されているか、スケールするかなどを解説してくださいました。 ALB に新たに追加された新規の機能として「Target Optimizer」の紹介もあり、Target Optimizer を使うことで ALB がターゲットに流れる通信の同時実行数を制限することができるとのことです。 以下に古屋さんが Target Optimizer について書いたブログがあるので良ければ参考にしてみてください! dev.to なんとなく知っていたCacheを学ぶ - カミナシ いちび (@itiB_S144) 私自身も LT をさせていただきました。私の発表は「Cache me if you can, Valkey edition」という Valkey というメモリベースのデータベースについてのワークショップセッションをレポートしました。 自分のイメージとして持っているキャッシュは「画像を CloudFront でキャッシュすると読み込みが早い」「ログイン状態やカートを Redis に保存する」程度でしたがこのセッションでは書き込み時にキャッシュを作るWrite through や Write Behind などの実装パターンを知ることができました。 特にセッションの中で面白かったのは「生成 AI の結果をキャッシュする」という発想でした。 与えられたプロンプトをハッシュ化してキャッシュにヒットすれば返す、なければベクトル類似度検索で近いプロンプトの解答をキャッシュから返す。それでもヒットしなければようやく生成 AI に問い合わせるというキャッシュの活用テクを教わりました。 re:Invent を振り返る - ゲスト Noritaka Sekiyama 様 (@moomindani) ゲストの moomindani さんのセッションです。 re:Invent 2025 は AI Agent 祭りだったと一言でまとめつつ、そんなかでも moomindani さんの注目したアップデートをいくつかピックアップして紹介してくださいました。 Iceberg v3 のスペックが出てきて、いろんなサービスでサポートされた S3 Tables が進化して、テーブルレプリケーションなどができるようになりより便利に Iceberg テーブルを扱えるようになった SageMaker Unified Studio がかなり変わって、簡単に始められるようになった S3 Tables は 2024 の re:Invent で登場して以来、大幅にアップデートされていることをまとめて知れて非常にありがたかったです!現地で Iceberg のセッションにいくつか参加しましたが、どれも大盛況で盛り上がりを感じたので要注目のテクノロジーだと感じています。 カミナシの re:Invent 補助事情 - カミナシ 原トリ (@toricls) カミナシの CTO であるトリさんからはカミナシの re:Invent 参加補助制度について紹介していただきました。 カミナシでは「全額補助(普通の出張)、一部補助、業務時間扱い、有給を使って勝手に行く」など柔軟に会社から受けられる補助を選択でき、それぞれの補助ごとに出すべきアウトプットなどの成果が決められています。 柔軟に自分の re:Invent にかける思いに合わせて補助を決められるいい制度だなぁと感じています やっぱり EC2 / JAM の勝ち方 [検索] - ゲスト 星 北斗 様 (@kani_b) 2人目のゲストセッションでは LayerX の星さんに登壇していただきました。 星さんは世の中はサーバレスに染まっているがこだわりを持って EC2 のセッションを受けてきたとのこと。 昨今の EC2 はインスタンスの種類が豊富で様々な選択肢があります。適切に選ぶことでコスト効率がよくなることや Flex インスタンスなどの紹介をしていただきました。 また今回の re:Invent で AWS JAM(競技形式の技術演習)で優勝したとのことで星さん流、勝ち方のポイントを教えてくださり、さらに優勝景品を紹介していただけました。 教えていただいた勝ち方のポイントは私も勝ちたいのでここには書きません^^ re:Invent Lv.500 セッションの歩き方 LLM の未知の未知を知る - カミナシ 高井 真人 (@manaty0226) 最後はカミナシエンジニアのまなてぃさんの発表です。 re:Invent や re:Inforce, AWS Summit ではセッションごとに難易度別に Level がつけられています。Level 500 のセッションに参加しどんな紹介があったか、どんな雰囲気だったかを紹介していただけました。 詳細についてはブログでも記載してくださっているのでそちらを御覧ください! kaminashi-developer.hatenablog.jp 懇親会の様子 発表が終わったあとは懇親会として re:Invent の話しで盛り上がりつつ、技術の話しで盛り上がりました。 会場の案内をするごーとん(弊社マスコット) まとめ カミナシ Tech Night #1 大成功だったと思います!ご参加いただけた皆様、ありがとうございます。 初開催で緊張しましたが、登壇者の皆さんの熱い発表と参加者の皆さんの温かい雰囲気のおかげで、とても良いイベントになりました。re:Invent に行った人も行けなかった人も、最新のAWSの動向をキャッチアップできる良い機会になったのではないでしょうか。 また Tech Night を開催したいと思いますのでぜひお楽しみに! 来年の re:Invent 2026 に向けて、すでにカミナシメンバーは何人か航空券を予約済みとのこと。Slack には「re:Invent 2026」チャンネルが爆誕しています。 re:Invent 2026 でお会いしましょう!