Best Practices and Patterns
Level: Intermediate
ℹ️ What You'll Learn
- Architecture patterns
- Code organization
- Performance optimization
- Security best practices
- Testing strategy
Architecture Pattern
src/
├── app/
│ ├── core/ # Singleton services
│ │ ├── auth.service.ts
│ │ ├── http.interceptor.ts
│ │ └── guards/
│ ├── shared/ # Shared components
│ │ ├── navbar/
│ │ ├── footer/
│ │ └── pipes/
│ ├── features/ # Feature modules
│ │ ├── students/
│ │ ├── exams/
│ │ └── fees/
│ └── app.component.ts
Core = services used once. Shared = reusable components. Features = feature modules.
Smart/Dumb Components
// Smart component (container)
@Component({
selector: 'app-student-container',
template: `
<app-student-list
[students]="students$ | async"
(delete)="onDelete($event)">
</app-student-list>
`
})
export class StudentContainerComponent {
students$ = this.service.getStudents();
constructor(private service: StudentService) {}
onDelete(id: number) {
this.service.deleteStudent(id).subscribe();
}
}
// Dumb component (presentational)
@Component({
selector: 'app-student-list',
template: `
<tr *ngFor="let student of students">
<td>{{ student.name }}</td>
<button (click)="onDelete(student.id)">Delete</button>
</tr>
`
})
export class StudentListComponent {
@Input() students!: any[];
@Output() delete = new EventEmitter<number>();
onDelete(id: number) {
this.delete.emit(id);
}
}
Smart = data, logic. Dumb = UI only.
Unsubscribe Pattern
export class StudentListComponent implements OnInit, OnDestroy {
private destroy$ = new Subject<void>();
students: any[] = [];
constructor(private service: StudentService) {}
ngOnInit() {
this.service.getStudents()
.pipe(takeUntil(this.destroy$))
.subscribe(data => this.students = data);
}
ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
}
}
takeUntil auto-unsubscribes.
Performance Tips
// Use OnPush change detection
@Component({
changeDetection: ChangeDetectionStrategy.OnPush
})
// Lazy load routes
{
path: 'students',
loadChildren: () => import('./students').then(m => m.ROUTES)
}
// TrackBy in ngFor
<tr *ngFor="let student of students; trackBy: trackByStudentId">
trackByStudentId(index: number, student: any) {
return student.id;
}
// Use async pipe
students$ = this.service.getStudents();
<tr *ngFor="let student of students$ | async">
Security Best Practices
// Always validate input
constructor(private sanitizer: DomSanitizer) {}
safeHtml = this.sanitizer.sanitize(SecurityContext.HTML, userInput);
// Don't store secrets in code
// Use environment variables
apiUrl = import.meta.env.NG_APP_API_URL;
// HTTPS only
// Protect against XSS
// CSRF tokens in requests
Testing Strategy
// Unit test services
// Integration test components
// E2E test user flows
describe('StudentService', () => {
it('should load students', () => {
// Unit test
});
});
describe('StudentListComponent', () => {
it('should display students', () => {
// Integration test
});
});
Code Style
// ✓ Good
private students$ = this.service.getStudents();
// ✗ Avoid
private students = this.service.getStudents();
// ✓ Use observables
students$ = this.service.getStudents();
// ✗ Avoid manual subscription
students: any[];
this.service.getStudents().subscribe(data => this.students = data);
SMS Best Practices
- Feature modules per domain (Student, Exam, Fee)
- Core services for API/Auth
- Smart/Dumb component split
- Lazy load feature modules
- Unsubscribe pattern
- OnPush change detection
- TrackBy in loops
- Async pipe
Key Takeaways
- Architecture = clear structure
- Smart/Dumb = separation of concerns
- Unsubscribe = memory leaks prevention
- Performance = lazy load, OnPush, TrackBy
- Security = validate input, HTTPS
- Testing = unit, integration, E2E
💡 Backend Developer Tip
Architecture patterns similar to layered architecture in .NET. Core services like repositories, features like controllers/services.
⚠️ Anti-Patterns
- Everything in app.component — No organization
- Subscribing in component — Use async pipe
- No lazy loading — Large bundles
- Manual unsubscribe — Memory leaks
- Logic in templates — Hard to test
🤖Use AI to Learn Faster
Use ChatGPT, Claude, or Copilot to go deeper on Best Practices. Try these prompts:
"Why use Smart/Dumb component pattern?""How do you prevent memory leaks?""What's benefit of OnPush change detection?""Quiz me on Angular patterns"
💡 Tip: After reading this article, paste your own code into AI and ask "What could go wrong here and why?" — fastest way to find edge cases and deepen understanding.
nexcoding.in
Have questions on your tech stack, ongoing projects, or need one-to-one training?