카테고리 없음

02 리팩터링 원칙 - 리팩터링 자동화

씨씨상 2024. 10. 22. 18:25

 

 

리팩터링 자동화

 

 

리팩터링과 관련하여 지난 수십 년 사이에 일어난 가장 큰 변화는 자동 리팩터링을 지원하는 도구가 등장한 것이다. 예를 들어 〈인텔리제이 IDEA〉나 〈이클립스〉에서 자바로 프로그래밍할 때는 메서드 이름을 바꾸는 작업을 메뉴에서 원하는 항목을 클릭하는 것만으로 처리할 수 있다. 실제 리팩터링은 나 대신 개발 도구가 처리해주며, 따로 테스트할 필요가 없을 정도로 안정적이다.

 

자동 리팩터링 기능은 존 브랜트와 돈 로버츠가 개발한 스몰토크용 〈리팩터링 브라우저〉에서 최초로 등장했다. 이 아이디어는 2000년대 초반에 자바 커뮤니티에 급속도로 퍼졌다. 젯브레인즈JetBrains에서 〈인텔리제이 IDEA〉를 출시할 때 내세운 대표 기능 중 하나가 바로 자동 리팩터링이었다. IBM도 뒤따라 〈비주얼 에이지 포 자바Visual Age for Java〉에 리팩터링 기능을 추가했다. 〈비주얼 에이지 포 자바〉는 큰 인기를 얻지 못했지만, 리팩터링을 비롯해 많은 기능을 〈이클립스〉에 물려주었다.

 

C#용 리팩터링 도구도 등장했다. 젯브레인즈가 만든 〈비주얼 스튜디오〉용 플러그인인 〈리샤퍼ReSharper〉가 처음으로 지원했고, 나중에 〈비주얼 스튜디오〉 팀에서 자체적으로 리팩터링 기능을 추가했다.

 

현재는 에디터나 독립 도구에서도 리팩터링 기능을 제공할 정도로 자동 리팩터링이 흔해졌다. 물론 완성도는 저마다 제법 차이가 난다. 그 원인은 도구 자체에 있기도 하고, 언어마다 리팩터링을 자동화할 수 있는 범위가 다르기 때문이기도 하다. 이 책에서는 도구들의 차이는 분석하지 않는다. 단, 그 이면에 깔린 원칙들은 잠시 짚어볼 가치가 있다.

 

리팩터링을 자동화하는 가장 어설픈 방법은 소스 코드의 텍스트를 직접 조작하는 것이다. 가령 '찾아 바꾸기' 기능으로 이름을 변경하거나, 변수 추출하기를 위해 간단히 코드를 재구성하는 식이다. 이 방식은 허점이 많기 때문에 테스트해보기 전에는 결과를 신뢰해서는 안 된다. 하지만 리팩터링에 첫 발을 내딛는 데는 유용하다. 나라면 완성도 높은 리팩터링 도구가 없을 때는 〈이맥스Emacs〉에 해당 매크로를 만들어 활용하는 식으로 리팩터링 속도를 높일 것이다.

 

자동 리팩터링을 제대로 구현하려면 코드를 텍스트 상태가 아닌, 구문 트리syntax tree로 해석해서 다뤄야 한다. 구문 트리를 조작하는 방식이 코드의 원래 의미를 보존하는 데 훨씬 유리하기 때문이다. 그래서 뛰어난 IDE가 자동 리팩터링도 더 풍부하게 제공하는 경우가 많다. IDE는 리팩터링뿐 아니라 코드 탐색과 린팅linting: 정적 분석을 비롯한 다양한 기능을 구현하는 데 구문 트리를 활용한다. 텍스트와 구문 트리를 함께 활용하기 때문에 단순한 코드 에디터 수준을 훌쩍 뛰어넘는다.

 

그런데 단순히 구문 트리를 해석해서 수정하는 것만으로는 리팩터링을 구현할 수 없다. 변경된 구문 트리를 다시 에디터 화면에 텍스트로 바꿔 표현해야 한다. 그래서 리팩터링 기능을 제대로 구현하기란 상당히 어렵다. 이 기능을 즐겨 쓰는 나조차도 이러한 사실을 인지하지 못할 때가 많다.

 

