Angular 입문 가이드: 컴포넌트, DI, RxJS로 시작하는 엔터프라이즈 앱

Angular는 Google이 개발하고 유지보수하는 TypeScript 기반의 풀-프레임워크입니다. 라우팅, 상태 관리, HTTP 클라이언트, 폼 처리까지 모든 것을 내장하여 대규모 엔터프라이즈 앱 개발에 최적화되어 있습니다.

Angular의 핵심 철학

React나 Vue와 달리 Angular는 Opinionated Full Framework입니다. 구조와 패턴이 명확하게 정해져 있어 팀 규모가 커도 일관된 코드 스타일을 유지할 수 있습니다.

  • TypeScript 네이티브: 타입 안전성과 IDE 지원
  • 의존성 주입(DI): 테스트 용이성과 모듈화
  • RxJS 통합: 비동기 데이터 스트림 처리
  • SSR 지원: Angular Universal로 서버사이드 렌더링

컴포넌트(Component)

Angular 앱의 기본 빌딩 블록입니다. 템플릿, 스타일, 로직을 하나의 단위로 캡슐화합니다.

import { Component, signal, computed } from '@angular/core';

@Component({
  selector: 'app-counter',
  standalone: true,
  template: `
    <div class="counter">
      <p>현재 카운트: {{ count() }}</p>
      <p>2배: {{ doubled() }}</p>
      <button (click)="increment()">+1</button>
      <button (click)="decrement()">-1</button>
    </div>
  `,
})
export class CounterComponent {
  count = signal(0);                    // 반응형 신호(Signal)
  doubled = computed(() => this.count() * 2); // 파생 상태

  increment() { this.count.update(v => v + 1); }
  decrement() { this.count.update(v => v - 1); }
}

의존성 주입(Dependency Injection)

Angular의 DI 시스템은 서비스의 인스턴스를 컴포넌트에 자동으로 제공합니다. 테스트 시 모의 객체로 손쉽게 교체할 수 있어 단위 테스트가 매우 용이합니다.

import { Injectable, inject } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';

@Injectable({ providedIn: 'root' }) // 앱 전체에서 싱글턴
export class PostService {
  private readonly http = inject(HttpClient);

  getPosts(): Observable<Post[]> {
    return this.http.get<Post[]>('/api/posts');
  }
}

// 컴포넌트에서 inject()로 사용
@Component({ ... })
export class PostListComponent {
  private readonly postService = inject(PostService);
  posts = signal<Post[]>([]);

  ngOnInit() {
    this.postService.getPosts().subscribe(posts => this.posts.set(posts));
  }
}

RxJS와 반응형 프로그래밍

Angular는 비동기 처리를 위해 RxJS Observable을 적극 활용합니다. 여러 비동기 스트림을 선언적으로 조합하는 강력한 패턴을 제공합니다.

import { combineLatest } from 'rxjs';
import { map, debounceTime, switchMap } from 'rxjs/operators';

// 검색어와 필터 조건이 변경될 때마다 자동으로 API 호출
combineLatest([searchQuery$, filterCategory$])
  .pipe(
    debounceTime(300),          // 타이핑 중 불필요한 요청 방지
    switchMap(([query, category]) =>
      this.postService.search(query, category) // 이전 요청 자동 취소
    ),
    map(results => results.filter(p => p.published))
  )
  .subscribe(posts => this.posts.set(posts));

SSR과 점진적 하이드레이션

Angular 17+부터 provideClientHydration(withEventReplay())를 통해 서버에서 렌더링된 HTML을 클라이언트에서 재활용합니다. 이를 통해 FCP(First Contentful Paint)를 크게 향상시킬 수 있습니다.

// app.config.ts
export const appConfig: ApplicationConfig = {
  providers: [
    provideRouter(routes),
    provideHttpClient(withFetch()),
    provideClientHydration(withEventReplay()), // 점진적 하이드레이션
  ],
};
F

Fit System

10년 이상의 소프트웨어 엔지니어링 경험을 가진 개발자입니다. 고성능 시스템 설계와 클라우드 네이티브 아키텍처를 전문으로 합니다.