Copilot を使用してコードを整理する
長期的な保守性を確保するには、よく整理されたコード構造が重要です。 この記事では、Copilot を使用して定義する方法を説明します。 フォルダ構造, 命名規則, 構成管理 e クリーンでプロフェッショナルなコードベースのパターン。
🗂️ コード構成の原則
- 凝集: 関連ファイルは互いに近くにある
- 予測可能性: どこに何があるか簡単に見つけられる
- スケーラビリティ: この構造はプロジェクトの成長に合わせて機能します
- 一貫性: 同じ規則がどこにでも適用されます
- 発見可能性: 新しい開発者は探しているものをすぐに見つけます
シリーズ概要
| # | モジュール | Stato |
|---|---|---|
| 1 | 財団 – パートナーとしての副操縦士 | ✅ 完了 |
| 2 | コンセプトと要件 | ✅ 完了 |
| 3 | バックエンドとフロントエンドのアーキテクチャ | ✅ 完了 |
| 4 | 規範の構造と組織 | 📍 あなたはここにいます |
| 5 | 迅速なエンジニアリングと MCP エージェント | ⏳ 次へ |
| 6 | テストと品質 | ⏳ |
| 7 | ドキュメント | ⏳ |
| 8 | デプロイとDevOps | ⏳ |
| 9 | 進化と維持 | ⏳ |
フォルダー構造バックエンドの完成
Create a detailed folder structure for a Node.js + Express + TypeScript backend.
PROJECT: TaskFlow (time tracking + task management)
ARCHITECTURE: Layered (Controller → Service → Repository)
Requirements:
- Clean Architecture layers clearly separated
- Modular organization by feature/domain
- Clear separation of concerns
- Support for unit, integration, and e2e testing
- Environment-based configuration
- Database migrations and seeds
- Shared utilities and helpers
- API documentation structure
Show the complete tree with explanations for each folder/file.
推奨されるバックエンド構造
backend/
├── src/
│ ├── config/ # 🔧 Application configuration
│ │ ├── index.ts # Main config export (loads from env)
│ │ ├── database.config.ts # Database connection settings
│ │ ├── auth.config.ts # JWT, OAuth settings
│ │ ├── cors.config.ts # CORS policy
│ │ └── rate-limit.config.ts # Rate limiting rules
│ │
│ ├── modules/ # 📦 Feature modules (domain-driven)
│ │ ├── users/
│ │ │ ├── users.controller.ts # HTTP handling
│ │ │ ├── users.service.ts # Business logic
│ │ │ ├── users.repository.ts # Data access
│ │ │ ├── users.routes.ts # Route definitions
│ │ │ ├── dto/ # Data Transfer Objects
│ │ │ │ ├── create-user.dto.ts
│ │ │ │ ├── update-user.dto.ts
│ │ │ │ └── user-response.dto.ts
│ │ │ ├── entities/ # Domain entities
│ │ │ │ └── user.entity.ts
│ │ │ └── __tests__/ # Module-specific tests
│ │ │ ├── users.service.spec.ts
│ │ │ └── users.controller.spec.ts
│ │ │
│ │ ├── auth/
│ │ │ ├── auth.controller.ts
│ │ │ ├── auth.service.ts
│ │ │ ├── strategies/ # Passport strategies
│ │ │ │ ├── jwt.strategy.ts
│ │ │ │ └── local.strategy.ts
│ │ │ ├── dto/
│ │ │ └── auth.routes.ts
│ │ │
│ │ ├── tasks/
│ │ │ ├── tasks.controller.ts
│ │ │ ├── tasks.service.ts
│ │ │ ├── tasks.repository.ts
│ │ │ ├── tasks.routes.ts
│ │ │ ├── dto/
│ │ │ ├── entities/
│ │ │ └── __tests__/
│ │ │
│ │ └── time-entries/
│ │ └── ... (same structure)
│ │
│ ├── shared/ # 🔄 Shared across modules
│ │ ├── middleware/
│ │ │ ├── auth.middleware.ts
│ │ │ ├── validation.middleware.ts
│ │ │ ├── rate-limit.middleware.ts
│ │ │ └── request-logger.middleware.ts
│ │ ├── guards/
│ │ │ ├── roles.guard.ts
│ │ │ └── ownership.guard.ts
│ │ ├── decorators/
│ │ │ ├── current-user.decorator.ts
│ │ │ └── roles.decorator.ts
│ │ ├── errors/
│ │ │ ├── app-error.ts
│ │ │ ├── validation.error.ts
│ │ │ ├── not-found.error.ts
│ │ │ └── unauthorized.error.ts
│ │ ├── utils/
│ │ │ ├── hash.util.ts
│ │ │ ├── jwt.util.ts
│ │ │ ├── pagination.util.ts
│ │ │ └── date.util.ts
│ │ └── types/
│ │ ├── express.d.ts # Express type extensions
│ │ └── common.types.ts
│ │
│ ├── database/ # 💾 Database setup
│ │ ├── connection.ts # DB connection pool
│ │ ├── migrations/ # Schema migrations
│ │ │ ├── 001_create_users.ts
│ │ │ ├── 002_create_tasks.ts
│ │ │ └── 003_create_time_entries.ts
│ │ ├── seeds/ # Test/dev data
│ │ │ ├── users.seed.ts
│ │ │ └── tasks.seed.ts
│ │ └── queries/ # Complex SQL queries
│ │ └── reports.queries.ts
│ │
│ ├── api/ # 🌐 API versioning
│ │ ├── v1/
│ │ │ └── index.ts # v1 router aggregator
│ │ └── index.ts # Main API router
│ │
│ ├── app.ts # Express app setup
│ └── server.ts # Entry point (starts server)
│
├── tests/ # 🧪 Test files (by type)
│ ├── unit/ # Isolated unit tests
│ ├── integration/ # API integration tests
│ │ └── users.integration.spec.ts
│ ├── e2e/ # End-to-end tests
│ ├── fixtures/ # Test data
│ │ └── users.fixture.ts
│ └── helpers/ # Test utilities
│ ├── db.helper.ts # Test DB setup/teardown
│ └── auth.helper.ts # Get test tokens
│
├── scripts/ # 📜 Utility scripts
│ ├── migrate.ts # Run migrations
│ ├── seed.ts # Seed database
│ └── generate-types.ts # Generate TS from DB
│
├── docs/ # 📚 Documentation
│ ├── api/ # OpenAPI specs
│ │ └── openapi.yaml
│ └── adr/ # Architecture Decision Records
│ └── 001-database-choice.md
│
├── .env.example # Environment template
├── .env.test # Test environment
├── tsconfig.json
├── jest.config.js
├── package.json
└── README.md
フォルダー構造のフロントエンドの完成
frontend/
├── src/
│ ├── app/
│ │ ├── core/ # 🔧 Singleton services (providedIn: 'root')
│ │ │ ├── services/
│ │ │ │ ├── api.service.ts # HTTP client wrapper
│ │ │ │ ├── auth.service.ts # Auth state management
│ │ │ │ ├── storage.service.ts # LocalStorage/SessionStorage
│ │ │ │ ├── toast.service.ts # Notification service
│ │ │ │ └── theme.service.ts # Dark/light mode
│ │ │ ├── guards/
│ │ │ │ ├── auth.guard.ts # Protect routes
│ │ │ │ ├── guest.guard.ts # Redirect if logged in
│ │ │ │ └── unsaved-changes.guard.ts # Prevent accidental navigation
│ │ │ ├── interceptors/
│ │ │ │ ├── auth.interceptor.ts # Add JWT to requests
│ │ │ │ ├── error.interceptor.ts # Global error handling
│ │ │ │ ├── loading.interceptor.ts # Show/hide loading
│ │ │ │ └── retry.interceptor.ts # Retry failed requests
│ │ │ └── models/
│ │ │ ├── api-response.model.ts
│ │ │ └── user.model.ts
│ │ │
│ │ ├── shared/ # 🔄 Reusable components (import in features)
│ │ │ ├── components/
│ │ │ │ ├── ui/ # Design system primitives
│ │ │ │ │ ├── button/
│ │ │ │ │ │ ├── button.component.ts
│ │ │ │ │ │ ├── button.component.html
│ │ │ │ │ │ ├── button.component.scss
│ │ │ │ │ │ └── button.component.spec.ts
│ │ │ │ │ ├── input/
│ │ │ │ │ ├── select/
│ │ │ │ │ ├── checkbox/
│ │ │ │ │ ├── modal/
│ │ │ │ │ ├── tooltip/
│ │ │ │ │ └── dropdown/
│ │ │ │ ├── layout/ # Layout components
│ │ │ │ │ ├── card/
│ │ │ │ │ ├── page-header/
│ │ │ │ │ └── empty-state/
│ │ │ │ └── feedback/ # Feedback components
│ │ │ │ ├── loading-spinner/
│ │ │ │ ├── skeleton/
│ │ │ │ ├── error-message/
│ │ │ │ └── toast/
│ │ │ ├── directives/
│ │ │ │ ├── click-outside.directive.ts
│ │ │ │ ├── autofocus.directive.ts
│ │ │ │ ├── debounce-click.directive.ts
│ │ │ │ └── tooltip.directive.ts
│ │ │ ├── pipes/
│ │ │ │ ├── time-ago.pipe.ts
│ │ │ │ ├── duration.pipe.ts
│ │ │ │ ├── truncate.pipe.ts
│ │ │ │ └── highlight.pipe.ts
│ │ │ └── index.ts # Barrel export
│ │ │
│ │ ├── features/ # 📦 Feature modules (lazy loaded)
│ │ │ ├── auth/
│ │ │ │ ├── components/
│ │ │ │ │ ├── login-form/
│ │ │ │ │ ├── register-form/
│ │ │ │ │ └── forgot-password-form/
│ │ │ │ ├── pages/
│ │ │ │ │ ├── login.page.ts
│ │ │ │ │ ├── register.page.ts
│ │ │ │ │ └── forgot-password.page.ts
│ │ │ │ ├── services/
│ │ │ │ │ └── auth-api.service.ts
│ │ │ │ ├── models/
│ │ │ │ │ └── auth.model.ts
│ │ │ │ └── auth.routes.ts
│ │ │ │
│ │ │ ├── tasks/
│ │ │ │ ├── components/
│ │ │ │ │ ├── task-list/
│ │ │ │ │ ├── task-item/
│ │ │ │ │ ├── task-form/
│ │ │ │ │ ├── task-timer/
│ │ │ │ │ └── task-filters/
│ │ │ │ ├── pages/
│ │ │ │ │ ├── tasks-list.page.ts
│ │ │ │ │ └── task-detail.page.ts
│ │ │ │ ├── services/
│ │ │ │ │ └── tasks-api.service.ts
│ │ │ │ ├── state/ # Feature-specific state
│ │ │ │ │ └── tasks.store.ts # Signals-based store
│ │ │ │ ├── models/
│ │ │ │ │ └── task.model.ts
│ │ │ │ └── tasks.routes.ts
│ │ │ │
│ │ │ ├── dashboard/
│ │ │ │ ├── components/
│ │ │ │ │ ├── stats-card/
│ │ │ │ │ ├── recent-tasks/
│ │ │ │ │ ├── time-summary/
│ │ │ │ │ └── quick-actions/
│ │ │ │ ├── pages/
│ │ │ │ │ └── dashboard.page.ts
│ │ │ │ └── dashboard.routes.ts
│ │ │ │
│ │ │ └── settings/
│ │ │ ├── components/
│ │ │ ├── pages/
│ │ │ └── settings.routes.ts
│ │ │
│ │ ├── layouts/ # 🖼️ Layout components
│ │ │ ├── main-layout/
│ │ │ │ ├── main-layout.component.ts
│ │ │ │ ├── components/
│ │ │ │ │ ├── header/
│ │ │ │ │ ├── sidebar/
│ │ │ │ │ └── footer/
│ │ │ └── auth-layout/
│ │ │ └── auth-layout.component.ts
│ │ │
│ │ ├── app.component.ts
│ │ ├── app.routes.ts # Root routes
│ │ └── app.config.ts # App providers
│ │
│ ├── assets/
│ │ ├── images/
│ │ ├── icons/
│ │ │ └── svg/ # SVG icons
│ │ └── fonts/
│ │
│ ├── styles/
│ │ ├── _variables.scss # Design tokens
│ │ ├── _mixins.scss # SCSS mixins
│ │ ├── _typography.scss # Typography rules
│ │ ├── _utilities.scss # Utility classes
│ │ └── global.scss # Global styles
│ │
│ └── environments/
│ ├── environment.ts
│ └── environment.prod.ts
│
├── angular.json
├── tsconfig.json
└── package.json
命名規則
一貫した名前付けは、Copilot が一貫したコードを生成し、コードベースを作成するのに役立ちます。 チームの全員 (6 か月後の自分も含む) にとって読みやすくなります。
📝 命名規則
| タイプ | 大会 | Esempio |
|---|---|---|
| ファイル(一般) | ケバブハウス | ユーザープロファイル.component.ts |
| クラス | パスカル・ケース | ユーザープロファイルコンポーネント |
| 変数/関数 | キャメルケース | getUserProfile() |
| 絶え間ない | SCREAMING_SNAKE_CASE | MAX_RETRY_COUNT |
| インタフェース | PascalCase (プレフィックスなし) | ユーザープロフィール |
| タイプ | パスカル・ケース | タスクステータス |
| 列挙型 | パスカル・ケース | ユーザーロール |
| 列挙メンバー | SCREAMING_SNAKE_CASE | ユーザーロール.ADMIN |
| ブール変数 | プレフィックスがある/ある/できる | isLoading、hasError |
| イベントハンドラ | オン/ハンドル接頭辞 | onSubmit、ハンドルクリック |
| 観測可能 | $接尾辞 | ユーザー$、isLoading$ |
| 信号 | サフィックスなし (Angular 18+) | ユーザー、isLoading |
ファイルの推奨サフィックス
バックエンド
// Controllers
user.controller.ts → UserController
// Services
user.service.ts → UserService
// Repositories
user.repository.ts → UserRepository
// Entities
user.entity.ts → User
// DTOs
create-user.dto.ts → CreateUserDto
update-user.dto.ts → UpdateUserDto
// Middleware
auth.middleware.ts → authMiddleware
// Guards
roles.guard.ts → RolesGuard
// Routes
user.routes.ts → userRoutes
フロントエンド (Angular)
// Components
user-list.component.ts → UserListComponent
// Pages (Smart Components)
users-list.page.ts → UsersListPage
// Services
user.service.ts → UserService
user-api.service.ts → UserApiService
// Models
user.model.ts → User (interface)
// Guards
auth.guard.ts → authGuard (function)
// Interceptors
auth.interceptor.ts → authInterceptor
// Pipes
time-ago.pipe.ts → TimeAgoPipe
// Directives
tooltip.directive.ts → TooltipDirective
関心事の分離
各ファイル/クラスには単一の明確な責任がある必要があります。 これにより、コードのテスト、再利用、保守が容易になります。
❌ 誤: ゴッドコントローラー
// user.controller.ts - TUTTO insieme
class UserController {{ '{' }}
async create(req, res) {{ '{' }}
// 1. Validation (dovrebbe essere in middleware)
if (!req.body.email) {{ '{' }}
return res.status(400).json(...);
{{ '}' }}
if (!/^[^\s@]+@[^\s@]+$/.test(req.body.email)) {{ '{' }}
return res.status(400).json(...);
{{ '}' }}
// 2. Business logic (dovrebbe essere in service)
const exists = await db.query('SELECT...');
if (exists) throw new Error('...');
const hashedPassword = await bcrypt.hash(...);
// 3. Database (dovrebbe essere in repository)
await db.query('INSERT INTO users...');
// 4. Send email (dovrebbe essere in service)
await sendgrid.send({{ '{' }}
to: req.body.email,
subject: 'Welcome!',
...
{{ '}' }});
res.json({{ '{' }} success: true {{ '}' }});
{{ '}' }}
{{ '}' }}
✅ 正: 別々の責任
// Controller: SOLO HTTP handling
async create(req, res, next) {{ '{' }}
try {{ '{' }}
const user = await this.userService
.createUser(req.body);
res.status(201).json({{ '{' }} data: user {{ '}' }});
{{ '}' }} catch (err) {{ '{' }}
next(err);
{{ '}' }}
{{ '}' }}
// Service: SOLO business logic
async createUser(dto: CreateUserDto) {{ '{' }}
await this.validateUniqueEmail(dto.email);
const user = new User(dto);
const saved = await this.userRepo.save(user);
await this.emailService.sendWelcome(saved);
return saved;
{{ '}' }}
// Repository: SOLO data access
async save(user: User): Promise<User> {{ '{' }}
return this.db.users.create(user);
{{ '}' }}
// EmailService: SOLO email
async sendWelcome(user: User) {{ '{' }}
await this.mailer.send({{ '{' }}...{{ '}' }});
{{ '}' }}
構成管理
検証と型安全性を使用して環境ごとに構成を一元化します。
// config/index.ts
import dotenv from 'dotenv';
import {{ '{' }} z {{ '}' }} from 'zod';
// Load .env file
dotenv.config();
// Define schema with validation
const configSchema = z.object({{ '{' }}
// Environment
NODE_ENV: z.enum(['development', 'test', 'production']).default('development'),
PORT: z.string().transform(Number).default('3000'),
// Database
DATABASE_URL: z.string().url(),
DATABASE_POOL_MIN: z.string().transform(Number).default('2'),
DATABASE_POOL_MAX: z.string().transform(Number).default('10'),
// Authentication
JWT_SECRET: z.string().min(32),
JWT_EXPIRES_IN: z.string().default('7d'),
BCRYPT_ROUNDS: z.string().transform(Number).default('12'),
// CORS
CORS_ORIGIN: z.string().default('http://localhost:4200'),
// External Services (optional in dev)
SENDGRID_API_KEY: z.string().optional(),
SENTRY_DSN: z.string().optional(),
{{ '}' }});
// Parse and validate
const parsed = configSchema.safeParse(process.env);
if (!parsed.success) {{ '{' }}
console.error('❌ Invalid environment variables:');
console.error(parsed.error.format());
process.exit(1);
{{ '}' }}
// Export typed config
export const config = {{ '{' }}
env: parsed.data.NODE_ENV,
port: parsed.data.PORT,
isProduction: parsed.data.NODE_ENV === 'production',
isDevelopment: parsed.data.NODE_ENV === 'development',
database: {{ '{' }}
url: parsed.data.DATABASE_URL,
pool: {{ '{' }}
min: parsed.data.DATABASE_POOL_MIN,
max: parsed.data.DATABASE_POOL_MAX,
{{ '}' }},
{{ '}' }},
jwt: {{ '{' }}
secret: parsed.data.JWT_SECRET,
expiresIn: parsed.data.JWT_EXPIRES_IN,
{{ '}' }},
bcrypt: {{ '{' }}
rounds: parsed.data.BCRYPT_ROUNDS,
{{ '}' }},
cors: {{ '{' }}
origin: parsed.data.CORS_ORIGIN.split(','),
{{ '}' }},
sendgrid: {{ '{' }}
apiKey: parsed.data.SENDGRID_API_KEY,
{{ '}' }},
sentry: {{ '{' }}
dsn: parsed.data.SENTRY_DSN,
{{ '}' }},
{{ '}' }} as const;
// Type for config
export type Config = typeof config;
.env.サンプル ファイル
# ═══════════════════════════════════════════════════════════
# TaskFlow Backend Configuration
# Copy this file to .env and fill in your values
# ═══════════════════════════════════════════════════════════
# ─────────────────────────────────────────────────────────────
# Environment
# ─────────────────────────────────────────────────────────────
NODE_ENV=development
PORT=3000
# ─────────────────────────────────────────────────────────────
# Database (PostgreSQL)
# ─────────────────────────────────────────────────────────────
DATABASE_URL=postgresql://user:password@localhost:5432/taskflow
DATABASE_POOL_MIN=2
DATABASE_POOL_MAX=10
# ─────────────────────────────────────────────────────────────
# Authentication
# ─────────────────────────────────────────────────────────────
# Generate with: openssl rand -base64 32
JWT_SECRET=your-super-secret-key-at-least-32-chars
JWT_EXPIRES_IN=7d
BCRYPT_ROUNDS=12
# ─────────────────────────────────────────────────────────────
# CORS
# ─────────────────────────────────────────────────────────────
CORS_ORIGIN=http://localhost:4200
# ─────────────────────────────────────────────────────────────
# External Services (optional for development)
# ─────────────────────────────────────────────────────────────
# SENDGRID_API_KEY=SG.xxxxx
# SENTRY_DSN=https://xxxxx@sentry.io/xxxxx
インデックスファイルとバレルエクスポート
クリーンなエクスポートと簡素化されたインポートには、index.ts ファイルを使用します。
// ═══════════════════════════════════════════════════════════
// shared/components/index.ts - Barrel Export
// ═══════════════════════════════════════════════════════════
// UI Components
export {{ '{' }} ButtonComponent {{ '}' }} from './ui/button/button.component';
export {{ '{' }} InputComponent {{ '}' }} from './ui/input/input.component';
export {{ '{' }} SelectComponent {{ '}' }} from './ui/select/select.component';
export {{ '{' }} ModalComponent {{ '}' }} from './ui/modal/modal.component';
// Layout Components
export {{ '{' }} CardComponent {{ '}' }} from './layout/card/card.component';
export {{ '{' }} PageHeaderComponent {{ '}' }} from './layout/page-header/page-header.component';
export {{ '{' }} EmptyStateComponent {{ '}' }} from './layout/empty-state/empty-state.component';
// Feedback Components
export {{ '{' }} LoadingSpinnerComponent {{ '}' }} from './feedback/loading-spinner/loading-spinner.component';
export {{ '{' }} SkeletonComponent {{ '}' }} from './feedback/skeleton/skeleton.component';
export {{ '{' }} ToastComponent {{ '}' }} from './feedback/toast/toast.component';
// ═══════════════════════════════════════════════════════════
// Usage in feature module
// ═══════════════════════════════════════════════════════════
// PRIMA (senza barrel)
import {{ '{' }} ButtonComponent {{ '}' }} from '../../../shared/components/ui/button/button.component';
import {{ '{' }} InputComponent {{ '}' }} from '../../../shared/components/ui/input/input.component';
import {{ '{' }} CardComponent {{ '}' }} from '../../../shared/components/layout/card/card.component';
// DOPO (con barrel) ✅
import {{ '{' }}
ButtonComponent,
InputComponent,
CardComponent
{{ '}' }} from '@shared/components';
// ═══════════════════════════════════════════════════════════
// tsconfig.json - Path aliases
// ═══════════════════════════════════════════════════════════
{{ '{' }}
"compilerOptions": {{ '{' }}
"baseUrl": "./src",
"paths": {{ '{' }}
"@shared/*": ["app/shared/*"],
"@core/*": ["app/core/*"],
"@features/*": ["app/features/*"],
"@environments/*": ["environments/*"]
{{ '}' }}
{{ '}' }}
{{ '}' }}
輸入組織
// ═══════════════════════════════════════════════════════════
// Ordine consigliato degli import
// ═══════════════════════════════════════════════════════════
// 1. Angular/Framework imports
import {{ '{' }} Component, OnInit, inject {{ '}' }} from '@angular/core';
import {{ '{' }} CommonModule {{ '}' }} from '@angular/common';
import {{ '{' }} RouterModule {{ '}' }} from '@angular/router';
import {{ '{' }} FormBuilder, ReactiveFormsModule {{ '}' }} from '@angular/forms';
// 2. Third-party library imports
import {{ '{' }} Observable {{ '}' }} from 'rxjs';
import {{ '{' }} map, catchError {{ '}' }} from 'rxjs/operators';
// 3. Core/Shared imports (using path aliases)
import {{ '{' }} AuthService {{ '}' }} from '@core/services/auth.service';
import {{ '{' }} ButtonComponent, CardComponent {{ '}' }} from '@shared/components';
import {{ '{' }} TimeAgoPipe {{ '}' }} from '@shared/pipes';
// 4. Feature-specific imports (relative paths)
import {{ '{' }} TasksApiService {{ '}' }} from './services/tasks-api.service';
import {{ '{' }} TaskItemComponent {{ '}' }} from './components/task-item/task-item.component';
import {{ '{' }} Task {{ '}' }} from './models/task.model';
// 5. Constants and types
import {{ '{' }} TASK_STATUS {{ '}' }} from './constants/task.constants';
import type {{ '{' }} TaskFilters {{ '}' }} from './types/task.types';
Copilot のテンプレート ファイル
Copilot が参照して一貫性のあるコードを生成できるテンプレートを作成します。
// ═══════════════════════════════════════════════════════════
// Template: Angular Standalone Component
// ═══════════════════════════════════════════════════════════
import {{ '{' }} Component, Input, Output, EventEmitter, ChangeDetectionStrategy {{ '}' }} from '@angular/core';
import {{ '{' }} CommonModule {{ '}' }} from '@angular/common';
/**
* [ComponentName] - [Brief description]
*
* @example
* <app-[component-name]
* [inputProp]="value"
* (outputEvent)="handler($event)"
* />
*/
@Component({{ '{' }}
selector: 'app-[component-name]',
standalone: true,
imports: [CommonModule],
templateUrl: './[component-name].component.html',
styleUrl: './[component-name].component.scss',
changeDetection: ChangeDetectionStrategy.OnPush,
{{ '}' }})
export class [ComponentName]Component {{ '{' }}
// ─────────────────────────────────────────────────────────
// Inputs
// ─────────────────────────────────────────────────────────
@Input() inputProp: string = '';
// ─────────────────────────────────────────────────────────
// Outputs
// ─────────────────────────────────────────────────────────
@Output() outputEvent = new EventEmitter<void>();
// ─────────────────────────────────────────────────────────
// Public methods
// ─────────────────────────────────────────────────────────
onAction(): void {{ '{' }}
this.outputEvent.emit();
{{ '}' }}
{{ '}' }}
コード構成チェックリスト
✅ チェックリスト
| アイテム | 完了 |
|---|---|
| フォルダー構造の定義と文書化 | ☐ |
| 文書化された命名規則 | ☐ |
| tsconfig で構成されたパス エイリアス | ☐ |
| 共有モジュールのバレルエクスポート | ☐ |
| 検証による一元的な構成管理 | ☐ |
| すべての変数を含む .env.example | ☐ |
| ESLint/Prettier の設定済み | ☐ |
| Husky + lint ステージングされたコミット前フック | ☐ |
結論
適切に組織化されたコード構造は、プロジェクトの存続期間全体を通じて利益をもたらします。 明確な規則の定義に時間を投資すると、開発が迅速化され、 より保守しやすいコードと新しい貢献者 (または 6 か月後の自分自身) のオンボーディング はるかに簡単です。
🎯 記事の要点
- 機能ベースの構造: ファイルの種類ではなく機能ごとに整理する
- 命名規則: ファイルの場合は kebab-case、クラスの場合は PascalCase
- 懸念事項の分離: コントローラー → サービス → リポジトリ
- 構成管理: スキーマ検証による一元化 (Zod)
- バレル輸出: クリーンインポート用の Index.ts
- パスのエイリアス: @shared、@core、@features を回避する ../../../
📚 次の記事
次の記事で 「迅速なエンジニアリングと MCP エージェント」 効果的なプロンプトを作成するための高度なテクニックとその設定方法を見ていきます。 プロジェクト内の永続的なコンテキスト用の MCP エージェント。







