반응형



 부서를 처음 배정받고 선배님들이 'Legacy 코드'라는 말을 자주 사용하는 것을 들을 수 있었다. 그 당시에는 Legacy코드가 뭔지에 대해서 감도 전혀 없었고 Legacy 코드에서 작업하는 것이 새롭게 프로젝트를 진행하는 것보다 어려운지 또한 알지 못했다. 하지만 요즘 Legacy 코드 위에서 작업을 하면서 몸소 그 어려움에 대해 체험하는 중이다. 하지만 반면으론 현재 서비스되고 있는 거대한 양의 코드들을 다루며 내가 그동안 프로그래밍을 하면서 알지 못했던 방식이나 방법들에 대해서도 프로그래밍을 함에 있어 지향해야 할 부분과 지양해야 할 부분에 대해서도 많이 생각해보고 적용해보며 견문을 넓혀 가고 있는 중이다.그렇다면 Legacy코드가 무엇인지에 대해서 알아보고 그 위에서 어떻게 작업해가면 좋을지에 대해서 살펴보도록하자

 Legacy란???먼저 Legacy의 사전적인 의미로는 "(남이 남긴)유산"으로 해석할 수 있다. 그럼 Legacy코드란? 많은 사람들이 이에 대해 다양한 정의를 내리고 있지만 간단히 말해 '다른 사람에게 넘겨받은 읽기 어렵고 수정하기 어려운 오래된 코드'를 말한다. 특히 기술의 변화가 많은 웹 프로젝트들에 있어서는 시간이 지나면서 기술이 발전할 수록 Legacy 코드들이 점점 쌓여저만 간다. 그렇다면 Legacy 코드 위에서 작업할 때 부딪히는 문제들에는 어떠한 것들이 있을까?


 Legacy Code에서 작업할 때 부딪히는 문제점은??? 첫번 째, 해당 코드를 이해하기 어려운 문제점이 있다. (변수명, 메소드명이 명확하지 않거나 매우 복잡함)

 두번 째, 해당 코드에 대해 완벽하기 이해하기가 어렵기 때문에 수정이 필요한 곳도 쉽게 수정하기 힘들어 진다. 또한 해당 부분을 수정한다고 했을 때 그에 따른 사이드 이펙트(기능 수정으로 인해 예상치 못한 부분에서 에러 발생)가 어디에서 발생할지에 대해서도 예측하기가 힘들다.

 세번 째, 코드에 대해 이해가 힘들다보니 해당 프로젝트에 대한 유지보수 작업을 진행함에 있어 자신감이 하락하게 된다.

 그렇다면 Legacy 코드를 만들지 않기 위해서는 어떻게 해야할까??? 1. Magic Number를 사용하지 말자.

 ①번 방식처럼 사용하게 될 경우 숫자1과 숫자2과 무엇을 의미하는 코드인지 알기 힘들다 ②번 방식처럼 Magic Number를 제거하고 사용하게 되면 좀 더 이해하기 쉬운 코드를 짤 수 있다.


 2. 의도를 나타내는 이름을 사용하자. 예를 들어 다음과 같은 메소드가 있다고 하자. (밑의 코드를 예를 들기 위해 짠 코드이기 때문에 메서드 명에 집중해주기 바란다)

 위 메서드가 어떠한 작업을 하는지 메서드명만 봐서는 도무지 감을 잡을 수가 없다. 반면 밑의 코드를 보면

 해당 메소드가 무엇을 하는 메소드인지 단번에 알 수 있다. 이렇든 명확한 이름을 사용하여 코드를 이해하는데 드는 시간을 줄일 수 있다.


 3. 가급적 프로그래밍을 할 때 부분만 옳은 것보다 전체적 대칭을 지키자. 예를 들어,district.setDong("정자")district.setGu("분당")district.setMetroPolitanOrSi("성남") 와 같이 부분만 옳은 동떨어진 메서드를 사용하기 보다는district.setDong("정자")district.setGu("분당")district.setSi("성남") 와 같이 전체적 대칭을 지키는게 나을 때가 많다. 따라서 기존의 코드와 대칭을 이루는 메서드명을 사용하는게 명칭이 잘못됬다 할지라도 나을 경우가 있다.


 4. if문이 덕지덕지 붙어있는 복잡한 조건식을 피하자.될 수 있으면 조건문을 사용하기 보단 다양한 패턴들을 활용해 복잡한 조건식을 피하고 메서드를 세분화 시켜주자.


 5. 사용하면 안 되는 클래스/메서드가 있을 경우

