React 디자인 패턴에 대한 고민

손완서·2022년 5월 24일
41
post-thumbnail

배경

2022년 5월 24일 밤 10시, 테오님의 프론트엔드 오픈채팅방에

전부터 계속 고민하던 건데 다른 분들의 의견을 듣고 싶어 여쭤봅니다 ..

혹시 React 애플리케이션을 개발하실 때 비즈니스 로직을 뷰 코드와 분리하시나요?
만약 분리하신다면 어떤 방식으로 분리하시나요 ??

라는 질문을 남겼다.

여러 의견들이 오갔다.
그 중 내가 전에 고민했었던 내용도 있었고, 처음으로 생각해보게 된 내용도 있었다.

이 글에서 내가 지금까지 했던 디자인 패턴, 아키텍처 등에 대한 고민들을 공유하고 조언을 구하려고 한다.

참고로 필자는 아직 클린 코드와 클린 아키텍처 등에 대하여 깊게 공부해본 적이 없다.
이 글에서 나열되는 고민들은 현업에서 구르다 피부로 느낀 고민들이다.

메인

용어 정리

  • 뷰: React 컴포넌트에서 반환하는 JSX 및 기타 CSS 관련 코드
  • 뷰 로직: isLoading, errorText와 같은 UI/UX 개선을 위한 코드
  • 비즈니스 로직: API Call, 데이터 가공 및 저장 로직

1. 컴포넌트는 어떻게 분리해야 할까?

컴포넌트란 프로그래밍에서 재사용 가능한 단위의 독립적 모듈을 일컫는다.

내가 컴포넌트를 분리하는 기준은 2가지이다.

첫 번째는, 재사용성.
컴포넌트의 가장 기본적인 역할이다.
중복되는 뷰 코드 조각이 있다면 이를 컴포넌트화하여 여러 파일에서 사용할 수 있게 한다.

두 번째는, 가독성 향상.
프론트엔드에서 뷰 관련 코드는 필수불가결하게 존재할 수 밖에 없다.
종종 한 파일에서 뷰 관련 코드가 너무 많아 코드의 가독성이 저하되는 경우가 발생한다.
이 때 재사용성과는 관련이 없지만 코드 라인 수를 줄이고 개별 모듈로 분리하여 가독성을 높일 수 있다.

2. 뷰 로직은 어떻게 관리해야 할까?

첫 번째로 생각했던 방법은, Container - Presenter 패턴이다.

2~3년 전 필자가 막 웹 개발 공부를 시작할 때, Container - Presenter 패턴으로 작성된 프로젝트가 많았다.
(이는 Redux라는 상태 관리 라이브러리를 활용하여 데이터 로직과 뷰 코드를 분리할 수 있기 때문이었다.)

하지만 최근 개발되는 프로젝트에서는 해당 패턴을 사용하지 않는 경우가 대부분이다.
이유는 이곳에서 설명해준다.

또한, 개인적으로 Container - Presenter 선호하지 않는 이유는 생산성 저하 때문이다.
해당 패턴은 Container 내부에서 Presenter 컴포넌트를 반환하는 구조가 된다.
Container에서 대부분의 뷰 로직을 처리하고 state를 props로 Presenter에게 전달해주다보니 전달되는 Props가 많아지고(Container의 JSX 부분이 해괴망측한 코드가 되어버리는...), 뷰와 뷰 로직이 서로 다른 파일로 분리되어 있다보니, 개발할 때 파일을 왔다갔다 하는 게 생산성 저하로 이어지는 느낌을 크게 받았다.

위 문제점을 해결하기 위해 생각했던 방법은, 뷰와 뷰 로직을 분리하지 말고 한 파일에서 같이 관리하자!였다.

이렇게 했을 때, 기존에 방법에서 느꼈던 문제점을 단 번에 해결할 수 있었다.

아직 경험하지 못해봤지만 추후에 뷰 로직이 많은 서비스를 개발하게 되면 그 때는 또 다른 패턴을 고민해봐야 할 것 같다.

3. 비즈니스 로직은 어떻게 관리해야 할까?

가장 고민을 많이 했던 부분이고, 아직까지도 그렇다 할 답을 못 내렸다...
여러 방법을 생각해봤는데, 각각 장단점이 있는 것 같다.

첫 번째 방법은 Page 파일에 뷰, 뷰 로직과 함께 작성하기이다.

개인적으로 선호하지 않는 방법이다.
이렇게 되면 Page 파일이 방대해진다.
한 눈에 파일의 역할 및 기능들을 파악하기 어렵고, 이는 심각한 생산성 저하로 이어진다.

두 번째 방법은 비즈니스 로직을 Custom Hook으로 개발하기이다.

이는 실제로 많이 사용하고 있는 방법으로 알고 있다.
필자도 이 방법을 시도해 본 적이 있었다.

개인적으로는 이 방법도 선호하지 않는다.
기본적으로 React Hook은 여러 파일에서 반복되는 React State 관련 코드를 모듈화하는 목적으로서 사용한다. 참고
반복되지 않는 비즈니스 로직도 Custom Hook으로 개발하는 건 본래 목적에 어긋난다고 생각한다.

