SW/DevOps

DevOps : 리팩토링 기법 (3)

얇은생각 2019. 12. 14. 07:30
반응형

리팩토링

 

관심사의 분리

낮은 결합도, 높은 응집도를 가지게 하는 관심사의 분리 방법에 대해서 알아보겠습니다. 클래스 간 결합이 일어날 때 느슨하게 되어야 하는데, 그렇지 못할 경우 시간이 지남에 따라 왜 문제가 되는지 살펴보겠습니다.

웹 어플리케이션의 비즈니스 로직 계층에 멤버 정보를 처리하는 Service 클래스가 있다고 가정하겠습니다. 처음에는 멤버 정보 조회, 존재 여부 확인, 정보 변경을 처리하는 세 가지 기능으로 이루어진 Service 클래스입니다.

이 클래스를 서비스 발행 계층에서 front end 등 외부에 REST API로 노출하는 방식은 시간이 지나서 알림의 종류를 받고, 등록 및 해지하는 새 요구사항을 받게 되어 화면처럼 관련 메서드가 새로 추가하게 되었습니다. 서비스 발행 계층에서 추가된 메서드에 해당하는 REST API 형태의 메서드도 추가하였습니다.

시간이 지나 멤버 검색 및 차단하고, 해당 차단된 멤버들을 조회하는 추가 요구사항을 받았습니다. 요구사항과 가장 연관이 있는 MemberService 클래스에 메서드를 추가하게 됩니다. UI에서 멤버 프로필과 알림 기능, 관리자용 차단 멤버 검색 기능 등이 이 MemberService 클래스를 호출하게 됩니다. 이 클래스의 Code Smell은 너무 많은 기능들이 있고 앞으로도 멤버와 관련된 요구사항은 이 클래스에 포함될 가능성이 높습니다.

즉 관심사에 따라 분리되지 못한 채, 엉킨 스파게티 코드처럼 될 것입니다. 이런 스파게티 코드는 시간이 지남에 따라 해당 클래스의 크기가 커지고 호출도 많이 일어나게 됩니다. 기능에 따라 클래스의 기능들을 분리하여 작게 나누고 결합도를 낮춰야 합니다. 시간이 지나면서 클래스가 하나의 기능에서 점차 비대해지는데, Code Smell이 나기 전에 관심사에 따라 기능을 나누는 작업이 필요합니다.

MemberService 클래스는 본연의 기능과 알림, 차단 기능의 세 개로 나눌 수 있습니다. 새로운 요구사항에 따라 기능을 각각의 클래스 또는 새로운 클래스로 개발해 나가면 됩니다.

 

 

수레바퀴의 재발명

기능을 구현하기 전에 해당 기능이 혹시 존재하는지 팀원들 또는 관련 팀에게 문의하고, 추가적으로 표준 라이브러리, 오픈소스 라이브러리, 표준 프로토콜이 없는지를 확인해야 합니다. 문자열이나 파일 입출력 처리 등 유틸리티 성격의 기능일 경우 더욱 그렇습니다.

일반적으로 많이 사용되는 오픈소스 라이브러리, 프레임워크, 유틸리티 등을 살펴보고, 수레바퀴를 만들기보다는 재활용하는 방법을 찾는 것이 좋습니다. 또한 사용할 경우 직접 호출이 아닌 결합도를 낮춰서 간접 호출하는 것이 좋습니다.

 

 

아키텍처의 균형

아키텍처의 균형에 관련해 알아보겠습니다. 관심사의 분리 원칙에 따라 서로 다른 작업은 서로 다른 계층, 즉 레이어에서 처리하도록 하는 것이 좋습니다. 

물리적인 구분 기준인 Tier와 조금 다르게 레이어는 논리적인 개념의 구분으로, 작업을 정해진 기준에 따라 구분하여 코드 베이스 간 결합도를 낮추는 역할을 합니다.

하지만 레이어를 지나치게 많이 둘 경우 소프트웨어 유지보수가 힘들어지는 경우도 있으므로 상황에 따라 적절한 판단이 필요합니다.

 

 

Paradigm Shift - Reactive

패러다임의 변화 reactive에 대해서 알아보겠습니다. 현대의 UI는 Aiax 등장 이후로 점점 응답이 빨라지고 화려하게 바뀌고 있는데, Back end 시스템은 고유 특성상 복잡한 연산 및 DB 접속, transaction으로 많은 시간이 걸리는 작업을 합니다.

하지만 객체지향, CBD, SOA, MSA 등 architecture의 발전 및 클라우드 개념이 나오고, 멀티 코어가 발전함에 따라 기존 명령형, 동기 처리의 반대되는 개념인 선언형, 비동기 처리, reactive 개념이 부각되었습니다.

reactive는 화면과 같은 특성을 강조합니다. 물 흐르듯이 오고 가는 데이터를 사용자에게 자연스러운 응답을 주고, 규모 탄력적으로 리소스를 사용하며 실패에 있어서 유연하게 대처합니다.

Spring 및 기타 언어들의 발전에 더불어 Java 언어도 늦었지만 Java5의 future에 이어서 Java8의 completable future, Java9의 flow 등으로 발전하고 있습니다.

 

 

패러다임의 변화에 따른 아키텍처의 진화

명령형, 동기 처리 형태의 강결합 형태로 개발하거나 2번의 선언형, 비동기 처리 형태의 느슨한 형태로 개발할 수도 있습니다. customer Service에서 의존 관계에 있는 다른 개별 서비스로 각각의 상태 변화를 통제하는 강결합 형태에서 이벤트 발행이라는 이벤트를 통해서 좀 더 느슨한 약결합 형태로 바꾸는 게시-구독 패턴을 적용할 수도 있습니다.

이런 패턴을 적용할 경우 느슨한 결합과 확장성을 가지는 장점이 있지만, 전달이 보장되지 않을 수 있는 단점도 있습니다. transaction 처리에 익숙한 상태에서 MSA를 적용하게 되면 겉모습만 MSA 형태인 monolith architecture가 될 가능성이 높은데, command와 event를 통해 각 마이크로서비스 간 느슨한 결합을 하게 되면 cloud-native architecture 형태로 발전하게 됩니다.

 

 

Singularity & Digital Transformation

가진 것이 망치뿐이라면 모든 것이 못으로 보인다는 말이 있습니다. 모든 기술에 장점과 단점이 공존하듯이 cloud-native architecture가 반드시 정답은 아닙니다. 자신이 속한 프로젝트 상황 또는 비즈니스 도메인 상황에 따라 적절한 기술의 선택과 팀 구성이 반드시 필요합니다. 우리가 만드는 소프트웨어 시스템은 선택한 기술과 사람이 모인 조직이 함께 빚어내는 유기체이기 때문에 항시 적절한 선택을 하는 지혜가 필요합니다.

반응형

'SW > DevOps' 카테고리의 다른 글

DevOps : UnitTest 개요, 방법  (0) 2019.12.16
DevOps : SW 테스트 개요  (0) 2019.12.15
DevOps : 리팩토링 기법 (2)  (0) 2019.12.13
DevOps : 리팩토링 기법 (1)  (0) 2019.12.12
DevOps : 리팩토링 개념과 필요성  (0) 2019.12.11