여러분의 코드를 Agile로 - 리펙토링



여러분의 코드를 Agile로: 리펙토링


Chris MountfordAgile에 대해 이야기 합니다. (2009년 7월)
http://www.atlassian.com/agile
우선, 저희 리펙토링 정의입니다:
리펙토링은 구현한 기능을 변경하지 않고 코드를 개선시키는 것입니다.

만약 여러분이 리펙토링 하신다면, 버그를 수정하거나 성능을 개선시키거나, 혹은 안정성을 높이는 것이 아닙니다. 리펙토링은 단지 코드 디자인을 개선시키며 코드가 동일하게 동작하도록 하는 작업입니다.


만약 여러분이 오늘 가진 기능 관점에서 그 경제적 가치를 따진다면, 여러분은 언제인가는 아마도 기술적인 빚(technical debt)을 지게될 것입니다(현재의 여러분의 기술이 향후 큰 가치를 못 가질 수 있게 되기 때문입니다); 오늘 여러분은 미래에 계속 가치가 증가될 여러분의 능력을 추가할 수 있습니다.

리펙토링의 가치는 전적으로 프로그래머가 코드를 수정하고 이해하는 능력에 전적으로 포함되어 있습니다. 그래서 관리능력(maintainability)라고 하는 것입니다. 그렇지만 용어가 지루하기 애자일성(Agility) 이라고 합시다.
멋지고, 잘 정리된 코드는 언제든 쉽게 변경가능하기 때문에 애자일(agile) 코드입니다.

경제학적 용어로, 리펙토링은 투자이며 혹은 채무에 대한 상환이라고 할 수 있습니다. 수익률이 좋기를 희망하는 비즈니스나 프로젝트 스폰서는 항상 이러한 리펙토링 기간을 계획합니다.

리펙토리이란 용어는 수학에서 비롯되었습니다. 고등학교 시절의 수학을 떠올리실 수 있을 것입니다.:
2x2 + 10x

Stay with me! No glazing over! 수식을 리펙토링 한다면, 공동인수를 추출함으로서 우리는 2x 를 얻을 수 있습니다:
2x . (x+5)
때때로 공통인수를 분리하는 것이 어려울 수도 있습니다. 수학이나 프로그래밍이나 모두 어려울 수 있지만 프로그래밍쪽이 더 어려울 것입니다.(주관적인 관점)

소프트웨어 개발에서의 다른 강력한 기술처럼, 리펙토링의 목적은 복잡성을 제어하고 관리하는 것입니다.

복잡성은 나쁘며, 악이다.

저는 프로젝트의 복잡성에 대해 그 유명한 JAOO SydneyDave Thomas (OTI, Eclipse)와 5월경 채팅을 하는 행운을 얻은적이 있습니다.
코드베이스에서의 복잡성과 규모는 전체 스케쥴을 무너뜨리고, 속도를 떨어뜨리며, 개발비용을 초과에 기여하는 중요 요소라고 언급했습니다.
Fred Brooks 또한 복잡성의 두가지 범주에 대해 논의하였습니다.
필수적인 복잡성우연적인 복잡성.
필수적인 복잡성은 도메인의 복잡성을 말합니다. NASA의 소프트웨어에서는, 로켓과학을 다루지 않을 수 없는 것입니다.
이러한 필수적인 복잡성은 분리되고 잘게 쪼개질 수 있지만, 없앨 수는 없습니다. 필수적인 복잡성은 문제 자체에 포함되기 때문입니다.
그렇지만 대조적으로, 우연적인 복잡성은 사용하는 시스템, 언어, 프레임워크의 부산물입니다. 이론적으로 시스템을 변경함으로서 우리는 이러한 복잡성을 축소시킬수 있습니다. 우연적인 복잡성은 솔루션에 포함되는 것이기 때문입니다. 리펙토링은 이러한 우연적인 복잡성을 줄이는 것입니다.

만약 여러분이 이런 리펙토링 경헙이 별로 없거나, 혹은 리펙토링에 대한 어떠한 구체적인 튜토리얼을 찾는다면, 저는 Martin Fowler의 세미나북인 Refactoring을 추천합니다. Fowler은 또한 객체지향방식의 리펙토리 처리법에 대한 catalog를 다루고 있습니다.

가장 기본적인 기법중의 하나는 모든 괜찮은 IDE에서 제공하는 Extract Method 기능을 통해 자동으로 수행할 수 있습니다.

애자일 개발(agile development)의 내부 루프는 이와 같아야 합니다: 빨강, 녹색, 리펙토어.
빨강은 통과되지 않은 테스트를 가지고 있음을 의미합니다. 테스트를 통과하는 것은 다음 단계로 가는 것을 말하며, 녹색은 모든 테스트를 통과했음을 의미합니다.

