TECH PLAY

NestJS

イベント

該当するコンテンツが見つかりませんでした

マガジン

該当するコンテンツが見つかりませんでした

技術ブログ

プログラミング言語を選ぶとき、開発効率や学習コスト、エコシステムの充実度など、考慮すべき要素は多岐にわたります。OSS パッケージを標的にしたサプライチェーン攻撃の増加や脆弱性に対するゼロデイ攻撃の発生といった状況を踏まえると、「アプリケーションが依存するライブラリをどう管理するか」も技術選定の重要な軸となっています。 私の所属する Control Plane 部の認証認可グループでは、2025年から、 Go の利用を本格化しました。技術選定時に挙げられていたメリットの一つが、まさに依存管理にあります。 本記事では、私たちが Go を選んだ背景と、1年間実際に開発してみて分かったことを振り返ります。 なぜ Go を選んだか 対象システムの特性 キャディの主流言語: TypeScript Go の特徴 1年間やってみてどうだったか 良かった点 メンテナンスコストの低さ AIコーディングとの相性 苦労した点 ライブラリに頼らないことのトレードオフ Go の慣習に慣れるまでのコスト 期待と現実のギャップ 採用した技術スタック まとめ なぜ Go を選んだか 対象システムの特性 キャディでは、製造業AIデータプラットフォームCADDi の基盤として「Control Plane」と呼ばれるシステム群を開発しています。Control Plane は、テナント管理や認証認可など、アプリケーションの機能から独立した管理層を担うシステムです。詳しくは こちらの記事 で紹介しています。 開発言語を選ぶにあたって重要だったのは、Control Plane が持つ特性です。Control Plane は、1つの大きなサービスではなく、認証ゲートウェイ、トークン発行、テナント管理、認可といった、それぞれが明確な責務を持つ小さなサービスの集合体です。各サービスはシンプルな機能を提供する一方で、プラットフォーム基盤としての信頼性が求められます。 つまり、「小さなサービスを多数、手堅く作れること」が言語選定において重要な要件でした。 キャディの主流言語: TypeScript キャディのバックエンドでは TypeScript が主流です。TypeScript の開発エコシステムの充実度は群を抜いています。 また、フロントエンドとバックエンドを同じ言語で統一できるのも大きなメリットです。 一方で、依存管理の観点では、ライブラリの数が増えがちで、依存管理のコストが増大します。 Go の特徴 Go は Web API の構築に向いた言語です。標準ライブラリもサードパーティのライブラリもシンプルなものが多く、必要なパーツを組み合わせて開発するようなスタイルを取りやすいです。 こうした特性が、小さなサービスを数多く開発・運用する Control Plane とよくマッチすると判断しました。 1年間やってみてどうだったか 良かった点 メンテナンスコストの低さ Go を採用して最も良かったと感じているのは、メンテナンスコストの低さです。 Control Plane のアプリケーションは、一度作った後は数ヶ月単位で改修が入らないことも珍しくありません。そのような場合でも、セキュリティアップデートは定期的に適用する必要があります。このような作業は1つ1つは小さくても、積み重なると大きな負担になります。 Control Plane には、Go採用以前から開発・運用されている TypeScript(NestJS)アプリケーションがありますが、これと比較して Go アプリケーションはセキュリティアップデートが必要になる頻度が低いと感じています(およそ1/5程度)。 AIコーディングとの相性 Claude Code や Devin を用いたAIコーディングはキャディ社内でも主流となっていますが、構文がシンプルで書き手による差異が生じづらい Go は、AIが読み書きしやすいという点でもメリットがあります。また、コードフォーマッター( go fmt )やテストランナー( go test )が標準のツールチェインに組み込まれていて、かつ、高速に動作するという点も Go の強みです。 苦労した点 ライブラリに頼らないことのトレードオフ Go では依存ライブラリを少なく保って開発することができます。これは裏を返せば、基本的な処理を自前で実装する必要があるということです。例えば、以下のコードではサーバのグレースフルシャットダウンを行なっています。 ctx, stop := signal.NotifyContext(ctx, os.Interrupt, syscall.SIGTERM) defer stop() go func () { // e は Echo インスタンス if err := e.Start( ":" + c.Port); err != nil && !errors.Is(err, http.ErrServerClosed) { slog.Error(fmt.Sprintf( "error occurred when starting the server: %v" , err)) } }() ... <-ctx.Done() ctx, cancel := context.WithTimeout(ctx, 10 *time.Second) defer cancel() if err := e.Shutdown(ctx); err != nil { slog.Error(fmt.Sprintf( "error occurred when shutting down the server: %v" , err)) } このような、他の言語であればフレームワークが担ってくれるような処理も自分たちで書く必要がありました *1 。 依存の少なさと自前実装の手間は、トレードオフの関係にあります。私たちはこのトレードオフを意図的に受け入れました。長期的な運用コストの低さのほうが、初期の実装コストより重要だと判断したからです。 Go の慣習に慣れるまでのコスト チームメンバーの多くは Go での開発経験がそれほど多くありませんでした。Go 特有の慣習やイディオム ── たとえばエラーハンドリングの作法や、パッケージ構成の考え方 ── に慣れるまでには時間がかかりました。言語仕様の学習コストは低くても、「Go らしいコード」がわかるようになるまでには別のハードルがあります。 期待と現実のギャップ Go の採用にあたっては、goroutine による並行処理のしやすさにも期待していました。しかし、現時点では並行処理を積極的に活用する場面はまだありません。現在の Control Plane のサービス群は、典型的なリクエスト/レスポンス型の API が中心であり、goroutine の恩恵を実感する局面がまだ訪れていないのが実情です。 今後、バッチ処理や非同期ワーカーのようなワークロードが増えてきた際に、この特性が活きてくると考えています。 採用した技術スタック Goコミュニティにおいて実績のある技術スタックの中で、薄めのものを選定しました。 通信: Connect フレームワーク: Echo ※アプリケーションによってはフレームワーク無しの場合も ORM: Bun JWT: lestrrat-go/jwx いずれも優れたライブラリですが、特に Connect は素の gRPC に比べてデバッグしやすく、重宝しています。 まとめ Go は万能な言語ではありません。例えば、Go の特徴の一つである明示的なエラー処理は、コードの冗長さと表裏一体です。しかし、小さなサービスを数多く開発・運用する Control Plane においては、Go のシンプルさが強みになりました。 技術選定は常に文脈次第であり、私たちの経験がそのまま他の組織に当てはまるとは限りません。それでも、「Control Planeを Go で作る」という選択は、私たちにとって正しかったと考えています。 今後も Go を活用しながら Control Plane を拡充し、CADDi のマルチテナントプラットフォームをより堅牢なものにしていきます。 Go を使った Control Plane の開発に興味がある方は、ぜひ以下のページもご覧ください。 caddi.tech tech.caddi.com *1 : このサンプルコードは Echo v4 です。Echo v5 ではフレームワークに グレースフルシャットダウン機能 が搭載されています。
はじめに # 本記事では、GitHub Copilotのエージェント(Agents)およびインストラクション(Instructions)の設定方法について説明します。 Agents(エージェント)とは 特定のタスクや分野に特化した専門家としてCopilotをカスタマイズする機能です。 たとえば、バックエンド開発用、フロントエンド開発用など、異なる専門性を持つ複数のエージェントを定義し、状況に応じて使い分けることができます。 Issueにアサインしたり、VS Code上で選択して利用します。 Instructions(インストラクション)とは Copilotに対する共通のルールや制約を定義する機能です。 コーディング規約、命名規則、プロジェクト固有のベストプラクティスなどを記載し、すべての開発者が一貫したコード生成の支援を受けられるようにします。 エージェントと併用され、VS CodeでのコーディングやPull Requestのレビューなど、あらゆる場面で適用されます。 適用順序 # 以下の順序でルールが適用されます。競合するルールがある場合、数字の小さいルールが優先されます。 選択したエージェント(例: agents/backend.agent.md ) マッチするインストラクション(例: instructions/typescript.instructions.md ← applyToパターンに一致) 全体のインストラクション( copilot-instructions.md ) ファイルの配置 # GitHub Copilotが認識できるよう、下記のように配置します。 .github/ agents/ xxx.agent.md : 特定の分野(ロールなど)に合わせて定義するエージェントファイル(e.g. backend, frontend, test) copilot-instructions.md : 全体に適用されるルールや制約を定義するファイル instructions/ xxx.instructions.md : 特定の分野(テクノロジーなど)に合わせて定義するファイル。(e.g. typescript, python, react)※サブフォルダーで分類したくなりますが、フォルダー分けすると読み込まれません。 --> Caution AGENTS.mdについて .github/AGENTS.md (ディレクトリ直下)は GitHub CLI用 のファイルです。 VS Codeでは読み込まれませんので注意してください。 VS Codeでは agents/ ディレクトリ内の *.agent.md ファイルのみが有効です。 --> Information ワークスペースでの配置 VS Codeでマルチリポジトリ(複数のリポジトリを同時に開いて作業)する場合、 設定ファイルは ワークスペースのルートディレクトリ の .github/ に配置する必要があります。 各リポジトリに個別の設定を使いたい場合は、リポジトリごとに別のVS Codeウィンドウで開いてください。 .github/agents/sample.agent.md : ワークスペースルートに配置すると選択できます repo-A/.github/agents/sample.agent.md : 各リポジトリ配下のエージェントは読み込まれません repo-B/.github/agents/sample.agent.md ヘッダー部の用途 # 定義ファイルのヘッダー部に設定できるプロパティの一部を紹介します。 エージェント --- name: Backend Agents(TypeScript) description: This custom agent implements backend features using TypeScript. model: GPT-5.2 --- ※エージェント選択画面(VS Code) プロパティ 設定時 未設定時 name エージェント名として使用 拡張子を除いたファイル名をエージェント名として使用 description エージェントの説明として使用 空欄 model 使用するAIモデルを指定 デフォルトモデル インストラクション --- applyTo: "src/**/*.ts" # e.g. src配下のtsファイルを対象 --- プロパティ 設定時 未設定時 applyTo 指示を適用するファイルのパターンを指定(globパターン) すべてのファイルに適用 --> Information applyToの指定例 **/*.ts - すべてのTypeScriptファイル src/** - srcディレクトリ配下のすべてのファイル **/*.{js,ts} - JavaScriptとTypeScriptファイル 定義例 # エージェントおよびインストラクションの定義例を以下に示します。 これらを組み合わせることで、プロジェクトやタスクに最適化されたCopilotの動作を実現できます。 エージェント:バックエンド開発者 # .github/agents/backend-specialist.agent.md --- name: Backend Developer Agent description: NestJSを使用したバックエンド開発の専門家 --- # 役割 あなたはNestJSとTypeScriptを使用したバックエンド開発の専門家です。 # 技術スタック - **フレームワーク**: NestJS 11.x - **言語**: TypeScript 5.x - **データベース**: PostgreSQL - **ORM**: TypeORM - **テスト**: Jest # コーディング規約 - ヘキサゴナルアーキテクチャを遵守してください - DTOには必ずバリデーションデコレータを付与してください - 例外処理は適切なHTTPステータスコードを返すカスタム例外を使用してください # テスト方針 - 単体テストはすべてのServiceクラスに対して作成してください - テストカバレッジは80%以上を目標としてください 全体インストラクション:プロジェクト共通規約 # .github/copilot-instructions.md # コーディング規約 ## 共通ルール - **言語**: 日本語でコメントとドキュメントを記載してください - **命名規則**: - クラス名: PascalCase - 関数名・変数名: camelCase - 定数: UPPER_SNAKE_CASE - **インデント**: スペース2文字 - **文字列**: シングルクォートを使用 ## 禁止事項 - `any`型の使用は原則禁止(型定義を適切に行うこと) - `console.log`のコミットは禁止(ロガーを使用すること) - 機密情報のハードコードは厳禁 ## セキュリティ - 外部入力は必ずバリデーションを行うこと - SQLインジェクション対策を実施すること - 認証・認可が必要なエンドポイントにはガードを設定すること 分野別インストラクション:TypeScript専用ルール # .github/instructions/typescript.instructions.md --- applyTo: "**/*.ts" --- # TypeScript固有のルール ## 命名規則 - ファイル名: kebab-case ## 型定義 - 明示的な型注釈を優先してください - Utility Typesを活用してください(`Partial`, `Pick`, `Omit`など) - 複雑な型は`type`エイリアスで定義してください ```typescript // Good type UserProfile = { id: string; name: string; email: string; }; type UserProfileUpdate = Partial<Pick<UserProfile, 'name' | 'email'>>; // Bad const updateUser = (data: any) => { ... }; ``` ## 非同期処理 - `async/await`を使用してください(Promiseチェーンは避ける) - エラーハンドリングは`try-catch`で行ってください ## インポート順序 1. 外部ライブラリ 2. 内部モジュール(絶対パス) 3. 相対パス ```typescript // 外部ライブラリ import { Injectable } from '@nestjs/common'; import { Repository } from 'typeorm'; // 内部モジュール import { UserEntity } from '@/entities/user.entity'; import { CreateUserDto } from '@/dto/create-user.dto'; // 相対パス import { UserService } from './user.service'; ``` 運用上の注意事項 # VS Codeでのキャッシュ管理 # エージェントやインストラクションのファイルを変更した場合、初回ロードした内容がキャッシュされます。 変更を反映するには、以下のいずれかの操作が必要です。 チャットで変更したファイルを明記して再読み込みを促す(例: sample.agent.mdを変更したので再読み込みしてください ) 新しいチャットを開始する VS Codeを再起動する GitHubでのファイルサイズ制限 # エージェントファイルの文字数が30,000文字(バイト数ではなく、ヘッダー部は含まない)を超えると選択できなくなります。 適切な粒度でファイルを分割してください。 GitHub IssueでCopilotをアサイン後に表示されるダイアログ
本記事は、Luup Advent Calendar 2025 の7日目の記事になります。 はじめに こんにちは、Software部でiOSエンジニアをしている大坪(つぼやん)です! 今回は、部内で実施しているLT(ライトニングトーク)会についてお話しします。 技術共有の場としてLT会を開催されている会社さんも多いかと思いますが、LuupのSoftware部ではどのような目的や運用で行っているのか、その裏側をご紹介します! LT会実施までの背景 現在、Software部には20名を超えるメンバーが在籍しています。 このメンバーの役割は、LUUPのユーザーが利用するアプリやそのバック

動画

該当するコンテンツが見つかりませんでした

書籍

該当するコンテンツが見つかりませんでした