왜 자꾸 관심사를 분리하라고 할까?

유정정·2025년 5월 4일

생각해보기

목록 보기
1/5

들어가기 전에

지금까지 여러 미션을 진행하며 '관심사 분리'라는 말을 수도 없이 들었다.

UI와 도메인을 나누고, 라우터 설정과 사용 코드를 나누고, 상태 관리와 유효성 검사를 나누고, 스타일링도 따로 빼보았다.

하지만 이렇게 많은 분리를 시도하면서도 '관심사 분리'가 정확히 무엇인지는 명확하게 설명하기 어려웠다.
그래서 이번 글에서는 다음과 같은 내용을 정리해보려 한다:

  1. 관심사 분리의 개념을 명확히 정의
  2. 리팩터링 과정에서 어떤 관심사들을 분리할 수 있을지
  3. 그리고 실제로 리팩터링을 진행할 때 어떤 기준으로 판단하고 논의할지

관심사 분리란?

관심사 분리(SoC, Separation of Concerns)는 복잡한 시스템을 더 작고 관리하기 쉬운 부분으로 나누는 것을 목표로 하는 소프트웨어 설계 원칙이다.
각 부분은 하나의 관심사 또는 기능만을 담당하도록 구성되어야 하며, 서로 다른 관심사가 한 코드에 섞이지 않도록 해야 한다.

즉, 관심사 분리는 서로 다른 책임을 가진 코드들을 분리하자는 개념이다.
그래서 화면을 그리는 UI와 데이터를 처리하는 도메인 로직은 각각 다른 역할(관심사)을 가지므로 분리하는 것이다.

하지만 실제로 처음 코드를 작성할 때는 이 기준을 항상 지키는 것은 쉽지 않다. 기능을 빠르게 구현해야 하거나, 처음부터 전체 구조를 파악하지 못하는 경우가 많기 때문이다. 그래서 나도 미션을 진행하면서 코드 리뷰에서

“이 부분에서 관심사 분리를 해줬으면 좋겠습니다!”

라는 피드백을 받아왔다.

내 경우에는 보통 완전한 기능을 먼저 구현한 뒤, 리팩터링 과정에서 관심사 분리를 고민하게 되는 것 같다.

그렇다면, 리팩터링을 시작하게 되었을 때 구체적으로 어떤 관심사들을 나눠볼 수 있을까?

리팩터링 할 때 어떤 관심사를 분리할 수 있을까?

1. UI vs Domain

  • UI: 화면에 무엇을 보여줄지를 결정하는 부분 (JSX, 스타일, 레이아웃 등)
  • Domain: 데이터 처리, 상태 관리, 유효성 검사, 비즈니스 로직 등 실제 동작을 담당

2. State vs View

  • 상태는 useState, useReducer, Context 등을 통해 추상화
  • View 컴포넌트는 해당 상태를 기반으로 화면만 그리도록 위임

3. API 호출 vs 화면 처리

  • fetch, axios 등 데이터 요청 로직은 hooks나 apis 폴더로 분리
  • UI 컴포넌트는 그 데이터를 받아서 렌더링만 담당

4. 이벤트 핸들링 vs 상태 변경 로직

  • handleClick 안에 비즈니스 로직이 모두 섞여 있을 때 이벤트 처리 함수와 실제 동작을 담당하는 함수로 역할 분리

5. 유효성 검사 vs 입력 상태 관리

  • 유효성 검사는 validate.ts 파일이나 별도 커스텀 훅으로 분리
  • 입력값 관리는 useState 또는 useReducer 등으로 따로 담당하도록 구성

이처럼 리팩터링 과정에서는 다양한 관심사들을 분리해볼 수 있다. 하지만 중요한 것은 단순히 "어떻게 나누는가"가 아니라, "왜 나누는가"에 대한 고민이라고 생각한다.

그렇다면, 우리는 왜 이런 분리를 하는 걸까?
그리고 관심사 분리를 통해 실제로 무엇을 얻을 수 있을까?

관심사 분리를 통해 우리가 얻을 수 있는 것

내가 직접 관심사 분리를 목표로 리팩터링을 해보면서, 다음과 같은 장점들을 체감할 수 있었다.