여러분이 설사 간단히 리펙토링을 수행하는 좋은 애자일 개발자(agile developer)라고 하여도, 공통 요소의 복잡성과 중복성은 여러분이 테스트를 통과하려 할 때 언제나 발생합니다.
모든사람이 오류를 범하며, 복사하고 잘라 붙입니다. 이것은 여러분이 언제든 녹색 바를 얻을 때 되돌아가서 리텍토링하는 경우 상관없습니다.

단위(Unit) 테스트는 정말로 리펙토리에서 중요합니다. 만약 단위 테스트를 하지 않는다면 아직 갈길이 먼 것입니다.
좋 은 단위 테스트 도구는 리펙토링의 필수적인 조건입니다. 또한 개인적인 생각으로는 좋은 형태의 시스템 또한 자동화된 리펙토링에서 필수 조건입니다. 오래된 시스템에서는 때로는 효과적인 자동화 테스트를 할 수 없습니다. 그리고 그 시스템 자체가 스파게티(spaghetti) 로 구성되어 그 자체가 리펙토어를 필요로 하는 경우도 있습니다. 이런 경우 닭이 먼저냐 달걀이 먼저냐의 문제가 됩니다.
여기서 제가 말할 수 있는 것은 작게 시작하라 입니다.


리펙토링성(Refactoritis)



너무 많은 리펙토링을 할 수 있을까요? 물론입니다. 만약 여러분이 다소 이러한 리펙토링에 열광하는 중간단계 정도의 상태라면 단순 잘라 붙이기 방식의 코드 작성의 오류를 범하지는 않을지라도, 팀에서 사용하는 기본 형태를 넘어서는 리펙토링이나 언어 추상화에 빠져들 수 있습니다.

모든 언어는 그 설계와 구현에서 오는 한계를 가집니다. 예를들면 Java와 C#에서는 동적언어에서는 참기 어려울 정도로 많은 제약사항을 가집니다. 예를들면, 여러분이 어떤 Java 혹은 C# 코드르 리펙토링한다고 생각해 보십시요.
하나의 구체적인 클래스와 일부의 커다란 if-else 블록을 가진 코드를 몇 개의 구현 코드를 가진 새로운 interface를 생성 변경하여 3개의 파일과 실질적인 소스코드를 가질 수 있습니다.
이것은 때때로 다소 주관적일 수도 있지만, 결과적으로는 중복을 제거하였음에도 불구하고 복잡성은 더욱 증가되는 경우입니다.

이런 경우가 발생하면, 아마도 리펙토링이라는 기차에서 잠이 들어 다음 정거장에서 내리지 못하게 되는 상황이 여러분에게 생기게 될 것입니다.
때때로 코드를 다시 원복하고 다시 코드를 작성해야 할 것입니다. 어떠한 중복코드는 경우에 따라 (특히 하나의 페이지에 맞게 되어 있고 다른 사람이 패턴을 잘 볼 수 있다면) 보기 쉽고 대응하기도 쉽습니다.
다른 언어에서는, Lisp 가 떠오르는데, 자바에서는 우아하게 정리할 수 없는(cannot be elegantly factored in, say, Java) 수식을 함축하도록 하는 생성자가 있을 수 있습니다.

그러므로 언어의 표현력은 리펙토링성(refactorability)을 이미 포함할 수 있습니다. 다시말하면 언어가 이미 우연적인 복잡성을 포함하며 그 복잡성을 없애기 위해서는 그 언어자체를 변경해야 하는 것입니다.
여기서 제가 말하고자 하는 점은 최근 저는 Groovy라는 언어를 보면서 자바 프로젝트에서 이러한 일을 할 수 있는 대안이라는 생각을 하였다는 것입니다.

좀 더 구체적인 예로서, Java 1.5에서 소개된 어휘적 클로저(lexical closures)는 루프(반복문)와 같은 것에 대해 새로운 구현을 할 수 있는 좋은 방법입니다. 유사한 목적으로 자바에서 익명 내부 클래스(anonymous inner classes)를 채용한 펑터 프레임워크(functor framework)도 때로는 최근의 클러저 구현과 비교하면 매우 성가셔 보입니다.

정리하면, 빨강, 녹색, 리펙토어에 너무 치중하지 말며 현재 사용하는 언어로 시스템에서 보이는 리펙토링 요소를 찾으려고 애쓰는 것이 시스템을 더욱 나쁘게 할 수 있다는 점을 아셔야 합니다.

관심이 있으시다면, 제 블로그에 오셔서 다른 주제등에 대해 얘기를 나누실 수 있을 것입니다.

댓글

이 블로그의 인기 게시물

Confluence 내의 스프레드 시트 기능이 필요하시다면 애드온을 활용해 보십시요

시스템에 숨어있는 "윤초" 버그에 대해 준비하십시요

Confluence 페이지의 분류와 관련된 잘 몰랐던 기능 3가지를 확인해 보십시요