보호 구문

  • 아래와 같은 코드를 본다면
if (조건)
	...코드...
if (조건)
	if (다른 조건 부정)
		...코드...
  • 아래와 같이 정리할 수 있다.
if (조건 부정) return
if (다른 조건) return
...코드...

안 쓰는 코드

  • 일단 지워라.
  • 리플렉션을 사용한 코드일수도 있지 않은가?
    • 로그를 활용해 지우고 나서 다시 실행해서 확인 해본다.
    • 확신이 된다면 지울 수 있다.
  • 지웠다가 나중에 필요할 경우는?
    • 형상 관리 도구가 이를 해결해준다.
  • 정리 과정에는 코드를 조금만 삭제해라.
    • 그렇게 하면 잘못 고친 것으로 밝혀져도 비교적 쉽게 복구할 수 있다.

대칭으로 맞추기

  • 같은 동작이라도 두 가지 이상의 패턴을 섞어 쓰면 혼란스러워진다.
  • 한 가지 방식을 선택해서 정한다.
  • 공통성이 있지만 세부 사항이 다른 것이 끼어 있다면 분리한다.

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

  • 루틴을 호출해야 하는데 기존 인터페이스 때문에 어렵거나, 복잡하거나, 혼란스러울 수 있다.
  • 이 경우 호출하고 싶은 인터페이스를 새롭게 구현해서 호출하도록 해라.
    • 기존 인터페이스를 호출하는 코드를 새 인터페이스를 호출하도록 모두 이전한 후에, 이전 인터페이스를 제거하고 새 인터페이스가 직접 루틴을 구현하도록 변경할 수 있다.
  • 어떤 동작을 변경해야 할 때, 이런 통로 인터페이스를 통해 구현했다면 변경하기 한층 더 수월하다.
  • 아래의 경우도 통로 인터페이스 적용과 비슷한 느낌을 받을 것이다.
    • 거꾸로 코딩하기: 루틴의 마지막 줄부터 시작. 마치 마지막 줄에 이르기까지 필요한 결과를 모두 확보한 듯이 짠다.
    • 테스트 우선 코딩: 테스트부터 작성하여 통과 요건을 정한다.
    • 도우미 설계: 나에게 특정 업무를 해 주는 루틴, 객체, 서비스가 있다면 나머지 작업은 쉬워진다.

읽는 순서

  • 코드를 읽기 좋은 순서로 정렬하라.
  • 완벽한 순서는 없다. 때로는 기본 요소를 먼저 이해한 다음 구성 방법을 이해하고 싶을 때가 있고, API를 먼저 이해한 다음 세부 구현을 이해하고 싶을 떄도 있다.
    • 스스로가 코드를 읽어 왔을 테니 최근 경험을 살려 판단해라.

응집도를 높이는 배치

  • 두 루틴에 결합도가 있으면 서로 옆에 두면된다.
  • 두 파일에 결합도가 있으면 같은 디렉토리에 넣는다.
  • 결합도 제거 기준
    • 결합도 제거 비용 + 변경 비용 < 결합도에 따른 비용 + 변경 비용
  • 하지만 여러 가지 이유로 결합도 제거가 어려울 수 있다.
    • 당장 어떻게 해야 할지 모른다면 결합도 제거가 곤란할 수 있다.
    • 할 수 있더라도 당장은 시간적 여유가 없다면 결합도 제거는 부담스러운 시간 투자가 된다.
    • 팀이 이미 충분한 변경을 수행하고 있다면 결합도를 제거하는 일이 팀원 간의 잠재적 갈등으로 번질 수 있다.

선언과 초기화를 함께 옮기기

  • 보통 변수 이름에서 힌트를 얻어 프로그램에서 역할을 알게 되지만, 변수 초기화는 이름이 주는 의미를 더 강화한다.
  • 변수 선언 한참 뒤에 초기화 코드를 보게 된다면, 이미 변수가 어떤 맥락에서 선언되었는지 잊어버릴지도 모른다.

