본문 바로가기

Refactoring

리팩토링 관련 문제

반응형

리팩토링 관련 문제들


데이터베이스

수많은 비즈니스 애플리케이션은 바탕이 되는 데이터베이스 스키마와 강력히 결합되어 있다.

이 때문에 데이터베이스 수정이 어려워지는 것이다.

또 다른 이유로는 데이터 이전 문제를 들 수 있다.

아무리 데이터베이스 스키마와 객체 모델의 상호 의존성을 최소화하려고 시스템을 꼼꼼하게 계층 구주로 제작했더라도, 데이터베이스 스키마를 수정하면 데이터도 이전해야 하는데, 이것은 시간도 오래 걸릴 뿐아니라 위험성도 높다.

데이터 이전 작업은 오래 걸릴수 있으며, 일부 시스템에서는 스키마를 정기적으로 수정하는 일이 불가능할 수도 있다.

이 문제를 해결하기 위해 객체 모델과 데이터베이스 모델 사이에 별도 소프트웨어 계층을 두는 방법이 있다.

이렇게 하면 두 모델이 생긴 변경 사항을 따로 유지할 수 있어서 한 모델을 수정할 때 다른 모델을 수정할 필요 없이 그저 중개 계층만 수정하면 된다.

그러한 중개 계층이 생기면 복잡하긴 하나 상당한 유연성이 생긴다.

리팩토링을 실시하지 않더라도 데이터베이스가 여러 개이거나 개발자 본인에게 관리 권한이 없는 복합 데이터베이스 모델일 경우 유연성은 매우 중요한 요소다.


객체 데이터베이스는 도움될 때도 있고 방해될때도 있다.

일부 객체지향 데이터베이스는 한 각채에서 다른 객체로의 자동 마이그레이션 기능이 있다.

이 기능을 이용하면 수고를 줄일수 잇지만 마이그레이션 시간이 절약되진 않는다.

자동 마이그레이션 기능을 이용하지 않으면 직접 마이그레이션하느라 엄청나게 고생해야 한다.

수동으로 마이그리에션을 실시할 땐 클래스의 데이터 구조 변경에 신경써야한다.

기능은 맘편히 어디로든 옮겨도 되지만 필드를 옮길 댄 주의를 기울어야 한다.

데이터가 옮겨졌든 안 옮겨졌든 간에 읽기/쓰기 메서드를 사용해서 데이터가 옮겨진 것으로 인식되게 해야한다.

데이터가 있어야 할 위치를 분명히 알고 있을땐 데이터 이동과 마이그레이션을 한방에 끝낼수 있다.

오로지 읽기/쓰기 메서드만 수정하면 되므로 버그 발생 위험이 줄어든다.


인터페이스 변경

객체의 중대한 장점 하나는 인터페이스를 건드리지 않고 내부의 구현 코드를 수정할 수 있다는 점이다.

객체를 이용하는 부분을 수정하지 않고도 객체의 내부 구조를 안전하게 수정할수 있지만, 인터페이스를 수정하면 무슨 문제가 생길지 알 수 없으므로 인터페이스를 건들이지 않을 수 있다는 큰 장점이 있다.

리팩토링에서 불안한 점은 상당수의 리팩토링이 인터페이스를 건드린다는 것이다.

메서드명 변경 같이 간단한 기법은 그 자체가 인터페이스를 수정하는 작업이다.

그렇다면 이것이 객체의 주요 개념인 캡슐화에 어떤 영향을 미칠까?

메서드를 사용하는 모든 코드에 접근할 수 있다면 메서드명을 변경하는 것쯤은 문제가 되지 않는다.

심지어 메서드가 public이라도 해도 그 메서드를 호출하는 부분을 찾아 수정할 수 만 있다면 메서드명을 바꿔도 상관없다.

그러나 인터페이스가 사용되는 부분을 찾는게 불가능하거나 수정할 수 없을 경우엔 문제가 생긴다.

그럴 경우 그 인터페이스는 published 인터페이스(public 인터페이스보다 한 단계 더 적극적으로 공개된)가 된다.

한번 배포 publish 타입이 된 인터페이스는 안전하게 수정할 수 없으며 호출자만 수정하는 것이 불가능해지므로 더 복잡한 절차를 수행해야한다.

그런 점을 생각해보면 다른 의문이 들게 된다.

그렇다면 인터페이스를 수정하는 리팩토링기법들을 실시할 때는 어떻게 해야 할까?

간단히 말하면 어떤 리팩토링 기법이 배포 인터페이스를 건드릴 경우 개발자는 적어도 그 인터페이스를 사용하는 부분이 그 인터페이스 변경에 맞춰 수정되기 전까지는 기존 인터페이스와 새 인터페이스를 모두 그대로 유지시켜야 한다.

