SLASH 21 / 실무에서 바로 쓰는 Frontend Clean Code
📄

SLASH 21 / 실무에서 바로 쓰는 Frontend Clean Code

Created
Jul 14, 2021 08:05 AM
Tags
web
javascript
refactoring

실무에서 바로 쓰는 Frontend Clean Code

 

실무에서의 클린 코드란

  • 특정 개발자만이 다룰 수 있는 코드는 클린 코드라 할 수 없음
    • 이를 '지뢰 코드'라 함
    • 흐름 파악이 어려움 / 도메인 맥락 표현이 안 됨 / 동료에게 물어봐야 함
    • 즉, 유지보수 시간이 늘어나게 됨
 
  • 실무에서의 클린 코드 = 유지보수 시간의 단축
 
  • 처음에는 클린했음
    • 하지만, 기존 코드에 기능을 추가하며 더러워짐
    • 회사 일의 90%가 기존 코드에 기능을 추가하는 것이라 더더욱 중요
 

안일한 코드 추가의 함정

  • 마구잡이로 생각 없이 추가하다 보면 금방 들쑥날쑥한 코드가 되어버림
 
더러운 코드
  • 하나의 목적인 코드가 흩뿌려져 잇어 기능 파악 시 스크롤을 위아래로 이동해줘야 함
  • 하나의 함수가 여러가지 일을 함
  • 함수의 세부 구현 단계가 제각각
    • 비슷한 이름의 함수인데, 서로 다른 기능을 하고 있다거나...
    • 가령 getAgetB 라는 이름의 함수가 있다 하면
      • getA 는 서버에 데이터를 Request한 뒤 이를 파싱하고, 그 결과를 반환해주는 함수
      • getB 는 단순히 b 라는 이름의 Class member를 반환하는 함수
      • 이러한 함수는 서로 구현 단계가 제각각이라 볼 수 있음
 
리팩토링 방안
  • 함수의 세부 구현 단계 통일
    • 비슷한 이름의 함수는 서로 비슷한 동작을 하게끔 함
    • 가령, getAgetB 는 둘 다 각각 ab 라는 이름의 Class member를 반환하도록 함
 
  • 하나의 목적인 코드는 뭉쳐 두기
    • 만약 팝업을 여는 버튼 컴포넌트 코드와 팝업 컴포넌트 코드가 동떨어져 있는 경우
      • // jsx
        
        return (
          <article>
            <button onClick={openPopup}>팝업 열기</button>
            {popupOpened && (<PopupComponent />)}
          </article>
        );
    • 이를 버튼의 Properties에 팝업 컴포넌트를 바인딩하던가 해서 하나로 뭉쳐둠
      • // jsx
        
        return (
          <article>
            <PopupTriggerButton popup={(<PopupComponent />)}>
              팝업 열기
            </PopupTriggerButton>
          </article>
        );
    • 따로 떼서 두지 않음
 
  • 함수가 한 가지 일만 하도록 쪼개기
    • 함수 하나에서 하나의 일만 하도록
      • // before
        
        async function fetchX() {
          const data = await (await fetch('url_1')).text();
          const parsedData = parse(data);
          const xValue = parsedData.x;
        
          await fetch('url_2', { method: 'post', body: { value: xValue } });
        
          return xValue;
        }
        
        
        
        // after
        
        async function fetchUrl_1() {
          return await (await fetch('url_1')).text();
        }
        
        async function postValueToUrl_2(value) {
          return await fetch('url_2', { method: 'post', body: { value } });
        }
        
        async function fetchXFromUrl_1() {
          const data = await fetchUrl_1();
          const parsedData = parse(data);
          return parsedData.x;
        }
 
클린 코드란
  • 클린 코드 ≠ 짧은 코드
  • 클린 코드 = 원하는 로직을 빠르게 찾을 수 있는 코드
 
  • 원하는 로직을 빠르게 찾으려면?
    • 응집도를 높임: 하나의 목적을 가진 코드는 뭉쳐두기
    • 단일책임 원칙: 함수는 하나의 일만 하도록
    • 추상화: 추상화 단계를 조정해 함수의 세부 구현 단계를 네이밍과 일관되게 맞춰줌
 

로직을 빠르게 찾을 수 있는 코드

