Extract Method

그룹으로 함꼐 묶을 수 있는 코드 조각이 있으면 코드의 목적이 잘 드러나도록 메소드의 이름을 지어 별도의 메소드로 뽑아낸다.

동기

지나치게 긴 메소드나 주석이 필요한 코드를 보면 그 부분을 하나의 메소드로 뽑는다.(Martin Fowler 曰).

  1. 메소드가 잘게 쪼개져 있을 때 다른 곳에서 사용하기 좋다.
  2. High-level의 메소드를 보면 주석을 읽는 것 같은 느낌이 들도록 할 수 있다.
  3. 오버라이드 하는 것도 훨씬 쉽다.

작은 메소드들은 작명을 잘했을 때 그 진가를 드러내므로 이름을 잘 짓도록 하자.

절차

  1. 메소드를 새로 만들고, 무엇을 하는지를 나타내도록 이름을 정한다.
  2. 원래 메소드에서 뽑아내고자 했던 부분을 복사하여 새 메소드로 옮긴다.
  3. 원래 메소드에서 사용되고 있는 지역변수가 뽑아낸 코드에 있는지 확인한다. 있으면 새로운 메소드의 임시변수로 선언한다.
  4. 뽑아낸 코드 안에서 지역변수의 값이 변화는지 확인한다. 만약에 하나의 지역변수만 수정 된다면, 뽑아낸 코드를 질의(query)로 보고, 수정된 결과를 관련된 변수에 대입할 수 있는지 본다. 이렇게 하는 것이 이상하거나, 값이 수정되는 지역변수가 두개 이상 있다면 쉽게 메소드로 추출할 수 없는 경우이다. 이럴 때는 Split Temporary Variable을 사용한 다음 다시 시도해야 한다. 임시변수는 Replace Temp with Query로 제거할 수 있다.
  5. 뽑아낸 코드에서 읽기만 하는 코드는 파라미터로 넘긴다.
  6. 지역변수와 관련된 사항을 다룬 후에는 컴파일을 한다.
  7. 원래 메소드에서 새로 만든 메소드를 호출하도록 바꾼다.
  8. 컴파일과 테스트를 한다.

예제 : 지역변수가 없는 경우
위 코드에서 처음에 수정할 부분은 노란색으로 표시된 부분입니다. 매우 단순한 경우이기 때문에 잘라서 새로운 메소드로 붙여넣고 저 노란 부분에서 새로운 메소드를 호출하면 되겠습니다.

이클립스에서 리팩토링 할 부분을 드래그 한 상태에서 Alt + Shift + m 을 클릭합니다. 그리고 새로운 메소드의 이름을 적어 줍니다.
그리고 OK 버튼을 클릭하면…
짠… 멋지게 처리해 주는 군요.. 주석만 빼고. ^^; 주석은 Ctrl + d (행삭제)를 사용하여 지워줍시다.

예제 : 지역변수가 포함되어 있는 경우

지역변수가 옮겨질 코드에 들어있는 경우 중에 가장 쉬운 경우가 바로 그 지역변수를 읽기만 하는 경우입니다.  이런 경우에는 변수를 파라미터로 넘겨주면 됩니다.


이번에는 저 노란 부분을 메소드로 뽑아 낼 것입니다. 보아하니 _name이라는 변수와 outstanding이라는 변수를 사용하고 있는데 outstanding만 지역변수고 _name은 필드네요. 따라서 outstanding만 넘겨주면 되겠습니다. 메소드  이름은 printDetails로 하는군요. 이번에도 뽑아내고 싶은 부분을 드래그 하고 Alt + Shift + m …와오..


똑똑한 이클립스… 파라미터가 필요한 줄 알고.. 그것도 딱 지역변수만.. 아 정말 똑똑하네요. 역시 OK만 누르면..


대단합니다. 이클립스.

