당신의 프레임워크는 교체 가능하다. 당신의 아키텍처는 아니다.

발행: (2026년 2월 8일 오전 12:05 GMT+9)
8 분 소요
원문: Dev.to

Source: Dev.to

프레임워크는 본질적으로 일시적입니다.
프레임워크는 등장하고, 주목을 받으며, 몇 년간 논의를 장악한 뒤 결국 교체되거나 근본적으로 재구성됩니다. 이것은 프론트엔드 개발의 결함이 아니라, 도구, 브라우저, 그리고 개발자 기대치의 급속한 혁신에 따른 자연스러운 결과입니다.

많은 팀이 저지르는 실수는 “잘못된” 프레임워크를 선택하는 것이 아니라, 오늘 선택한 프레임워크가 내일도 동일한 방식으로 코드베이스를 형성할 것이라고 가정하는 것입니다. 시간이 지나도 안정적으로 유지되어야 할 것은 애플리케이션의 비즈니스 로직입니다: 실제 요구사항을 나타내는 규칙, 검증, 워크플로우, 제약 조건 등. 안타깝게도 많은 프론트엔드 프로젝트에서 이 두 가지가 긴밀하게 얽혀 있습니다.

문제: 프레임워크 결합

이론적으로 프레임워크는 단지 도구일 뿐이며 비즈니스 규칙은 컴포넌트 내부에 구현됩니다. 처음에는 효율적으로 느껴집니다—모든 것이 가깝게 위치하고, 인지적 부담이 적으며, 진행 속도가 빠릅니다. 그러나 시간이 지나면서 프레임워크는 교체 가능한 세부 사항이 아니라 시스템이 핵심적으로 작동하는 방식을 정의하게 됩니다. 프레임워크를 변경하는 것은 단순한 UI 수정이 아니라 근본적인 재작성으로 이어집니다.

이러한 결합을 드러내는 전형적인 시나리오:

  • 새로운 프레임워크 버전으로 마이그레이션
  • 두 번째 UI 도입(예: 모바일 또는 데스크톱)
  • 다른 환경에서 로직 재사용
  • 의미 있는 방식으로 테스트 커버리지 향상

비즈니스 로직이 프레임워크 개념과 얽혀 있을 때, 이를 추출하려면 컴포넌트 렌더링, 라이프사이클 시뮬레이션, 광범위한 목킹을 함께 수행해야 합니다. 기본 규칙은 변하지 않아도 작은 변경이 UI 계층 전체에 파급 효과를 일으킵니다.

지침: 변화 속도에 따라 구분

예상되는 변화 속도에 따라 관심사를 구분하는 유용한 아키텍처 원칙입니다:

  • Frameworks는 빠르게 변합니다.
  • UI paradigms는 진화합니다.

Guideline: UI 레이어는 조정하고, 도메인 레이어는 결정합니다.

  • UI layer – 사용자 상호작용 및 프레젠테이션을 담당합니다. 입력을 수집하고, 애플리케이션 로직을 호출하며, 결과를 렌더링합니다. 여기에는 검증 규칙, 비즈니스 결정, 부수 효과가 포함되지 않아야 합니다.
  • Domain layer – UI 기술과 무관하게 핵심 비즈니스 규칙 및 워크플로우를 포함합니다.

예시: UI vs. 도메인 코드

UI‑중심 구현 (프레임워크 코드)

// UI component (framework code)
component CheckoutForm {
  state email = ""

  onSubmit() {
    if (!email.includes("@")) {
      showError("Invalid email")
      return
    }

    const response = http.post("/checkout", { email })

    if (response.ok) {
      navigate("/success")
    } else {
      showError("Checkout failed")
    }
  }

  render() { /* ... */ }
}

문제점:

  • 검증 및 결제 워크플로우가 컴포넌트 라이프사이클, 프레임워크 상태 관리, UI 수준 오류 처리에 고정되어 있습니다.
  • 논리를 재사용하거나 테스트하려면 프레임워크가 필요합니다.

리팩터링된 분리 (순수 도메인 코드)

// Domain / application layer (plain code, no framework)
function validateEmail(email) {
  if (!email) return { error: "Email is required" }
  if (!email.includes("@")) return { error: "Invalid email" }
  return { ok: true }
}

async function submitCheckout(email, httpClient) {
  const validation = validateEmail(email)
  if (validation.error) return validation

  const response = await httpClient.post("/checkout", { email })
  if (!response.ok) return { error: "Checkout failed" }

  return { ok: true }
}
// UI component (framework code) using the domain layer
component CheckoutForm {
  state email = ""
  state error = null
  state loading = false

  async onSubmit() {
    loading = true
    error = null

    const result = await submitCheckout(email, http)

    loading = false

    if (result.error) {
      error = result.error
    } else {
      navigate("/success")
    }
  }

  render() { /* ... */ }
}

장점:

  • 도메인 함수는 어디서든 호출할 수 있습니다 (UI, CLI, 백그라운드 작업, 테스트).
  • 컴포넌트를 렌더링하지 않아도 테스트할 수 있습니다.
  • UI 프레임워크가 변경되더라도 재사용 가능하며, UI를 가볍고 교체 가능하게 유지합니다.

테스트 가능성을 넘어선 중요성

  • 위험 감소: 프레임워크가 진화할 때 마이그레이션 위험과 리팩토링 비용을 낮춤.
  • 장수: 코드베이스의 유용한 수명이 더 길어짐.
  • 명확성: 비즈니스 로직이 UI 메커니즘과 분리된 한 곳에 존재해 전체 코드 품질이 향상됨.

프레임워크 업그레이드는 종종 점진적이라고 가정되지만, 많은 프레임워크가 그들의 사고 모델을 크게 변경한다. 따라서 아키텍처는 우아함보다 위험 관리에 더 중점을 둔다.

실용적인 성찰

5년 후에 프론트엔드 프레임워크를 교체해야 한다면, 스스로에게 물어보세요:

  1. 시스템의 어떤 부분이 그대로 유지될 수 있을까요?
  2. 어떤 부분을 처음부터 다시 작성해야 할까요?

답이 “거의 모든 것을 다시 작성해야 한다”라면, 프레임워크가 곧 여러분의 아키텍처가 된 것입니다—재고할 가치가 있는 선택이죠.

Back to Blog

관련 글

더 보기 »

무한 코드 시대의 이해도 우위

수십 년 동안 소프트웨어 엔지니어링의 “hard part”는 바로 창조 행위였다. 당신은 앉아 논리와 씨름하고, 그 의도를 수동으로 구문으로 번역했다....