Architecture
28 décembre 2024
12 min
1,850 vues

Architecture Clean avec Node.js et TypeScript

Apprenez à structurer vos APIs Node.js avec une architecture clean, séparation des responsabilités et tests automatisés.

SC
Sarah Chen
Architecte logiciel senior avec 8 ans d'expérience. Experte en design patterns et architectures scalables.

Architecture Clean : Guide pratique avec Node.js


L'architecture clean (Clean Architecture) est un principe de conception qui vise à créer des systèmes maintenables, testables et indépendants des frameworks.


Principes fondamentaux


Séparation des responsabilités


L'architecture clean organise le code en couches concentriques :


1. **Entités** : Logique métier pure

2. **Use Cases** : Logique applicative

3. **Interface Adapters** : Controllers, Presenters

4. **Frameworks & Drivers** : Base de données, Web


Structure du projet


src/
├── domain/
│   ├── entities/
│   ├── repositories/
│   └── use-cases/
├── infrastructure/
│   ├── database/
│   ├── web/
│   └── external/
└── application/
    ├── controllers/
    ├── presenters/
    └── middleware/

Implémentation pratique


Entités métier


typescript
// domain/entities/User.ts
export class User {
  constructor(
    public readonly id: string,
    public readonly email: string,
    public readonly name: string,
    private readonly passwordHash: string
  ) {}

  public changeEmail(newEmail: string): User {
    if (!this.isValidEmail(newEmail)) {
      throw new Error('Invalid email format');
    }
    
    return new User(this.id, newEmail, this.name, this.passwordHash);
  }

  private isValidEmail(email: string): boolean {
    const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    return emailRegex.test(email);
  }
}

Use Cases


typescript
// domain/use-cases/CreateUser.ts
import { User } from '../entities/User';
import { UserRepository } from '../repositories/UserRepository';
import { PasswordHasher } from '../services/PasswordHasher';

export class CreateUser {
  constructor(
    private userRepository: UserRepository,
    private passwordHasher: PasswordHasher
  ) {}

  async execute(userData: {
    email: string;
    name: string;
    password: string;
  }): Promise<User> {
    const existingUser = await this.userRepository.findByEmail(userData.email);
    
    if (existingUser) {
      throw new Error('User already exists');
    }

    const passwordHash = await this.passwordHasher.hash(userData.password);
    
    const user = new User(
      this.generateId(),
      userData.email,
      userData.name,
      passwordHash
    );

    return this.userRepository.save(user);
  }

  private generateId(): string {
    return Math.random().toString(36).substr(2, 9);
  }
}

Tests et qualité


Cette architecture facilite grandement les tests :


typescript
// __tests__/CreateUser.test.ts
import { CreateUser } from '../src/domain/use-cases/CreateUser';
import { MockUserRepository } from './mocks/MockUserRepository';
import { MockPasswordHasher } from './mocks/MockPasswordHasher';

describe('CreateUser', () => {
  let createUser: CreateUser;
  let mockUserRepository: MockUserRepository;
  let mockPasswordHasher: MockPasswordHasher;

  beforeEach(() => {
    mockUserRepository = new MockUserRepository();
    mockPasswordHasher = new MockPasswordHasher();
    createUser = new CreateUser(mockUserRepository, mockPasswordHasher);
  });

  it('should create a new user', async () => {
    const userData = {
      email: 'test@example.com',
      name: 'Test User',
      password: 'password123'
    };

    const user = await createUser.execute(userData);

    expect(user.email).toBe(userData.email);
    expect(user.name).toBe(userData.name);
  });
});

Avantages de cette approche


  • **TestabilitĂ©** : Chaque couche peut ĂŞtre testĂ©e indĂ©pendamment
  • **MaintenabilitĂ©** : Code organisĂ© et prĂ©visible
  • **FlexibilitĂ©** : Changement de framework facilitĂ©
  • **RĂ©utilisabilitĂ©** : Logique mĂ©tier indĂ©pendante

Cette architecture représente un investissement initial, mais les bénéfices à long terme sont considérables.


Tags

ArchitectureNode.jsTypeScriptClean Code

Partager cet article