Home [리팩터링] chapter 6 기본적인 리팩터링
Post
Cancel

[리팩터링] chapter 6 기본적인 리팩터링

p.159 코드는 목적과 구현을 분리하여 함수로 구현한다. 코드를 보고 무슨 일을 하는지 파악하는데 한참이 걸린다면 그 부분을 함수로 추출한 뒤 ‘무슨 일’에 걸맞는 이름을 짓는다. 이렇게 해두면 나중에 코드를 다시 읽을 때 함수의 목적이 눈에 확 들어오고 본문코드에 대해서는 더이상 신경 쓸 일이 거의 없다. 짧은 함수의 이점은 이름을 잘 지어야만 발휘되므로 이름 짓기에 특별히 신경 써야 한다.

절차

  1. 함수를 새로 만들고 목적이 잘 드러내는 이름을 붙인다.(‘어떻게’가 아닌 ‘무엇을’ 하는지가 드러나야한다.)
  2. 추출한 코드를 원본 함수에서 복사하여 새 함수를 붙여 넣는다.
  3. 추출한 코드 중 원본 함수의 지역 변수를 참조하거나 추출한 함수의 유효범위를 벗어나는 변수는 없는지 검사한다. 있다면 매개변수로 전달한다.
  4. 변수를 다 처리했다면 컴파일한다.
  5. 원본 함수에서 추출한 코드 부분을 새로만든 함수를 호출하는 문장으로 바꾼다.
  6. 테스트한다.
  7. 다른 코드에 방금 추출한 것과 똑같거나 비슷한 코드가 없는지 살핀다. 있다면 방금 추출한 새 함수를 호출하도록 바꿀지 검토한다.

P.169 함수 인라인하기. 간접호출을 너무 과하게 쓰는 코드도 흔한 인라인 대상이다. 가령 다른 함수로 단순히 위임하기만 하는 함수들이 너무 많아서 위임관계가 복잡하게 얽혀있으면 인라인 해버린다.

절차

  1. 다형 메서드 인지 확인한다.
  2. 인라인할 함수를 호출하는 곳을 모두 찾는다.
  3. 각 호출문을 함수 본문으로 교체한다.
  4. 하나씩 교체할 때마다 테스트한다.
  5. 원래 함수를 삭제한다.

p.173 변수 추출하기. 표현식이 너무 복잡해서 이해하기 어려울 때는 지역변수를 활용한다. 그러면 복잡한 로직을 구성하는 단계마다 이름을 붙일 수 있어 코드의 목적을 훨씬 명확하게 드러낼 수 있다. 이 과정에서 추가한 변수는 디버깅에도 도움이 된다. 현재 함수 안에서만 의미가 있다면 변수로 추출하는 것이 좋다. 그러나 함수를 벗어난 넓은 문맥에서 까지 의미가 된다면 그 넓은 범위에서 통용되는 이름을 생각해야 한다. 다시말해 변수가 아닌 함수로 추출해야한다.

p.177 (변수가 아닌 함수로 추출할때) 객체의 엄청난 장점을 볼 수 있다. 객체는 특정 로직과 데이터를 외부와 공유할 때 공유할 정보를 설명해주는 적당한 크기의 문맥이 되어준다. … 덩치가 큰 클래스에서 공통 동작을 별도 이름으로 뽑아내서 추상화해두면 그 객체를 다룰 때 쉽게 활용할 수 있어서 매우 유용하다.

p.179 함수는 프로그램을 작은 부분으로 나누는 주된 수단이다.함수 선언은 각 부분이 서로 맞물리는 방식을 표현하며, 실질적으로 소프트웨어 시스템의 구성요소를 조립하는 연결부 역할을 한다. 매개변수는 함수가 외부 세계와 어우러지는 방식을 정의한다. (매개변수는 함수를 사용하는 문맥을 설정한다. )매개변수를 다르게 정의하면 함수의 활용 범위를 넓힐 수 있다. (심화 학습 필요)

