Tidy First? Part 1. 코드 정리법

이희제·2024년 5월 19일
post-thumbnail

Chapter 1. 보호 구문

보호 구문이 있는 코드라면 전제 조건이 명시적으로 드러날 때 분석하기 쉽다.

function canDrive(age) {
  // 보호구문: 나이 유효성 검사
  if (typeof age !== 'number' || age < 0) {
    console.error("Invalid age provided!");
    return false;
  }

  if (age >= 16) {
    console.log("You are old enough to drive.");
    return true;
  } else {
    console.log("You are not old enough to drive.");
    return false;
  }
}

Chapter 2. 안 쓰는 코드

안 쓰는 코드는 지워버리자.(조금만) 형상 관리 도구를 쓴다면 나중에 다시 불러올 수 있기 때문에 걱정말자.

Chapter 3. 대칭으로 맞추기

같은 로직임에도 불구하고 다양한 방식으로 코드를 작성할 수 있다. 하지만 같은 패턴을 일관성 있게 코드 작성 방식에 적용시키자.

그래야 코드를 읽기 편하다. 읽는 입장에서는 코드의 일관성이 중요하다.

  1. 한 가지 방식을 선택 후 다른 방식으로 작성한 코드를 선택한 방식으로 고치자
  2. 비슷해 보이지만 같지 않은 루틴을 찾고 그 같은 부분들 속에 다른 부분을 분리하자.

Chapter 4. 새로운 인터페이스로 기존 루틴 부르기

루틴을 호출해야 하는데 기존 인터페이스 때문에 어렵거나, 복잡하거나, 혼란스럽다면 호출하고 싶은 인터페이스를 새롭게 구현해서 호출하자.

이처럼 새로 구현한 통로 인터페이스를 이용해 설계하면 변경하기 한층 더 수월하다.

Chapter 5. 읽는 순서

코드를 읽을 때는 독자의 입장이 되어 보자. 읽기 좋은 순서로 코드를 작성하면 코드의 세부 사항을 파악하는데 좋다.

읽는 순서가 영향을 크게 주는 것들부터 바꾸자. 경험을 살려서 순서를 결정하자.

Chapter 6. 응집도를 높이는 배치

변경할 요소들은 코드의 순서를 바꿔서 가까이 두자. 두 루틴에 결합도가 있으면 서로 옆에 두자.

파일에도 적용할 수 있는데 결합도가 있다면 같은 디렉토리에 파일을 두자.

결합도를 제거할 수 있으면 제거하는게 가장 좋다.

Chapter 7. 선언과 초기화를 함께 옮기기

선언과 초기화 코드가 떨어져 있으면 읽어내기 어렵다. 한참 뒤에야 초기화 코드를 보게 된다면, 어떤 맥락에서 변수가 선언되었는지 잊어버릴 수 있기 때문이다.

되도록이면 변수의 선언과 초기화를 함께 하거나 가까이 두자. 다만, 데이터 종속 순서도 같이 유지해야 한다. (작은 단계로 해보자.)

Chapter 8. 설명하는 변수

표현식의 의도가 드러나도록 변수 이름을 만들자.

예시) 너비와 높이, 위쪽과 왼쪽, 뛰기와 오르기 등으로 변수명으로 만드는 것

Chapter 9. 설명하는 상수

상징적인 상수를 만든자. 리터럴 상수로 사용된 곳은 상징적인 상수로 바꾸자.

한번에 바뀌어야 하거나 함께 이해해야 하는 상수들은 한곳에 모아두고, 다른 이유로 묶인 변수들은 분리하는 후속 작업이 필요하다.

const MAX_LOGIN_ATTEMPTS = 3;
const SESSION_TIMEOUT = 30; // minutes
const DEBUG_MODE = true;

function checkLoginAttempts(attempts) {
  if (attempts >= MAX_LOGIN_ATTEMPTS) {
    console.log("Account locked due to too many login attempts.");
  } else {
    console.log("Login attempt allowed.");
  }
}

checkLoginAttempts(3);  // Account locked due to too many login attempts.

Chapter 10. 명시적인 매개변수

명시적으로 데이터 입력을 명확하게 하려면 루틴을 나누고 앞부분에서 매개변수 값을 채운 후, 뒷부분에서 명시적으로 전달하자.

//as-is
params = { a: 1, b: 2 }
foo(params)

function foo(params)
	...params.a... ...params.b...

//to-be
function foo(params)
	foo_body(params.a, params.b)

function foo_body(a, b)
	...a... ...b...

매개변수를 명시적으로 드러나게 만든 다음 함수를 연쇄적으로 호출할 수 있게 준비하자. 코드 읽기와 테스트, 분석이 쉬워진다.

Chapter 11. 비슷한 코드끼리

모든 코드 정리 중 가장 단순한 정리법이다. 긴 코드 덩어리를 읽다가 서로 다른 로직을 담당하는 코드를 발견하고 구분될 때 빈 줄을 넣어서 분리하자.

관련 있는 코드를 뭉쳐두면 작은 소프트웨어 설계가 가능하여 변화를 좀 더 쉽게 만들 수 있다.

Chapter 12. 도우미 추출

루틴 속 코드 중에 목적이 분명하고 나머지 코드와는 상호작용이 적은 코드 블록은 도우미(helper)로 추출한 후에 이름이 붙이자. 이름은 작동 방식이 아니라 목적에 따라 짓는다.

=> '메서드 추출' 리팩터링이다.

도우미를 추출할 때 몇 가지 특수한 경우가 있다.

  1. 큰 루틴 안에서 몇 줄을 변경해야 하는 경우 - 해당 줄들을 도우미로 추출하고 도우미 안의 내용만 변경하고 호출하자.
  2. 시간적 결합을 표현하는 경우 - A()가 B()보다 앞서 호출되어야 하는 경우는 다음과 같이 코드를 작성하자.
    • 사용자가 함수의 호출 순서를 신경쓰지 않아도 된다.
foo.a()
foo.b()

// 아래와 같이 작성하자.
ab()
	a()
	b()

Chapter 13. 하나의 더미

코드가 여러 개의 작은 조각으로 나뉘어져 있기도 하는데 흩어진 코드는 이해하기 어렵다. 따라서 필요한 만큼의 코드를 하나의 더미(One Pile)처럼 느껴질 때까지 코드를 모으자.

작은 코드 조각을 지향하는 목적은 코드를 한 번에 조금씩 이해할 수 있도록 하는 것이지만 작은 코드 조각들이 서로 교류하는 방식은 코드를 더 알기 어렵게 할 수 있다.

먼저 코드를 한데 모아서 이해하기 어려운 부분을 추출해서 정리해보자. 다음 증상들을 찾아보자

  • 길고 반복되는 인자 목록
  • 반복되는 코드, 그 중에서도 반복되는 조건문
  • 도우미에 대한 부적적한 이름
  • 공유되어 변경에 노출된 데이터 구조

Chapter 14. 설명하는 주석

코드에서 명확하지 않은 내용만 골라 주석으로 작성하자.
코드의 결함을 발견했다면, 그 즉시 해당 위치에 주석을 달아야 한다.

Chapter 15. 불필요한 주석 지우기

코드만으로 내용을 모두 이해할 수 있다면 주석은 삭제하자.

주석과 코드는 작성할 때와 나중에 볼 때, 시간이 흐르고 나면 서로 맞지 않는 경우가 있다. 또한, 코드가 변경될 경우에 원래 있던 주석이 불필요해질 수 있다.

해당 부분이 맞는지 확인하는 시간도 하나의 비용이 된다.

profile
그냥 하자

0개의 댓글