[Spring] 프로젝트 리팩토링 및 구조 개선

한호성·2023년 7월 19일

Introduction

이번 글에서는, 회사 프로젝트 기능이 확장되면서, 개발했던 내용들을 어떻게 했는지 추상화해서 간단하게 설명하도록 하겠다.

Spring 3 tier-layer에서, service layer의 구조를 같은 팀원이랑 머리를 맞대고 논의하면서, 구조를 갖추게 되었다.

순서대로 차분히 설명하도록 하겠다.


INDEX

  • 프로젝트 간단 설명
  • 구조개선 포인트
  • 사용한 디자인 패턴

프로젝트 설명

현재 개발하고 있는 프로젝트는 회사 간의 계약을 진행할 때, 계약내용 기록 및 진행 상황 체크를 위한 프로젝트이다.

특별히 많은 기능이 있는 것은 아니지만, 시간에 쫒기면서 개발을 진행하다 보니, 구조가 유지보수에 유연하지 못하다고 판단했고, 실제로 기능이 확장되면서 구조를 생각하고 변경할 필요성을 느꼈다.

같이 작업하는 팀원분도 비슷한 생각을 하고 있으셔서, 요구사항을 받은 후, 각자 생각을 정리하면서 구조를 같이 생각하면서 완성했다. 아래에 차분히 이야기 해보겠다.

(추후에 기능이 플랫폼화까지 확장되면, 외부로 오픈할 수도 있다고 하신다.)

구조 개선 포인트

원래 구조

스프링 프레임워크의 기본 구조로 많이 사용되는 Controller - Service - Repository 3 Tier Layer를 사용하고 있었고, Service layer에서 많은 도메인 레포지토리에 접근해서 데이터를 취합하야 하는 경우는, 통합해주는 다른 계층 개념의
Manage Class를 만들어서 처리했다.

그림으로 보자.

각 도메인 서비스는, 순수하게 자신의 도메인과 관련되어 있는 처리만 진행하는 service Class 들이고, 이를 종합하는것이 Manage Service class들이다.

이 구조도, 다른 팀원분이 제안해주셔서, 적용하고 나름 잘 쓰고 있었는데, 기능이 추가되면서, 조금 더 생각이 필요하게 되었다.

가장 큰 문제점은, 현재 Interface를 사용하고 있지 않아서, 결합도가 너무 높은 상태였다.

유지보수 할 때, 손봐야할 곳이 많았다. 이런 문제점도 해결하고자 새 기능은 충분히 생각하는 시간을 갖고 설계를 하고 개발을 진행하였다.

추가기능 및 구조 변경

추가기능

이런 구조에서 service layer의 business가 굉장히 복잡하게 되었다. 회사 프로젝트라 대략적으로만 이야기하면, 계약서를 처리하는 단계가 추가되었고, 각 단계는 비슷한 기능을 하는데 굉장히 세세하게 다른점이 있었다.

이를 각각의 클래스로 만들거나, 한 클래스에서 분기처리 하기란, 만들 때 편할 수 있어도, 유지보수에 최악일 것이라 판단했다.
그래서 다음과 같이 생각이 발전해 나갔다.

  1. 비슷한 기능을 하는 method를 interface를 빼자
  2. 공통적으로 처리해야하는 부분들을 모아서, 추상클래스에, method로 분리하자.
  3. 분리한 추상클래스를 상속받는 클래스들을 만들고, 거기에 비슷한 기능을 하지만 비지니스 로직이 다른 method들을 갖는 interface들도 구현시키자.
  4. 기존 ManagerService에서 같은 메소드를 호출하고, 각 호출에 맞는 구현체들을 사용해서 비지니스 로직이 수행되게 하자.

이렇게 생각이 흘러가면서 구조를 짜게 되었다.

간단하게 각 클래스 및 인터페이스들의 역할을 설명해보자.

구조 변경에 사용된 클래스 설명

추상클래스

: 구현체의 부모 클래스 (아래 그림이 있으니 확인해보셔도 좋을거 같습니다.)

  • 계약서 관련 비지니스 로직을 수행할 때, 필요한 다른 service 혹은 Repostiory들을 멤버변수로 갖음
  • 계약서 관련 비지니스 로직을 수행할 때, 공통적으로 사용되는 메소드들을 구현해놓음
    - 필요하실, override해서 수정하도록 했음.

계약관련Interface

  • 계약서 관련 비지니스 로직을 수행할 때, 비지니스적으로 다른 부분이 있는 부분을 메소드로 뺴두었음.

구현체 클래스

: 추상클래스를 상속받고, Interface 메소드들을 구현한 클래스

  • 계약서 단계별로 존재함
  • 단계별로의 비지니스 로직을 수행하는 service class

이렇게만 글만 보면 무엇인지 모를테니, 도식표를 추가하겠습니다.

계약구현체 팩토리 클래스

: 들어오는 요청에 따라, 적절한 구현체를 전달하기위한 클래스

흐름설명

  1. Controller 에 요청이 들어옴
  2. ContractMangeService 에서 요청 정보에서 단계정보를 사용해 Factory로 부터 구현체들을 가져옴
  3. 각 구현체에 구현되어있는 함수 호출
  4. 작업 수행

정리

이렇게 흐름을 설명하니 굉장히 간단해보이는데... 생각할 때는,
처음하다보니 시행착오도 굉장히 많이 겪고, 각 함수들의 위치를 정하기 위해 고민을 많이했습니다.

구조를 역할에 따라 잘 나누고, 그 역할에 맞는 함수들을 배정하는 방법을 사용하였습니다.

분류가 애매한 부분들이 없도록 역할을 잘 나누는 것이 포인트였습니다.

사용한 디자인 패턴은 : Factory Pattern이란 것이 저희가 원하던 것이여서 찾아서 적용하였습니다.

profile
개발자 지망생입니다.

1개의 댓글

comment-user-thumbnail
2023년 7월 19일

이 글은 정말 인상적이었습니다.

답글 달기