응집도: 같은 목적의 코드는 뭉쳐 두자
  • React의 Custom Hooks나 Vue의 Composables를 이용해 같은 목적의 코드를 뭉침
    • 다만 어떤 내용을 담고 있고, 어떤 동작을 하는지 명확하지 않다는 단점이 있음
 
  • 뭉치는 코드는 ⇒ 당장 몰라도 되는 디테일을 뭉침
    • 짧은 코드만 보고도 빠르게 파악이 가능하도록 함
    • 코드 파악에 필수적인 핵심 정보까지 뭉쳐두면 되려 파악이 어려워짐
    • 클린 코드 ≠ 짧은 코드
 
  • 코드 응집 팁: 핵심 데이터와 세부 구현 나누기
    • 남겨야 할 핵심 데이터와 숨겨도 될 세부 구현을 나눔
      • 팝업을 예로 들자면...
      • 핵심 데이터: 팝업 버튼 클릭 시 액션, 팝업 제목, 팝업 내용
      • 세부 구현: 팝업을 여닫을 때 사용되는 State, 컴포넌트의 세부 마크업, 팝업 버튼 클릭 시 팝업을 열어야 한다는 데이터 바인딩
    • 핵심 데이터인 팝업 제목, 내용, 팝업 버튼 Action은 외부에서 넘기도록 구성
 
  • 이를 선언적 프로그래밍이라 함
    • 핵심 데이터를 전달하면 미리 구성된 세부 구현을 이용해 결과물을 보여줌
    • 무엇을 해야할지만 알려주는 것 ⇒ "무엇"을 하는 함수인지 빠르게 파악이 가능
    • 명령형 프로그래밍의 경우 어떻게 해야 할지 하나 하나 구성이 필요
    • 다만 당연히 패러다임은 뭐가 좋다 이런게 아니고 특정 상황마다 유동적으로 사용
 
  • 이렇게 구성하는 것이 좋은 이유 한 가지 더
    • 각각의 코드(함수)가 Testable 해짐
 
단일책임: 하나의 일을 하는 뚜렷한 이름의 함수를 만들자
  • 함수가 하는 일을 명확하게 나타내는 함수 이름을 짓도록 함
    • handle질문제출 = 질문 제출만을 위한 함수
    • handle약관동의팝업&질문제출 = 약관동의 팝업과 질문 제출을 위한 함수 ⇒ 다만, 이 경우 이 둘을 나눠주도록 함 (handle약관동의팝업)
 
  • 단일책임 원칙을 따르지 않을 경우
    • 개발이 진행되며 함수명으로 의미를 파악하기 어려워지게 됨
    • 의미 파악이 어려워지면 함수의 세부 구현을 봐야 하고 ⇒ 개발 및 유지보수 비용 증가
 
  • 기능성 컴포넌트
    • 선언적 프로그래밍을 통해, 한 가지 일만 하는 컴포넌트를 정의해 사용
    • slot 을 통해 하위 컴포넌트를 감싸는 방식으로도 개발이 가능
      • <LogClick log-message='제출 버튼 클릭'>
        	<button onClick={openConfirm} />
        </LogClick>
 
  • 이름 짓기가 어렵다면 한글 변수도 유용
    • 결국 "빠르게 로직을 판별할 수 있도록 하는 것"이 목적
 
추상화: 핵심 개념을 뽑아내자
  • 핵심 데이터만 남기고 나머지는 추상화
 
  • 얼마나 추상화? 추상화 레벨
    • 최대한 재사용 가능한 레벨까지 상황에 따라 필요한 만큼 추상화
    • 사용하는 입장에서 알아야 하는 레벨까지, 그리고 유연성을 생각해볼 수 있겠지
 
  • 추상화 레벨은 서로 맞춰줌
    • 전체적인 코드가 어느 수준으로 추상화 되어있는지 파악할 수 있어야 함
    • 추상화 단계를 비슷하게 정리해주면 코드를 빠르게 이해할 수 있음
 

바로 사용 가능한 액션 아이템

  • 담대하게 기존 코드 수정하기
    • pr에 file changes가 많아져도 괜찮음
    • 이를 피하고자 한다면 새로운 branches를 따서 refactoring pr하도록 해도 됨
 
  • 큰 그림 보는 연습하기
    • 기능 추가 자체는 클린해도, 전체적으로 보기에 어지러울 수 있음
 
  • 팀과 함께 공감대 형성하기
    • 코드에 정답은 없음 ⇒ 명시적으로 이야기를 나누는 시간이 필요
    • 클린 코드 관련된 코멘트가 필요하다고 판단되면 달자
    • 당장에 "이게 굳이 Clean 해야 하나?" 생각되어도 점차 쌓이면 더러워질 것이 분명하기 때문
 
  • 문서로 적어보기: 글로 적어야 명확해진다
    • 향후 어떤 점에서 이 로직이 위험할 수 있는가?
    • 이 로직을 어떻게 개선할 수 있는가?
 

Loading Comments...