예제 : 지역변수에 다른 값을 여러 번 대입하는 경우 (마지막입니다. 🙂

이 경우는 복잡한데 이런 경우 중 임시변수에 대해서만 생각을 해봅니다. (파라미터에 다른 값을 대입하는 코드가 있다면 즉시 Remove Assignments to Parameters를 적용해야 한다.)만약에 그 임시변수가 뽑아내는 코드에서만 사용이 된다면 뽑아낸 코드로 그냥 그 임시변수까지 이동하면 되겠습니다. 하지만 그 임시변수가 뽑아내는 코드 밖에서도 사용이 된다면 뽑아낸 코드에서 그 값을 리턴해 주어야 합니다.
노란 부분을 보시면 each라는 임시변수는 뽑아내게 될 코드 안에서만 사용되는 것을 볼 수 있습니다. 그렇기 때문에 그냥 이동 시키면 되겠지요

위에 보이는 노란 부분이 뽑아 낼 부분입니다. 저 중에 each는 노란 부분에서만 쓰이기 때문에 당연히 그냥 빼내는 메소드로 이동하면 되겠습니다. 하지만 문제는 outstanding인데 이 변수가 printDetails 메소드에서 사용되고 있습니다. 따라서 위의 코드에서 계산 부분의 코드를 뽑아내고 outstaning의 값을 리턴하도록 합니다.

이번에는 이클립스의 덕을 잘 못보겠더군요.

임시변수가 너무 많아 코드를 뽑아내기 어려울 때는 Replace Temp with Query를 사용하여 임시변수를 줄이고 어떻게 해봐도 여전히 난처할 때는 Replace Method with Method Object를 사용한다. 이 리팩토링은 임시변수가 얼마나 많든, 그리고 뭘 하든 상관하지 않는다.

3장 코드 속의 나쁜 냄새 – 중복된 코드

1장2장을 통해서 리팩토링이 어떻게 돌아가는지 알게 됐습니다. 하지만 리팩토링을 어떻게 하는지 안다고 해서 할 수 있는 것은 아닙니다. 언제 해야 하는지를 알아야 하는데… 그게 어려운 것 같네요. 3장을 Kent Beck이랑 Martin Fowler가 썼는데도 명확한 시점이라기 어떤 “냄새”가 날 때 라는 모호한 시점을 제기했네요. 경험적으로 인간의 직관보다 나은 기분은 없기 때문이라고 합니다. 그럼 이제 부터 어떠한 “냄새”들이 있으며 그런 “냄새”들은 어떻게 제거할지 살펴봅시다.

중복된 코드(Duplicated Code)

악취 중에 일등이 중복된 코드라고 하네요.

  • 한 클래스의 서로 다른 두 메소드 안에 같은 코드가 있는 경우 => Extract Method로 메쏘드로 뽑아내고 호출하도록 변경.
  • 동일한 슈퍼클래스를 갖는 두 서브 클래스에서 같은 코드가 나타나는 경우 => 양쪽 클래스에서 Extract Method를 한 뒤 Pull UP Method를 사용할 수 있슴.
  • 만약 메소드들이 같은 작업을 하지만 다른 알고리즘을 사용한다면 => 더 명확한 것을 선택하여 Substitute Algorithm을 사용할 수 있습니다.
  • 서로 관계가 없는 두 클래스에서 중복된 코드가 있는 경우에는 한쪽 클래스에서 Extract Class를 사용한 다음 양 쪽에서 이 클래스를 사용하도록 하는 것을 고려할 것.
  • 다른 가능성 : 메소드가 클래스 중 하나에 포함되어 있고, 다른 클래스에서 호출되어야 하거나 또는 세 번째 클래스에 속하는 그 메소그가 원래 두 클래스에서 참조되어야 하는 경우. => 뭔말인지…전혀 감이 안잡히는데요;;;

1장 리팩토링, 첫 번째 예제

먼저 리팩토링이란? 외부 동작을 바꾸지 않으면서 내부 구조를 개선하는 방법으로, 소프트웨어 시스템을 변경하는 프로세스이다. 이것은 버그가 끼어 들 가능성을 최소화하면서 코드를 정리하는 정형화된 방법이다.

“코드가 작성된 후에 디자인을 개선한다.”

물론 그 코드는 디자인을 거쳐 작성이 되었겠지만 코드가 디자인을 잘 따르지 않았거나 디자인이 잘 못 됐을 수도 있기 때문에 어감이 반대로 된 듯해도 맞는 말이다.

새로운 기능을 추가해야 하는데 프로그램의 코드가 새로운 기능을 추가하기 쉽도록 구조화되어 있지 않은 경우에는 먼저 리팩토링을 해서 프로그램에 기능을 추가하기 쉽게 하고, 그 다음에 기능을 추가한다.

유지보수에는 네 종류의 유지보수가 있는데 기억이 가물가물 하지만 억지로라도 떠올려 보면
에러가 발생하여 수정하는 유지보수(corrective maintanance)
환경의 변화에 따라 적응시키는 유지보수(adaptive maintanance)
미래에 발생할 문제를 미리 예방하는 유지보수
완벽을 기하기 위한 기능을 추가하는 유지보수 가 있다고 배웠다.(시스템 분석 및 설계 시간에…)
여기서는 네번째 유지보수 측면을 고려한 듯하다. 하긴 리팩토링 자체를 유지보수로 본다면 위 네가지 모두 고려대상인 듯하다.

리팩토링을 시작하기 전에 견고한 테스트 세트를 가지고 있는지 확인하라. 이 테스트는 자체 검사여야 한다.

테스트의 중요함을 할 수 있다. 요새 Agile Java 책을 스터디 하면서 TDD(Test Driven Development)를 공부하고 있는데 하나의 습관인지라 역시 쉽지 않다. 습관을 바꾸는게 가장 힘든일인듯 하다.(내 글씨는 악필인데 초등학교 때 서예학원도 다녀보고 맞기도 엄청 맞았지만 아직도 악필이다 –)

리팩토링은 작은 단계로 나누어 프로그램을 변경한다. 실수를 하게 되더라도 쉽게 버그를 찾을 수 있다.

조금씩 고쳐 나갈 때마다 계속해서 test를 해줘야 한다. 그래야 쉽게 버그도 찾을 수 있고 오히려 한번에 왕창 해두고 버그가 발생해서 어디가 문제인지 찾는데 시간이 더 오래 걸린다.

컴퓨터가 이해할 수 있는 코드는 어느 바보나 다 짤 수 있다. 좋은 프로그래머는 사람이 이해할 수 있는 코드를 짠다.

아~ 감명깊은 말이다. 주석의 중요함에 대해 써있는 책을 몇 번 봤었다. 그러나 주석이 잘 달린 프로그램 보다는 주석이 없어도 이해가 되는 프로그램인 듯하다. 물론 주석도 없고 이해도 안되는 코드는…최악이겠지만 말이다. 그러려면 역시 작명에도 신경을 잘 써야 하지만 대부분의 프로그램 언어가 영어인 관계로 작명+작문 이 합쳐지게 된다는 태생적인 문제가 있다.(영어 공부도 열심히?ㅋ)

오늘은 여기까지 보고 자야겠다. 내일 데이트를 해야한다.

Good Night!

1장을 다 보았다.(자랑인가? ㅋ) 보기만 했고 손으로 안따라 해봤기 때문에 아직 제대로 본건 아니다.

추가할 요약사항이 있어서 수정한다.

리팩토링의 리듬!

테스트 -> 조금 수정 -> 테스트 -> 조금 수정