[Project] Spring - 관심사의 분리

짱수·2023년 5월 4일

Project -Tumblbug

목록 보기
3/3

현재 텀블벅 이라는 클라우드 펀딩 서비스를 클론코딩 중이다.
그 과정에서의 고민과 개발 경험을 공유한다.

배경

프로젝트를 조회하는 과정에서 프로젝트가 두가지의 상태로 구분이 된다.

프로젝트 런칭이 진행중인 onGoing 과 프로젝트 런칭 예정인 preLaunching 이 구분되는 프로젝트의 상태이다.

하지만, 두 상태의 프로젝트를 DB를 분리하게 되면 계속해서 preLaunching 프로젝트 DB의 프로젝트들을 onGoing 프로젝트 DB에 옮겨 담는 과정이 필요하다.

즉, DB가 분리된다면 매 순간 런칭이 시작된 프로젝트를 preLaunching 프로젝트 DB에서 onGoing 프로젝트 DB로 이동시키는 오버헤드가, DB를 통합한다면 조회할 상태에 해당하지 않는 프로젝트가 같이 조회되는 오버헤드가 발생한다.

두 상황에 대한 트레이드 오프는 추후 DB를 연동하고 나서 성능 비교를 해보기로 하고, 우선은 DB를 통합하여 사용하기로 하였다.

날짜 비교

이제 우리는 하나의 DB 안에 저장되어 있는 프로젝트가 onGoing 상태인지 검증해야 할 필요가 생겼다.

물론, 날짜를 비교하는 것은 너무나 일반적인 상황이고, 제공되는 라이브러리 또한 다양하다!

그 중에서도, 나는 문자열 형식의 날짜를 날짜 객체로 생성해 주는 java.text.SimpleDateFormat 라이브러리와 날짜 객체 java.util.Date 라이브러리를 사용해 날짜를 비교하는 로직을 작성하였다.

아래는 ProjectCardService 클래스에서 현재 진행중인 프로젝트를 조회하는 로직 findOngoingProject()를 재구성한 것이다.

import java.util.Date;
import java.text.SimpleDateFormat;

public class ProjectCardService{
		ProjectRepository projectRepository = ProjectRepository.getProjectRepository();
		private SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");

		public ArrayList<ProjectCard> findOngoingProject(){
				ArrayList<ProjectCard> projectCards = new ArrayList<>();
        long projectId = 0l;
				Date today = new Date();

				while(projectCards.size() < 20){
						Project project = projectRepository.findProjectById(projectId);
						Date projectStartDate = dateFormat.parse(project.getStartDate());
		
						if(today.before(projectStartDate)){
		            projectId++;
		            continue;
		        }
				    User creater = findCreater(project);
				    ProjectCard card = new ProjectCard(project, creater);
		
						projectCards.add(card);
		        projectId++;
				}
				return projectCards;
		}
}

위 코드는 물론 잘 동작하지만, 이 코드에는 하나의 문제가 존재한다. ProjectCardService 클래스는 본래 프로젝트를 조회 후 ProjectCard 객체 형태로 반환 해 주는 역할을 하기 위한 클래스이다. 즉, 날짜를 비교하는 기능은 원래의 관심사에서 벗어난다. 게다가, 특정 라이브러리를 사용하고 있기 때문에 사용 라이브러리에 의존적인 코드가 작성되었다.

이러한 문제로 인해 나중에 라이브러리를 변경 하거나, 날짜의 형식이 바뀌는 등의 변화에 대응하기 어려워 진다.

문제 해결

그렇다면 이 문제를 어떻게 해결할 수 있을까?’

우리의 당장의 목표는 하나이다. ProjectCardService 클래스에서 주요 관심사 이외의 관심사들을 분리하는 것.

이를 위해 우리는 문자열 형식의 날짜 비교를 위한 새로운 클래스를 생성하고, projectCardService 는 날짜 비교를 위해 생성된 클래스를 가져와 쓰는 방법을 선택할 것이다.

아래는 새로 생성된 Callendar 클래스와 ProjectCardService의 리팩토링 결과이다.

public class Callendar {
		static private Date date;
    static private SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");

    public static String getTodayString(){
        date = new Date();
        String today = Callendar.format.format(date);
        return today;
    }

    public static Date convertDate(String dateString) throws ParseException {
        try {
            date = format.parse(dateString);
        } catch (ParseException e) {
            e.printStackTrace();
            throw e;
        }
        return date;
    }

    public static boolean before(String dateString1, String dateString2) {
        Date date1 = format.parse(dateString1);
        Date date2 = format.parse(dateString2);

        return date1.before(date2);
    }
}

public class ProjectCardService {
		UserRepository userRepository = UserRepository.getUserRepository();
    ProjectRepository projectRepository = ProjectRepository.getProjectRepository();

		public ArrayList<ProjectCard> findOngoingFromIdx(){
				String today = getTodayString();
        ArrayList<ProjectCard> projectCards = new ArrayList<>();
        long projectId = 0l;

        while(projectCards.size() < 20) {
		        Project project = projectRepository.findProjectById(projectId);
            String projectStartDate = project.getStartDate();

            if(Callendar.before(today, projectStartDate)){
		            projectId++;
                continue;
		        }
		        User creater = findCreater(project);
		        ProjectCard card = new ProjectCard(project, creater);
		
		        projectCards.add(card);
		        projectId++;
		    }
	      return projectCards;
		}
}

위 처럼 Callendar 객체를 생성해 날짜 객체와 포멧등을 추상화 하여 ProjectCardService 객체에서 날짜 비교의 관심사를 분리할 수 있게 되었다.

이제는 날짜의 저장 형태가 바뀌거나, 특정 이유로 날짜 객체 라이브러리의 변경이 있더라도 기존의 비즈니스 로직의 변경 없이 Callendar 객체의 수정만으로도 기존과 같은 동작을 기대할 수 있게 되었다!

profile
Zangsu

0개의 댓글