다행스럽게도 이렇게 하는 일은 그리 어렵지 않다.

대체로 깔금하게 정리하는 것만으르도 기존 인터페이스까지 계속 사용할 수 있다.

기존 인터페이스가 새 인터페이스를 호출하게 하면 된다.

메서드명을 변경할 때는 기존 메서드가 새 메서드를 호출하게 수정해서 계속 유지되게 해야 한다.

메서드의 내용 자체를 복사해서는 안된다.

복사해서 붙여 넣으면 중복 코드가 생겨서 오히려 문제를 만든 꼴이 된다.

더불어 자바의 deprecatioin 같은 타입을 작성해서 호출자아게 그 코드를 사용하지 말아야 함을 알려야 한다.

인터페이스를 유지하는 것은 가능하긴해도 불편하고 까다롭다.

최소한 일정기간 동안은 이러한 불필요한 메서드를 남겨둬야 하기 때문이다.

이런 메서드로 인해 인터페이스가 복잡해져서 인터페이스 사용만 어려워진다.

물론 다른 방법도 있긴하다.

인터페이스를 published 타입이 되지 않게 하는 것이다.

완벽히 차단하자는 얘기는 아니다.

어차피 published 인터페이스는 필요하기 때문이다.

외부에서 사용하기 위한 API를 제작한다면 published 인터페이스는 꼭 필요하다.

이건 주위에서 published 인터페이스를 많이 사용하는 개발 팀을 자주 볼수 있기에 하는 얘기다.

3명으로 구성된 팀에서 본인 외의 2명이 사용할수 있게 하려고 인터페이스를 배포(pulished 타입으로 만듦)하는 경우가 있는데, 이런 식의 작업은 코드로 더 손쉽게 접근해서 수정할 수 있어서 인터페이스가 원래대로 유지될 가능성이 낮다.

코드 저작권(소유권)을 과도하게 철저히 따지는 업체들은 이런 실수를 할 가능성이 높다.

그렇게 하면 유용하긴 해도 비용이 많이 든다.

그러므로 꼭 필요할 때가 아니면 인터페이스를 published 타입으로 만들지 않는게 좋다.

이를 위해서 인터페이스 수정을 촉진하기 위해 팀원이 다른 사람의 코드를 수정할수 있게 코드 소유권 정책을 수정해야 할 수도 있다. 대체로 페어 프로그래밍을 이용하는 것이 바람직하다.


리팩토링을 어렵게 하는 설계를 수정하는 일

설계 자체에 오류가 있을 때나 설계에 대한 결정이 나중에 바뀌었을 때, 혹은 수정하기 힘들 것 같은 민감한 부분일 때도 과연 자유자재로 리팩토링할 수 있을까?

거의 모든 경우는 리팩토링으로 해결된다.

프레임워크 선택이라든지 연동 기술 선택 같은 특정 설계적 판단을 배제한 채 리패토링 공정은 어렵긴해도 분명 가능하다.


리팩토링하면 안 되는 상황

리팩토링하지 말아야 할 때도 있다.

대표적으로 코드를 처음부터 새로 작성해야 할 때가 그렇다.

기존 코드가 지극히 지저분해서 리팩토링은 가능하지만 차라리 완전히 새로 작성하는게 더 쉬울 때가 있다.

물론 이 판단은 쉽게 내릴 수 없으며 기준도 없다.

코드가 돌아가지 않는다면 그건 완전히 새로 작성하라는 신호다.

테스트만 하려다 코드가 버그 투성이라 안정화할 수 없음을 알게 될 경우가 바로 그 때다.

코드는 반드시 대부분 제대로 돌아가는 것이 우선이고, 리팩토링은 나중 일임을 명심하자.

한가지 절충안은 하나의 거대 소프트웨어를 강력한 캡슐화를 통해 여러 개의 컴포넌트로 나누는 것이다.

그런 다음에 한번에 한 개의 컴포넌트씩 리팩토링할지 코들르 새로 작성할지를 결정하면 된다.

이 방법은 괜찮을 것 같긴한데 세부 규칙을 알려줄 만큼의 데이터를 모으지 못했다.

중대한 구형 시스템은 확실히 이 방법을 사용해볼 만하다.

납기가 임박했을 때도 리팩토링은 삼가야 한다.

납기가 가까운 시점에 리팩토링 해봤자 그로 인해 생상성은 납기가 지난 후에 가시화될 테니 쓸데 없다.

납기가 임박한 경우가 아니면 시간이 없다는 핑계로 리팩토링을 미루면 안된다.


-출처 리팩토링 코드의 품질을 개선하는 객체지향 사고법 (마틴 파울러)

반응형

'Refactoring' 카테고리의 다른 글

리팩토링  (0) 2018.03.02