본 포스팅은
[토스] Youtube 채널의 "SLASH 21 - 실무에서 바로 쓰는 Frontend Clean Code"
영상을 보고 작성한 리뷰입니다.
[목차]
- 실무에서 클린 코드의 의의
- 안일한 코드 추가의 함정 (코드 리팩토링 예제)
- 로직을 빠르게 찾을 수 있는 코드
1. 응집도
2. 단일책임
3. 추상화
실무에서 클린 코드의 의의
좋지 않은 코드란 무엇일까?
1) 좋지 않은 코드는 흐름 파악이 어렵다.
2) 좋지 않은 코드는 도메인 맥락 표현이 안 되어 있다.
3) 좋지 않은 코드는 동료에게 물어봐야 알 수 있는 코드이다.
좋지 않은 코드는 개발의 병목이 되며, 유지보수할 때 시간이 오래 걸리며, 기능 추가가 불가능할 수도 있다. 따라서, 우리는 읽기 좋은 코드를 작성하여, 코드 리뷰 시간과 디버깅 시간을 단축함으로써 개발의 유지보수 시간을 단축해야 한다.
안일한 코드 추가의 함정
예제 : 보험에 대한 질문 입력 시, 내 설계사가 있는 경우 설계사 사진이 있는 팝업 추가하기
1) 기존 코드
현재 QuestionPage 컴포넌트는 form의 버튼을 클릭하면, 약관 동의를 받아서 팝업을 열고, 질문을 전송하는 역할을 한다.
2) 추가할 기능
- 팝업 상태 추가
- 기존 클릭 함수에 연결 중인 전문가를 검사하여 팝업을 여는 조건문 추가
- 연결 전문가 팝업에서 확인 버튼을 눌렀을 때 부를 새로운 클릭 함수 추가
- 연결 전문가 팝업 컴포넌트 추가
문제 정의
문제 1. 하나의 목적인 코드가 흩뿌려져 있다.
현재 코드는 추가한 팝업 관련 코드가 서로 떨어져있어서 유지보수할 때 스크롤을 위아래로 이동하며 찾아야한다는 문제가 있다.
문제 2. 하나의 함수가 여러 가지 일을 하고 있다.
현재 handleQuestionSubmit() 함수가 3가지 일을 하고 있다.
(1) 연결 전문가 받아서 팝업
(2) 약관 동의 받아서 팝업
(3) 질문 전송
이 경우, 해당 함수의 세부 구현을 모두 읽어야 함수의 역할을 알 수 있다는 문제가 있다.
문제 3. 함수의 세부 구현 단계가 제각각이다.
현재 코드는 handleQuestionSubmit()과 handleMyExpertQuestionSubmit()의 역할과 구분이 모호하다.
리팩토링
리팩토링 1. 함수 세부 구현 위계 맞추기
질문 전송하는 코드를 MyExpert와 NewExpert로 구분하여 함수를 분리한다.
리팩토링 2. form과 떨어져있던 팝업 컴포넌트를 form 내부로 뭉치기
- <PopupTriggerButton>이라는 하나의 컴포넌트를 만들어서 띄워줄 팝업 컴포넌트는 props로 내려보냄
- 연결 전문가가 있으면 MyExpert 함수를 담은 <연결전문가 팝업>
- 연결 전문가 없으면, NewExpert 함수를 담은 <Button> 컴포넌트
리팩토링 3. 함수가 한 가지 일만 하도록 쪼개기
- 여러 역할을 했던 handleQuestionSubmit()을 쪼개어 [약관 동의] 함수와 [연결 전문가] 함수로 분리
클린 코드는 짧은 코드가 아니라, 원하는 코드를 빠르게 찾을 수 있는 코드
로직을 빠르게 찾을 수 있는 코드
1. 하나의 목적을 가진 코드가 흩뿌려져 있을 때, 응집도를 높여 뭉쳐두어야 한다.
2. 함수가 여러가지 일을 하고 있을 때, 단일책임 원칙에 의거하여 쪼개줘야 한다.
3. 함수의 세부구현 단계가 제각각일 때, 추상화 단계를 조정하여 핵심 개념을 필요한 만큼만 조정해야 한다.
1. 응집도 : 서로 관련 있는 코드가 잘 뭉쳐져 있는가?
아래 코드 예제는 팝업을 조작하는 코드가 서로 떨어져 있어서 응집도가 낮다고 평가할 수 있다.
개선 1. 커스텀 훅을 사용하여 한 군데로 뭉친다.
useMyExpertPopup이라는 커스텀 훅으로 분리하여 openPopup 함수만 가져와 팝업을 열 수 있게 되었다. 하지만, 이는 openPopup이 무엇이고, 어떤 역할을 하는지, 그리고 버튼을 클릭 했을 때 어떤 액션이 취해지는지 알 수 없게 된다는 문제가 있다. 오히려 읽기 어려워진 것이다. 이는 커스텀 훅을 크게 분리하는 것으로만 사용한 대표적인 안티패턴이다.
그럼 어떻게 읽기 좋은 응집을 할 수 있을까?
그것은 바로, 남겨야할 핵심 데이터와 숨길 데이터를 나누는 것이다!
핵심 데이터 | 세부 구현 |
Button action Title Contents |
Popup state Popup markup 버튼 클릭 시, 호출할 함수 바인딩 |
즉, openPopup이라는 커스텀 훅에 핵심 데이터인 [팝업 제목], [팝업 내용], [액션]은 바깥에서 넘겨주도록 하고, 나머지는 숨긴다. 그러면, 해당 openPopup을 사용하는 컴포넌트에서도 핵심 내용을 파악할 수 있게 된다.
이러한 프로그래밍 방식을 선언형 프로그래밍이라고 한다.
물론, 선언형이 항상 좋은 것은 아니다. props로 어떤 데이터를 넘겨주어야하는지 등은 명령형으로 작성될 필요도 있다.
2. 단일책임 : 하나의 일을 하는 뚜렷한 이름의 함수를 만들자
함수 이름 후보 1번 : handle질문제출()
함수 이름은 질문 제출인데, [약관 체크]와 [질문 제출]이 섞여있고, 중요 포인트가 모두 담겨있지 않다. 이런 함수 이름은 읽는 이가 예상한 대로 코드가 동작하지 않으며, 코드에 대한 신뢰하락으로 이어진다.
개선 방법 1번 : 함수를 역할에 따라 분리하고, 필요에 따라 호출한다.
개선 방법 2-1번 : 리액트 컴포넌트를 통해 역할을 분리할 수 있다.
아래 예제에서는 onClick 함수에 [로그를 찍는 함수]와 [API 콜]이 섞여있다. <LogClick>이라는 컴포넌트를 만들어서 버튼을 감싸고, 버튼을 클릭하면 자동으로 클릭 로그가 전송되도록 리팩토링했다. 이제 버튼의 클릭 함수는 [API 콜]만 신경쓸 수 있게 된다.
개선 방법 2-2번 : 리액트 컴포넌트를 통해 역할을 분리할 수 있다.
IntersectionObserver를 다는 코드와 API 콜이 섞여 있다. 이 또한 Intersection 컴포넌트를 만들어 prop으로 API 콜을 넘겨주는 방식으로 분리할 수 있다.
3. 추상화 : 핵심 개념 뽑아내기
항상 높은 추상화 단계를 적용하는 것이 아닌, 상황에 따른 적절한 추상화 단계를 적용하여 개발해야 한다.
주의) 추상화 수준이 섞여 있으면 코드 파악이 어렵다.
높은 추상화가 항상 좋은 것은 아니며, 일관성을 유지하는 것이 중요하다.
Review
CleanCode를 읽고, 함수 역할 분리나 추상화 등의 개념들은 알고 있었지만, 대부분의 자료들이 java 등의 언어로 되어있어 javascript의 예제를 찾기 어려웠는데, 해당 영상에서 실무 예제와 함께 설명을 해줘서 상당히 도움이 되었다. 이제 프로젝트 리팩토링을 진행하며 해당 학습 내용을 적용할 것이다. 영상 끝에 언급한 것처럼, 두려워하지 말고 기존 코드를 씹고 뜯고 맛보고 즐기자. 과정을 문서로 작성하며 명확하게 기존의 문제를 파악하고 개선할 것이다.
'Development > Front-End' 카테고리의 다른 글
[UI/UX] 다수 데이터 등록 '한 번에 저장' vs '입력마다 저장' (0) | 2022.08.11 |
---|---|
[프로젝트 회고] WEVOTE - 온라인 선거 관리 서비스 (0) | 2022.06.27 |
[Review] FEConf Korea - 상태관리, 이제 Recoil 하세요 (0) | 2022.06.10 |
[온라인 선거 홍보 서비스] 프로젝트 회고 - UNIVVOTE편 (0) | 2021.11.14 |
Javascript Style Guide 와 ESLint에 대한 이해 (0) | 2021.11.09 |