정적 타입 언어라면 안전하게 구현할 수 있는 리팩터링 수가 늘어난다. 간단히 함수 이름 바꾸기를 적용하는 경우를 생각해보자. Salesperson 클래스와 Server 클래스 모두에 addClient()라는 메서드가 있다고 하자. 그중 Salesperson 클래스에 정의된 addClient()의 이름을 변경하려고 한다. Server 클래스의 addClient()는 의미가 다르기 때문에 변경하지 않고 그대로 둔다. 정적 타입을 지원하지 않는다면 addClient()를 호출하는 코드 중에서 어느 것이 Salesperson 클래스에 해당하는지 구분하기 쉽지 않다. 그래서 도구는 이 메서드를 호출하는 지점의 목록을 제공할 것이고, 우리는 목록을 일일이 살펴보면서 이름을 바꿀 대상을 직접 골라야 한다. 이런 식의 리팩터링은 안전하지 않기 때문에 반드시 테스트를 거쳐야 한다. 이정도만 제공해도 꽤 도움이 되지만, 자바 코드라면 같은 작업을 완전히 안전하면서도 자동으로 처리할 수 있다. 도구에서 자바의 정적 타입 능력을 활용하여 메서드가 속한 클래스를 정확히 알아낼 수 있기 때문에, 변경할 메서드만 제대로 골라낼 거라고 믿을 수 있다.

 

간혹 도구에서 그 이상까지 처리해주는 경우도 있다. 가령 변수 이름을 바꾸려 하면 코드는 물론 주석에 쓰인 이름도 함께 바꿀지 물어볼 것이다. 혹은 함수 추출하기를 적용할 때, 새 함수의 본문과 같은 코드를 찾으면 해당 코드를 강조해 보여주면서, 이 역시 추출한 함수를 호출하게끔 바꾸라고 권하기도 한다. 이처럼 IDE가 제공하는 리팩터링 기능이 강력하기 때문에 손에 익은 텍스트 에디터만 고집하지 말고 IDE를 사용하는 편이 프로그래밍 효율 면에서 훨씬 유리하다. 나는 〈이맥스〉 광팬이지만, 자바 프로그래밍할 때 만큼은 〈인텔리제이 IDEA〉나 〈이클립스〉를 사용한다. 그 이유의 상당 부분은 리팩터링 지원 때문이다.

 

이러한 멋진 리팩터링 도구들이 코드 리팩터링을 안전하면서도 요술 부리듯 처리해줘서 좋긴 하지만, 간혹 문제를 일으킬 때가 있다. 가령 완성도가 낮은 도구는 Method.invoke()처럼 자바의 리플렉션 기능을 써서 메서드를 호출하는 부분을 제대로 처리하지 못한다(완성도가 높은 메이저 도구는 이런 부분도 깔끔하게 처리한다). 그래서 대부분의 리팩터링이 믿을만하더라도 중간에 꼬인 부분이 없는지 이따금 테스트로 확인하는 것이 바람직하다. 나는 주로 자동 리팩터링과 수동 리팩터링을 함께 사용한다. 그래서 테스트도 충분히 거친다.

 

IDE는 구문 트리를 분석해서 리팩터링하기 때문에 단순한 텍스트 에디터와는 비교할 수 없을 만큼 유리하다. 하지만 상당수의 프로그래머는 각자 좋아하는 텍스트 에디터가 주는 자유를 만끽하도자 두 가지 도구를 모두 활용한다. 최근에는 언어 서버Language Server라는 기술이 뜨고 있다. 언어 서버란 구문 트리를 구성해서 텍스트 에디터에 API 형태로 제공하는 소프트웨어다. 언어 서버는 다양한 텍스트 에디터를 지원할 수 있고, 정교한 코드 분석과 리팩터링 기능을 제공할 수 있다.

 

 

 

 

 

[출처]

리팩터링 2판 - 마틴 파울러

 

[정리]

최근엔 자동 리팩터링을 지원하는 IDE가 많아졌다. 자신이 사용하는 하나의 텍스트 에디터만 고집하지 말고 자동 리팩터링을 지원하는 IDE도 사용해보는 것을 권한다.