또한, 적어도 필자의 경험에 한해서는 비즈니스 로직에 React State가 필요했던 적은 적었고, 그런 코드는 좋은 코드라고 생각하지 않는다.
애초에 React는 뷰 개발을 도와주는 라이브러리로서 만들어졌기 때문에, 뷰 관련 코드 외에는 React State 사용을 지양해야 한다고 생각한다.

이를 허용한다고 하더라도, 위에서 말했듯이 비즈니스 로직에 React State가 필요했던 적은 적기 때문에 코드의 일관성을 해칠 수 있다.
어떤 함수에서는 React State가 필요하여 Custom Hook으로 만들고, 어떤 함수는 React State가 필요하지 않아 일반 함수로 만든다면 코드의 일관성이 맞지 않는다.

React State가 필요하지 않아도 Custom Hook으로 만든다면, 사실상 그건 Custom Hook이 아닌 것

개인적으로 채택한 세 번째 방법은 Service 파일, Helper 파일을 분리하여 개발하기이다.

위에서 언급했다시피 필자는 비즈니스 로직을 Custom Hook으로 개발하는 것을 선호하지 않는다.
일반 함수로 작성해야 한다고 생각한다.
따라서 비즈니스 로직은 Service 파일로 분리하여 Class로 작성하는 편이다.
이 중에서 API Call을 하는 부분은 서버와 통신하는 부분이기 때문에 비즈니스 로직과 결을 달리하므로 Helper 파일로 분리하여 개발하는 것을 선호한다.

결론

중간중간 필자가 왜 채택하지 않았는지에 대한 이유를 설명하려고 다른 패턴을 비판하는 내용을 포함했지만, 이 모든 것은 주관적인 의견이 크게 반영된 글이고 답은 없다고 생각한다.

모든 고민들은 가치있고, 중요하다.
이 글은 필자의 고민을 공유하고 결과에 대하여 피드백 받기 위해 작성한 글이다.

반대 의견은 언제나 환영이고, 클린 코드와 아키텍처에 대하여 공부해 본 적 없는 실전 압축형 경험이기 때문에, 필자가 고려하지 못한 이론적인 개념도 환영이다.

이 글이 필자와 비슷한 고민을 한 독자에게 도움이 되고, 서로의 의견을 공유하는 토론의 장이 되었으면 좋겠다.

필자의 고민 정리

스스로에 대한 비판

  1. 정말 글을 못쓴다는 걸 체감하게 되었습니다 ...
  2. 코드의 가독성은 그렇게 강조했으면서, 정작 이 글의 가독성은 챙기지 못했습니다 ...
  3. 새벽에 갑자기 작성하게 된 글이라 논리적인 요소가 부족했을 수 있습니다 ...

짧지만 굵었던 토론의 흔적

좋은 의견 주신 파이버님과 O_O님에게 감사 인사 드립니다.

profile
프론트엔드 개발자

8개의 댓글

comment-user-thumbnail
2022년 5월 24일

진짜 고민이 느껴지고 전달되는 글이네요~ 어떻게해야 좋은 코드인지 어떻게 해야 좋은 구조인지는 끊임없이 고민을 해야 하는 개발자의 숙명과도 같은거 같아요 ㅎ

함수형 프로그래밍을 공부하면서 좋은 구조는 계층을 잘 분리하고 섞이지 않도록 하는것이 중요하다고 생각했고 많은 계층에 이름을 붙여보는 것을 해본적이 있습니다. action store state filter service query mutation story effect libs utils ...

아직 저도 Best를 찾아가는 중이지만 이렇게 카테고리화를 세분화 하다보니 저에게 맞는 구조가 조금 보이는거 같아요~

많은 고민과 시도들이 공유가 되었으면 좋겠습니다 :)

1개의 답글
comment-user-thumbnail
2022년 5월 26일

React Native라 웹이랑은 약간 다를 수도 있겠지만, 저 같은 경우에는 _Container + _Presenter (+ _Cmpnt) 구조에 비즈니스 로직을 담당하는 Custom Hook을 사용하는 식으로 살짝 변형해 사용하고 있습니다.

Container에서는 그 페이지의 Custom Hook들이 모여서 서로 데이터를 주고받고, 페이지에 의존성이 있는 State 들을 관리하는 식으로 구현합니다. Presenter는 Custom Hook의 반환 객체를 통째로 넘겨서 필요한 데이터들을 불러와 사용합니다.

이렇게 사용하니까, Custom Hook을 통한 중복되는 비즈니스 로직이 Container (페이지)에 의존하지 않으니 다른 페이지에서 재사용할 수 있게 되고, Presenter는 내부적으로 컴포넌트화 해서 많다면 _Cmpnt로 별도로 빼서 재사용할 수 있도록 하구요.

2개의 답글
comment-user-thumbnail
2022년 5월 30일

저도 관심있게 공부했던 주제여서, 나름 도움이 됐었던 자료를 공유해드리고 싶네요.. :)
5 advanced react patterns
이건 제 번역글입니다..!

1개의 답글