From 3eae97200db8f41871e3219d0038767972cefce8 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Thu, 26 Mar 2026 19:06:12 +0000 Subject: [PATCH] feat(docs): expand technical knowledge on vibe coding agents and refactor markdown ui style(ui): autonomous visual optimization of frontend/angular/readme.md, backend/nestjs/readme.md, frontend/javascript/readme.md chore(nav): optimize internal connectivity by linking docs/vibe-coding-agents.md in README.md Co-authored-by: beginwebdev2002 <102213457+beginwebdev2002@users.noreply.github.com> --- README.md | 2 + backend/nestjs/readme.md | 245 +++++++------- docs/vibe-coding-agents.md | 68 ++++ frontend/angular/readme.md | 593 +++++++++++++++++----------------- frontend/javascript/readme.md | 412 +++++++++++------------ 5 files changed, 710 insertions(+), 610 deletions(-) create mode 100644 docs/vibe-coding-agents.md diff --git a/README.md b/README.md index 578a80a..c5b06b3 100644 --- a/README.md +++ b/README.md @@ -188,6 +188,8 @@ graph TD * 🛡️ [security.md](./backend/nestjs/security.md) * 🟢 **[nodejs/](./backend/nodejs/)** * 📄 [readme.md](./backend/nodejs/readme.md) + * 📄 **[docs/](./docs/)** + * 🤖 [vibe-coding-agents.md](./docs/vibe-coding-agents.md) * 🖥️ **[frontend/](./frontend/)** * 📄 [readme.md](./frontend/readme.md) * 🅰️ **[angular/](./frontend/angular/)** diff --git a/backend/nestjs/readme.md b/backend/nestjs/readme.md index d2bc321..a5cb62a 100644 --- a/backend/nestjs/readme.md +++ b/backend/nestjs/readme.md @@ -19,7 +19,7 @@ last_updated: 2026-03-23 Этот документ определяет **лучшие практики (best practices)** для фреймворка NestJS. Руководство создано для обеспечения масштабируемости, безопасности и качества Enterprise-приложений. -# Context & Scope +## 🎯 Context & Scope - **Primary Goal:** Предоставить строгие архитектурные правила и 30 паттернов разработки на NestJS. - **Target Tooling:** AI-агенты (Cursor, Windsurf, Copilot) и Senior-разработчики. - **Tech Stack Version:** NestJS 10+ @@ -29,47 +29,47 @@ last_updated: 2026-03-23 --- -## 1. Clean Architecture Modules (Изоляция логики) -### ❌ Bad Practice +### 🚨 1. Clean Architecture Modules (Изоляция логики) +#### ❌ Bad Practice ```typescript @Injectable() export class UsersService { constructor(@InjectRepository(User) private repo: Repository) {} // Жесткая привязка к TypeORM } ``` -### ✅ Best Practice +#### ✅ Best Practice ```typescript @Injectable() export class UsersService { constructor(@Inject('IUserRepository') private repo: IUserRepository) {} // Интерфейс порта } ``` -### 🚀 Solution +#### 🚀 Solution Применяйте инверсию зависимостей (Dependency Inversion). Бизнес-логика зависит от абстракций (интерфейсов), а не от конкретных ORM. -## 2. Global ValidationPipe -### ❌ Bad Practice +### 🚨 2. Global ValidationPipe +#### ❌ Bad Practice ```typescript @Post() create(@Body() dto: CreateUserDto) { if (!dto.email) throw new BadRequestException('Email required'); } ``` -### ✅ Best Practice +#### ✅ Best Practice ```typescript // main.ts app.useGlobalPipes(new ValidationPipe({ whitelist: true, forbidNonWhitelisted: true })); ``` -### 🚀 Solution +#### 🚀 Solution Включите глобальную валидацию на основе `class-validator` и `whitelist`, чтобы автоматически отсекать неизвестные поля. -## 3. Data Transfer Objects (DTO) -### ❌ Bad Practice +### 🚨 3. Data Transfer Objects (DTO) +#### ❌ Bad Practice ```typescript @Post() create(@Body() body: any) {} // Потеря типизации ``` -### ✅ Best Practice +#### ✅ Best Practice ```typescript export class CreateUserDto { @IsEmail() @@ -78,11 +78,11 @@ export class CreateUserDto { @Post() create(@Body() dto: CreateUserDto) {} ``` -### 🚀 Solution +#### 🚀 Solution Все данные от клиента должны строго описываться через DTO с декораторами валидации. -## 4. Fat Controllers vs Thin Controllers -### ❌ Bad Practice +### 🚨 4. Fat Controllers vs Thin Controllers +#### ❌ Bad Practice ```typescript @Post() async createUser(@Body() dto: CreateDto) { @@ -90,22 +90,22 @@ async createUser(@Body() dto: CreateDto) { return this.db.users.create({ ...dto, hash }); } ``` -### ✅ Best Practice +#### ✅ Best Practice ```typescript @Post() async createUser(@Body() dto: CreateDto) { return this.userService.register(dto); } ``` -### 🚀 Solution +#### 🚀 Solution Контроллеры только маршрутизируют запросы. Вся логика — в Service Layer. -## 5. Global Exception Filter -### ❌ Bad Practice +### 🚨 5. Global Exception Filter +#### ❌ Bad Practice ```typescript try { ... } catch (e) { throw new HttpException('Error', 500); } ``` -### ✅ Best Practice +#### ✅ Best Practice ```typescript @Catch() export class AllExceptionsFilter implements ExceptionFilter { @@ -114,15 +114,15 @@ export class AllExceptionsFilter implements ExceptionFilter { // main.ts app.useGlobalFilters(new AllExceptionsFilter()); ``` -### 🚀 Solution +#### 🚀 Solution Используйте фильтры исключений для стандартизации формата всех HTTP-ошибок API. -## 6. Async Module Configuration -### ❌ Bad Practice +### 🚨 6. Async Module Configuration +#### ❌ Bad Practice ```typescript TypeOrmModule.forRoot({ url: process.env.DB_URL }) // Переменные могут быть еще не загружены ``` -### ✅ Best Practice +#### ✅ Best Practice ```typescript TypeOrmModule.forRootAsync({ imports: [ConfigModule], @@ -130,105 +130,105 @@ TypeOrmModule.forRootAsync({ inject: [ConfigService], }) ``` -### 🚀 Solution +#### 🚀 Solution Для сторонних модулей всегда используйте `forRootAsync` / `registerAsync`, чтобы безопасно внедрять конфигурации. -## 7. Configuration Management -### ❌ Bad Practice +### 🚨 7. Configuration Management +#### ❌ Bad Practice ```typescript const secret = process.env.JWT_SECRET; // Прямой вызов ``` -### ✅ Best Practice +#### ✅ Best Practice ```typescript constructor(private configService: ConfigService) {} const secret = this.configService.get('JWT_SECRET'); ``` -### 🚀 Solution +#### 🚀 Solution Используйте `@nestjs/config` для безопасного извлечения переменных с типизацией. -## 8. Custom Decorators (Извлечение User) -### ❌ Bad Practice +### 🚨 8. Custom Decorators (Извлечение User) +#### ❌ Bad Practice ```typescript @Get() getProfile(@Req() req: Request) { return req.user; } ``` -### ✅ Best Practice +#### ✅ Best Practice ```typescript export const CurrentUser = createParamDecorator((data, ctx: ExecutionContext) => ctx.switchToHttp().getRequest().user); @Get() getProfile(@CurrentUser() user: UserEntity) { return user; } ``` -### 🚀 Solution +#### 🚀 Solution Создавайте кастомные декораторы для чистой экстракции данных из Request (например, текущего пользователя). -## 9. JWT Guards (Защита роутов) -### ❌ Bad Practice +### 🚨 9. JWT Guards (Защита роутов) +#### ❌ Bad Practice ```typescript @Get() getData(@Req() req) { if (!req.headers.auth) throw new UnauthorizedException(); } ``` -### ✅ Best Practice +#### ✅ Best Practice ```typescript @UseGuards(JwtAuthGuard) @Get() getData() {} ``` -### 🚀 Solution +#### 🚀 Solution Авторизация должна происходить до контроллера через Guards (например, стратегия Passport JWT). -## 10. Role-Based Access Control (RBAC) -### ❌ Bad Practice +### 🚨 10. Role-Based Access Control (RBAC) +#### ❌ Bad Practice ```typescript @Get() getAdminData(@CurrentUser() user) { if (user.role !== 'ADMIN') throw new ForbiddenException(); } ``` -### ✅ Best Practice +#### ✅ Best Practice ```typescript @Roles('ADMIN') @UseGuards(JwtAuthGuard, RolesGuard) @Get() getAdminData() {} ``` -### 🚀 Solution +#### 🚀 Solution Используйте кастомные декораторы ролей (`@Roles`) и `RolesGuard` для декларативного контроля доступа. -## 11. Built-in Pipes for Transformation -### ❌ Bad Practice +### 🚨 11. Built-in Pipes for Transformation +#### ❌ Bad Practice ```typescript @Get(':id') getUser(@Param('id') id: string) { const userId = parseInt(id, 10); } ``` -### ✅ Best Practice +#### ✅ Best Practice ```typescript @Get(':id') getUser(@Param('id', ParseIntPipe) id: number) {} ``` -### 🚀 Solution +#### 🚀 Solution Используйте встроенные Pipes (`ParseIntPipe`, `ParseUUIDPipe`) для автоматической конвертации и валидации параметров. -## 12. Response Interceptors (Трансформация ответа) -### ❌ Bad Practice +### 🚨 12. Response Interceptors (Трансформация ответа) +#### ❌ Bad Practice ```typescript return { success: true, data: result, timestamp: new Date() }; // Дублирование везде ``` -### ✅ Best Practice +#### ✅ Best Practice ```typescript @Injectable() export class TransformInterceptor implements NestInterceptor { intercept(context, next) { return next.handle().pipe(map(data => ({ success: true, data }))); } } ``` -### 🚀 Solution +#### 🚀 Solution Стандартизируйте структуру успешного ответа глобально через Interceptor. -## 13. Logging Interceptors -### ❌ Bad Practice +### 🚨 13. Logging Interceptors +#### ❌ Bad Practice ```typescript @Get() getData() { console.log('Request started'); /* ... */ console.log('Done'); } ``` -### ✅ Best Practice +#### ✅ Best Practice ```typescript @Injectable() export class LoggingInterceptor implements NestInterceptor { @@ -238,233 +238,236 @@ export class LoggingInterceptor implements NestInterceptor { } } ``` -### 🚀 Solution +#### 🚀 Solution Логируйте время выполнения и детали запроса абстрактно через Interceptors. -## 14. Transaction Handling (TypeORM) -### ❌ Bad Practice +### 🚨 14. Transaction Handling (TypeORM) +#### ❌ Bad Practice ```typescript await this.repo1.save(data1); await this.repo2.save(data2); // Нет транзакции ``` -### ✅ Best Practice +#### ✅ Best Practice ```typescript await this.dataSource.transaction(async manager => { await manager.save(Entity1, data1); await manager.save(Entity2, data2); }); ``` -### 🚀 Solution +#### 🚀 Solution Критические мутации нескольких таблиц должны оборачиваться в транзакции через `DataSource.transaction`. -## 15. Swagger / OpenAPI Documentation -### ❌ Bad Practice +### 🚨 15. Swagger / OpenAPI Documentation +#### ❌ Bad Practice ```typescript // Нет никаких аннотаций DTO export class CreateDogDto { name: string; } ``` -### ✅ Best Practice +#### ✅ Best Practice ```typescript export class CreateDogDto { @ApiProperty({ example: 'Rex', description: 'The name of the dog' }) name: string; } ``` -### 🚀 Solution +#### 🚀 Solution Документируйте все свойства DTO через `@ApiProperty()`. Swagger автоматически сгенерирует схему. -## 16. Rate Limiting (ThrottlerModule) -### ❌ Bad Practice +### 🚨 16. Rate Limiting (ThrottlerModule) +#### ❌ Bad Practice // Нет защиты от DDoS и брутфорса -### ✅ Best Practice +#### ✅ Best Practice ```typescript // app.module.ts ThrottlerModule.forRoot([{ ttl: 60000, limit: 10 }]) ``` -### 🚀 Solution +#### 🚀 Solution Обязательно подключайте `@nestjs/throttler` для защиты API от перегрузок. -## 17. Caching Results -### ❌ Bad Practice +### 🚨 17. Caching Results +#### ❌ Bad Practice // Каждый запрос делает тяжелый расчет в БД -### ✅ Best Practice +#### ✅ Best Practice ```typescript @UseInterceptors(CacheInterceptor) @CacheTTL(30) // 30 секунд @Get('stats') getStats() {} ``` -### 🚀 Solution +#### 🚀 Solution Кешируйте тяжелые запросы через `CacheModule` (в памяти или Redis), чтобы разгрузить БД. -## 18. Event Emitter (Слабая связность) -### ❌ Bad Practice +### 🚨 18. Event Emitter (Слабая связность) +#### ❌ Bad Practice ```typescript await this.userService.create(); await this.emailService.send(); // Жесткая привязка зависимостей ``` -### ✅ Best Practice +#### ✅ Best Practice ```typescript await this.userService.create(); this.eventEmitter.emit('user.created', new UserCreatedEvent(user)); ``` -### 🚀 Solution +#### 🚀 Solution Используйте `@nestjs/event-emitter`. Сервис не должен ждать отправки письма, а просто публикует событие. -## 19. Task Scheduling (Cron) -### ❌ Bad Practice +### 🚨 19. Task Scheduling (Cron) +#### ❌ Bad Practice ```typescript setInterval(() => this.cleanupData(), 1000 * 60 * 60); ``` -### ✅ Best Practice +#### ✅ Best Practice ```typescript @Cron(CronExpression.EVERY_DAY_AT_MIDNIGHT) handleCron() { this.cleanupData(); } ``` -### 🚀 Solution +#### 🚀 Solution Для фоновых задач используйте `@nestjs/schedule` с декларативными декораторами. -## 20. Microservices: Message Patterns -### ❌ Bad Practice +### 🚨 20. Microservices: Message Patterns +#### ❌ Bad Practice ```typescript @Post() // Использование HTTP для межсервисного общения ``` -### ✅ Best Practice +#### ✅ Best Practice ```typescript @MessagePattern({ cmd: 'get_user' }) getUser(data: any) { return this.userService.findById(data.id); } ``` -### 🚀 Solution +#### 🚀 Solution Для общения микросервисов внутри кластера используйте TCP, Redis или RabbitMQ через `@MessagePattern`. -## 21. Health Checks (Terminus) -### ❌ Bad Practice +### 🚨 21. Health Checks (Terminus) +#### ❌ Bad Practice ```typescript @Get('ping') ping() { return 'pong'; } ``` -### ✅ Best Practice +#### ✅ Best Practice ```typescript @Get('health') @HealthCheck() check() { return this.health.check([() => this.db.pingCheck('database')]); } ``` -### 🚀 Solution +#### 🚀 Solution Используйте `@nestjs/terminus` для глубоких проверок (БД, память) для Kubernetes Liveness Probes. -## 22. Avoiding Circular Dependencies -### ❌ Bad Practice +### 🚨 22. Avoiding Circular Dependencies +#### ❌ Bad Practice ```typescript // UserService -> AuthService -> UserService @Injectable() class UserService { constructor(private auth: AuthService) {} } ``` -### ✅ Best Practice +#### ✅ Best Practice ```typescript @Injectable() class UserService { constructor(@Inject(forwardRef(() => AuthService)) private auth: AuthService) {} } ``` -### 🚀 Solution +#### 🚀 Solution Если архитектура вынуждает циклическую зависимость, используйте `forwardRef()`, однако лучше отрефакторить код. -## 23. Module Re-exporting -### ❌ Bad Practice +### 🚨 23. Module Re-exporting +#### ❌ Bad Practice ```typescript // Модуль B импортирует Модуль А, Модуль С импортирует Модуль А... ``` -### ✅ Best Practice +#### ✅ Best Practice ```typescript @Module({ imports: [DatabaseModule], exports: [DatabaseModule] }) export class CoreModule {} // Глобальный фасад ``` -### 🚀 Solution +#### 🚀 Solution Используйте экспорт модулей для создания общих Core/Shared модулей, инкапсулирующих общую логику. -## 24. Global Middleware -### ❌ Bad Practice +### 🚨 24. Global Middleware +#### ❌ Bad Practice // Определение логгера запросов в каждом месте -### ✅ Best Practice +#### ✅ Best Practice ```typescript export class AppModule implements NestModule { configure(consumer: MiddlewareConsumer) { consumer.apply(LoggerMiddleware).forRoutes('*'); } } ``` -### 🚀 Solution +#### 🚀 Solution Глобальные операции до попадания в Guards (например, Request ID) делайте через `NestMiddleware`. -## 25. Unit Testing Providers -### ❌ Bad Practice +### 🚨 25. Unit Testing Providers +#### ❌ Bad Practice ```typescript const service = new UserService(new Database()); // Реальная БД в тестах ``` -### ✅ Best Practice +#### ✅ Best Practice ```typescript const module = await Test.createTestingModule({ providers: [UserService, { provide: getRepositoryToken(User), useValue: mockUserRepo }], }).compile(); ``` -### 🚀 Solution +#### 🚀 Solution Все юнит-тесты должны использовать инъекцию моков (Mocks) через `Test.createTestingModule`. -## 26. Custom Validation Constraints -### ❌ Bad Practice +### 🚨 26. Custom Validation Constraints +#### ❌ Bad Practice ```typescript if (!isEmailUnique(dto.email)) throw error; // Ручная логика в сервисе ``` -### ✅ Best Practice +#### ✅ Best Practice ```typescript @ValidatorConstraint({ async: true }) export class IsUniqueConstraint implements ValidatorConstraintInterface { ... } @Validate(IsUniqueConstraint) email: string; ``` -### 🚀 Solution +#### 🚀 Solution Создавайте кастомные правила для `class-validator`, в том числе асинхронные проверки (проверка БД). -## 27. File Uploading (Multer) -### ❌ Bad Practice +### 🚨 27. File Uploading (Multer) +#### ❌ Bad Practice // Обработка потоков руками -### ✅ Best Practice +#### ✅ Best Practice ```typescript @Post('upload') @UseInterceptors(FileInterceptor('file')) uploadFile(@UploadedFile() file: Express.Multer.File) {} ``` -### 🚀 Solution +#### 🚀 Solution Для приема файлов стандартом является встроенный `FileInterceptor` на базе Multer. -## 28. Serialization (ClassSerializerInterceptor) -### ❌ Bad Practice +### 🚨 28. Serialization (ClassSerializerInterceptor) +#### ❌ Bad Practice ```typescript const { password, ...safeUser } = user; // Ручное удаление пароля ``` -### ✅ Best Practice +#### ✅ Best Practice ```typescript class UserEntity { @Exclude() password: string; } @UseInterceptors(ClassSerializerInterceptor) // Авто-очистка @Get() getUser() { return new UserEntity(data); } ``` -### 🚀 Solution +#### 🚀 Solution Используйте `@Exclude()` из `class-transformer` вместе с `ClassSerializerInterceptor` для скрытия полей. -## 29. Fastify Integration -### ❌ Bad Practice +### 🚨 29. Fastify Integration +#### ❌ Bad Practice // Вызов специфичных методов req.expressMethod -### ✅ Best Practice +#### ✅ Best Practice ```typescript const app = await NestFactory.create(AppModule, new FastifyAdapter()); ``` -### 🚀 Solution +#### 🚀 Solution Пишите платформо-независимый код. Если нужна экстремальная производительность, Nest легко переключается с Express на Fastify. -## 30. Shutdown Hooks (Graceful Shutdown) -### ❌ Bad Practice +### 🚨 30. Shutdown Hooks (Graceful Shutdown) +#### ❌ Bad Practice // Приложение убивается мгновенно, прерывая активные соединения -### ✅ Best Practice +#### ✅ Best Practice ```typescript app.enableShutdownHooks(); @Injectable() class MyService implements OnApplicationShutdown { onApplicationShutdown() { /* Закрыть соединения */ } } ``` -### 🚀 Solution +#### 🚀 Solution Вызывайте `enableShutdownHooks()`, чтобы отлавливать SIGINT/SIGTERM и безопасно завершать процессы базы данных. +--- +[⬆️ Back to Top](#) +
diff --git a/docs/vibe-coding-agents.md b/docs/vibe-coding-agents.md new file mode 100644 index 0000000..2d9dc03 --- /dev/null +++ b/docs/vibe-coding-agents.md @@ -0,0 +1,68 @@ +--- +description: Discover the best strategies and production-ready techniques for optimizing AI Agents and Vibe Coding workflows to generate clean, scalable code architectures seamlessly. +tags: [vibe coding, ai agents, production-ready, clean code, code generation, ai tools, architecture patterns, prompt engineering] +--- + +> 📦 [best-practise](../README.md) / 📄 [docs](./) + +# 🤖 Vibe Coding Agents: Production-Ready Automation + +## 1. 🎯 Context & Scope + +- **Primary Goal:** Guide engineers and AI agents on optimizing instruction sets to achieve deterministic, production-ready "Vibe Coding" results. +- **Target Tooling:** Cursor, Windsurf, GitHub Copilot, Antigravity IDE. +- **Tech Stack Version:** Agnostic + +> [!IMPORTANT] +> **Vibe Coding Integrity:** Never trust an AI Agent blindly. Always provide strict architectural constraints and explicit context. + +--- + +## 2. 🧠 The "Vibe Coding" Mindset + +Vibe Coding shifts the developer's role from writing syntax to managing logic and constraints. By establishing robust meta-instructions, you can direct AI Agents to implement features flawlessly on the first attempt. + +### 📊 Agent Capability Matrix + +| Agent Characteristic | Advantage in Vibe Coding | Drawback without Context | +| :--- | :--- | :--- | +| **Speed** | Extremely fast code generation. | May introduce untested, legacy APIs. | +| **Refactoring** | Excellent at large-scale structural changes. | Can overwrite existing business logic. | +| **Boilerplate** | Instant scaffolding of complex setups. | Prone to generic, non-scalable patterns. | + +--- + +## 3. 🗺️ Agent Execution Architecture + +To harness Vibe Coding effectively, integrate a defined execution pipeline. + +```mermaid +graph TD + UserIntent[🗣️ User Intent] --> ContextLayer[📂 Context Retrieval] + ContextLayer --> ConstraintCheck[🛡️ Architectural Constraints] + ConstraintCheck --> CodeGeneration[⚡ AI Generation] + CodeGeneration --> Validation[✅ Validation & Tests] + + %% Design Token Styles for Mermaid Diagrams + classDef default fill:#e1f5fe,stroke:#03a9f4,stroke-width:2px,color:#000; + classDef component fill:#e8f5e9,stroke:#4caf50,stroke-width:2px,color:#000; + classDef layout fill:#f3e5f5,stroke:#9c27b0,stroke-width:2px,color:#000; + + class CodeGeneration component; + class ContextLayer component; + class UserIntent default; + class ConstraintCheck layout; + class Validation component; +``` + +--- + +## 4. ✅ Actionable Checklist for Vibe Coding + +Before deploying AI Agents for production tasks, verify the following: + +- [ ] Ensure all prompts explicitly reference the required files or functions. +- [ ] Confirm that `.cursorrules` or `.windsurfrules` are active and updated. +- [ ] Restrict the agent's context window to prevent hallucination. +- [ ] Review the generated code specifically for memory leaks or unhandled exceptions. +- [ ] Always write a failing test before instructing the AI to implement the solution. diff --git a/frontend/angular/readme.md b/frontend/angular/readme.md index 546cdf7..794a2df 100644 --- a/frontend/angular/readme.md +++ b/frontend/angular/readme.md @@ -9,9 +9,9 @@ ai_role: Senior Angular Performance Expert last_updated: 2026-03-22 --- -# Angular Best Practices & Production-Ready Patterns +# 🅰️ Angular Best Practices & Production-Ready Patterns -# Context & Scope +## 🎯 Context & Scope - **Primary Goal:** Enforce strict adherence to modern Angular v20 patterns, specifically Zoneless reactivity and functional APIs for optimal best practices. - **Target Tooling:** Cursor, Windsurf, Antigravity. - **Tech Stack Version:** Angular 20 @@ -22,65 +22,65 @@ last_updated: 2026-03-22 > - **Never** use `@Input()` or `@Output()` decorators; strictly use `input()` and `output()` functional APIs. > - **Always** utilize the built-in control flow (`@if`, `@for`, `@switch`) instead of structural directives (`*ngIf`, `*ngFor`). -## I. Basics & Popular (1-15) +## 🚀 I. Basics & Popular (1-15) -## 1. Using `@Input()` Decorator +### 🚨 1. Using `@Input()` Decorator **Context:** Component Inputs -### ❌ Bad Practice +#### ❌ Bad Practice ```typescript @Input() title: string = ''; ``` -### ⚠️ Problem +#### ⚠️ Problem The `@Input()` decorator operates outside the Signals reactivity system. Changes are not tracked granularly, requiring checks of the entire component tree (Dirty Checking) via Zone.js. -### ✅ Best Practice +#### ✅ Best Practice ```typescript title = input(''); ``` -### 🚀 Solution +#### 🚀 Solution Use Signal Inputs (`input()`). This allows Angular to precisely know *which* specific component requires an update, paving the way for Zoneless applications. -## 2. Using `@Output()` Decorator +### 🚨 2. Using `@Output()` Decorator **Context:** Component Outputs -### ❌ Bad Practice +#### ❌ Bad Practice ```typescript @Output() save = new EventEmitter(); ``` -### ⚠️ Problem +#### ⚠️ Problem The classic `EventEmitter` adds an unnecessary layer of abstraction over RxJS Subject and does not integrate with the Angular functional API. -### ✅ Best Practice +#### ✅ Best Practice ```typescript save = output(); ``` -### 🚀 Solution +#### 🚀 Solution Use the `output()` function. It provides strict typing, better performance, and a unified API with Signal Inputs. -## 3. Two-Way Binding with `@Input()` and `@Output()` +### 🚨 3. Two-Way Binding with `@Input()` and `@Output()` **Context:** Model Synchronization -### ❌ Bad Practice +#### ❌ Bad Practice ```typescript @Input() value: string; @Output() valueChange = new EventEmitter(); ``` -### ⚠️ Problem +#### ⚠️ Problem Boilerplate code that is easy to break if you make a mistake in naming the `Change` event. -### ✅ Best Practice +#### ✅ Best Practice ```typescript value = model(); ``` -### 🚀 Solution +#### 🚀 Solution Use `model()`. This creates a Signal that can be both read and written to, automatically synchronizing its state with the parent. -## 4. Structural Directives (`*ngIf`, `*ngFor`) +### 🚨 4. Structural Directives (`*ngIf`, `*ngFor`) **Context:** Template Control Flow -### ❌ Bad Practice +#### ❌ Bad Practice ```html
  • {{ item }}
  • ``` -### ⚠️ Problem +#### ⚠️ Problem Directives require importing `CommonModule` or `NgIf/NgFor`, increasing bundle size. Micro-template syntax is complex for static analysis and type-checking. -### ✅ Best Practice +#### ✅ Best Practice ```html @if (isLoaded()) { @for (item of items(); track item.id) { @@ -90,48 +90,48 @@ Directives require importing `CommonModule` or `NgIf/NgFor`, increasing bundle s } ``` -### 🚀 Solution +#### 🚀 Solution Use the built-in Control Flow (`@if`, `@for`). It is built into the compiler, requires no imports, supports improved type-narrowing, and runs faster. -## 5. Subscribing in Components (Logic in `ngOnInit`) +### 🚨 5. Subscribing in Components (Logic in `ngOnInit`) **Context:** Data Fetching -### ❌ Bad Practice +#### ❌ Bad Practice ```typescript data: any; ngOnInit() { this.service.getData().subscribe(res => this.data = res); } ``` -### ⚠️ Problem +#### ⚠️ Problem Imperative subscriptions lead to memory leaks (if you forget to `unsubscribe`), "Callback Hell", and state desynchronization. Requires manual subscription management. -### ✅ Best Practice +#### ✅ Best Practice ```typescript data = toSignal(this.service.getData()); ``` -### 🚀 Solution +#### 🚀 Solution Use `toSignal()` to convert an Observable into a Signal. This automatically manages the subscription and integrates the data stream into the reactivity system. -## 6. `BehaviorSubject` for Local State +### 🚨 6. `BehaviorSubject` for Local State **Context:** Component State Management -### ❌ Bad Practice +#### ❌ Bad Practice ```typescript private count$ = new BehaviorSubject(0); getCount() { return this.count$.value; } ``` -### ⚠️ Problem +#### ⚠️ Problem RxJS is overkill for simple synchronous state. `BehaviorSubject` requires `.value` for access and `.next()` for writes, increasing cognitive load. -### ✅ Best Practice +#### ✅ Best Practice ```typescript count = signal(0); // Access: count() // Update: count.set(1) ``` -### 🚀 Solution +#### 🚀 Solution Use `signal()` for local state. It is a primitive designed specifically for synchronizing UI and data. -## 7. Derived State with `ngOnChanges` +### 🚨 7. Derived State with `ngOnChanges` **Context:** Reactivity -### ❌ Bad Practice +#### ❌ Bad Practice ```typescript ngOnChanges(changes: SimpleChanges) { if (changes['firstName']) { @@ -139,34 +139,34 @@ ngOnChanges(changes: SimpleChanges) { } } ``` -### ⚠️ Problem +#### ⚠️ Problem `ngOnChanges` is triggered only when Inputs change, has complex typing, and runs before View initialization. -### ✅ Best Practice +#### ✅ Best Practice ```typescript fullName = computed(() => `${this.firstName()} ${this.lastName()}`); ``` -### 🚀 Solution +#### 🚀 Solution Use `computed()`. The signal is recalculated *only* when its dependencies change, and the result is memoized (cached). -## 8. Constructor Dependency Injection +### 🚨 8. Constructor Dependency Injection **Context:** DI Pattern -### ❌ Bad Practice +#### ❌ Bad Practice ```typescript constructor(private http: HttpClient, private store: Store) {} ``` -### ⚠️ Problem +#### ⚠️ Problem Constructors become cluttered with many dependencies. When inheriting classes, dependencies must be passed through `super()`. -### ✅ Best Practice +#### ✅ Best Practice ```typescript private http = inject(HttpClient); private store = inject(Store); ``` -### 🚀 Solution +#### 🚀 Solution Use the `inject()` function. It operates in the initialization context (fields or constructor), is type-safe, and does not require `super()` during inheritance. -## 9. Modules (`NgModule`) +### 🚨 9. Modules (`NgModule`) **Context:** App Architecture -### ❌ Bad Practice +#### ❌ Bad Practice ```typescript @NgModule({ declarations: [AppComponent], @@ -174,221 +174,224 @@ Use the `inject()` function. It operates in the initialization context (fields o }) export class AppModule {} ``` -### ⚠️ Problem +#### ⚠️ Problem Modules create an unnecessary level of indirection. Components become dependent on the module context, complicating Lazy Loading and testing. -### ✅ Best Practice +#### ✅ Best Practice ```typescript @Component({ standalone: true, imports: [CommonModule] }) ``` -### 🚀 Solution +#### 🚀 Solution Use Standalone Components. This is the Angular v14+ standard that makes components self-sufficient and tree-shakable. -## 10. String-based Route Loading +### 🚨 10. String-based Route Loading **Context:** Lazy Loading Routing -### ❌ Bad Practice +#### ❌ Bad Practice ```typescript loadChildren: () => import('./module').then(m => m.UserModule) ``` -### ⚠️ Problem +#### ⚠️ Problem Loading modules pulls in transitive dependencies that might not be needed. -### ✅ Best Practice +#### ✅ Best Practice ```typescript loadComponent: () => import('./user.component').then(c => c.UserComponent) ``` -### 🚀 Solution +#### 🚀 Solution Use `loadComponent` for routing to Standalone components. This ensures minimal chunk size. -## 11. Heavy Logic in Templates +### 🚨 11. Heavy Logic in Templates **Context:** Template Performance -### ❌ Bad Practice +#### ❌ Bad Practice ```html
    {{ calculateTotal(items) }}
    ``` -### ⚠️ Problem +#### ⚠️ Problem The `calculateTotal` function is called during *every* Change Detection (CD) cycle, even if `items` have not changed. This kills UI performance. -### ✅ Best Practice +#### ✅ Best Practice ```typescript total = computed(() => this.calculateTotal(this.items())); ``` ```html
    {{ total() }}
    ``` -### 🚀 Solution +#### 🚀 Solution Extract logic into `computed()` signals or Pure Pipes. They are only executed when input data changes. -## 12. Manual Subscription Management (`takeUntil`) +### 🚨 12. Manual Subscription Management (`takeUntil`) **Context:** RxJS Memory Leaks -### ❌ Bad Practice +#### ❌ Bad Practice ```typescript destroy$ = new Subject(); ngOnDestroy() { this.destroy$.next(); } stream$.pipe(takeUntil(this.destroy$)).subscribe(); ``` -### ⚠️ Problem +#### ⚠️ Problem It's easy to forget `takeUntil` or `unsubscribe`. Requires a lot of boilerplate code in every component. -### ✅ Best Practice +#### ✅ Best Practice ```typescript stream$.pipe(takeUntilDestroyed()).subscribe(); ``` -### 🚀 Solution +#### 🚀 Solution Use the `takeUntilDestroyed()` operator. It automatically unsubscribes upon context destruction (component, directive, service). -## 13. Deeply Nested Components Passing Data +### 🚨 13. Deeply Nested Components Passing Data **Context:** Prop Drilling -### ❌ Bad Practice +#### ❌ Bad Practice ```html ``` -### ⚠️ Problem +#### ⚠️ Problem "Prop drilling" heavily couples intermediate components to data they don't need, just for the sake of passing it deeper. -### ✅ Best Practice +#### ✅ Best Practice ```typescript // Service theme = signal('dark'); // Grandchild theme = inject(ThemeService).theme; ``` -### 🚀 Solution +#### 🚀 Solution Use Signal Stores or services for state sharing, or the new `input()` API with context inheritance (in the future). -## 14. Accessing DOM directly (`ElementRef.nativeElement`) +### 🚨 14. Accessing DOM directly (`ElementRef.nativeElement`) **Context:** Security & Abstraction -### ❌ Bad Practice +#### ❌ Bad Practice ```typescript el.nativeElement.style.backgroundColor = 'red'; ``` -### ⚠️ Problem +#### ⚠️ Problem Direct DOM access breaks abstraction (doesn't work in SSR/Web Workers) and opens up XSS vulnerabilities. It bypasses Angular Sanitization mechanisms. -### ✅ Best Practice +#### ✅ Best Practice ```typescript // Use Renderer2 or bindings
    ``` -### 🚀 Solution +#### 🚀 Solution Use style/class bindings or `Renderer2`. For direct manipulations, consider directives. -## 15. Zone.js overhead +### 🚨 15. Zone.js overhead **Context:** Change Detection -### ❌ Bad Practice +#### ❌ Bad Practice The application relies on Zone.js for any asynchronous event (setTimeout, Promise, XHR). -### ⚠️ Problem +#### ⚠️ Problem Zone.js patches all browser APIs, adding overhead and increasing bundle size. CD triggers more often than necessary. -### ✅ Best Practice +#### ✅ Best Practice ```typescript bootstrapApplication(App, { providers: [provideExperimentalZonelessChangeDetection()] }); ``` -### 🚀 Solution +#### 🚀 Solution Migrate to Zoneless mode. Use Signals to notify Angular when a re-render is needed. --- +--- +[⬆️ Back to Top](#) + ## II. Architecture & DI (16-30) -## 16. Services provided in 'root' vs Modules +### 🚨 16. Services provided in 'root' vs Modules **Context:** Tree Shaking -### ❌ Bad Practice +#### ❌ Bad Practice ```typescript @NgModule({ providers: [MyService] }) ``` -### ⚠️ Problem +#### ⚠️ Problem The service is included in the bundle even if it is not used. -### ✅ Best Practice +#### ✅ Best Practice ```typescript @Injectable({ providedIn: 'root' }) ``` -### 🚀 Solution +#### 🚀 Solution Always use `providedIn: 'root'`. This allows the bundler to remove unused services (Tree Shaking). -## 17. Class-based Guards +### 🚨 17. Class-based Guards **Context:** Routing Security -### ❌ Bad Practice +#### ❌ Bad Practice ```typescript @Injectable() export class AuthGuard implements CanActivate { ... } ``` -### ⚠️ Problem +#### ⚠️ Problem Class-based guards require more code and injections. They are less flexible for composition. -### ✅ Best Practice +#### ✅ Best Practice ```typescript export const authGuard: CanActivateFn = (route, state) => { return inject(AuthService).isLoggedIn(); }; ``` -### 🚀 Solution +#### 🚀 Solution Use functional Guards (`CanActivateFn`). They are concise, easy to test, and composable. -## 18. Class-based Interceptors +### 🚨 18. Class-based Interceptors **Context:** HTTP Requests -### ❌ Bad Practice +#### ❌ Bad Practice ```typescript @Injectable() export class TokenInterceptor implements HttpInterceptor { ... } ``` -### ⚠️ Problem +#### ⚠️ Problem Similar to guards: lots of boilerplate, complex registration in the providers array. -### ✅ Best Practice +#### ✅ Best Practice ```typescript export const tokenInterceptor: HttpInterceptorFn = (req, next) => { const token = inject(AuthService).token(); return next(req.clone({ setHeaders: { Authorization: token } })); }; ``` -### 🚀 Solution +#### 🚀 Solution Use functional Interceptors (`HttpInterceptorFn`) with `provideHttpClient(withInterceptors([...]))`. -## 19. State Mutation in Services +### 🚨 19. State Mutation in Services **Context:** Data Integrity -### ❌ Bad Practice +#### ❌ Bad Practice ```typescript updateUser(user: User) { this.currentUser = user; // Mutable assignment } ``` -### ⚠️ Problem +#### ⚠️ Problem Object mutations complicate change tracking and can lead to unpredictable behavior in components using the `OnPush` strategy. -### ✅ Best Practice +#### ✅ Best Practice ```typescript currentUser = signal(null); updateUser(user: User) { this.currentUser.set({ ...user }); // Immutable update } ``` -### 🚀 Solution +#### 🚀 Solution Use Signals for state management. They guarantee reactivity and atomicity of updates. -## 20. Calling functions inside `@for` tracking +### 🚨 20. Calling functions inside `@for` tracking **Context:** Rendering Performance -### ❌ Bad Practice +#### ❌ Bad Practice ```html @for (item of items; track getItemId(item)) ``` -### ⚠️ Problem +#### ⚠️ Problem The tracking function is called for each element during every re-render. -### ✅ Best Practice +#### ✅ Best Practice ```html @for (item of items; track item.id) ``` -### 🚀 Solution +#### 🚀 Solution Use an object property (ID or a unique key) directly. If a function is needed, it must be as simple and pure as possible. -## 21. `host` property vs `@HostListener` +### 🚨 21. `host` property vs `@HostListener` **Context:** Component Metadata -### ❌ Bad Practice +#### ❌ Bad Practice ```typescript @HostListener('click') onClick() { ... } @HostBinding('class.active') isActive = true; ``` -### ⚠️ Problem +#### ⚠️ Problem Decorators increase class size and scatter host configuration across the file. -### ✅ Best Practice +#### ✅ Best Practice ```typescript @Component({ host: { @@ -397,146 +400,149 @@ Decorators increase class size and scatter host configuration across the file. } }) ``` -### 🚀 Solution +#### 🚀 Solution Use the `host` property in component metadata. This centralizes all host element settings. -## 22. Dynamic Components with `ComponentFactoryResolver` +### 🚨 22. Dynamic Components with `ComponentFactoryResolver` **Context:** Dynamic Rendering -### ❌ Bad Practice +#### ❌ Bad Practice ```typescript const factory = this.resolver.resolveComponentFactory(MyComponent); this.container.createComponent(factory); ``` -### ⚠️ Problem +#### ⚠️ Problem `ComponentFactoryResolver` is deprecated. It is an old imperative API. -### ✅ Best Practice +#### ✅ Best Practice ```typescript this.container.createComponent(MyComponent); // Or strictly in template ``` -### 🚀 Solution +#### 🚀 Solution Use `ViewContainerRef.createComponent` directly with the component class or the `ngComponentOutlet` directive. -## 23. Shared Modules (The "Dump" Module) +### 🚨 23. Shared Modules (The "Dump" Module) **Context:** Modular Architecture -### ❌ Bad Practice +#### ❌ Bad Practice `SharedModule` imports and exports *all* UI components, pipes, and directives. -### ⚠️ Problem +#### ⚠️ Problem If a component needs a single button, it is forced to pull the entire `SharedModule`. This breaks Tree Shaking and increases the initial bundle size. -### ✅ Best Practice +#### ✅ Best Practice Import only what is needed directly into the `imports` of the Standalone component. -### 🚀 Solution +#### 🚀 Solution Abandon `SharedModule` in favor of granular imports of Standalone entities. -## 24. Circular Dependencies in DI +### 🚨 24. Circular Dependencies in DI **Context:** Architecture -### ❌ Bad Practice +#### ❌ Bad Practice Service A injects Service B, which injects Service A. -### ⚠️ Problem +#### ⚠️ Problem Leads to runtime errors ("Cannot instantiate cyclic dependency"). Indicates poor architectural design. -### ✅ Best Practice +#### ✅ Best Practice Use `forwardRef()` as a crutch, but it's better to extract the shared logic into a third Service C. -### 🚀 Solution +#### 🚀 Solution Refactoring: break services into smaller ones following SRP (Single Responsibility Principle). -## 25. Logic in Pipes +### 🚨 25. Logic in Pipes **Context:** Separation of Concerns -### ❌ Bad Practice +#### ❌ Bad Practice A Pipe performs HTTP requests or complex business logic. -### ⚠️ Problem +#### ⚠️ Problem Pipes are intended for data transformation in the template. Side effects in pipes violate function purity and kill CD performance. -### ✅ Best Practice +#### ✅ Best Practice Pipes should be "Pure" (without side effects) and fast. -### 🚀 Solution +#### 🚀 Solution Extract logic into services/signals. Leave only formatting to pipes. -## 26. `any` in Services +### 🚨 26. `any` in Services **Context:** TypeScript Safety -### ❌ Bad Practice +#### ❌ Bad Practice ```typescript getData(): Observable { ... } ``` -### ⚠️ Problem +#### ⚠️ Problem `any` disables type checking, nullifying the benefits of TypeScript. Errors only surface at runtime. -### ✅ Best Practice +#### ✅ Best Practice ```typescript getData(): Observable { ... } ``` -### 🚀 Solution +#### 🚀 Solution Use DTO interfaces (generate them from Swagger/OpenAPI) and Zod for API response validation. -## 27. Multiple `async` pipes for same stream +### 🚨 27. Multiple `async` pipes for same stream **Context:** RxJS Subscriptions -### ❌ Bad Practice +#### ❌ Bad Practice ```html
    {{ (user$ | async).name }}
    ``` -### ⚠️ Problem +#### ⚠️ Problem Each `async` pipe creates a new subscription. This can lead to duplicated HTTP requests. -### ✅ Best Practice +#### ✅ Best Practice ```html @if (user$ | async; as user) {
    {{ user.name }}
    } ``` -### 🚀 Solution +#### 🚀 Solution Use aliases in the template (`as varName`) or convert the stream to a signal (`toSignal`). -## 28. ProvidedIn 'any' +### 🚨 28. ProvidedIn 'any' **Context:** DI Scopes -### ❌ Bad Practice +#### ❌ Bad Practice ```typescript @Injectable({ providedIn: 'any' }) ``` -### ⚠️ Problem +#### ⚠️ Problem Creates a new service instance for each lazy-loaded module. This is often unexpected behavior, leading to state desynchronization (different singleton instances). -### ✅ Best Practice +#### ✅ Best Practice `providedIn: 'root'` or providing at the level of a specific component (`providers: []`). -### 🚀 Solution +#### 🚀 Solution Avoid `any`. Explicitly control the scope: either global (`root`) or local. -## 29. Imperative Routing +### 🚨 29. Imperative Routing **Context:** Navigation -### ❌ Bad Practice +#### ❌ Bad Practice ```typescript this.router.navigateByUrl('/users/' + id); ``` -### ⚠️ Problem +#### ⚠️ Problem Hardcoding route strings makes route refactoring a pain. -### ✅ Best Practice +#### ✅ Best Practice ```typescript this.router.navigate(['users', id]); ``` -### 🚀 Solution +#### 🚀 Solution Use an array of segments. It is safer (automatic encoding of URL parameters) and cleaner. -## 30. Ignoring `OnPush` Strategy +### 🚨 30. Ignoring `OnPush` Strategy **Context:** Change Detection Strategy -### ❌ Bad Practice +#### ❌ Bad Practice Default components (`ChangeDetectionStrategy.Default`). -### ⚠️ Problem +#### ⚠️ Problem Angular checks this component on *every* app event, even if the component data hasn't changed. -### ✅ Best Practice +#### ✅ Best Practice ```typescript changeDetection: ChangeDetectionStrategy.OnPush ``` -### 🚀 Solution +#### 🚀 Solution Always set `OnPush`. With signals, this becomes the de facto standard, as updates occur precisely. --- +--- +[⬆️ Back to Top](#) + ## III. Advanced Performance (31-45) -## 31. Eager Loading of Heavy Components +### 🚨 31. Eager Loading of Heavy Components **Context:** Bundle Size -### ❌ Bad Practice +#### ❌ Bad Practice ```html ``` -### ⚠️ Problem +#### ⚠️ Problem A charting library (e.g., ECharts) loads immediately, blocking TTI (Time to Interactive), even if the chart is below the "fold". -### ✅ Best Practice +#### ✅ Best Practice ```html @defer (on viewport) { @@ -544,315 +550,321 @@ A charting library (e.g., ECharts) loads immediately, blocking TTI (Time to Inte
    Loading chart...
    } ``` -### 🚀 Solution +#### 🚀 Solution Use `@defer`. This defers component code loading until a trigger occurs (viewport, interaction, timer). -## 32. Heavy Computation in Main Thread +### 🚨 32. Heavy Computation in Main Thread **Context:** Event Loop Blocking -### ❌ Bad Practice +#### ❌ Bad Practice Sorting an array of 100k elements directly in the component. -### ⚠️ Problem +#### ⚠️ Problem Freezes the UI. -### ✅ Best Practice +#### ✅ Best Practice Offload computations to a Web Worker. -### 🚀 Solution +#### 🚀 Solution Use Angular Web Workers. In v20, this is easily configured via the CLI. -## 33. Memory Leaks in `effect()` +### 🚨 33. Memory Leaks in `effect()` **Context:** Signal Effects -### ❌ Bad Practice +#### ❌ Bad Practice ```typescript effect(() => { const timer = setInterval(() => ..., 1000); // No cleanup }); ``` -### ⚠️ Problem +#### ⚠️ Problem Effects restart when dependencies change. If you don't clean up timers/subscriptions inside an effect, they accumulate. -### ✅ Best Practice +#### ✅ Best Practice ```typescript effect((onCleanup) => { const timer = setInterval(() => ..., 1000); onCleanup(() => clearInterval(timer)); }); ``` -### 🚀 Solution +#### 🚀 Solution Always use the `onCleanup` callback to release resources. -## 34. Excessive Change Detection with `NgZone.run()` +### 🚨 34. Excessive Change Detection with `NgZone.run()` **Context:** Zone Integration -### ❌ Bad Practice +#### ❌ Bad Practice Wrapping third-party libraries in `ngZone.run()` unnecessarily. -### ⚠️ Problem +#### ⚠️ Problem Forces redundant checks of the entire component tree. -### ✅ Best Practice +#### ✅ Best Practice ```typescript ngZone.runOutsideAngular(() => { // Heavy chart rendering or canvas animation }); ``` -### 🚀 Solution +#### 🚀 Solution Run frequent events (scroll, mousemove, animationFrame) *outside* the Angular zone. Update signals only when UI updates are required. -## 35. Signals equality check default +### 🚨 35. Signals equality check default **Context:** Signal Performance -### ❌ Bad Practice +#### ❌ Bad Practice ```typescript data = signal({ id: 1 }, { equal: undefined }); // Default checks reference ``` -### ⚠️ Problem +#### ⚠️ Problem If you create a new object with the same data `{ id: 1 }`, the signal triggers an update, even though the data hasn't fundamentally changed. -### ✅ Best Practice +#### ✅ Best Practice ```typescript import { isEqual } from 'lodash-es'; data = signal(obj, { equal: isEqual }); ``` -### 🚀 Solution +#### 🚀 Solution Use a custom comparison function for complex objects to avoid redundant re-renders. -## 36. Lacking `trackBy` in iterables +### 🚨 36. Lacking `trackBy` in iterables **Context:** Re-rendering Lists -### ❌ Bad Practice +#### ❌ Bad Practice ```html
  • {{ item }}
  • ``` -### ⚠️ Problem +#### ⚠️ Problem Without tracking, any array change leads to the recreation of all DOM nodes in the list. $O(n)$ DOM operations. -### ✅ Best Practice +#### ✅ Best Practice ```html @for (item of items; track item.id) ``` -### 🚀 Solution +#### 🚀 Solution Always use a unique key in `track`. This allows Angular to move DOM nodes instead of recreating them. -## 37. Recursive Template without Caching +### 🚨 37. Recursive Template without Caching **Context:** Tree Rendering -### ❌ Bad Practice +#### ❌ Bad Practice Recursive component call without `OnPush` and memoization. -### ⚠️ Problem +#### ⚠️ Problem Exponential growth in change detection checks. -### ✅ Best Practice +#### ✅ Best Practice Using the `Memoization` pattern or `computed()` to prepare the tree data structure. -## 38. Global Styles Leakage +### 🚨 38. Global Styles Leakage **Context:** CSS Encapsulation -### ❌ Bad Practice +#### ❌ Bad Practice ```css /* global.css */ button { padding: 10px; } ``` -### ⚠️ Problem +#### ⚠️ Problem Global styles unpredictably affect components. -### ✅ Best Practice +#### ✅ Best Practice Use `ViewEncapsulation.Emulated` (default) and specific selectors. -### 🚀 Solution +#### 🚀 Solution Keep styles locally within components. -## 39. Large Component Bundle +### 🚨 39. Large Component Bundle **Context:** Split Chunks -### ❌ Bad Practice +#### ❌ Bad Practice A single huge component of 3000 lines. -### ⚠️ Problem +#### ⚠️ Problem Poor readability, rendering lazy loading of UI parts impossible. -### ✅ Best Practice +#### ✅ Best Practice Decompose into "dumb" (UI) and "smart" components. -### 🚀 Solution +#### 🚀 Solution Break down the UI into small, reusable blocks. -## 40. Image Optimization Ignorance +### 🚨 40. Image Optimization Ignorance **Context:** Core Web Vitals (LCP) -### ❌ Bad Practice +#### ❌ Bad Practice ```html ``` -### ⚠️ Problem +#### ⚠️ Problem The browser loads the full image, shifting the layout (CLS). -### ✅ Best Practice +#### ✅ Best Practice ```html ``` -### 🚀 Solution +#### 🚀 Solution Use the `NgOptimizedImage` directive. It automatically handles lazy loading, preconnect, and srcset. -## 41. Hydration Mismatch +### 🚨 41. Hydration Mismatch **Context:** SSR / SSG -### ❌ Bad Practice +#### ❌ Bad Practice Rendering `Date.now()` or random numbers (`Math.random()`) directly in the template. -### ⚠️ Problem +#### ⚠️ Problem The server generates one number, the client another. This causes "flickering" and a hydration error; Angular discards the server DOM and renders from scratch. -### ✅ Best Practice +#### ✅ Best Practice Use stable data or defer random generation until `afterNextRender`. -### 🚀 Solution +#### 🚀 Solution Pay attention to template determinism with SSR. -## 42. Synchronous `inject()` inside loops +### 🚨 42. Synchronous `inject()` inside loops **Context:** DI Performance -### ❌ Bad Practice +#### ❌ Bad Practice Calling `inject()` inside a function that loops. -### ⚠️ Problem +#### ⚠️ Problem Although `inject` is fast, in hot paths these are unnecessary DI tree lookups. -### ✅ Best Practice +#### ✅ Best Practice Inject dependency once at the class/file constant level. -## 43. Unused Signal Dependencies +### 🚨 43. Unused Signal Dependencies **Context:** Signal Graph -### ❌ Bad Practice +#### ❌ Bad Practice Reading a signal inside `computed` whose value doesn't affect the result (an unexecuted logical branch). -### ⚠️ Problem +#### ⚠️ Problem Angular dynamically builds the dependency graph. If you accidentally read a signal, it becomes a dependency. -### ✅ Best Practice +#### ✅ Best Practice Use `untracked()` to read signals whose changes should not trigger a recalculation. -## 44. Excessive Wrappers (`div` soup) +### 🚨 44. Excessive Wrappers (`div` soup) **Context:** DOM Size -### ❌ Bad Practice +#### ❌ Bad Practice ```html
    ``` -### ⚠️ Problem +#### ⚠️ Problem Increases DOM tree depth, slowing down Style Recalculation and Layout. -### ✅ Best Practice +#### ✅ Best Practice Use `` to group elements without creating extra DOM nodes. -## 45. Neglecting `runOutsideAngular` for Events +### 🚨 45. Neglecting `runOutsideAngular` for Events **Context:** High-frequency events -### ❌ Bad Practice +#### ❌ Bad Practice `@HostListener('window:scroll')` -### ⚠️ Problem +#### ⚠️ Problem Every scroll event triggers Change Detection. -### ✅ Best Practice +#### ✅ Best Practice Subscribe manually in `runOutsideAngular` and update the signal only when necessary. --- +--- +[⬆️ Back to Top](#) + ## IV. Data & Forms (46-55) -## 46. Template-Driven Forms without Types +### 🚨 46. Template-Driven Forms without Types **Context:** Form Safety -### ❌ Bad Practice +#### ❌ Bad Practice `[(ngModel)]` without strict model typing. -### ⚠️ Problem +#### ⚠️ Problem Risk of assigning a string to a numeric field. -### ✅ Best Practice +#### ✅ Best Practice Use Reactive Forms with `FormControl` typing or new Signal-based Forms (when out of developer preview). -## 47. Untyped `FormGroup` +### 🚨 47. Untyped `FormGroup` **Context:** Reactive Forms -### ❌ Bad Practice +#### ❌ Bad Practice ```typescript const form = new FormGroup({ ... }); // Untyped ``` -### ⚠️ Problem +#### ⚠️ Problem `form.value` returns `any`. -### ✅ Best Practice +#### ✅ Best Practice ```typescript const form = new FormGroup({ email: new FormControl('', { nonNullable: true }), ... }); ``` -### 🚀 Solution +#### 🚀 Solution Always type forms. Use `nonNullable: true` to avoid `string | undefined` hell. -## 48. Subscribe inside Subscribe +### 🚨 48. Subscribe inside Subscribe **Context:** RxJS Patterns -### ❌ Bad Practice +#### ❌ Bad Practice ```typescript this.route.params.subscribe(params => { this.api.getUser(params.id).subscribe(user => ...); }); ``` -### ⚠️ Problem +#### ⚠️ Problem Classic Race Condition. If parameters change rapidly, response order is not guaranteed. -### ✅ Best Practice +#### ✅ Best Practice ```typescript this.route.params.pipe( switchMap(params => this.api.getUser(params.id)) ).subscribe(); ``` -### 🚀 Solution +#### 🚀 Solution Use Flattening Operators (`switchMap`, `concatMap`, `mergeMap`). -## 49. Ignoring `AbortSignal` in HTTP +### 🚨 49. Ignoring `AbortSignal` in HTTP **Context:** Network Efficiency -### ❌ Bad Practice +#### ❌ Bad Practice Ignoring request cancellation when navigating away from the page. -### ⚠️ Problem +#### ⚠️ Problem Requests continue hanging, consuming traffic. -### ✅ Best Practice +#### ✅ Best Practice HttpClient automatically supports cancellation upon unsubscription. With signals: ensure `rxResource` or the effect correctly cancels the request. -## 50. Mutating Inputs directly +### 🚨 50. Mutating Inputs directly **Context:** Unidirectional Data Flow -### ❌ Bad Practice +#### ❌ Bad Practice ```typescript this.inputData.push(newItem); ``` -### ⚠️ Problem +#### ⚠️ Problem The parent component remains unaware of the change. Violates the One-Way Data Flow principle. -### ✅ Best Practice +#### ✅ Best Practice Emit event (`output`) upwards; the parent changes the data and passes the new object downwards. -## 51. `ngModel` inside Reactive Form +### 🚨 51. `ngModel` inside Reactive Form **Context:** Form Mixing -### ❌ Bad Practice +#### ❌ Bad Practice Using `formControlName` and `[(ngModel)]` on the same input. -### ⚠️ Problem +#### ⚠️ Problem Deprecated behavior. Causes form and model synchronization conflicts. -### ✅ Best Practice +#### ✅ Best Practice Use only one approach: either Reactive or Template-driven. -## 52. Complex Validators in Template +### 🚨 52. Complex Validators in Template **Context:** Form Logic -### ❌ Bad Practice +#### ❌ Bad Practice Validation via HTML attributes for complex logic. -### ⚠️ Problem +#### ⚠️ Problem Hard to test, no reusability. -### ✅ Best Practice +#### ✅ Best Practice Custom Validator Functions or Async Validators in the component class. -## 53. Forgetting `updateOn: 'blur'` +### 🚨 53. Forgetting `updateOn: 'blur'` **Context:** Performance -### ❌ Bad Practice +#### ❌ Bad Practice Validating a complex field on every keystroke (`change`). -### ⚠️ Problem +#### ⚠️ Problem Slows down user input. -### ✅ Best Practice +#### ✅ Best Practice ```typescript new FormControl('', { updateOn: 'blur' }); ``` -### 🚀 Solution +#### 🚀 Solution Trigger validation/update only when the user has finished typing. -## 54. Not handling API Errors +### 🚨 54. Not handling API Errors **Context:** UX -### ❌ Bad Practice +#### ❌ Bad Practice `.subscribe(data => ...)` without an error callback. -### ⚠️ Problem +#### ⚠️ Problem On a 500 error, the application "hangs" in a loading state. -### ✅ Best Practice +#### ✅ Best Practice Global Error Handler or `catchError` in the pipe returning a safe value. -## 55. Hardcoded API URLs +### 🚨 55. Hardcoded API URLs **Context:** Maintainability -### ❌ Bad Practice +#### ❌ Bad Practice `http.get('https://api.com/users')` -### ⚠️ Problem +#### ⚠️ Problem Inability to switch environments (dev/prod). -### ✅ Best Practice +#### ✅ Best Practice Using InjectionToken `API_URL` and environment configuration. --- +--- +[⬆️ Back to Top](#) + ## V. Expert/Niche (56-60) -## 56. `untracked()` usage +### 🚨 56. `untracked()` usage **Context:** Fine-grained Reactivity -### ❌ Bad Practice +#### ❌ Bad Practice Accidentally creating a cyclic dependency in `computed`. -### ⚠️ Problem +#### ⚠️ Problem `Error: Detected cycle in computations`. -### ✅ Best Practice +#### ✅ Best Practice ```typescript computed(() => { const user = this.user(); @@ -860,57 +872,60 @@ computed(() => { return user.name; }); ``` -### 🚀 Solution +#### 🚀 Solution Use `untracked()` for side effects or reads that shouldn't affect recalculation. -## 57. V8 Hidden Classes Optimization +### 🚨 57. V8 Hidden Classes Optimization **Context:** Micro-optimization -### ❌ Bad Practice +#### ❌ Bad Practice ```typescript user = signal({}); // later user.set({ name: 'A', age: 10 }); // Shape change ``` -### ⚠️ Problem +#### ⚠️ Problem Initializing with an empty object and later adding fields changes the object "shape" (Hidden Class), breaking V8 JIT compiler optimization. -### ✅ Best Practice +#### ✅ Best Practice ```typescript interface User { name: string | null; age: number | null; } user = signal({ name: null, age: null }); ``` -### 🚀 Solution +#### 🚀 Solution Always initialize signals with the full object shape (even with null) to preserve property access monomorphism. -## 58. Signal Glitch Freedom abuse +### 🚨 58. Signal Glitch Freedom abuse **Context:** Reactivity Theory -### ❌ Bad Practice +#### ❌ Bad Practice Relying on `effect` to fire synchronously. -### ⚠️ Problem +#### ⚠️ Problem Signals guarantee "Glitch Freedom" (absence of intermediate inconsistent states), but effects are asynchronous (microtask timing). -### ✅ Best Practice +#### ✅ Best Practice Do not use effects to synchronize local state. Use `computed`. -## 59. Memory leaks in `root` Effects +### 🚨 59. Memory leaks in `root` Effects **Context:** Application Lifecycle -### ❌ Bad Practice +#### ❌ Bad Practice Creating an effect in a service without `manualCleanup`. -### ⚠️ Problem +#### ⚠️ Problem Effects in `root` services live forever. If they subscribe to something global, it can leak. -### ✅ Best Practice +#### ✅ Best Practice Usually fine, but if the service is destroyed (rare lazy loading case), the effect must be cleaned up with `effectRef.destroy()`. -## 60. `runInInjectionContext` +### 🚨 60. `runInInjectionContext` **Context:** Advanced DI -### ❌ Bad Practice +#### ❌ Bad Practice Passing an `Injector` instance manually into functions. -### ⚠️ Problem +#### ⚠️ Problem Bulky code. -### ✅ Best Practice +#### ✅ Best Practice ```typescript runInInjectionContext(this.injector, () => { // can use inject() here dynamically const service = inject(MyService); }); ``` -### 🚀 Solution +#### 🚀 Solution Use this helper to execute functions requiring a DI context outside the constructor/initialization. + +--- +[⬆️ Back to Top](#) diff --git a/frontend/javascript/readme.md b/frontend/javascript/readme.md index 7471a9c..33c7d00 100644 --- a/frontend/javascript/readme.md +++ b/frontend/javascript/readme.md @@ -13,11 +13,14 @@ last_updated: 2026-03-22 ![JavaScript Logo](https://img.icons8.com/?size=100&id=108784&format=png&color=000000) +--- +[⬆️ Back to Top](#) + ## I. Fundamentals (The Basics) -## 1. `var` vs `const/let` +### 🚨 1. `var` vs `const/let` **Context:** Scoping and hoisting mechanisms in modern JavaScript. `var` is function-scoped and hoisted, leading to unpredictable behavior and accidental global leakage. -### ❌ Bad Practice +#### ❌ Bad Practice ```javascript var price = 100; if (true) { @@ -25,9 +28,9 @@ if (true) { } console.log(price); // 200 ``` -### ⚠️ Problem +#### ⚠️ Problem `var` does not respect block scope. Its hoisting behavior allows variables to be accessed before declaration (as `undefined`), which bypasses the Temporal Dead Zone (TDZ) safety mechanism, increasing cognitive load and bug density. -### ✅ Best Practice +#### ✅ Best Practice ```javascript const price = 100; if (true) { @@ -35,39 +38,39 @@ if (true) { } console.log(price); // 100 ``` -### 🚀 Solution +#### 🚀 Solution Use `const` by default to ensure immutability of the reference. Use `let` only when reassigning a variable is strictly necessary. This enforces block-level scoping and prevents accidental overrides. -## 2. Loose equality `==` +### 🚨 2. Loose equality `==` **Context:** JavaScript's type coercion rules are complex and often counter-intuitive. -### ❌ Bad Practice +#### ❌ Bad Practice ```javascript if (userCount == '0') { // Executes if userCount is 0 (number) or '0' (string) } ``` -### ⚠️ Problem +#### ⚠️ Problem The Abstract Equality Comparison Algorithm (`==`) performs implicit type conversion. This leads to edge cases like `[] == ![]` being `true` or `0 == ''` being `true`, which can cause silent logic failures. -### ✅ Best Practice +#### ✅ Best Practice ```javascript if (userCount === 0) { // Strict comparison } ``` -### 🚀 Solution +#### 🚀 Solution Always use strict equality `===` and inequality `!==`. This forces the developer to handle type conversions explicitly, making the code's intent clear and predictable. -## 3. Global Scope Pollution +### 🚨 3. Global Scope Pollution **Context:** The global namespace is shared. Overwriting global properties can break third-party libraries or browser APIs. -### ❌ Bad Practice +#### ❌ Bad Practice ```javascript // In a script file const config = { api: '/v1' }; function init() { /* ... */ } ``` -### ⚠️ Problem +#### ⚠️ Problem Variables declared in the top-level scope of a non-module script are attached to `window` (in browsers) or `global` (in Node). This increases the risk of name collisions and memory leaks. -### ✅ Best Practice +#### ✅ Best Practice ```javascript // use modules export const config = { api: '/v1' }; @@ -77,37 +80,37 @@ export const config = { api: '/v1' }; const config = { api: '/v1' }; })(); ``` -### 🚀 Solution +#### 🚀 Solution Use ES Modules (`import/export`) to encapsulate code. Modules have their own scope and do not leak to the global object. -## 4. String concatenation vs Template Literals +### 🚨 4. String concatenation vs Template Literals **Context:** Readability and handling of multi-line strings/expressions. -### ❌ Bad Practice +#### ❌ Bad Practice ```javascript const greeting = 'Hello, ' + user.firstName + ' ' + user.lastName + '! ' + 'Welcome to ' + siteName + '.'; ``` -### ⚠️ Problem +#### ⚠️ Problem Concatenation with `+` is error-prone, hard to read, and difficult to maintain for multi-line strings. It often leads to missing spaces and poor visual structure. -### ✅ Best Practice +#### ✅ Best Practice ```javascript const greeting = `Hello, ${user.firstName} ${user.lastName}! Welcome to ${siteName}.`; ``` -### 🚀 Solution +#### 🚀 Solution Use Template Literals (backticks). They allow for embedded expressions, multi-line strings, and superior readability. -## 5. Magic Numbers +### 🚨 5. Magic Numbers **Context:** Numbers with no context make the codebase hard to maintain. -### ❌ Bad Practice +#### ❌ Bad Practice ```javascript if (user.age >= 18) { grantAccess(); } ``` -### ⚠️ Problem +#### ⚠️ Problem "18" is a magic number. If the legal age changes, you must find and replace every instance, risking errors if the same number is used for different contexts elsewhere. -### ✅ Best Practice +#### ✅ Best Practice ```javascript const LEGAL_AGE = 18; @@ -115,53 +118,53 @@ if (user.age >= LEGAL_AGE) { grantAccess(); } ``` -### 🚀 Solution +#### 🚀 Solution Extract magic numbers into named constants. This provides semantic meaning and a single source of truth for configuration. -## 6. Boolean comparisons `(if x === true)` +### 🚨 6. Boolean comparisons `(if x === true)` **Context:** Redundancy in conditional logic. -### ❌ Bad Practice +#### ❌ Bad Practice ```javascript if (isValid === true) { /* ... */ } ``` -### ⚠️ Problem +#### ⚠️ Problem Comparing a boolean to `true` or `false` is redundant. It adds visual noise without increasing safety. -### ✅ Best Practice +#### ✅ Best Practice ```javascript if (isValid) { /* ... */ } if (!isPending) { /* ... */ } ``` -### 🚀 Solution +#### 🚀 Solution Leverage JavaScript's truthiness/falsiness or direct boolean evaluation. It makes the code more concise and idiomatic. -## 7. Array/Object literal vs `new` constructor +### 🚨 7. Array/Object literal vs `new` constructor **Context:** Object and Array instantiation. -### ❌ Bad Practice +#### ❌ Bad Practice ```javascript const list = new Array(1, 2, 3); const map = new Object(); ``` -### ⚠️ Problem +#### ⚠️ Problem The `Array` constructor is inconsistent: `new Array(3)` creates an empty array of length 3, while `new Array(3, 4)` creates `[3, 4]`. Literals are faster and more readable. -### ✅ Best Practice +#### ✅ Best Practice ```javascript const list = [1, 2, 3]; const map = {}; ``` -### 🚀 Solution +#### 🚀 Solution Use literals `[]` and `{}`. They are visually cleaner and perform slightly better as they don't involve a function call. -## 8. Function length/complexity +### 🚨 8. Function length/complexity **Context:** The Single Responsibility Principle (SRP). -### ❌ Bad Practice +#### ❌ Bad Practice ```javascript function processOrder(order) { // 100 lines of validation, DB saving, email sending... } ``` -### ⚠️ Problem +#### ⚠️ Problem Large functions are hard to test, debug, and reuse. High cyclomatic complexity makes it difficult for the JIT compiler to optimize the function. -### ✅ Best Practice +#### ✅ Best Practice ```javascript function validateOrder(order) { /* ... */ } function saveToDatabase(order) { /* ... */ } @@ -173,12 +176,12 @@ function processOrder(order) { notifyUser(order); } ``` -### 🚀 Solution +#### 🚀 Solution Break functions into smaller, pure components. Aim for functions under 20 lines that do exactly one thing. -## 9. Deeply nested `if/else` (Arrow code) +### 🚨 9. Deeply nested `if/else` (Arrow code) **Context:** Cognitive load and code readability. -### ❌ Bad Practice +#### ❌ Bad Practice ```javascript function getData(user) { if (user) { @@ -190,9 +193,9 @@ function getData(user) { } } ``` -### ⚠️ Problem +#### ⚠️ Problem "Arrow code" (code that expands horizontally) is hard to follow. It forces the reader to keep track of multiple nesting levels in their mental stack. -### ✅ Best Practice +#### ✅ Best Practice ```javascript function getData(user) { if (!user || !user.isActive || !user.hasPermission) { @@ -201,33 +204,36 @@ function getData(user) { return fetchData(); } ``` -### 🚀 Solution +#### 🚀 Solution Use "Guard Clauses" to return early. This flattens the structure and handles edge cases first, leaving the happy path at the lowest nesting level. -## 10. Improper naming (Single letters) +### 🚨 10. Improper naming (Single letters) **Context:** Self-documenting code. -### ❌ Bad Practice +#### ❌ Bad Practice ```javascript const d = new Date(); const u = users.map(i => i.n); ``` -### ⚠️ Problem +#### ⚠️ Problem Single-letter variables (except for standard loop indices like `i` or `j`) provide no context. They make the code unsearchable and confusing for other developers. -### ✅ Best Practice +#### ✅ Best Practice ```javascript const today = new Date(); const userNames = users.map(user => user.name); ``` -### 🚀 Solution +#### 🚀 Solution Use descriptive, camelCase names that convey the intent and data type of the variable. --- +--- +[⬆️ Back to Top](#) + ## II. Modern Syntax & FP (ES6-ES2024) -## 11. Manual object property assignment vs Shorthand +### 🚨 11. Manual object property assignment vs Shorthand **Context:** Reducing boilerplate in object creation. -### ❌ Bad Practice +#### ❌ Bad Practice ```javascript const name = 'Alice'; const user = { @@ -235,37 +241,37 @@ const user = { age: age }; ``` -### ⚠️ Problem +#### ⚠️ Problem Redundant repetition of keys and values increases file size and makes the code noisier. -### ✅ Best Practice +#### ✅ Best Practice ```javascript const name = 'Alice'; const user = { name, age }; ``` -### 🚀 Solution +#### 🚀 Solution Use Property Shorthand. When the key and variable name match, omit the value. -## 12. Using `arguments` vs Rest parameters +### 🚨 12. Using `arguments` vs Rest parameters **Context:** Handling variable numbers of arguments. -### ❌ Bad Practice +#### ❌ Bad Practice ```javascript function sum() { const args = Array.prototype.slice.call(arguments); return args.reduce((a, b) => a + b); } ``` -### ⚠️ Problem +#### ⚠️ Problem The `arguments` object is not a real array (it lacks methods like `map` or `reduce`). It is also incompatible with arrow functions and optimization in some V8 versions. -### ✅ Best Practice +#### ✅ Best Practice ```javascript const sum = (...args) => args.reduce((a, b) => a + b); ``` -### 🚀 Solution +#### 🚀 Solution Use Rest Parameters (`...args`). They create a real array and are more explicit about the function's intent. -## 13. Manual array copying vs Spread +### 🚨 13. Manual array copying vs Spread **Context:** Immutability and array manipulation. -### ❌ Bad Practice +#### ❌ Bad Practice ```javascript const original = [1, 2, 3]; const copy = []; @@ -273,91 +279,91 @@ for (let i = 0; i < original.length; i++) { copy.push(original[i]); } ``` -### ⚠️ Problem +#### ⚠️ Problem Manual loops for copying are verbose and imperative. They increase the surface area for bugs (off-by-one errors). -### ✅ Best Practice +#### ✅ Best Practice ```javascript const original = [1, 2, 3]; const copy = [...original]; ``` -### 🚀 Solution +#### 🚀 Solution Use the Spread Operator (`...`). It is concise, declarative, and highly optimized by modern engines. -## 14. Nested Destructuring +### 🚨 14. Nested Destructuring **Context:** Extracting data from complex objects. -### ❌ Bad Practice +#### ❌ Bad Practice ```javascript const city = user.location.address.city; const zip = user.location.address.zip; ``` -### ⚠️ Problem +#### ⚠️ Problem Repetitive property access is verbose and risks "cannot read property of undefined" errors if any parent object is missing. -### ✅ Best Practice +#### ✅ Best Practice ```javascript const { location: { address: { city, zip } } } = user; ``` -### 🚀 Solution +#### 🚀 Solution Use nested destructuring to extract deeply nested values in a single statement. (Note: Combine with optional chaining if path existence isn't guaranteed). -## 15. Default Parameters +### 🚨 15. Default Parameters **Context:** Handling missing arguments. -### ❌ Bad Practice +#### ❌ Bad Practice ```javascript function setRole(role) { role = role || 'guest'; // ... } ``` -### ⚠️ Problem +#### ⚠️ Problem Using `||` for defaults is dangerous if the argument is a "falsy" but valid value (like `0`, `false`, or `''`). -### ✅ Best Practice +#### ✅ Best Practice ```javascript function setRole(role = 'guest') { // ... } ``` -### 🚀 Solution +#### 🚀 Solution Use ES6 Default Parameters. They only apply if the argument is `undefined`. -## 16. `forEach` for data transformation vs `map/filter` +### 🚨 16. `forEach` for data transformation vs `map/filter` **Context:** Declarative vs Imperative programming. -### ❌ Bad Practice +#### ❌ Bad Practice ```javascript const double = []; numbers.forEach(n => { double.push(n * 2); }); ``` -### ⚠️ Problem +#### ⚠️ Problem `forEach` relies on side effects (mutating an outer array). It is less expressive and harder to chain than functional alternatives. -### ✅ Best Practice +#### ✅ Best Practice ```javascript const double = numbers.map(n => n * 2); ``` -### 🚀 Solution +#### 🚀 Solution Use `map`, `filter`, and `reduce` for data transformations. They return new arrays and promote immutability. -## 17. Object mutation vs Immutability +### 🚨 17. Object mutation vs Immutability **Context:** State management and predictability. -### ❌ Bad Practice +#### ❌ Bad Practice ```javascript function updateAge(user) { user.age = 30; // Mutates original object return user; } ``` -### ⚠️ Problem +#### ⚠️ Problem Mutating objects passed by reference can lead to side effects in other parts of the application that share the same reference, making debugging a nightmare. -### ✅ Best Practice +#### ✅ Best Practice ```javascript const updateAge = (user) => ({ ...user, age: 30 }); ``` -### 🚀 Solution +#### 🚀 Solution Treat objects as immutable. Use the spread operator to create copies with updated properties. -## 18. Switch statements vs Object Literals +### 🚨 18. Switch statements vs Object Literals **Context:** Simplifying conditional branching. -### ❌ Bad Practice +#### ❌ Bad Practice ```javascript switch (action) { case 'CREATE': return doCreate(); @@ -365,9 +371,9 @@ switch (action) { default: return doNothing(); } ``` -### ⚠️ Problem +#### ⚠️ Problem `switch` statements are verbose, require `break` to prevent fallthrough bugs, and have a non-standard block scope. -### ✅ Best Practice +#### ✅ Best Practice ```javascript const actions = { CREATE: doCreate, @@ -375,46 +381,49 @@ const actions = { }; return (actions[action] || doNothing)(); ``` -### 🚀 Solution +#### 🚀 Solution Use an Object Literal (or Map) as a lookup table. It is cleaner, faster, and more extensible. -## 19. Not using Optional Chaining `?.` +### 🚨 19. Not using Optional Chaining `?.` **Context:** Safe property access in nested objects. -### ❌ Bad Practice +#### ❌ Bad Practice ```javascript const street = user && user.address && user.address.street; ``` -### ⚠️ Problem +#### ⚠️ Problem The "logical AND" chain is verbose and repetitive. It quickly becomes unreadable with deeper nesting. -### ✅ Best Practice +#### ✅ Best Practice ```javascript const street = user?.address?.street; ``` -### 🚀 Solution +#### 🚀 Solution Use Optional Chaining (`?.`). It short-circuits to `undefined` if any part of the chain is nullish. -## 20. Not using Nullish Coalescing `??` +### 🚨 20. Not using Nullish Coalescing `??` **Context:** Providing fallback values safely. -### ❌ Bad Practice +#### ❌ Bad Practice ```javascript const timeout = config.timeout || 5000; ``` -### ⚠️ Problem +#### ⚠️ Problem If `config.timeout` is `0`, the code will incorrectly fall back to `5000` because `0` is falsy. -### ✅ Best Practice +#### ✅ Best Practice ```javascript const timeout = config.timeout ?? 5000; ``` -### 🚀 Solution +#### 🚀 Solution Use Nullish Coalescing (`??`). It only falls back if the value is `null` or `undefined`, allowing `0`, `false`, and `''` to be valid. --- +--- +[⬆️ Back to Top](#) + ## III. Asynchronous & Logic -## 21. Callback Hell vs Promises +### 🚨 21. Callback Hell vs Promises **Context:** Managing asynchronous execution flow. -### ❌ Bad Practice +#### ❌ Bad Practice ```javascript getData(url, (err, res) => { getDetails(res.id, (err, details) => { @@ -424,21 +433,21 @@ getData(url, (err, res) => { }); }); ``` -### ⚠️ Problem +#### ⚠️ Problem Deeply nested callbacks (the "Pyramid of Doom") make error handling extremely difficult and code unreadable. -### ✅ Best Practice +#### ✅ Best Practice ```javascript fetchData(url) .then(res => fetchDetails(res.id)) .then(details => saveData(details)) .catch(err => handleError(err)); ``` -### 🚀 Solution +#### 🚀 Solution Use Promises to flatten the structure and centralize error handling with `.catch()`. -## 22. Promise.then() nesting vs Async/Await +### 🚨 22. Promise.then() nesting vs Async/Await **Context:** Modern syntax for asynchronous code. -### ❌ Bad Practice +#### ❌ Bad Practice ```javascript function load() { return api.get().then(res => { @@ -448,9 +457,9 @@ function load() { }); } ``` -### ⚠️ Problem +#### ⚠️ Problem Even with Promises, `.then()` nesting can occur. It still feels like "callback style" logic. -### ✅ Best Practice +#### ✅ Best Practice ```javascript async function load() { const res = await api.get(); @@ -458,39 +467,39 @@ async function load() { return processed; } ``` -### 🚀 Solution +#### 🚀 Solution Use `async/await`. It allows asynchronous code to be written and read like synchronous code, improving maintainability. -## 23. Sequential `await` in loops vs `Promise.all` +### 🚨 23. Sequential `await` in loops vs `Promise.all` **Context:** Parallelizing independent asynchronous operations. -### ❌ Bad Practice +#### ❌ Bad Practice ```javascript for (const id of ids) { await fetchItem(id); // Pauses loop for each request } ``` -### ⚠️ Problem +#### ⚠️ Problem Sequential `await` in a loop causes a "waterfall" effect, where each request waits for the previous one to finish, significantly increasing total execution time. -### ✅ Best Practice +#### ✅ Best Practice ```javascript const promises = ids.map(id => fetchItem(id)); await Promise.all(promises); ``` -### 🚀 Solution +#### 🚀 Solution Use `Promise.all` to execute independent promises in parallel. This utilizes the full network/IO bandwidth. -## 24. Missing `try/catch` in async +### 🚨 24. Missing `try/catch` in async **Context:** Handling failures in async functions. -### ❌ Bad Practice +#### ❌ Bad Practice ```javascript async function getData() { const data = await fetch(url); // If this fails, the process might crash return data; } ``` -### ⚠️ Problem +#### ⚠️ Problem Unhandled exceptions in `async` functions result in unhandled promise rejections, which can lead to silent failures or process termination in Node.js. -### ✅ Best Practice +#### ✅ Best Practice ```javascript async function getData() { try { @@ -501,18 +510,18 @@ async function getData() { } } ``` -### 🚀 Solution +#### 🚀 Solution Wrap `await` calls in `try/catch` blocks or use a higher-order function to catch errors. -## 25. Floating point math errors (`0.1 + 0.2`) +### 🚨 25. Floating point math errors (`0.1 + 0.2`) **Context:** Precision issues in IEEE 754 arithmetic. -### ❌ Bad Practice +#### ❌ Bad Practice ```javascript if (0.1 + 0.2 === 0.3) { /* False! */ } ``` -### ⚠️ Problem +#### ⚠️ Problem $\text{0.1} + \text{0.2} = \text{0.30000000000000004}$ due to binary representation limits. This leads to critical bugs in financial or scientific applications. -### ✅ Best Practice +#### ✅ Best Practice ```javascript const EPSILON = Number.EPSILON; const areEqual = (a, b) => Math.abs(a - b) < EPSILON; @@ -520,38 +529,38 @@ const areEqual = (a, b) => Math.abs(a - b) < EPSILON; // Or for money: const totalCents = (10 + 20); // 30 cents ``` -### 🚀 Solution +#### 🚀 Solution Use `Number.EPSILON` for comparisons or represent decimals as integers (e.g., cents instead of dollars) to avoid floating point drift. -## 26. Multiple Boolean flags vs State Machine +### 🚨 26. Multiple Boolean flags vs State Machine **Context:** Managing complex component logic. -### ❌ Bad Practice +#### ❌ Bad Practice ```javascript const [isLoading, setIsLoading] = useState(false); const [isError, setIsError] = useState(false); const [isSuccess, setIsSuccess] = useState(false); ``` -### ⚠️ Problem +#### ⚠️ Problem Multiple flags allow for "impossible states" (e.g., `isLoading` and `isError` both being `true`). This makes logic branches exponentially complex. -### ✅ Best Practice +#### ✅ Best Practice ```javascript const [status, setStatus] = useState('IDLE'); // IDLE, LOADING, ERROR, SUCCESS ``` -### 🚀 Solution +#### 🚀 Solution Use a single state variable or a state machine. This ensures only one state is active at a time and simplifies transitions. -## 27. Sync logic in Event Loop +### 🚨 27. Sync logic in Event Loop **Context:** Keeping the UI responsive. -### ❌ Bad Practice +#### ❌ Bad Practice ```javascript function processLargeArray(arr) { // Blocks the main thread for 2 seconds arr.sort().forEach(item => complexCalc(item)); } ``` -### ⚠️ Problem +#### ⚠️ Problem JavaScript is single-threaded. Heavy synchronous computation blocks the Event Loop, causing the UI to freeze and preventing user interaction. -### ✅ Best Practice +#### ✅ Best Practice ```javascript // Use Web Workers or break into chunks function processInChunks(arr) { @@ -561,36 +570,36 @@ function processInChunks(arr) { setTimeout(() => processInChunks(arr), 0); } ``` -### 🚀 Solution +#### 🚀 Solution Offload heavy tasks to Web Workers or use `requestIdleCallback`/`setTimeout` to break long tasks into smaller chunks, allowing the browser to render between frames. -## 28. Overusing `classes` where functions suffice +### 🚨 28. Overusing `classes` where functions suffice **Context:** Paradigm choice (OOP vs FP). -### ❌ Bad Practice +#### ❌ Bad Practice ```javascript class Calculator { add(a, b) { return a + b; } } const calc = new Calculator(); ``` -### ⚠️ Problem +#### ⚠️ Problem Classes introduce unnecessary overhead (prototype chain, `this` binding issues) and make tree-shaking harder for bundlers. -### ✅ Best Practice +#### ✅ Best Practice ```javascript export const add = (a, b) => a + b; ``` -### 🚀 Solution +#### 🚀 Solution Use simple functions and modules for logic. Use classes only when you need to manage complex stateful instances with shared behavior. -## 29. Hard-coded Error messages vs Error Classes +### 🚨 29. Hard-coded Error messages vs Error Classes **Context:** Robust error handling and debugging. -### ❌ Bad Practice +#### ❌ Bad Practice ```javascript throw new Error('User not found'); ``` -### ⚠️ Problem +#### ⚠️ Problem Parsing error messages in `catch` blocks is brittle. If the string changes, the error handling logic breaks. -### ✅ Best Practice +#### ✅ Best Practice ```javascript class UserNotFoundError extends Error { constructor(userId) { @@ -600,138 +609,141 @@ class UserNotFoundError extends Error { } } ``` -### 🚀 Solution +#### 🚀 Solution Extend the `Error` class to create custom error types. Use `instanceof` check in catch blocks to handle specific errors differently. -## 30. Unhandled Rejections +### 🚨 30. Unhandled Rejections **Context:** Reliability of asynchronous flows. -### ❌ Bad Practice +#### ❌ Bad Practice ```javascript // No .catch() or try/catch fetch('/api/data'); ``` -### ⚠️ Problem +#### ⚠️ Problem Unhandled rejections create silent failures. In production environments, this can lead to memory leaks as the promise state stays pending or rejected without being cleared. -### ✅ Best Practice +#### ✅ Best Practice ```javascript window.addEventListener('unhandledrejection', event => { reportToSentry(event.reason); }); ``` -### 🚀 Solution +#### 🚀 Solution Always handle promise rejections. Implement a global unhandled rejection listener as a safety net for monitoring. --- +--- +[⬆️ Back to Top](#) + ## IV. Professional & Niche (Senior Level) -## 31. Memory Leaks: Unremoved Event Listeners +### 🚨 31. Memory Leaks: Unremoved Event Listeners **Context:** Long-lived applications (SPAs). -### ❌ Bad Practice +#### ❌ Bad Practice ```javascript window.addEventListener('resize', () => this.handleResize()); // Component unmounts, but listener remains ``` -### ⚠️ Problem +#### ⚠️ Problem The event listener keeps a reference to the component/context, preventing garbage collection even after the component is destroyed. -### ✅ Best Practice +#### ✅ Best Practice ```javascript const handler = () => this.handleResize(); window.addEventListener('resize', handler); // Cleanup: window.removeEventListener('resize', handler); ``` -### 🚀 Solution +#### 🚀 Solution Always remove event listeners in cleanup phases (e.g., `componentWillUnmount` or `useEffect` return). Use `AbortController` for an even more modern approach to listener cleanup. -## 32. Memory Leaks: Forgotten Intervals/Timeouts +### 🚨 32. Memory Leaks: Forgotten Intervals/Timeouts **Context:** Managing temporal background tasks. -### ❌ Bad Practice +#### ❌ Bad Practice ```javascript setInterval(() => { fetchStatus(); }, 1000); ``` -### ⚠️ Problem +#### ⚠️ Problem Intervals continue to run indefinitely until the page is closed, even if the data they process is no longer needed, consuming CPU and memory. -### ✅ Best Practice +#### ✅ Best Practice ```javascript const intervalId = setInterval(fetchStatus, 1000); // Later: clearInterval(intervalId); ``` -### 🚀 Solution +#### 🚀 Solution Store the ID returned by `setTimeout` or `setInterval` and clear it when the task is no longer relevant. -## 33. Closures inside loops (Memory/Scope issues) +### 🚨 33. Closures inside loops (Memory/Scope issues) **Context:** Understanding the Event Loop and closure capture. -### ❌ Bad Practice +#### ❌ Bad Practice ```javascript for (var i = 0; i < 5; i++) { setTimeout(() => console.log(i), 100); // Prints '5' five times } ``` -### ⚠️ Problem +#### ⚠️ Problem `var` is function-scoped. By the time the `setTimeout` executes, the loop has finished and `i` is 5. Each closure shares the same reference to `i`. -### ✅ Best Practice +#### ✅ Best Practice ```javascript for (let i = 0; i < 5; i++) { setTimeout(() => console.log(i), 100); // Prints 0, 1, 2, 3, 4 } ``` -### 🚀 Solution +#### 🚀 Solution Use `let` in loop headers. It creates a new binding for each iteration, ensuring the closure captures the value of `i` at that specific moment. -## 34. Throwing Strings instead of `new Error()` +### 🚨 34. Throwing Strings instead of `new Error()` **Context:** Ensuring useful stack traces. -### ❌ Bad Practice +#### ❌ Bad Practice ```javascript throw 'Something went wrong'; ``` -### ⚠️ Problem +#### ⚠️ Problem Throwing a string provides no stack trace. It makes it nearly impossible to determine where the error originated in a complex call stack. -### ✅ Best Practice +#### ✅ Best Practice ```javascript throw new Error('Something went wrong'); ``` -### 🚀 Solution +#### 🚀 Solution Always throw an instance of `Error` (or a subclass). This captures the `stack` property, which is vital for debugging. -## 35. Modifying Built-in Prototypes +### 🚨 35. Modifying Built-in Prototypes **Context:** Ecosystem compatibility and stability. -### ❌ Bad Practice +#### ❌ Bad Practice ```javascript Array.prototype.last = function() { return this[this.length - 1]; }; ``` -### ⚠️ Problem +#### ⚠️ Problem "Monkey patching" built-ins can lead to collisions if a future ECMAScript version implements a method with the same name but different behavior. It also breaks for-in loops if not handled carefully. -### ✅ Best Practice +#### ✅ Best Practice ```javascript const last = (arr) => arr[arr.length - 1]; ``` -### 🚀 Solution +#### 🚀 Solution Use utility functions or wrapper classes instead of modifying global prototypes. -## 36. Premature Optimization (e.g., bitwise for rounding) +### 🚨 36. Premature Optimization (e.g., bitwise for rounding) **Context:** Readability vs Micro-benchmarks. -### ❌ Bad Practice +#### ❌ Bad Practice ```javascript const floor = ~~x; // Double bitwise NOT to floor ``` -### ⚠️ Problem +#### ⚠️ Problem While `~~` is slightly faster in some engines, it makes the code cryptic. It also only works for numbers within the 32-bit integer range. -### ✅ Best Practice +#### ✅ Best Practice ```javascript const floor = Math.floor(x); ``` -### 🚀 Solution +#### 🚀 Solution Prioritize readability. Modern JIT compilers are smart enough to optimize `Math.floor`. Only use bitwise tricks if profiling proves it's a critical bottleneck in a hot path. -## 37. V8 Hidden Classes: Changing object shape after initialization +### 🚨 37. V8 Hidden Classes: Changing object shape after initialization **Context:** V8 JIT optimization. -### ❌ Bad Practice +#### ❌ Bad Practice ```javascript function User(name) { this.name = name; @@ -739,9 +751,9 @@ function User(name) { const u1 = new User('Alice'); u1.age = 25; // Dynamically adding property ``` -### ⚠️ Problem +#### ⚠️ Problem V8 creates "Hidden Classes" to optimize object property access. Adding properties after initialization changes the "shape" of the object, causing V8 to drop to a slower "Dictionary Mode" for that object. -### ✅ Best Practice +#### ✅ Best Practice ```javascript function User(name, age) { this.name = name; @@ -749,53 +761,53 @@ function User(name, age) { } const u1 = new User('Alice', 25); ``` -### 🚀 Solution +#### 🚀 Solution Initialize all object properties in the constructor or a factory function. Maintain a consistent object "shape" to keep V8 in the optimized path. -## 38. Array Hole (Sparse Arrays) performance +### 🚨 38. Array Hole (Sparse Arrays) performance **Context:** Memory allocation and JIT optimization. -### ❌ Bad Practice +#### ❌ Bad Practice ```javascript const arr = new Array(100); arr[50] = 'val'; ``` -### ⚠️ Problem +#### ⚠️ Problem Creating "holes" in arrays makes them "sparse". Sparse arrays are stored differently (as hash maps) which is much slower for iteration and access than "packed" arrays. -### ✅ Best Practice +#### ✅ Best Practice ```javascript const arr = Array.from({ length: 100 }, () => null); ``` -### 🚀 Solution +#### 🚀 Solution Initialize arrays with default values (like `null` or `0`) instead of leaving empty slots. This keeps the array in "packed" mode. -## 39. Using `eval()` or `new Function()` +### 🚨 39. Using `eval()` or `new Function()` **Context:** Security and performance. -### ❌ Bad Practice +#### ❌ Bad Practice ```javascript const result = eval('2 + 2'); ``` -### ⚠️ Problem +#### ⚠️ Problem `eval()` executes strings as code, opening a massive XSS security vulnerability if the string contains user input. It also prevents the JIT compiler from optimizing the surrounding scope. -### ✅ Best Practice +#### ✅ Best Practice ```javascript const result = new Function('a', 'b', 'return a + b')(2, 2); // Slightly better, but still risky // Better: const operations = { '+': (a, b) => a + b }; ``` -### 🚀 Solution +#### 🚀 Solution Avoid `eval()`. Use lookup tables, JSON parsing, or safe math libraries to handle dynamic logic. -## 40. Micro-optimizations that hurt readability +### 🚨 40. Micro-optimizations that hurt readability **Context:** Maintaining a healthy codebase. -### ❌ Bad Practice +#### ❌ Bad Practice ```javascript for (let i = 0, len = arr.length; i < len; i++) { /* ... */ } ``` -### ⚠️ Problem +#### ⚠️ Problem Caching `arr.length` was necessary 15 years ago. Today, modern engines optimize this automatically. Adding extra variables for micro-gains makes the code harder to read. -### ✅ Best Practice +#### ✅ Best Practice ```javascript for (const item of arr) { /* ... */ } ``` -### 🚀 Solution +#### 🚀 Solution Focus on "Big O" complexity and clean code. Only micro-optimize after profiling identifies a specific performance hotspot.