Organizzare il Codice con Copilot
Una struttura del codice ben organizzata è fondamentale per la manutenibilità a lungo termine. In questo articolo vedremo come usare Copilot per definire folder structure, naming conventions, gestione delle configurazioni e pattern per un codebase pulito e professionale.
🗂️ Principi di Organizzazione del Codice
- Coesione: File correlati stanno vicini tra loro
- Prevedibilità: Facile trovare dove sta ogni cosa
- Scalabilità: La struttura funziona anche quando il progetto cresce
- Consistenza: Stesse convenzioni applicate ovunque
- Discoverability: Un nuovo developer trova subito ciò che cerca
Panoramica della Serie
| # | Modulo | Stato |
|---|---|---|
| 1 | Foundation – Copilot come Partner | ✅ Completato |
| 2 | Ideazione e Requisiti | ✅ Completato |
| 3 | Architettura Backend e Frontend | ✅ Completato |
| 4 | Struttura del Codice e Organizzazione | 📍 Sei qui |
| 5 | Prompt Engineering e Agenti MCP | ⏳ Prossimo |
| 6 | Testing e Qualità | ⏳ |
| 7 | Documentazione | ⏳ |
| 8 | Deploy e DevOps | ⏳ |
| 9 | Evoluzione e Manutenzione | ⏳ |
Folder Structure Backend Completa
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.
Struttura Backend Consigliata
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
Folder Structure Frontend Completa
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
Naming Conventions
Naming consistente aiuta Copilot a generare codice coerente e rende il codebase più leggibile per tutti i membri del team (incluso te stesso tra 6 mesi).
📝 Convenzioni di Naming
| Tipo | Convenzione | Esempio |
|---|---|---|
| File (general) | kebab-case | user-profile.component.ts |
| Classe | PascalCase | UserProfileComponent |
| Variabile/Funzione | camelCase | getUserProfile() |
| Costante | SCREAMING_SNAKE_CASE | MAX_RETRY_COUNT |
| Interfaccia | PascalCase (no I prefix) | UserProfile |
| Type | PascalCase | TaskStatus |
| Enum | PascalCase | UserRole |
| Enum member | SCREAMING_SNAKE_CASE | UserRole.ADMIN |
| Boolean variable | is/has/can prefix | isLoading, hasError |
| Event handler | on/handle prefix | onSubmit, handleClick |
| Observable | $ suffix | users$, isLoading$ |
| Signal | no suffix (Angular 18+) | users, isLoading |
Suffissi Consigliati per File
Backend
// 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
Frontend (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
Separation of Concerns
Ogni file/classe dovrebbe avere una singola responsabilità chiara. Questo rende il codice più testabile, riutilizzabile e manutenibile.
❌ Sbagliato: God Controller
// 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 {{ '}' }});
{{ '}' }}
{{ '}' }}
✅ Corretto: Responsabilità Separate
// 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({{ '{' }}...{{ '}' }});
{{ '}' }}
Gestione Configurazioni
Centralizza le configurazioni per ambiente con validazione e type safety.
// 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;
File .env.example
# ═══════════════════════════════════════════════════════════
# 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 Files e Barrel Exports
Usa file index.ts per export puliti e import semplificati.
// ═══════════════════════════════════════════════════════════
// 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/*"]
{{ '}' }}
{{ '}' }}
{{ '}' }}
Organizzazione degli Import
// ═══════════════════════════════════════════════════════════
// 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';
File Templates per Copilot
Crea template che Copilot può usare come riferimento per generare codice consistente.
// ═══════════════════════════════════════════════════════════
// 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();
{{ '}' }}
{{ '}' }}
Checklist Organizzazione Codice
✅ Checklist
| Item | Completato |
|---|---|
| Folder structure definita e documentata | ☐ |
| Naming conventions documentate | ☐ |
| Path aliases configurati in tsconfig | ☐ |
| Barrel exports per shared modules | ☐ |
| Config management centralizzato con validazione | ☐ |
| .env.example con tutte le variabili | ☐ |
| ESLint/Prettier configurato | ☐ |
| Husky + lint-staged per pre-commit hooks | ☐ |
Conclusione
Una struttura del codice ben organizzata paga dividendi per tutta la vita del progetto. Investire tempo nella definizione di convenzioni chiare rende lo sviluppo più veloce, il codice più manutenibile e l'onboarding di nuovi contributor (o di te stesso tra 6 mesi) molto più semplice.
🎯 Punti Chiave dell'Articolo
- Feature-Based Structure: Organizza per feature, non per tipo di file
- Naming Conventions: kebab-case per file, PascalCase per classi
- Separation of Concerns: Controller → Service → Repository
- Config Management: Centralizza con validazione schema (Zod)
- Barrel Exports: Index.ts per import puliti
- Path Aliases: @shared, @core, @features per evitare ../../../
📚 Prossimo Articolo
Nel prossimo articolo "Prompt Engineering e Agenti MCP" vedremo tecniche avanzate per scrivere prompt efficaci e come configurare agenti MCP per contesto persistente nel progetto.