설명하는 변수

  • 어렵게 크고 복잡한 코드의 표현식이 있다면 일부 표현식을 추출한 후, 표현식의 의도가 드러나도록 변수 이름을 만들어 할당한다.
return new Point(
	... 표현식...,
	...다른  표현식...
)
x := ... 표현식...
y := ...다른  표현식...
return new Point(x, y)

설명하는 상수

  • 상징적인 상수를 만들어라. 리터런 상수로 사용된 곳은 상징적인 상수로 바꾸어라.
PAGE_NOT_FOUND := 404
if response.code = PAGE_NOT_FOUND
	...코드...
  • 빈약한 의미를 가진 코드 정리는 도움이 되지 않는다.
ONE = 1
...ONE...

명시적인 매개변수

  • 맵에서 매개변수가 블록으로 전달되는 경우는 흔하다.
    • 이렇게 하면, 코드를 읽으면서도 어떤 데이터가 필요한지 알기 어렵다.
params = { a: 1, b: 2 }
foo(params)

function foo(params)
	...params.a... ...params.b...
  • foo를 나누면 명시적 매개변수 정리를 적용할 수 있다.
function foo(params)
	foo_body(params.a, params.b)
	
function foo_body(a, b)
	...a... ...b...

비슷한 코드끼리

  • 긴 코드 덩어리를 읽다가 비슷한 코드끼리 사이에 빈 줄을 넣어 분리한다.
  • 제대로 된 소프트웨어 설계는 유연성을 확보하지만, 그렇지 못한 경우 자칫 변화 자체를 망각하고 소프트웨어 설계의 소용돌이에 빠질 수 있다.

도우미 추출

  • 코드를 보다가 루틴 속 코드 중에서, 목적이 분명하고 나머지 코드와는 상호작용이 적은 코드 블록을 만나면, 그 코드 블록을 도우미로 추출한 다음 이름을 붙여라.
    • 이 정리법이 ‘메서드 추출’ 리팩터링이다.
  • 큰 루틴 안에서 몇 줄을 변경해야 하는 경우 해당 줄들을 도우미로 추출하고, 도우미 안의 내용만 변경한 다음, 적절하다고 판단한 뒤에 도우미를 호출하는 문장에 반영해라.
  • 시간적 결합이 있는 경우에도 도우미로 추출할 수 있다.
    • 예) a()b()보다 앞서 호출되어야 하는 경우
  • 도우미는 필요한 모든 곳에서 사용할 수 있다. 도우미 사용은 또 다른 코드 정리에도 도움이 된다.

하나의 더미

  • 때로는 코드가 여러 개의 작은 조각으로 나뉘어져 있기도 하다.
    • 이렇게 흩어져 있는 코드를 전체적으로 이해하기가 어렵다.
    • 필요한 만큼의 코드를 하나의 더미처럼 느껴질 때까지 흩어진 코드를 모아라.
  • 작은 코드 조각을 지향하는 목적은 코드를 한 번에 조금씩 이해할 수 있도록 하는 것이지만, 때때로 작은 코드 조각들이 서로 교류하는 방식은 코드를 더 알기 어렵게 한다.
    • 명확성을 되찾으려면, 먼저 코드를 한데 모아서 이해하기 어려운 부분은 추출해서 새롭게 정리해라.
  • 다음 증상들을 찾아봐라.
    • 길고 반복되는 인자 목록
    • 반복되는 코드, 그 중에서도 반복되는 조건문
    • 도우미에 대한 부적절한 이름
    • 공유되어 변경에 노출된 데이터 구조

설명하는 주석

  • 코드에 명확하지 않은 내용이 있으면 처음 읽는 사람이라고 가정하고 주석을 적어라.
  • 코드의 결함을 발견했따면, 그 즉시 해당 위치에 주석을 달아야 한다.

불필요한 주석 지우기

  • 코드만으로 내용을 모두 이해할 수 있다면 주석을 삭제하라.
    • 주석과 코드는 작성할 떄와 나중에 볼 때, 시간이 흐르고 나면 서로 맞지 않는 경우가 있다.
    • 불필요한 주석은 코드를 읽는데 비용만 발생한다.