리팩토링
리팩토링(refactoring)은 외부 동작을 바꾸지 않으면서 내부 구조를 개선하는 방법으로, 소프트웨어 시스템을 변경하는 프로세스이다.
개요[편집]
리팩토링은 소프트웨어를 더욱 쉽게 이해할 수 있도록 만드는 작업이다. 이해하기 쉬운 코드가 수정하기도 쉽기 때문에 수정하기 쉬운 코드를 만든다는 또 하나의 목적 역시 자연스럽게 달성된다. 리팩토링은 들어가는 리소스를 최소화하기 위해서 외부 동작의 변화 없이 소프트웨어의 구조를 바꾸는 것을 중심으로 진행이 된다. 리팩토링이 적절하게 진행되면 소프트웨어가 이해하기 쉬워지고 수정도 용의해진다. 여기서 얻을 수 있는 다양한 이익이 리팩토링을 해야 하는 이유가 된다. 이해하기 쉽고 수정하기 쉬워지니 개발자의 개발 속도가 자연스럽게 빨라진다. 그리고 이해하기 쉽기 때문에 버그가 있다면 훨씬 쉽게 발견할 수 있다. 리팩토링을 마친 다음뿐만 아니라 코드의 구조를 수정하면서 버그를 발견할 가능성이 더 높을 수도 있다.[1]
특징[편집]
리팩토링은 소프트웨어의 디자인을 개선하고, 소프트웨어를 더 이해하기 쉽게 만든다. 프로그램의 구조를 명확히 함으로써 버그를 잡도록 도와주며, 소프트웨어의 개발 속도를 향상한다. 리팩토링을 사용하면 소프트웨어 설계 개선된다. 가끔 단기적인 목적으로 코드를 추가할 때가 있다. 이러한 방식으로 코드를 추가하다 보면, 코드가 뒤죽박죽되어서 코드를 보고 이해하기 어려워진다. 이렇게 산만해진 코드를 정리하는 작업이 리팩토링이다. 리팩토링 작업을 할 때, 중복 코드를 제거하게 된다. 중복 코드가 제거되면, 소프트웨어 설계와 유지보수를 하는 데 있어서 분명 도움이 된다. 동일한 기능을 하는 코드가 여기저기 있다 보면, 기능의 일부분을 수정하더라도 모든 중복 코드에 손을 대야 한다. 중복 코드를 제거하면 한 군데에서만 수정하고 불필요한 리소스를 줄일 수 있다. 또한, 소프트웨어를 이해하기가 더 쉬워진다. 소프트웨어 개발 프로젝트는 대부분 동료 팀원과 함께 진행하게 된다. 따라서 특정 코드를 작성할 때, 동료 개발자를 고려해야 한다. 리팩토링하면 코드를 더 파악하기 쉬워진다. 기능은 정상 동작하지만 구조가 완전하지 못한 코드에 대해 실시한다. 불필요한 부분을 제거하다 보면, 본연의 목적을 충실해지는 코드가 완성된다. 버그를 찾기가 쉬워진다. 리팩토링 작업을 하면 전체 코드를 살펴보게 되고, 코드를 파악하기 쉽게 변경하다 보면 버그 발견도 쉬워진다. 그리고 프로그래밍 속도가 빨라진다. 깔끔한 설계는 소프트웨어 개발 속도를 높이기 위한 핵심이다. 설계가 깔끔하지 않으면 시간이 지날수록 개발 속도는 더디게 된다. 반면에 깔끔한 설계는 소프트웨어 개발 속도를 적절히 유지하는데 필요하다. 리팩토링하면 설계가 깔끔해지며 새로운 기능을 추가하는 작업을 빨리 진행할 수 있다.[2]
문제점[편집]
데이터베이스 부분에서의 문제점. 대부분의 비즈니스 애플리케이션은 데이터베이스 스키마와 밀접하게 결합하여 있다. 데이터베이스 스키마와 객체 모델 간의 종속을 최소화하기 위해 계층구조로 만들었다 하더라도, 스키마를 변경하려면 데이터를 많이 위대한 해야 하는데, 시간도 오래 걸리고 위험도 큰 작업이다. 인터페이스 변경에 따른 문제점. 객체의 중요한 점 중 하나로 인터페이스를 변경하지 않고 내부 구현을 바꿀 수 있다는 것이다. 객체를 사용하는 부분을 변경하지 않고도 객체의 내부 구조를 안전하게 바꿀 수 있지만, 인터페이스를 변경하면 어떤 일이 발생할지 모르기 때문에 인터페이스를 유지하는 것은 중요하다. 하지만, 많은 리팩토링이 인터페이스를 변경시킨다. 그렇다면 언제 리팩토링을 하지 말아야 하는가? 코드를 처음부터 다시 작성해야 할 때이다. 기존 코드가 너무 엉망이라 처음부터 다시 시작하는 것이 더 쉬운 경우가 있다. 하지만 이런 결정은 쉽게 내릴 수 없고, 지침도 없다. 또한, 마감일에 가까울 때이다. 리팩토링으로 얻는 생산성 향상은 마감일이 지난 다음에나 나타날 것이다.[3]
권장 상황[편집]
기본적으로 리팩토링은 별도의 시간을 내는 것이 아니라 틈틈이 계속 진행되어야 한다. 또한 다음과 같은 경우에 리팩토링을 진행하는 것이 권장된다. 비슷한 것을 세 번째로 하게 되면 리팩토링을 해야 하는 신호이다. 이것을 삼진 규칙이라고 한다. 기능을 추가할 때도 리팩토링을 하는 것이 좋다. 기능을 추가할 때 어떤 부분을 수정해야 할지 더 쉽게 판단할 수 있기 때문이다. 버그를 수정할 때도 리팩토링을 할 필요가 있다. 이미 언급한 것처럼 리팩토링을 하는 도중에 버그가 발견될 수도 있고 이해하기 쉬운 코드에서 버그를 찾는게 훨씬 쉽기 때문이다. 그리고 팀원들과 함께 코드 리뷰를 할 때 리팩토링을 할 필요가 있다. 리팩토링을 진행하는 과정을 공유하면서 팀 전체에 지식이 공유될 수도 있고 다양한 관점으로 보기 때문에 디자인이나 코드의 장단점을 더 잘 파악할 수 있다.[1]
- 중복된 코드가 있을 때(Duplicated Code)
가장 단순한 경우는 서로 다른 두 메서드 안에서 같은 코드가 있을 때이다. 이때는 중복되는 코드를 하나의 메서드로 빼낼 필요가 있다. 갖은 슈퍼클래스를 가진 두 클래스에서 같은 코드가 나타난 경우도 리팩토링 대상이다. 슈퍼클래스에 반복되는 내용을 정의하고 상속을 받는다면 훨씬 깔끔한 구조가 된다.
- 메소드가 지나치게 길 때(Long Method)
메서드는 가능한 길이가 짧을수록 널리 활용되고 또 마지막까지 활용될 가능성이 높아진다. 메서드는 하나의 input에 하나의 output이 나오는 것이 이상적이다. 또한 메서드의 이름은 그 기능을 명확히 정의하는 것으로 지어서 내용을 보지 않더라도 기능을 파악할 수 있도록 짓는다. 뭔가 주석을 달아야겠다는 생각이 든다면 대신 단일한 기능을 가진 메서드로 분리해 내는 것을 먼저 고민해 보아야 한다.
- 클래스가 지나치게 클 때(Large Class)
하나의 클래스가 지나치게 많은 인스턴스 변수를 갖는다면 중복된 코드가 존재할 확률이 높다. 이 중복된 코드는 리팩토링을 통해서 수정을 할 필요가 있다.
- 클래스가 충분히 역할을 하지 않을 때(Lazy Class)
클래스를 생성하면 그것을 유지하고 이해하는데 비용이 계속 들어가게 된다. 만약 하나의 클래스가 그 비용을 투자할 만큼의 일을 처리하고 있지 않다면 이 클래스는 정리 대상이 된다.
- 필요하지 않는 것을 처리하기 위해 작성된 코드가 있을 때(추측성 일반화)
필요하지 않는 기능을 위한 코드라면 남겨둘 필요가 없다.
- 임시 필드가 있을 때(Temporary Field)
하나의 객체에서 인스턴스 벨리 에이블이 특정 환경에서만 set 되는 것과 같은 경우이다. 우리는 한 객체의 변수들이 모두 필요하다고 가정하고 보기 때문에 이 코드는 매우 이해하기 어려워진다. 이런 코드는 리팩토링이 필요하다.
- 메시지 체인이 있을 때(Message Chains)
만약 클라이언트가 어떤 객체를 얻기 위해서 다른 객체에 물어보고 다른 객체는 또다시 다른 객체에 물어본다. 이런 경우를 메시지 체인이라고 한다. 이런 구조는 리팩토링을 해주어야 한다.
- 미들 맨이 있을 때(Middle Man)
클래스의 인터페이스를 보았을 때 대부분 다른 클래스로 위임을 하고 있다면 이런 클래스를 미들맨이라고 부른다. 이 미들맨은 리팩토링이 필요한 신호이고 제거의 대상이 된다.
- 클래스들이 지나치게 친밀할 때(부적절한 친밀 Inappropriate Intimacy)
크리스가 서로 지나치게 친밀해서 결합도가 높다면 서로의 사적인 부분을 파고드느라 너무 많은 시간을 소모하게 된다. 이런 경우 리팩토링이 필요하다.
- 다른 인터페이스를 가진 대체 클래스가 있을 때(Alternative Classes with Different)
이런 경우는 개발자가 같은 기능을 가진 다른 클래스가 있다는 것을 몰랐을 때 발생하게 된다. 이 경우 리팩토링을 해서 중복을 제거할 필요가 있다.
- 불완전한 라이브러리 클래스일 때(Incomplete Library Class)
라이브러리의 작성자가 우리가 필요한 기능을 가지고 있지 않거나 추가하는 것을 거부했을 경우이다. 많은 라이브러리들이 일정 시간이 지나면 사용자들의 필요를 충족시키는 것을 멈추기 때문에 발생한다. 이 경우 해결책은 라이브러리를 수정하는 것이지만 만약 라이브러리가 수정을 허용하지 않는다면 이 방식으로 해결할 수가 없게 된다.
- 데이터 클래스가 있을 때(Data Class)
필드와 그 필드에 대한 get/set 메서드만 있는 클래스가 있다면 리팩토링이 필요하다.
- 클래스 상속 구조가 잘못되었을 때(거부된 유산)
클래스의 상속 구조가 잘못되었다면 수정할 필요가 있다.
- 주석이 잔 득 붙어 있는 코드를 보았을 때
주석이 잔뜩 있다는 것은 무엇인가 개발자가 서투른 부분이 있다는 신호일 경우가 많다. 이 경우 자세히 보고 리팩토링이 필요한지 확인할 필요가 있다.[4]
각주[편집]
- ↑ 1.0 1.1 AIdev, 〈리팩토링이란 무엇인가?〉, 《네이버 블로그》, 2017-05-07
- ↑ jayden jayden-lee, 〈리팩토링 - 리팩토링 개론〉, 《티스토리》, 2019-05-04
- ↑ 키훈키훈킴, 〈리팩토링이란 무엇인가?〉, 《네이버 블로그》, 2014-07-15
- ↑ WikiDocs, 〈코드속 나쁜 냄새〉, 《네이버 블로그》, 2018-02-17
참고자료[편집]
- AIdev, 〈리팩토링이란 무엇인가?〉, 《네이버 블로그》, 2017-05-07
- jayden jayden-lee, 〈리팩토링 - 리팩토링 개론〉, 《티스토리》, 2019-05-04
- 키훈키훈킴, 〈리팩토링이란 무엇인가?〉, 《네이버 블로그》, 2014-07-15
- WikiDocs, 〈코드속 나쁜 냄새〉, 《네이버 블로그》, 2018-02-17
같이 보기[편집]