angular-architect について
Angular Architect は、大規模な Angular アプリを設計・保守するチーム向けの開発スキルです。モダンなアーキテクチャ、状態管理、移行、パフォーマンスの実践を扱います。
主な機能
- 01大規模 Angular アーキテクチャ
- 02Signals と Standalone Components
- 03NgRx による状態管理
- 04RxJS のパターンと指針
- 05パフォーマンス最適化
活用シーン
- 01Nx モノレポやマイクロフロントエンドの計画
- 02NgModules から Standalone Components への移行
- 03Angular 機能の状態管理方式の選定
- 04パフォーマンスと変更検知の確認
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ 404kidwiz/ claude-supercode-skills --skill angular-architectインストール後、Claude Code で/angular-architectを入力して読み込まれたか確認します。
詳細
Angular アーキテクト
目的
Angular 16 以降の機能(Signals、Standalone Components)、RxJS のリアクティブプログラミング、NgRx による大規模な状態管理を専門とする、エンタープライズ Angular 開発の専門知識を提供します。パフォーマンスの最適化と最新のアーキテクチャパターンを取り入れた、大規模な Angular アプリケーションを設計します。
使用する場面
- 大規模な Angular アプリケーション(モノレポ、マイクロフロントエンド)のアーキテクチャ設計
- きめ細かなリアクティビティを実現する Signals の実装(Angular 16 以降)
- レガシーなモジュール(NgModule)から Standalone Components への移行
- NgRx または NgRx Signal Store を使用した複雑な状態管理の設計
- パフォーマンスの最適化(Zoneless、OnPush、Hydration)
- Nx または Turborepo を使用したエンタープライズ向け CI/CD のセットアップ
2. 意思決定フレームワーク
状態管理戦略
What is the complexity level?
│
├─ **Local State (Component)**
│ ├─ Simple? → **Signals (`signal`, `computed`)**
│ └─ Complex streams? → **RxJS (`BehaviorSubject`)**
│
├─ **Global Shared State**
│ ├─ Lightweight? → **NgRx Signal Store** (Modern, functional)
│ ├─ Enterprise/Complex? → **NgRx Store (Redux)** (Strict actions/reducers)
│ └─ Entity Collections? → **NgRx Entity**
│
└─ **Server State**
└─ Caching/Deduplication? → **TanStack Query (Angular)** or **RxJS + Cache Operator**
アーキテクチャパターン
| パターン | 使用例 | メリット | デメリット |
|---|---|---|---|
| Standalone | 15 以降のデフォルト | ボイラープレートが少なく、ツリーシェイキング可能 | レガシー開発者には学習が必要 |
| Nx Monorepo | 複数アプリを持つエンタープライズ | 共有ライブラリ、変更のあった箇所のみビルド | ツールの複雑さ |
| Micro-Frontends | チームやスタックが異なる場合 | 独立したデプロイ | 実行時の複雑さ、依存関係の共有による問題 |
| Zoneless | 高パフォーマンス | Zone.js のオーバーヘッドなし | 明示的な Change Detection が必要 |
要注意事項 → performance-engineer にエスカレーションしてください:
- 「ExpressionChangedAfterItHasBeenCheckedError」が頻繁に発生する
- 初回読み込み時のバンドルサイズが 5MB を超える
- Change Detection サイクルが常時実行される(Zone.js の過剰な動作)
- RxJS サブスクリプションでメモリーリークが発生する(
takeUntilDestroyedの指定漏れ)
ワークフロー 2:NgRx Signal Store(最新の状態管理)
目標: Redux よりも少ないボイラープレートで機能の状態を管理します。
手順:
-
ストアの定義
import { signalStore, withState, withMethods, patchState } from '@ngrx/signals'; export const UserStore = signalStore( { providedIn: 'root' }, withState({ users: [], loading: false, query: '' }), withMethods((store) => ({ setQuery(query: string) { patchState(store, { query }); }, async loadUsers() { patchState(store, { loading: true }); const users = await fetchUsers(store.query()); patchState(store, { users, loading: false }); } })) ); -
コンポーネントでの使用
export class UserListComponent { readonly store = inject(UserStore); constructor() { // クエリの変更時に自動読み込み(Effect) effect(() => { this.store.loadUsers(); }); } }
ワークフロー 4:Zoneless アプリケーション(Angular 18 以降)
目標: Zone.js を削除し、バンドルサイズを縮小してデバッグを改善します。
手順:
-
ブートストラップ設定
// main.ts bootstrapApplication(AppComponent, { providers: [ provideExperimentalZonelessChangeDetection() ] }); -
状態管理(Signals のみ)
ApplicationRef.tick()を手動で使用しないでください。- すべての状態に
signal()を使用します。 - イベントによって Change Detection が自動的に実行されます。
-
統合
- RxJS:
AsyncPipe(引き続き使用可能)またはtoSignalを使用します。 - タイマー:
setIntervalは CD を自動的に実行しません。タイマー内でsignalを更新してください。
- RxJS:
主な機能
エンタープライズ Angular アーキテクチャ
- 大規模な Angular アプリケーションのアーキテクチャを設計します
- モジュール型の設計パターン(Nx モノレポ、マイクロフロントエンド)を実装します
- チーム向けのコーディング規約とベストプラクティスを確立します
- 拡張性の高いフォルダー構成とモジュール構成を作成します
最新の Angular 開発
- きめ細かなリアクティビティを実現する Signals を実装します(Angular 16 以降)
- レガシーな NgModule ベースのコードを Standalone Components に移行します
- OnPush と Zoneless の戦略で Change Detection を最適化します
- Angular の新機能(遅延可能ビュー、Hydration)を活用します
状態管理
- エンタープライズアプリケーション向けの NgRx Store アーキテクチャを設計します
- 軽量な状態管理のために NgRx Signal Store を実装します
- 複雑な要件に対応するカスタムの状態管理ソリューションを作成します
- TanStack Query または RxJS のパターンを使用して、サーバー状態を統合します
パフォーマンスエンジニアリング
- ツリーシェイキングと遅延読み込みによってバンドルサイズを最適化します
- コード分割と差分読み込みを実装します
- パフォーマンス監視とメトリクス収集を構築します
- 大規模な Angular アプリケーション向けの最適化戦略を開発します
5. アンチパターンと注意点
❌ アンチパターン 1:ネストされたサブスクリプション(「コールバック地獄」)
どのような状態か:
this.route.params.subscribe(params => {
this.service.getData(params.id).subscribe(data => {
this.data = data; // Manual assignment
});
});
問題点:
- (パラメーターが頻繁に変わる場合)競合状態が発生します。
- (サブスクリプションを解除しない場合)メモリーリークが発生します。
正しい方法:
- SwitchMap:
this.data$ = this.route.params.pipe( switchMap(params => this.service.getData(params.id)) ); - テンプレートでは
AsyncPipeまたはtoSignalを使用します。
❌ アンチパターン 2:テンプレート内のロジック
どのような状態か:
<div *ngIf="user.roles.includes('ADMIN') && user.active && !isLoading">
問題点:
- テストが困難です。
- 変更検知のサイクルごとに実行されます。
正しい方法:
- Computed Signal / Getter:
isAdmin = computed(() => this.user().roles.includes('ADMIN'));<div *ngIf="isAdmin()">
❌ アンチパターン 3:共有モジュールの肥大化
どのような状態か:
- あらゆるもの(Material、Utils、Components)をインポートする巨大な
SharedModuleが 1 つあります。
問題点:
- ツリーシェイキングが妨げられます。
- 初期バンドルサイズが増加します。
正しい方法:
- スタンドアロンコンポーネント: コンポーネントの
imports: []配列には、必要なものだけをインポートします。
7. 品質チェックリスト
アーキテクチャ:
- スタンドアロン: 新機能では
NgModulesを使用しません。 - 遅延読み込み: すべての機能ルートを遅延読み込みにします(
loadComponent)。 - 状態: ローカル状態には Signals、共有状態には Store を使用します。
パフォーマンス:
- 変更検知: すべての箇所で
OnPushを有効にします。 - バンドル: 初期バンドルは 200KB 未満です。
- 遅延: ファーストビューより下にある重いコンポーネントに
@deferを使用します。
コード品質:
- 厳格モード: tsconfig で
strict: trueを設定します。 - サブスクリプションなし:
.subscribe()の代わりにAsyncPipeまたはtoSignalを使用します。 - セキュリティ: 入力を検証し、サニタイズせずに
innerHTMLを使用しません。
例
例 1:エンタープライズ E コマースプラットフォームのアーキテクチャ
シナリオ: 小売企業が、同時に 10 万人以上のユーザーに対応し、カタログ、カート、チェックアウト、ユーザー管理を個別のモジュールに分けた大規模な E コマースプラットフォームの設計を必要としています。
アーキテクチャ上の決定事項:
- Nx モノレポ構造:アプリ(storefront、admin、api)と共有ライブラリ(ui、utilities、data-access)に分割します
- 状態管理:カート/ユーザー状態には NgRx Signal Store、サーバー状態には TanStack Query を使用します
- パフォーマンス戦略:ファーストビューより下のコンテンツには遅延可能なビューを使用し、すべての箇所で OnPush を有効にし、機能モジュールを遅延読み込みします
- マイクロフロントエンド対応:将来的に分離できるよう、Module Federation を設定します
主な実装の詳細:
- Signals を使用し、計算済みの合計値と永続化された状態を備えたカートサービス
- TanStack Query のキャッシュと楽観的更新を使用した商品カタログ
- 複数ステップのウィザードとフォーム検証を備えたチェックアウトフロー
- 独立したビルドおよびデプロイパイプラインを備えた管理パネル
例 2:従来の NgModule からスタンドアロンへの移行
シナリオ: 金融サービス企業が、NgModules を使用する 5 年前の Angular アプリケーションを Angular 18 のスタンドアロンコンポーネントでモダナイズしようとしています。
移行戦略:
- 段階的なアプローチ:アプリケーションを停止させることなく、一度に 1 つの機能モジュールを移行します
- 依存関係の分析:
ng-dompurifyを使用して、すべてのモジュール依存関係を調べます - コンポーネントの変換:適切なインポートを設定して、コンポーネントをスタンドアロンに変換します
- サービスのリファクタリング:モジュールレベルの providedIn を削除し、ルートまたは機能レベルでインジェクションします
移行結果:
- ツリーシェイキングにより、初期バンドルサイズを 40% 削減
- NgModule のボイラープレートコードを 200 行以上削除
- 変更検出のパフォーマンスを 60% 向上
- 新しい Angular 機能(defer ブロック、ゾーンレス)の導入が可能に
例 3:Signals を使用したリアルタイムダッシュボード
シナリオ: SaaS 企業が、Zone.js のオーバーヘッドなしに細かなリアクティビティを実現し、1 秒ごとに更新されるリアルタイムメトリクスを表示する監視ダッシュボードを必要としています。
実装アプローチ:
- ゾーンレスブートストラップ:実験的なゾーンレス変更検出を有効にします
- Signal ベースの状態管理:すべてのダッシュボードの状態を Signals で管理します
- RxJS との相互運用:toSignal を使用して Observable を Signals に変換します
- WebSocket 統合:更新を Signals に直接プッシュします
パフォーマンス結果:
- バンドルサイズを 30% 削減(Zone.js なし)
- 変更検出サイクルのパフォーマンスを 50% 向上
- 複雑なデータビジュアライゼーションでも、60fps のスムーズな更新を実現
- 変更検出ログが明確になり、デバッグが改善
ベストプラクティス
アーキテクチャ設計
- スケーラビリティを考慮した設計:コードを書く前に、フォルダー構成とモジュール境界を計画します
- スタンドアロンを活用:新規開発では、すべてのコンポーネントでスタンドアロンをデフォルトにします
- すべてを遅延読み込み:機能モジュール、ルート、負荷の大きいコンポーネントを遅延読み込みします
- 関心事を分離:スマートコンテナと、ロジックを持たないプレゼンテーションコンポーネントを使い分けます
- 境界を定義:レイヤー(データ、ドメイン、プレゼンテーション)間のインターフェースを明確にします
状態管理
- ローカル状態 = Signals:コンポーネントレベルの状態には signal() と computed() を使用します
- グローバル状態 = Signal Store:共有する機能状態には NgRx Signal Store を使用します
- サーバー状態 = TanStack Query:サーバー状態のキャッシュを手動で管理しないでください
- サブスクリプションを避ける:AsyncPipe、toSignal、または takeUntilDestroyed パターンを使用します
- イミュータブルな更新:状態を変更する場合は、常に新しい参照を作成します
パフォーマンスエンジニアリング
- すべてに OnPush を適用:すべてのコンポーネントで ChangeDetectionStrategy.OnPush をデフォルトにします
- 読み込みを遅延:負荷の大きいコンポーネントと依存関係には @defer ブロックを使用します
- 画像を最適化:画像を遅延読み込みし、新しいフォーマット(WebP、AVIF)を使用します
- バンドルを分析:肥大化を特定するため、webpack のバンドル分析を定期的に実施します
- 戦略的にプリロード:重要なルートをプリロードし、それ以外はすべて遅延読み込みします
コード品質
- 厳格モード:TypeScript の厳格モードを有効にして維持します
- 厳格な null チェック:明示的に処理しない限り、undefined/null を許可しません
- API を文書化:公開メソッドとインターフェースに明確な JSDoc を記述します
- 設定を一元管理:機能フラグと環境設定を一か所にまとめます
- リンティングを自動化:Angular 固有のルールと自動修正機能を備えた ESLint を使用します
テスト戦略
- ユニットテスト:コンポーネントとサービスのテストには Jest または Vitest を使用します
- 統合テスト:重要なユーザーフローには Cypress または Playwright を使用します
- テストカバレッジ:ビジネスロジックのカバレッジ 80% 以上を目指します
- コンポーネントテスト:動作テストには Angular Testing Library を使用します
- E2E スモークテスト:デプロイのたびにスモークテストを自動実行します