위와 같이 deprecated를 해놓으면 이클립스 등에서 코딩할 때 메서드에 취소선이 나와, 개발자의 주의를 환기시킨다. 하지만 아무런 설명이 없기 때문에 왜 저 메서드를 사용하면 안되는지에 대해 알 수 없다. 그렇기 때문에 무책임하게 @deprecated만 선언하지 말고 왜 @deprecated 되었는지 설명 또한 달아주도록 하자.




 6. 뻔한 중복 주석은 피하자.메서드 명이나 변수명만 봐서도 충분히 파악할 수 있는 부분에 대해서는 추가적인 주석을 달 필요가 없다. 특별한 경우나 이름 만으로만 이해하기 힘든 부분이 있을 경우 꼭 필요한 부분에 있어서 주석을 사용해주자. (의미없는 주석 사용 nono)


 7. 기능에 해당하는 테스트 코드를 작성하자.


 8. 리팩토링 작업을 지속적으로 하자. 리팩토링 - 외부 동작을 바꾸지 않으면서 내부 구조를 개선하는 방법으로, 소프트웨어 시스템을 변경하는 프로세스이다. 리팩토링을 별도의 작업이 아니라 개발의 한 부분으로 생각하도록 하자.


 현장 TIP1. Q) 얼마 전 중복이 많고 복잡한 코드를 GOF 디자인 패턴을 적용하여 리팩토링 했다. 그런데 코드리뷰 때 다른 개발자가 더 코드가 더 보기 어려워졌다고 한다.

 A) Communicative Code의 요건 중 배려가 있다. 따라서 분명히 구조적으로 좋아졌다고 하더라도 팀 내 다른 개발자가 모두 코드 읽기를 어려워 한다면 한번 더 생각해볼 만한 부분이라고 생각한다. 가치의 상충이 일어나는 것인데 '구조적 개선 vs 읽기 어려움'이다. 각각을 통해 얻게 될 가치를 종합적으로 잘 비교해보고 취사선택하는 것이 좋을 것이라 본다. 또한 GOF 디자인 패턴 적용의 초점이 문제해결이 아닌 적용 그 자체에 있을 때가 종종 있다. 이런 형태의 적용은 득보단 실이 많기 때문에 가급적 피하는 것이 좋다.


2. Q) Legacy 코드를 수정 중인데 너무 읽고 이해하기 어려운 클래스 xxx가 있다. 아무래도 안될 것 같아 New XXX를 만들었다. 하지만 예전 클래스를 사용하는 곳 까지 모두 수정하기는 어려워 이번에 작업하는 범위의 클래스에서만 New XXX를 사용하게 바꾸었다. 이렇게 해도 괜찮은 건가?

 A) 경험이 비추어 볼 때 절대 하지 말아야 할 형태의 개선이다. 이런 형태의 개선을 할 때 New, New2, New3가 계속 생기며, 기존 클래스는 정리가 안 되어 이후 복잡도가 높아지고 혼란을 가중시키는 사례를 봐왔다. 따라서 가급적 신규 클래스를 도입하는 형태의 개선은 트랜잭션과 마찬가지로 'All or Noting' 원칙이 적용되어야 한다고 본다. 신규 클래스를 도입하려면 반드시 기존 클래스를 제거하고, 그게 힘들다면 신규 클래스를 만들지 말고 예전 클래스 기반에서 수정하는 것이 올바른 방향이락 본다.


3. Q) Legacy 코드를 수정하기에 앞서 Cover & Modify를 하려고 하고 있다. 그런데 의존하는 객체가 너무 많았다. 할 수 없이 하나하나 만들어가며 테스트를 만들었다. 그런데 새로운 객체를 생성하는 등의 리팩토링을 하다 보니 기존에 만든 테스트가 다 실패한다. 도움을 주기보다는 거추장스러운 느낌이 나는데 왜 그런가?

 A) BO나 Service를 대상으로 단위 테스트를 만들면 대게 객체간의 인터랙션을 테스트하는 코드를 만들게 된다. 하지만 이런 테스트는 객체 간의 인터랙션을 조정하는 등의 리팩토링을 하게 되면 테스트를 고쳐줘야 하고 따라서 위와 같이 의미가 퇴색 될 수 있다. 따라서 이런 때는 통합 테스트를 활용하여 상태를 기반으로 검증하는 것이 좋다. BO의 예를 들면 실제 BO나 Service를 호출하고 데이터베이스 등에 값이 제대로 들어갔는지 등을 검사하는 것이다. 이렇게 만든 테스트는 객체의 관계를 조정하는 등의 리팩토링을 해도 달성되는 결과는 같기 때문에 테스트를 수정할 필요가 없고 안전망으로써 역할을 잘 수행한다.

 지금까지 Legacy코드와 Legacy 코드를 만들지 않기 위한 방법, 현장 Tip등 에대해 알아보았다. 많은 내용은 NHN에서 교육했던 'Legacy 코드에서 작업하기'교재에서 참고하여 정리하였다.


반응형

+ Recent posts