리팩토링 중요 개념

리팩토링

겉으로 드러나는 기능은 그대로 둔 채, 알아보기 쉽고 수정하기 간편하게 소프트웨어 내부를 수정하는 작업

  • 코드 구조는 한번 엉망이 되면 갈수록 더 엉망이 된다. 그러므로 주기적인 리팩토링이 필요하다.
  • 어떤 코드를 실행할때 컴퓨터는 몇바퀴 헤매더라도 그다지 문제될 것 없지만, 기껏해야 한시간정도면 이해하고도 남을 코드를 다른 개발자가 신속히 이해하지 못해서 한 부분을 수정하는데 일주일 이상 걸린다면 그건 큰 문제다.
  • 설계가 깔끔하지 않으면 개발 초기 잠시 동안은 진행이 빠를지 몰라도, 얼마 못가서 개발 속도가 떨어진다
  • 리팩토링은 작정해서 하는것이 아니라, 뭔가 다른걸 해야겠는데 리팩토링을 실시하면 그 작업이 쉬워지기 때문에 하는 것이다
  • 리팩토링은 언제 필요할까?
    • 같은 작업을 3번째 반복하게 됐을 때
    • 기능을 추가할 때
      • 설계가 지저분해서 어떤 기능을 추가하기 힘들떄는, 주저하지 않고 리팩토링을 실시한다
    • 버그를 수정할 떄
      • 코드의 기능을 파악하다 이해하기 힘들면, 이해하기 쉽게 만드려고 리팩토링을 실시한다
      • 돌아가는 원리를 쉽게 파악 가능하게 되고, 버그 찾기도 쉬워진다
  • 테스트 메서드 작성은 필수이다(자체 테스트 가능해야한다)
  • 리팩토링은 프로그램을 조금씩 단계적으로 수행하므로 실수를 발견해도 고치기 쉽다
  • 좋은 코드는 그것이 무슨 기능을 하는지 분명히 드러나야 한다
  • 리팩토링의 각 단계는 간단해야 실수할 가능성이 줄어든다
  • 리팩토링 떄문에 성능이 안좋아질 수 있다. 하지만 그건 최적화 단계에서 수정하면 된다
  • 코드의 기능을 파악하는데 시간이 많이 걸리는데, 어쩌피 지나야 할 과정이다
  • 주기적 리팩토링을 통해 코드를 깔끔하게 해놓으면,

  • published 인터페이스

    • 인터페이스의 장점은 사용하는 곳을 수정하지 않고도 내부 구조를 수정할 수 있다는 점이다
    • 하지만 대다수의 리팩토링 기법은 인터페이스를 건드린다
      • 이 인터페이스를 사용하는 모든 코드에 접근할 수 있다면, 이 리팩토링 기법은 문제되지 않는다
      • 하지만 사용하는 모든 코드에 접근하지 못하는 상황이 있다. 외부에서 사용하기 위한 API를 작성하는 등의 행위를 예로 들 수 있다.
        • 이런 인터페이스를 published(배포된) 인터페이스라고 한다
    • published 인터페이스를 수정하는 경우, 사용하는 부분이 모든 변경될 때 까지 기존 인터페이스와 새 인터페이스를 모두 유지해야 한다
      • 기존 인터페이스에서 새로운 인터페이스를 호출하는 형태로 작성해야 한다
      • 기존 인터페이스는 @Deprecated 같은것을 사용해서 사용하지 않게끔 알려야한다
      • 최소한 일정 기간동안 사용하지 않는 메서드를 유지시켜야 하므로 불편하다
    • 방법은 published 메서드를 최대한 만들지 않는 것이다
      • java api 같은 외부 API를 만드는 상황을 빼고도 과하게 published 메서드를 만드는 경우가 있다
      • 이럴 경우는 코드 소유권 정책을 수정해서 인터페이스 수정을 촉진하도록 하는 것이 낫다
        • 인터페이스를 수정하는 사람이 인터페이스를 사용하는 곳의 코드까지 고칠 수 있게 하는것이다
  • 설계가 수정되었을 때

    • 설계에 오류가 있거나, 설계에 대한 결정이 바뀌었을 경우, 수정하기 힘든 민감한 부분일 경우라도 대부분 리팩토링으로 해결된다
    • 새로 추가되는 코드들에 새 구조(바뀐 설계)를 사용하도록 개발한다
    • 기존의 코드에 대한 기능추가나 버그 발견 등이 발생했을 경우 기존 코드를 새 구조를 사용하게 바꾼다
    • 리팩토링 한다고 all stop 하는 상황을 막을 수 있다
  • 리팩토링하면 안되는 상황

    • 코드가 제대로 돌아가지 않는다면, 그냥 새로 작성하는것이 낫다
      • 코드는 제대로 돌아가는 것이 우선이고, 리팩토링은 나중 일이다
    • 납기가 임박했을 때도 리팩토링은 삼가야한다
      • 납기가 임박한 경우가 아니면 시간이 없다는 핑계로 리팩토링을 미루면 안된다
    • 리팩토링은 미완료 대출금이다
      • 대출이자는 복잡한 코드로 유지보수하기, 확장의 어려움 이다
    • 언제나 시간에 쫓긴다면, 그건 리팩토링해야 한다는 신호이다

  • 처음부터 완벽한 설계를 할 필요는 없다

    • 애초에 처음부터 완벽한 설계란 너무 어렵고, 빈틈이 많을 가능성이 있다
    • 그러므로 완벽한 솔루션을 찾을 필요없이, 적당한 솔루션을 찾으면 된다
    • 구축해나가면서 문제를 더 잘 이해하게 되며, 처음 구축한 솔루션이 최상의 솔루션이 아니었다는걸 알게 된다
      • 이러면 처음 제시한 솔루션이 잘못되었더라도, 그 솔루션을 수정하는데 비용이 들지 않게된다
    • 간단하게 설계하고, 일단 구현한 다음, 리팩토링으로 다듬으면 된다
      • 소프트웨어는 실물의 기계와 달리 유연하기 때문이다
  • 시스템 전체를 유연하게 설계할 필요는 없다

    • 잠재적 가능성을 생각하여 유연한 설계를 하는 것은 매우 복잡하고 힘들다
      • 애초에 유연하게 복잡한 설계가 필요한 상황은 거의 없다
    • 단순한 솔루션을 구현해놓고, 나중에 그것을 리팩토링 하려면 얼마만큼의 수고가 들지 생각해본다
      • 별로 어려움이 없을 것이라고 판단되면, 단순하게 솔루션을 구현하면 된다
    • 리팩토링을 쉽게 할 수 있는 감각을 익히게 되면, 유연한 솔루션은 떠오르지도 않는다
      • 때가 되면 어련히 리팩토링하게 되리란 확신이 있기 때문이다

  • 리팩토링을 실시하면 소프트웨어 속도는 느려지지만, 성능을 더 간단하게 조절할 수 있다
    • 소프트웨어 성능을 올리려면 먼저 소프트웨어를 튜닝 가능하게 만들어놔야 한다
  • 성능 감소의 이유를 추측에 의존하지 말고 프로파일러를 통해 측정하도록 해야한다
  • 프로그램을 잘 쪼개어야 한다
    • 프로파일러로 성능을 감소시키는 작은 부분을 발견할 수 있게 되고, 이 부분에 집중하여 성능 개선을 할 수 있다
    • 성능을 분석할 때 더욱 정밀한 분석이 가능해진다

  • 켄트백의 모자 두개

    1. 기능을 추가할 땐 코드를 수정하지 말고 기능만 추가해야 한다
      • 테스트를 추가하고 테스트가 잘 되는지만 보면 됨
    2. 리팩토링할때는 코드를 추가하지 말고 구조 개선만 해야 한다
      • 테스트를 수정하지 않고 코드 구조만 수정해야 함
    3. 둘을 같이 하면 실패할 확률이 높다(경험…)
  • 랄프 존슨의 우선 창 밖이 보이게 뿌연 유리창부터 닦는 일

    • 리팩토링을 실시하면 낯선 코드를 쉽게 이해할 수 있다
    • 그렇게 첫 리팩토링을 마치고 코드가 깔끔해지면, 기존에 안보이던 설계가 보인다
  • 켄트백의 리팩토링의 효용성

    • 프로그램이 지닌 가치는 현재의 기능미래의 기능이라는 2개의 가치이다
    • 프로그램의 현재기능은 그저 일부에 불과하다
    • 과거의 판단이 현재의 기준으로 불합리하다는 사실을 발견했으면, 수정해야 한다
    • 프로그램이 수정하기 힘들어지는 4가지 상황
      1. 코드를 알아보기 힘들 때
      2. 중복된 로직이 들어있을 떄
      3. 추가기능을 넣어야해서 실행중인 코드를 변경해야 할 때
      4. 조건문 구조가 복잡할 떄
    • 프로그램은 코드를 알아보기 쉽고, 모든 로직이 한곳에 있으며, 기존 기능을 건드릴 필요 없이 조건문 구조가 최대한 간결하게끔 작성해야 한다.
  • 메서드는 대체로 자신이 사용하는 데이터와 같은 객체에 들어있어야 한다

  • 임시변수는 최대한 제거하는 것이 좋다

    • 변경되지 않는 변수는 매개변수로 전달할 수 있다
    • 변경되는 변수가 하나뿐이라면 리턴값으로 사용할 수 있다
    • 위 두 원칙을 적용하면서 임시변수를 계속 제거해보자
  • switch문의 인자로는 자신의 데이터를 사용해야 한다(타객체 데이터 X)

  • 질의 메서드를 따로 만들어서 편리하게끔 할 수 있음

참고 : 마틴 파울러, 『리팩토링』, 김지원 옮김, 한빛미디어(2012)