1. Pouvez-vous vous présenter et décrire votre expérience en développement .NET / Angular ?
Réponse exemple
Je suis développeur FullStack spécialisé en C# .NET et Angular, avec plusieurs années d'expérience dans la conception et le développement d'applications web.
J’ai travaillé sur :
-
le développement d’APIs REST en .NET
-
la création d’interfaces Angular
-
la gestion des bases SQL Server / PostgreSQL
-
l’intégration Cloud Azure
-
l’industrialisation avec Git et Azure DevOps
Je porte aussi une attention particulière au Clean Code, aux design patterns et aux tests unitaires, afin de garantir la maintenabilité et la qualité du code.
2. Quelle est la différence entre .NET Framework et .NET Core / .NET ?
Réponse
.NET Framework :
-
Windows uniquement
-
architecture monolithique
-
utilisé pour applications legacy
.NET Core / .NET :
-
cross-platform (Windows, Linux, Mac)
-
performance améliorée
-
microservices et cloud ready
-
architecture modulaire
Aujourd’hui la majorité des projets utilisent .NET 6 / .NET 8.
3. Comment concevez-vous une API REST en .NET ?
Réponse
Pour créer une API REST en .NET :
-
Création d’un projet ASP.NET Core Web API
-
Création des Controllers
-
Mise en place de DTOs
-
Utilisation d’un service layer
-
Accès aux données via Repository + Entity Framework
-
Gestion des exceptions et validation
-
Documentation avec Swagger
Exemple :
[HttpGet("{id}")]
public async Task<ActionResult<UserDto>> GetUser(int id)
{
var user = await _userService.GetUser(id);
if(user == null)
return NotFound();
return Ok(user);
}
4. Qu’est-ce que le Clean Code ?
Réponse
Le Clean Code signifie écrire un code :
-
lisible
-
maintenable
-
testable
Principes importants :
-
noms de variables explicites
-
fonctions courtes
-
une responsabilité par classe
-
éviter la duplication (DRY)
-
suivre les principes SOLID
5. Pouvez-vous expliquer les principes SOLID ?
Réponse
Les principes SOLID sont des règles de conception logicielle :
-
S – Single Responsibility
Une classe doit avoir une seule responsabilité. -
O – Open / Closed
Le code doit être ouvert à l’extension mais fermé à la modification. -
L – Liskov Substitution
Une classe enfant doit pouvoir remplacer sa classe parent. -
I – Interface Segregation
Interfaces spécifiques plutôt que générales. -
D – Dependency Inversion
Dépendre d’abstractions plutôt que d’implémentations.
6. Comment fonctionne l’injection de dépendance en .NET ?
Réponse
L’injection de dépendance permet de découpler les composants.
Dans .NET elle est configurée dans Program.cs :
builder.Services.AddScoped<IUserService, UserService>();
Puis injectée dans un controller :
public class UserController : ControllerBase
{
private readonly IUserService _userService;
public UserController(IUserService userService)
{
_userService = userService;
}
}
Avantages :
-
testabilité
-
maintenance
-
architecture propre
7. Comment Angular communique avec une API .NET ?
Réponse
Angular communique avec une API via HttpClient.
Exemple :
getUsers(): Observable<User[]> {
return this.http.get<User[]>('https://api/users');
}
Le flux est :
Angular → HTTP request → API .NET → Database → réponse JSON.
8. Comment gérez-vous les bases SQL et NoSQL ?
Réponse
SQL (SQL Server, PostgreSQL) :
-
données structurées
-
transactions
-
relations
NoSQL (CosmosDB, MongoDB) :
-
données semi-structurées
-
haute scalabilité
-
applications cloud
Dans .NET on peut utiliser :
-
Entity Framework pour SQL
-
SDK spécifiques pour CosmosDB.
9. Quelle est votre expérience avec le Cloud (Azure / AWS) ?
Réponse
J’ai utilisé Azure pour :
-
App Services
-
Azure Functions
-
Azure SQL
-
Azure DevOps CI/CD
Les avantages :
-
scalabilité
-
déploiement automatisé
-
monitoring
10. Comment assurez-vous la qualité du code ?
Réponse
J’utilise plusieurs pratiques :
-
tests unitaires (xUnit / NUnit)
-
revues de code
-
CI/CD pipelines
-
linting et analyse statique
-
Clean Code et design patterns
Cela permet d’améliorer la qualité, la stabilité et la maintenabilité du projet.
==========================
1. Quelle est la différence entre IEnumerable, IQueryable et List ?
Réponse
| Type | Exécution | Utilisation |
|---|---|---|
| IEnumerable | en mémoire | collections .NET |
| IQueryable | base de données | LINQ to Entities |
| List | collection concrète | stockage en mémoire |
Exemple :
var users = context.Users.Where(u => u.Age > 18);
-
avec IQueryable → requête SQL exécutée en base
-
avec IEnumerable → données chargées puis filtrées
Donc IQueryable améliore la performance.
2. Quelle est la différence entre Task, async/await et Thread ?
Thread
-
thread système
-
coûteux en ressources
Task
-
abstraction plus légère
-
gérée par le Thread Pool
async/await
-
permet l’écriture de code asynchrone non bloquant
Exemple :
public async Task<User> GetUser()
{
return await repository.GetUserAsync();
}
Avantage :
-
améliore la scalabilité des APIs
3. Expliquez le fonctionnement du Garbage Collector en .NET
Le Garbage Collector (GC) libère automatiquement la mémoire.
Fonctionnement :
-
gestion de mémoire par générations
| Génération | Description |
|---|---|
| Gen 0 | objets temporaires |
| Gen 1 | objets intermédiaires |
| Gen 2 | objets long terme |
Cycle :
-
allocation mémoire
-
GC détecte objets non référencés
-
libération mémoire
Cela évite les memory leaks manuels.
4. Quelle est la différence entre abstract class et interface ?
| Interface | Abstract class |
|---|---|
| pas d’implémentation (avant C# 8) | peut contenir logique |
| multiple inheritance | single inheritance |
| contrat | comportement + contrat |
Exemple :
public interface ILogger
{
void Log(string message);
}
5. Expliquez le pattern Repository
Le Repository Pattern sépare :
-
logique métier
-
accès aux données
Architecture :
Controller
Service
Repository
Database
Exemple :
public interface IUserRepository
{
Task<User> GetById(int id);
}
Avantages :
-
testabilité
-
abstraction
-
clean architecture
6. Quelle est la différence entre Singleton, Scoped et Transient en DI ?
| Lifetime | Description |
|---|---|
| Singleton | une seule instance |
| Scoped | une instance par requête HTTP |
| Transient | nouvelle instance à chaque injection |
Exemple :
services.AddScoped<IUserService, UserService>();
7. Qu’est-ce que le middleware dans ASP.NET Core ?
Les middlewares interceptent les requêtes HTTP.
Pipeline :
Request
↓
Middleware 1
↓
Middleware 2
↓
Controller
Exemple :
app.UseAuthentication();
app.UseAuthorization();
8. Quelle est la différence entre IHostedService et BackgroundService ?
IHostedService
-
interface pour tâches background
BackgroundService
-
implémentation simplifiée
Exemple :
public class Worker : BackgroundService
{
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while(!stoppingToken.IsCancellationRequested)
{
await Task.Delay(1000);
}
}
}
Utilisé pour :
-
jobs
-
workers
-
messaging
9. Comment optimiser les performances d’une API .NET ?
Techniques :
-
pagination
-
caching (Redis)
-
async/await
-
compression
-
minimiser les requêtes SQL
-
utiliser DTO
Exemple :
Skip()
Take()
10. Expliquez le fonctionnement de LINQ
LINQ permet de requêter des collections avec une syntaxe SQL-like.
Exemple :
var users = users.Where(u => u.Age > 18).ToList();
LINQ peut être :
-
LINQ to Objects
-
LINQ to SQL
-
LINQ to Entities
11. Qu’est-ce que le Deadlock en programmation asynchrone ?
Un deadlock se produit lorsque deux threads attendent mutuellement une ressource.
Exemple classique :
Task.Result
Task.Wait()
Solution :
-
utiliser async/await
-
éviter
.Result
12. Comment gérer les exceptions globalement dans ASP.NET Core ?
Utiliser Middleware global.
Exemple :
app.UseExceptionHandler("/error");
Ou middleware personnalisé :
try
{
await next(context);
}
catch(Exception ex)
{
}
Avantages :
-
gestion centralisée
-
logs
-
réponse standard API
13. Quelle est la différence entre record et class en C# ?
Class
-
mutable
Record
-
immutable
-
basé sur la valeur
Exemple :
public record User(string Name, int Age);
Utilisé pour :
-
DTO
-
modèles immuables
14. Comment implémenter le caching dans .NET ?
Types :
-
In Memory Cache
-
Distributed Cache (Redis)
Exemple :
services.AddMemoryCache();
Usage :
_cache.Set("users", users);
15. Expliquez une architecture Clean Architecture
Architecture en couches :
Presentation (API)
Application (Services)
Domain (Business rules)
Infrastructure (DB, external services)
Principe :
les dépendances vont vers le domaine
Avantages :
-
maintenabilité
-
testabilité
-
indépendance des frameworks
1. Quelle est la vraie différence entre IEnumerable, IQueryable et IAsyncEnumerable ?
Réponse
IEnumerable travaille sur des données déjà chargées en mémoire.
IQueryable construit une requête traduisible par un provider comme Entity Framework vers SQL.
IAsyncEnumerable permet de consommer des flux de données de manière asynchrone, élément par élément.
Le piège, c’est de dire seulement “IQueryable est plus performant”. Ce n’est pas toujours vrai. Il est performant si la requête est bien traduite côté base. Sinon, on peut provoquer des requêtes complexes, du N+1, ou des traductions inefficaces.
Réponse entretien solide :
J’utilise IQueryable à la frontière data access uniquement, pas comme contrat exposé partout. En général, je matérialise avec ToListAsync() ou je projette directement en DTO. IAsyncEnumerable est utile pour du streaming ou de très gros volumes, mais il faut vérifier le support réel du provider et l’impact sur la connexion DB.
2. Pourquoi exposer IQueryable depuis un repository est souvent une mauvaise idée ?
Réponse
Parce que cela fuit les détails d’implémentation du provider de persistence vers les couches supérieures.
La couche service peut alors composer des requêtes EF sans le vouloir, ce qui crée :
-
un couplage fort à Entity Framework
-
des requêtes imprévisibles
-
des difficultés de test
-
des responsabilités mal séparées
Bonne réponse :
Un repository doit exposer des méthodes orientées métier ou des méthodes de lecture claires. Si j’ai besoin de flexibilité avancée, je préfère le pattern Specification ou une couche query dédiée plutôt que de laisser remonter IQueryable partout.
3. Quelle est la différence entre async/await et le multithreading ?
Réponse
async/await n’est pas du multithreading au sens strict.
C’est une manière d’écrire du code asynchrone non bloquant, très utile pour les opérations I/O : base de données, HTTP, fichier, messaging.
Le piège est de dire : “async/await crée un thread en plus.” Ce n’est pas forcément vrai. En ASP.NET Core, l’objectif est surtout de libérer le thread pendant l’attente I/O afin d’améliorer la scalabilité.
Réponse senior :
J’utilise async/await pour les opérations I/O-bound. Pour les traitements CPU-bound, je réfléchis autrement : parallélisation contrôlée, background processing, ou architecture orientée messages selon le besoin.
4. Pourquoi Task.Result et Task.Wait() sont dangereux ?
Réponse
Ils peuvent provoquer :
-
des deadlocks dans certains contextes
-
du blocage de thread
-
une dégradation de la scalabilité
-
des agrégations d’exceptions moins lisibles
En ASP.NET Core, le deadlock classique est moins fréquent qu’en ancien ASP.NET ou UI apps, mais bloquer un thread reste une mauvaise pratique.
Bonne formulation entretien :
Je privilégie le “async all the way”. Si une méthode devient asynchrone, j’essaie de propager cette asynchronie jusqu’en haut de la pile d’appel au lieu de rebasculer en synchrone.
5. Quand utiliser record plutôt que class ?
Réponse
record est particulièrement adapté pour des objets de type :
-
DTO
-
messages
-
résultats immuables
-
objets orientés valeur
Le piège, c’est de dire : “record remplace class”. Non.
Une class reste souvent plus adaptée aux entités métier mutables avec cycle de vie, identité et comportements.
Réponse d’architecte :
J’utilise record quand l’égalité par valeur et l’immutabilité ont du sens. Pour les entités de domaine persistées, une class est souvent plus appropriée.
6. Quelle est la différence entre AddTransient, AddScoped et AddSingleton ? Où est le piège ?
Réponse
-
Transient: nouvelle instance à chaque injection -
Scoped: une instance par requête HTTP -
Singleton: une instance pour toute l’application
Le vrai piège est l’usage incorrect des dépendances entre lifetimes.
Par exemple, un singleton qui dépend d’un service scoped crée des problèmes de cycle de vie et de comportement inattendu.
Réponse solide :
Je choisis le lifetime selon l’état porté, le coût de création, et le contexte d’exécution. En web, beaucoup de services métier sont Scoped. Je suis particulièrement vigilant à ne pas injecter un scoped dans un singleton.
7. Pourquoi DbContext doit généralement être scoped ?
Réponse
Parce qu’il représente une unité de travail liée au cycle de la requête.
Il gère le change tracking, l’identité des entités suivies et la persistance transactionnelle.
Le déclarer singleton serait problématique :
-
non thread-safe
-
état partagé entre requêtes
-
fuites mémoire
-
bugs métier
Réponse entretien :
Le DbContext est pensé pour une durée de vie courte. En général, une instance par requête est le bon compromis.
8. DbContext est-il thread-safe ?
Réponse
Non.
Il ne doit pas être utilisé simultanément par plusieurs threads.
Le piège typique est de lancer plusieurs tâches parallèles partageant le même contexte, ce qui peut provoquer des erreurs subtiles ou des exceptions.
Bonne réponse :
Si j’ai un vrai besoin de parallélisme, je segmente le traitement et j’utilise des contextes distincts. En pratique, sur un flux web classique, je garde un usage séquentiel et scoped.
9. Qu’est-ce que le problème N+1 avec Entity Framework ?
Réponse
C’est le fait de charger une liste d’entités, puis de déclencher une requête supplémentaire pour chaque entité liée.
Résultat : explosion du nombre de requêtes et forte dégradation de performance.
Exemple classique : charger des Orders, puis accéder à Order.Customer ou Order.Items sans chargement approprié.
Bonne réponse :
Je surveille cela avec :
-
projection directe en DTO
-
Includequand pertinent -
désactivation prudente du lazy loading
-
profiling SQL
-
revue des logs EF
Le meilleur réflexe n’est pas de mettre des Include partout, mais de charger exactement ce qui est nécessaire.
10. Include partout est-il une bonne solution ?
Réponse
Non.
C’est une fausse bonne idée. On peut surcharger les requêtes SQL, ramener trop de données, dupliquer des lignes via des jointures, et dégrader les performances.
Réponse mature :
Le bon choix dépend du besoin. Pour une API de lecture, je préfère souvent une projection en DTO avec Select, qui évite de charger tout le graphe d’entités. Include est utile, mais il doit rester ciblé.
11. À quoi sert AsNoTracking() et quand l’utiliser ?
Réponse
AsNoTracking() indique à EF Core de ne pas suivre les entités dans le change tracker.
C’est utile pour les lectures seules, car cela réduit la consommation mémoire et améliore souvent les performances.
Le piège est de le mettre partout. Si derrière on veut modifier puis sauvegarder l’entité, cela devient contre-productif.
Réponse entretien :
Je l’utilise sur les requêtes purement read-only, surtout pour les listes, reporting, ou endpoints de consultation. Pour les scénarios update, je garde le tracking ou je gère explicitement l’état.
12. Faut-il utiliser le pattern Repository avec Entity Framework, alors que DbContext est déjà une abstraction ?
Réponse
Très bonne question piège.
DbContext joue déjà en partie le rôle de Unit of Work et Repository.
Créer un repository générique “CRUD partout” peut ajouter une couche inutile et appauvrir les capacités d’EF.
Bonne réponse d’architecte :
Je n’applique pas le repository de manière dogmatique.
Si j’ai un besoin métier clair, une abstraction métier spécifique peut avoir du sens. Sinon, ajouter un repository générique sur EF peut être du sur-design. Le choix dépend du niveau d’isolation recherché et de la complexité du domaine.
13. Quelle différence entre FirstOrDefault, SingleOrDefault et Find ?
Réponse
-
FirstOrDefault: prend le premier élément ou null -
SingleOrDefault: exige au plus un seul résultat, sinon exception -
Find: recherche optimisée par clé primaire, peut utiliser le cache local du contexte
Le piège, c’est d’utiliser FirstOrDefault partout, alors qu’on masque parfois une anomalie de données.
Réponse senior :
J’utilise SingleOrDefault quand l’unicité est une règle métier forte. Cela rend l’intention explicite. Find est intéressant pour les clés primaires avec EF, mais son usage dépend aussi du contexte de tracking.
14. Qu’est-ce que ConfigureAwait(false) et faut-il l’utiliser en ASP.NET Core ?
Réponse
ConfigureAwait(false) évite de capturer le contexte de synchronisation lors de la reprise après un await.
Dans ASP.NET Core, il n’y a généralement pas le même contexte de synchronisation qu’en WinForms/WPF/ancien ASP.NET. Donc son intérêt est plus limité.
Réponse attendue :
Dans du code applicatif ASP.NET Core, ce n’est pas systématiquement nécessaire. Dans des librairies partagées, on peut le considérer pour éviter des dépendances implicites au contexte appelant. Mais je ne l’utilise pas mécaniquement partout.
15. Différence entre throw; et throw ex;
Réponse
throw; relance l’exception en conservant la stack trace d’origine.
throw ex; réinitialise la stack trace, ce qui rend le diagnostic plus difficile.
C’est une question classique de niveau senior.
Bonne réponse :
Quand je veux relancer, j’utilise throw;.
Si je veux enrichir le contexte, je peux logger puis relancer, ou encapsuler dans une exception métier si c’est justifié, sans perdre l’information utile.
16. Qu’est-ce qu’une transaction distribuée et pourquoi faut-il souvent l’éviter ?
Réponse
Une transaction distribuée coordonne plusieurs ressources transactionnelles : plusieurs bases, DB + message broker, etc.
C’est complexe, coûteux, plus fragile, et pas toujours bien supporté en environnement cloud/microservices.
Réponse architecture :
Dans les architectures modernes, on évite souvent ce modèle au profit de mécanismes comme :
-
Outbox Pattern
-
Saga
-
compensation
-
idempotence
-
eventual consistency
L’objectif n’est pas d’avoir une cohérence immédiate partout, mais une cohérence fiable à l’échelle du système.
17. CQRS : dans quels cas est-ce utile, et dans quels cas c’est du sur-engineering ?
Réponse
CQRS sépare lecture et écriture.
C’est utile quand :
-
les besoins de lecture et d’écriture diffèrent fortement
-
les volumes de lecture sont élevés
-
la complexité métier côté commande est importante
-
on veut des modèles de lecture optimisés
Mais sur une application simple CRUD, mettre CQRS, MediatR, événements, handlers partout peut être du sur-engineering.
Bonne réponse :
Je n’applique pas CQRS par mode. Je l’utilise quand la séparation des modèles apporte une vraie valeur métier, de performance ou d’évolutivité.
18. Quelle différence entre architecture en couches, Clean Architecture et microservices ?
Réponse
Ce ne sont pas des opposés, mais des niveaux différents de structuration.
-
Architecture en couches : séparation présentation / métier / data
-
Clean Architecture : dépendances dirigées vers le domaine, forte isolation métier
-
Microservices : découpage distribué du système en services autonomes
Le piège est de croire que microservices = architecture plus moderne donc meilleure.
Réponse mature :
Je commence simple. Un monolithe modulaire bien conçu est souvent préférable à des microservices prématurés. Le découpage distribué n’a de sens que si l’organisation, les besoins de scalabilité, l’autonomie des équipes et la complexité métier le justifient.
19. Comment gérer l’idempotence dans une API ou dans un traitement asynchrone ?
Réponse
L’idempotence garantit qu’exécuter plusieurs fois la même opération produit le même résultat fonctionnel attendu.
C’est essentiel dans :
-
les retries HTTP
-
les consumers de messages
-
les paiements
-
les créations d’événements métier
Réponse solide :
On peut la gérer avec :
-
une clé d’idempotence
-
une contrainte d’unicité en base
-
une table de déduplication
-
des handlers conçus pour être rejouables
En architecture distribuée, c’est une propriété clé de robustesse.
20. Comment repérer qu’un code “propre” est en réalité mal architecturé ?
Réponse
Très bonne question piège.
Un code peut être lisible, bien nommé, bien formaté… mais rester mauvais sur le plan architectural.
Signaux d’alerte :
-
couches trop couplées
-
logique métier dispersée
-
classes “propres” mais trop nombreuses et sans valeur
-
interfaces partout sans besoin réel
-
sur-abstraction
-
tests difficiles malgré un code apparemment clean
-
performance ignorée
-
règles métier dépendantes de l’infrastructure
Réponse d’expert :
Le Clean Code ne suffit pas. Une bonne architecture se juge aussi sur la cohésion, le découplage, l’évolutivité, la testabilité réelle, l’observabilité et l’adéquation au besoin métier. Le plus beau code du monde peut rester un mauvais système.
===================================
1. Quelle est l’architecture d’une application Angular ?
Réponse
Angular est basé sur une architecture component-based.
Principaux éléments :
-
Modules (NgModule) : organisation de l’application
-
Components : UI et logique de vue
-
Services : logique métier / appels API
-
Directives : comportement du DOM
-
Pipes : transformation de données
-
Routing : navigation
Structure typique :
AppModule
├── Components
├── Services
├── Models
└── Routing
Cela permet une application modulaire et maintenable.
2. Quelle est la différence entre Component et Directive ?
Réponse
| Component | Directive |
|---|---|
| possède un template HTML | pas forcément de template |
| utilisé pour construire l’UI | modifie le comportement du DOM |
Exemple directive structurelle :
<div *ngIf="isLoggedIn">Welcome</div>
Exemple directive attribut :
<input appHighlight>
Un component est une directive avec template.
3. Quelle est la différence entre ngIf et hidden ?
Réponse
ngIf
-
supprime l’élément du DOM
hidden
-
masque l’élément via CSS
Exemple :
<div *ngIf="isVisible">Hello</div>
Si false, l’élément n’existe plus dans le DOM.
Avantage :
-
meilleure performance
-
évite le rendu inutile
4. Expliquez le Data Binding dans Angular
Angular supporte 4 types de binding :
| Type | Syntaxe |
|---|---|
| Interpolation | {{value}} |
| Property binding | [value]="name" |
| Event binding | (click)="save()" |
| Two-way binding | [(ngModel)]="name" |
Exemple :
<input [(ngModel)]="username">
Cela synchronise vue ↔ modèle.
5. Quelle est la différence entre Observable et Promise ?
Promise
-
une seule valeur
-
non annulable
Observable
-
plusieurs valeurs
-
cancelable
-
lazy
-
puissant avec RxJS
Exemple :
this.http.get<User[]>('/api/users')
.subscribe(users => console.log(users));
Angular utilise Observables pour HTTP et événements.
6. Comment Angular communique avec une API ?
Réponse
Via HttpClient.
Service exemple :
getUsers(): Observable<User[]> {
return this.http.get<User[]>('/api/users');
}
Puis dans le component :
this.userService.getUsers()
.subscribe(data => this.users = data);
Bonnes pratiques :
-
utiliser des services
-
gérer les erreurs
-
utiliser des interceptors
7. Qu’est-ce que le Change Detection ?
Réponse
Le Change Detection met à jour la vue quand les données changent.
Angular vérifie :
Model → DOM
Deux stratégies :
Default
Angular vérifie tout le component tree.
OnPush
Angular vérifie seulement si :
-
input change
-
event
-
observable update
Exemple :
changeDetection: ChangeDetectionStrategy.OnPush
Avantage :
-
meilleure performance
8. Qu’est-ce qu’un Angular Service ?
Réponse
Un service contient la logique métier ou les appels API.
Exemple :
@Injectable({
providedIn: 'root'
})
export class UserService {
}
Avantages :
-
séparation des responsabilités
-
réutilisation
-
testabilité
9. Qu’est-ce qu’un Angular Interceptor ?
Réponse
Un HTTP interceptor permet d’intercepter les requêtes HTTP.
Utilisations :
-
ajouter un token JWT
-
logging
-
gestion globale des erreurs
Exemple :
intercept(req: HttpRequest<any>, next: HttpHandler) {
const tokenReq = req.clone({
setHeaders: { Authorization: `Bearer ${token}` }
});
return next.handle(tokenReq);
}
Très utilisé pour authentification.
10. Quelle est la différence entre Subject, BehaviorSubject et ReplaySubject ?
Subject
-
simple observable
BehaviorSubject
-
garde la dernière valeur
ReplaySubject
-
rejoue plusieurs valeurs
Exemple :
private userSource = new BehaviorSubject<User | null>(null);
user$ = this.userSource.asObservable();
Avantage :
-
partage de données entre components
1. Performance dans Angular
Principe
La performance Angular consiste à optimiser :
-
le rendu du DOM
-
les appels API
-
la gestion du change detection
-
le chargement de l’application
Techniques principales
Lazy Loading
Chargement des modules uniquement quand ils sont nécessaires.
const routes: Routes = [
{
path: 'admin',
loadChildren: () =>
import('./admin/admin.module').then(m => m.AdminModule)
}
];
Avantage :
-
réduit le bundle initial
-
améliore le temps de chargement
TrackBy dans ngFor
Sans trackBy, Angular recrée toute la liste.
<li *ngFor="let user of users; trackBy: trackById">
trackById(index: number, user: User) {
return user.id;
}
Avantage :
-
évite les re-renders inutiles
OnPush Change Detection
Angular vérifie moins souvent le DOM.
Gain :
-
applications plus rapides
-
moins de calculs
Eviter les appels API multiples
Utiliser RxJS :
shareReplay(1)
2. Maintenabilité
Principe
La maintenabilité signifie que le code est :
-
facile à comprendre
-
facile à modifier
-
testable
-
modulaire
Bonnes pratiques Angular
Séparer les responsabilités
Structure typique :
components/
services/
models/
guards/
interceptors/
Utiliser les services pour la logique métier
Mauvais :
component qui fait tout
Bon :
Component → Service → API
Utiliser des interfaces / modèles
export interface User {
id: number;
name: string;
}
Cela améliore :
-
lisibilité
-
typage
-
robustesse
3. RxJS (Reactive Extensions)
Principe
RxJS permet de gérer des flux de données asynchrones.
Exemples :
-
appels API
-
événements UI
-
WebSocket
-
timers
Angular utilise RxJS partout :
-
HttpClient
-
Router
-
Forms
-
Event streams
Exemple Observable
this.http.get<User[]>('/api/users')
.subscribe(users => this.users = users);
Opérateurs RxJS importants
map
transforme les données
map(users => users.length)
switchMap
annule les requêtes précédentes.
Très utilisé pour recherche.
search$
.pipe(
switchMap(term => this.api.search(term))
)
debounceTime
évite trop d'appels API.
debounceTime(300)
Exemple complet
searchInput.valueChanges.pipe(
debounceTime(300),
switchMap(value => this.api.search(value))
)
4. Architecture modulaire
Principe
Angular organise l’application en modules indépendants.
Exemple :
app.module
auth.module
admin.module
shared.module
Types de modules
Core Module
services globaux.
AuthService
LoggerService
Shared Module
composants réutilisables.
ButtonComponent
LoaderComponent
Pipes
Directives
Feature Module
fonctionnalités métier.
UserModule
AdminModule
DashboardModule
Avantages
-
séparation claire
-
réutilisation
-
testabilité
-
lazy loading
5. Change Detection Strategy OnPush
Problème
Angular vérifie tous les components à chaque changement.
Cela peut être coûteux.
Solution : OnPush
Angular ne met à jour le component que si :
-
un Input change
-
un event se produit
-
un observable émet
Exemple
@Component({
selector: 'app-user',
changeDetection: ChangeDetectionStrategy.OnPush
})
Bonnes pratiques avec OnPush
Utiliser des données immuables.
Mauvais :
user.name = "John"
Bon :
user = {...user, name: "John"}
Avantages
-
performance améliorée
-
moins de re-render
-
plus prédictible
Réponse parfaite en entretien (résumé)
Si on te demande :
Comment assurer performance et maintenabilité dans Angular ?
Tu peux répondre :
Pour améliorer la performance et la maintenabilité dans Angular, j’applique plusieurs bonnes pratiques :
architecture modulaire avec des feature modules
séparation component / service
utilisation de RxJS pour gérer les flux asynchrones
optimisation du change detection avec OnPush
lazy loading des modules
utilisation de trackBy dans les listes.
======================================