[Project] Facade 패턴으로 의존성 개선하기

이상혁·2024년 11월 18일

Project

목록 보기
12/12

Service에서 코드 리팩토링의 필요성

프로젝트를 진행을 하면서 event의 service단을 작업을 하고 있었습니다. event를 생성하고 수정을 하는 과정에서 필드의 다른 엔티티들이 필요로 하다보니 event의 service단에서 repository들을 의존을 하는 것이 굉장히 컸습니다. 의존을 많이 하다가 보니 유지 보수도 힘들어진다고 느끼게 되었습니다.

무엇보다도 객체지향적이지 않았습니다. 우리는 객체지향을 사용을 하고 있습니다. 하지만 repository의 의존이 많아지면서 event의 service단이 너무 많은 책임을 지면서 객체지향을 활용하지 못하고 있다고 생각이 들었습니다. 그래서 service단의 책임을 줄이고 하나의 책임을 가지게 하고 싶었습니다.

그러면 왜 Facade 패턴인가?

저는 이 문제를 해결을 하기 위해서 Facade 패턴을 적용을 하기로 했습니다. 왜 Facade 패턴인지를 말하기 전에 Facade 패턴이 무엇인지부터 간단하게 알아보겠습니다.

Facde 패턴

Facade패턴은 구조적 디자인 패턴 중 하나입니다. Facade패턴은 복잡한 일을 쉽게 사용할 수 있도록 해주는 디자인 패턴입니다. 우리가 만약 컴퓨터를 실행을 시키려고 전원 버튼을 누르면 운영체제가 돌아가고 네트워크가 연결이 되고 여러 프로그램이 실행이 됩니다. 이렇게 하나의 동작으로 다양한 일들이 일어납니다. 이렇게 하나의 동작으로 많은 일과 복잡한 일을 해주는 것이 Facade 패턴입니다.

프로그래밍에서도 서브시스템 클래스들, 즉 실제 작업을 수행하는 클래스들을 Facade에서 클라이언트와 상호작용을 하는 인터페이스에서 서브시스템 클래스들이 상호작용을 할 수 있도록 해주는 역할을 합니다.

왜 Facade 패턴을 사용하는가?

Facade를 사용하는 이유는 service의 책임을 낮추기 위해서 입니다. service에서 controller에게 결과를 넘겨 줄 때, 다른 repository가 필요한 경우가 있습니다. 그러다보니 service가 다른 repository를 책임지는 경우가 발생을 합니다. 결국 service의 책임을 낮춰주어야 하는데 이 책임을 낮출 수 있는 패턴이 Facade 패턴입니다. Facade를 만들어서 service가 해줘야 하는 책임을 대신 지게 해주기 위해서입니다. 이렇게 되면 service는 하나의 repository만을 책임을 지면 solid원칙 중 단일 책임의 원칙 또한 지킬 수 있습니다.

Facade 패턴 적용을 해보기

이제 Facade 패턴 전에 코드를 보면서 문제를 살펴보기 Facade 패턴을 적용을 하면서 개선을 해보겠습니다.

개선 전

@Service
@RequiredArgsConstructor
public class EventService {
    private final EventRepository eventRepository;
    private final EventLocationRepository eventLocationRepository;
    private final DeletedEventRepository deletedEventRepository;
        
    @Transactional
    public EventEntity createEvent(EventRequestDTO dto) {
        EventLocationEntity eventLocationEntity = getEventLocationEntity(dto.getEventLocationId());
        EventEntity newEventEntity = new EventEntity(dto, eventLocationEntity);
        return eventRepository.save(newEventEntity);
    }
        
    @Transactional
    public EventEntity deletedEvent(Long eventId) {
        EventEntity eventEntity = getEventEntity(eventId);
        DeletedEventEntity deletedEventEntity = new DeletedEventEntity(eventEntity);
        deletedEventRepository.save(deletedEventEntity);
        eventRepository.delete(eventEntity);
        return eventEntity;
    }
    
    
    private EventLocationEntity getEventLocationEntity(Long eventLocationId) {
        return eventLocationRepository.findById(eventLocationId).orElseThrow(() ->
                new GlobalCommonException(EventLocationErrorResponsive.NOT_FOUND_EVENT_LOCATION)
        );
    }
    
}

지금 개선 전에 일부 코드를 보면 service 클래스에서 event를 생성, 삭제를 하면서 필요한 repository를 책임을 지면서 사용을 하고 있습니다. 그러면서 solid의 원칙 중 하나인 단일 책임 원칙을 위배하면서 객체지향적이지 않은 코드가 됩니다. 또 많은 책임으로 인해서 코드도 복잡해졌습니다. 이를 Facade 패턴을 사용을 해서 개선을 해보겠습니다.

개선 후

먼저, service단을 개선을 해보겠습니다.

@Service
@RequiredArgsConstructor
public class EventService {

    private final EventRepository eventRepository;

    public EventEntity createEvent(EventRequestDTO dto,
                                   EventLocationEntity eventLocationEntity) {
        EventEntity newEventEntity = new EventEntity(dto, eventLocationEntity);
        return eventRepository.save(newEventEntity);
    }

    public EventEntity deletedEvent(Long eventId) {
        EventEntity eventEntity = getEventById(eventId);
        eventRepository.delete(eventEntity);

        return eventEntity;
    }
}

service에서는 단 하나의 repository만을 책임을 집니다. 여기서는 event repository를 책임을 집니다. 이전 개선이 되기 전에 코드보다 간단해졌고 보기도 편해졌습니다.

@Component
@RequiredArgsConstructor
public class EventFacade {

    private final EventService eventService;
    private final EventLocationService eventLocationService;
    private final DeletedEventService deletedEventService;

    @Transactional
    EventEntity createEvent(EventRequestDTO dto) {
        EventLocationEntity eventLocationEntity = eventLocationService.getEventLocation(dto.getEventLocationId());
        CategoryEntity categoryEntity =  categoryService.getCategory(dto.getCategoryId());
        EventEntity eventEntity = eventService.createEvent(dto, eventLocationEntity);

        categoryEventService.createCategoryEvent(categoryEntity, eventEntity);
        return eventEntity;
    }

    @Transactional
    EventEntity deletedEvent(Long eventId) {
        EventEntity eventEntity = eventService.deletedEvent(eventId);
        deletedEventService.createDeletedEvent(eventEntity);

        return eventEntity;
    }

}

Facade를 만들어서 Facade가 service가 지고 있던 책임을 가지고 클래스 안에서 복잡한 작업을 대신 해주는 역할을 합니다. 이런한 방식의 service에 과중되어 있던 책임을 나누고 service에서 단일 책임 원칙을 지킬 수 있게 되었습니다. 이제 복잡한 것들은 Facade에서 조합을 통해서 처리를 할 수 있게 되었습니다.

마무리

이번 포스트에서는 가독성과 객체지향을 지키기 위해서 Facade 패턴을 적용을 해보았습니다. 사실 이전까지 디자인 패턴에 대한 중요성을 크게 느끼지 못 하고 있었는데 이번 계기를 통해서 디자인 패턴이 가독성과 더 나아가 객체지향을 위해서 사용이 될 수 있다는 것을 느낄 수 있었습니다. 그리고 새롭게 적용이 된 것을 보면서 개발의 즐거움을 느낄 수 있었습니다. 코드 또한 더 간단해지고 객체지향적이어지고 가독성이 좋아졌습니다.

profile
꾸준히!

0개의 댓글