p.188 변수 캡슐화하기. 접근할 수 있는 범위가 넓은 데이터를 옮길 때에는 먼저 그 데이터로의 접근을 독점하는 함수를 만드는 식으로 캡슐화하는 것이 가장 좋은 방법일 때가 많다. 데이터 재구성이라는 어려운 작업을 함수 재구성이라는 더 단순한 작업으로 변환하는 것이다. 데이터 캡슐화는 다른 경우에도 도움을 준다. 데이터를 변경하고 사용하는 코드를 감시할 수 있는 확실한 통로가 되어주기 때문에 데이터 변경 전 검증이나 변경 후 추가 로직을 쉽게 끼워 넣을 수 있다. 레거시 코드를 다룰 때는 이런 변수를 참조하는 코드를 추가하거나 변경할 때마다 최대한 캡슐화한다. 그래야 자주 사용하는 데이터에 대한 결합도가 높아지는 일을 막을 수 있다. 객체 지향에서 객체의 데이터를 항상 private으로 유지해야한다고 강조하는 이유가 있다.

p.192 값 캡슐화하기. 정확한 기준은 그 데이터가 어디서 오는지, 원본 데이터의 모든 변경을 그대로 반영할 수 있도록 원본으로의 링크를 유지해야 하는지에 따라 다르다. 링크가 필요없다면 데이터를 복제해 저장하여 나중에 원본이 변경되어 발생하는 사고를 방지할 수 있다. 복제본 만들기가 번거로울 때가 많지만, 이런 복제가 성능에 주는 영향은 대체로 미미하다. 반면, 원본을 그대로 사용하면 나중에 디버깅하기 어렵고 시간도 오래 걸릴 위험이 있다.

p.197 매개변수 객체 만들기 데이터 항목 여러 개가 몰려다니면 데이터 구조 하나로 모아준다. 데이터 뭉치를 데이터 구조로 묶으면 데이터 사이의 관계가 명확해진다. 함수가 이 데이터 구조를 받게 하면 매개변수의 수가 줄어든다. 같은 데이터 구조를 사용하는 모든 함수가 원소를 참조할 때 항상 똑같은 이름을 사용하기 때문에 일관성도 높여준다. 코드에 범위 개념이 필요함을 깨달았다면 최댓값과 최솟값쌍을 사용하는 코드(예시 코드)를 발견할 때마다 범위 객체로 바꾸자. 이러한 값 쌍이 어떻게 사용되는지 살펴보면 다른 유용한 동작도 범위 클래스로 옮겨서 코드베이스 전반에서 값을 활용하는 방식을 간소화할 수 있다.

p.202 여러 함수를 클래스로 묶기 공통데이터를 중심으로 긴밀하게 엮여 작동하는 함수 무리는 클래스 하나로 묶는다. 클래스로 묶으면 이 함수들이 공유하는 공통 환경을 더 명확하게 표현할 수 있고, 각 함수에 전달되는 인수를 줄여서 객체 안에서의 함수 호출을 간결하게 만들 수 있다. 함수를 한데 묶는 또 다른 방법으로 여러 함수를 변환함수로 묶기도 있다. 클래스로 묶을 때의 두드러진 장점은 클라리언트가 객체의 핵심 데이터를 변경할 수 있고, 파생 객체를 일관되게 관리할 수 있다는 점이다.

p.208 여러 함수를 변환 함수로 묶기 변환함수는 원본 데이터를 입력받아서 필요한 정보를 모두 도출한 뒤, 각각을 데이터 필드에 넣어 반환한다. 이렇게 해두면 도출 과정을 검토할 일이 생겼을 때 변환함수만 살펴보면 된다. 이 리팩터링 대신 여러함수를 클래스로 묶기로 처리해도 된다. 원본 데이터가 코드 안에서 갱신될때는 클래스로 묶는 것이 훨씬 낫다. 변환 함수로 묶으면 가공한 데이터를 새로운 레코드에 저장하므로, 원본 데이터가 수정되면 일관성이 깨질 수 있기 때문이다. 여러 함수를 한데 묶는 이유 하나는 도출 로직이 중복되는 것을 피하기 위해서다. 이 로직을 함수로 추출하는 것만으로도 같은 효과를 볼 수 있지만, 데이터 구조와 이를 사용하는 함수가 근처에 있지 않으면 함수를 발견하기 어려울 때가 많다. 변환 함수(또는 클래스)로 묶으면 이런 함수들을 쉽게 찾아 쓸 수 있다.

This post is licensed under CC BY 4.0 by the author.

[리팩터링] chapter 4 테스트 구축하기

[리팩터링] chapter 7 캡슐화

Comments powered by Disqus.