1. 가독성 향상

  • 하나의 파일, 그리고 하나의 함수가 하나의 일만 하게 만들었을 때 이 코드가 무슨 역할을 하는지 쉽게 파악할 수 있다.

2. 유지 보수성 향상

  • 기능을 추가하거나 버그를 수정할 때, 해당 책임을 가진 코드만 살펴보면 되기 때문에 디버깅과 수정이 수월했다.

3. 재사용성 증가

  • 비슷한 역할을 하는 다른 화면이나 상황에서도, 분리된 로직을 그대로 재사용할 수 있었다.

4. 테스트가 용이

  • 도메인 로직이 UI와 분리되어 있다 보니,
    화면 없이도 도메인 단위의 테스트가 가능했고, 반대로 UI 테스트도 도메인과 별개로 수행할 수 있었다.

5. 설계 유연성 & 확장성 향상

  • UI는 그대로 두고 로직만 교체하거나, 같은 로직을 다른 UI에 붙이는 구조도 가능해진다.
  • 도메인 로직이 명확히 분리되어 있다면, 다른 프로젝트에서도 재활용할 수 있다.
    (ex: 로또 미션에서의 UI 변경)

6. 사이드 이펙트 최소화

  • 로직이 한곳에 집중되어 있으면 변경 시 다른 코드에 미치는 영향이 줄어든다.
  • 반면에 관심사가 뒤섞여 있는 코드에서는 작은 수정도 전체 동작을 깨뜨릴 수 있다.

위에서 정리한 내용들은 내가 step1에서 기능을 먼저 완성한 뒤, step2에서 화면과 기능을 확장하는 구조의 미션들을 진행하면서 실제로 느낀 장점들이다.

하지만 이런 이점은 단지 특정 미션에서만 느낄 수 있는 것이 아니다. 실제 개발을 하다 보면, 기능이 어느 정도 완성된 이후에 새로운 요구사항이 추가되거나 화면이 확장되는 상황은 반복적으로 마주치게 된다.

그래서 관심사 분리와 같은 구조적인 리팩터링은, 미션을 넘어서 장기적으로 더 안정적이고 유연한 개발을 가능하게 해주는 핵심 전략이라는 생각이 들었다.

만약 앞으로 리팩터링을 해야 하는 상황을 마주친다면?

관심사 분리를 위한 리팩터링은 무조건 하는 것이 아니라, 명확한 목적과 기준이 있을 때 더 효과적이라는 생각이 든다.

특히 미션이나 실제 프로젝트에서, 리팩터링을 시작하기 전에 다음과 같은 질문을 먼저 던져보는 것이 도움이 될 것 같다.

내가 이 리팩터링을 왜 하려고 하는가?

  • UI가 단순히 화면 표시만을 담당하지 않고, 도메인 로직까지 함께 처리하고 있지는 않은가?
  • 로직과 스타일이 혼재되어 있어 유지보수가 어려운가?
  • 유효성 검사 로직이 컴포넌트 내부에 묶여 있어 테스트하기 어려운가?
  • 이 책임은 정말 이 컴포넌트의 몫인가? 혹은 훅/유틸로 분리하는 게 더 적절한가?
  • 리팩터링을 통해 테스트가 쉬워지거나, 로직 재사용이 쉬워질 수 있는가?

관심사 분리란 결국 "각 코드의 역할을 명확히 나누는 일"이다. 그래서 리팩터링을 시작할 때는 항상

"지금 이 코드에서 역할이 흐려진 지점은 어디일까?"

라는 질문을 먼저 던져봐야겠다.

마무리

이번 글을 정리하면서 관심사 분리는 그냥 코드를 나누는 기술이 아니라, 코드를 더 잘 이해하고 함께 다루기 위한 기준이라는 생각이 들었다.

앞으로 리팩터링을 할 때마다 '어떻게 나눌까?'보다는 '왜 나누는 게 좋을까?'를 먼저 떠올려보면 좋을 것 같다.

profile
🏖️ ㅤㅤ 🏊‍♂️

2개의 댓글

comment-user-thumbnail
2025년 5월 4일

"지금 이 코드에서 역할이 흐려진 지점은 어디일까?"
"'왜 나누는 게 좋을까?'를 먼저 떠올려보면 좋을 것 같다."
질문들이 좋은데요? 👍

1개의 답글