SLASH 21 - Front-end Clean Code를 보고 나서..

nyongho·2022년 8월 5일
0

목차

  1. 실무에서 클린 코드의 의의

  2. 안일한 코드 추가의 함정

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

  4. 액션 아이템

실무에서 클린 코드의 의의

그 코드는 안 건드리시는 게 좋을 거에요. 일단 제가 만질게요 &&;

=> 이런 코드의 특징: 흐름 파악이 어렵다, 도메인 맥락 표현이 안되어 동료에게 물어봐야 알 수 있는 코드

실무에서 클린 코드의 의의 = 유지보수 시간의 단축 (코드파악, 디버깅, 리뷰)

안일한 코드 추가의 함정

  1. 코드 컨벤션 맞추기

  2. 하나의 함수는 하나의 일만 해야한다. (순수함수)

  3. 하나의 목적을 가진 코드는 하나로 뭉쳐 컴포넌트화 하자.

클린코드 !== 짧은코드, 클린 코드 === 원하는 로직을 빠르게 찾을 수 있는 코드

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

예시 1. 팝업 관련 코드

QuestionPage 컴포넌트에서 팝업을 사용할 것이다. 그럼 우리는 그 컴포넌트 안에 popup 상태 관련 state를 정의하고 관련 함수를 만들고 마지막으로 Popup 컴포넌트를 불러와 상태값을 props로 전송해준다.

function QuestionPage () {
const [popupOpened, setPopupOpened] = useState<boolean>(false);

function handlePopupSubmit()
{
 await 질문전송(연결전문가.id);
 alert("질문을 전송했습니다.")
}

return(
 <Popup title="보험 질문하기" open={popupOpened}>
    <button onClick={handlePopupSubmit}>확인</button>
  </Popup>
)
}

하지만 이는 팝업을 조작하는 코드가 총 세 군데에 뚝뚝 떨어져있어서 가독성도 좋지 않을 뿐더러 버그 발생 위험이 높다.

function QuestionPage() {
  // custom-hook
 const [openPopup] = useMyExpertPopup(연결전문가.id);
  
  function handleClick () {
    openPopup();
  }
  
  return <button onClick={handleClick}>보험 질문하기</button>
}

그래서 다음과 같이 팝업과 관련된 코드를 모두 하나의 커스텀 훅으로 제작했다. 따라서 QuestionPage 컴포넌트의 총 코드의 길이는 현저히 줄게 되었다. 하지만 위 코드는 오히려 해당 팝업이 어떤 내용을 띄우는지, 버튼을 눌렀을 때 어떤 액션을 하는지가 보이지 않아 결국 마찬가지로 읽기 힘든 코드가 되어버린다.

보기 더러울때 일단 뭉쳐둔다 => 커스텀훅의 대표적인 안티패턴

따라서 당장 몰라도 되는 디테일은 숨기고, 코드 파악에 필수적인 핵심 정보를 보여주는 것이 중요하다.

function QuestionPage () {
const [popupOpened, setPopupOpened] = useState<boolean>(false);

function handlePopupSubmit()
{
 await 질문전송(연결전문가.id);
 alert("질문을 전송했습니다.")
}

return(
 <Popup title="보험 질문하기" open={popupOpened}>
    <button onClick={handlePopupSubmit}>확인</button>
  </Popup>
)
}

여기서 코드의 핵심 데이터는 팝업 버튼 클릭시 액션과 제목, 내용이다.
그리고 세부 구현은 팝업 열고 닫기 상태, 컴포넌트 관련 마크업이다.

function QuestionPage() {
  // custom-hook
 const [openPopup] = usePopup();
  
  async function handleClick () {
    const confirmed = await openPopup({
      title: "보험 질문하기",
      contents: <div>전문가가 설명드려요</div>,
    });
    if (confirmed) {
      await submitQuestion();
    }
  }
  
  async function submitQuestion(연결전문가) {
    await 질문전송(연결전문가.id);
    alert("질문을 전송했습니다.");
  }
  
  return <button onClick={handleClick}>질문하기</button>
}

핵심은 openPopup이라는 커스텀 훅 안에 모든 코드를 다 숨기는게 아니라 세부 구현만 숨겨놓고, 핵심 데이터를 밖에다 보여주는것이다.
이를 선언적 프로그래밍이라고 한다. 특징은 '무엇'을 하는 함수인지 빠르게 이해가 가능하다는 것이다.

<button onClick={async() => { const res = await 회원가입(); if (res.success) { 프로필로이동(); }}}
전송
</button>

다음과 같이 하나하나 세부 구현을 작성한 방식을 명령형 프로그래밍이라고 한다. (현재 실무에서 짠 코드도 명령형으로 짜여진 부분이 많다는 사실..)

단일 책임 원칙 (SRP)

최근 클린 아키텍처라는 책을 읽었을 때 객체 지향의 SOLID 원칙에 대해 알게 되었고 이를 리액트 같은 함수형 프로그래밍에 가까운 프레임워크에 어떻게 적용할까? 라는 고민을 했었다.
그리고 다음의 글을 발견하게 되어 어떻게 SOLID 원칙에 의거하여 더 좋은 코드 로직을 짤 수 있는지 감이 왔는데 이분도 마침 단일 책임 원칙을 언급해주셨다.

일단 단일 책임 원칙의 정의는 다음과 같다.

모든 클래스 혹은 메소드는 각각 하나의 책임만 가져야 한다.

이는 함수형 프로그래밍에서 하나의 함수는 하나의 책임만 가져야 한다. (순수함수)로 바라볼 수 있다.

async function handle질문제출() {
  const 약관동의 = await 약관동의_받아오기();
  if(!약관동의) {
    await 약관동의_팝업열기();
  }
  await 질문전송(questionValue);
  alert("질문이 등록되었어요.");
}

분명 함수의 이름은 질문제출만 해야하는 함수이지만 그 안을 들여다보면 약관동의와 질문제출이 동시에 이루어지고 있다.
이렇게 함수명과 그 안의 코드가 일관적이지 못한다면 유지보수 차원에서 의심이 가게되고 평소라면 바로 이해하고 넘겨도 되는 코드를 정말로 이 일만 하는 코드인지 다시 한 번 확인해야하는 웃픈 상황까지 연출된다.

만약 여기서 기능 추가까지 된다면 이 함수에 대한 신뢰도는 더욱 하락하게 될 것이고 결국 다음과 같은 말을 하게 될 것이다.

그 코드는 안 건드리시는게 좋을 거에요. 일단 제가 만질게요 ^^..

따라서 우리는 하나의 함수에 여러가지 일을 하는 함수보다는 함수를 여러개로 분리해 하나의 함수는 오직 한 가지 일만 하게끔 개발해야한다.

async function handle약관동의팝업() {
  const 약관동의 = await 약관동의_받아오기();
  if(!약관동의) {
    await 약관동의_팝업열기();
  }
}

async function새전문가질문제출() {
  await 질문전송(questionValue);
  alert("질문이 등록되었어요.")
}

추상화

액션 아이템

1. 담대하게 기존코드 수정하기

두려워하지 말고 기존 코드를 씹고 뜯고 맛보고 즐기자

2. 큰 그림 보는 연습하기

그 때는 맞고 지금은 틀리다. 기능 추가 자체는 클린해도, 전체적으로 어지러울 수 있다.

3. 팀과 함께 공감대 형성하기

코드에 정답은 없다. 명시적으로 이야기를 하는 시간이 필요하다.

4. 문서로 적어보기

향후 어떤점에서 위험할 수 있는지, 어떻게 개선할 수 있는지

profile
두 줄 소개

0개의 댓글