각각 다른 알림 타입에 대해서 객체지향적으로 처리해보자

개요

꼬꼬면 서비스에서 알림을 구현하다가 같은 알림임에도 불구하고 여러 타입으로 나뉘는 것을 알게 되었다.

현재의 알림의 경우 서버에서 다루는 알림은 세 가지가 있다.

  • 누군가 내 면접을 조회했을 때
  • 상대방이 내 면접에 좋아요를 눌렀을 때
  • 상대방이 내 면접을 보고 각 답변에 좋아요를 눌렀을 때 의 경우로 나뉘는 상황에서 나는 각각의 알림을 어떻게 UI에 표시할지를 생각하며 구현하고 있었다. 그런데 가면 갈수록 해당 방식의 문제점에 대해서 조금 생각을 하게 되었고, 이에 객체지향 개념을 적용하여 문제를 조금 더 간단하게 표현할 수 있을 것 같았기에 이러한 리팩토링 과정을 말해보려 한다.

기존의 문제점

기존의 문제점은 여러가지 Notification에 대해 따로 처리를 해줘야 한다는 점이다. 만약 컴포넌트에 각각의 알림을 띄우려고 한다면,

// 각각의 컴포넌트를 하나씩 구현하기..
const AnswerLikeComponent = () => {
	...
}
const InterviewLikeComponent = () => {
	...
}
const InterviewViewCountComponent = () => {
	...
}
 
function NotificationItem({notification} : {notification : Notification}) {
	switch(notification.type){
		case AnswerLike:
			...
		case InterviewLike:
			...
		case InterviewViewCount:
			...
			등등...
	}
}

와 같이 계속해서 각 컴포넌트에 대해서 만든다고 하더라도 안쪽 텍스트만 바뀌는 것임에도 불구하고 계속해서 분기처리의 늪에 빠지게 되며, 알림 전체의 부분들을 고친다고 하더라도 모든 세부알림 컴포넌트를 고쳐야 하는 등 컴포넌트의 유지보수가 어려워지게 된다.

const transferNotificationMessage = () => {
		switch(notification.type){
	 	case AnswerLike:
			...
		case InterviewLike:
			...
		case InterviewViewCount:
			...
			등등...
	}
}
	
function NotificationItem({notification} : {notification : Notification}){
	return (
		<div>transferNotificationMessage(notification.type)</div>
	)
}

이를 해결하기 위해 개별적인 컴포넌트로 나누기 보다는 메시지만 변환하여 사용하는 방식을 택한다면 이런 식으로 분기처리를 하여 조금 더 가독성이 좋게 바꿀 수 있을 것이다. 하지만 여기서 더 나아가

객체지향적으로 개선하기

export type NotificationDetails =
  | {
      notification_type: "ANSWER_LIKE";
      answer_id: number;
      interview_id: number;
      liker_member_id: number;
      like_count: number;
    }
  | {
      notification_type: "INTERVIEW_VIEW_COUNT";
      interview_id: number;
      view_count: number;
    }
  | {
      notification_type: "INTERVIEW_LIKE";
      interview_id: number;
      liker_member_id: number;
      like_count: number;
    };

각각의 Notification에 대해서 바뀌는 정보

export abstract class BaseNotification implements BaseNotificationInterface {
  public type: NotificationType;
  public createdAt: string;
  public isRead: boolean;
 
  constructor(
    type: NotificationType,
    createdAt: string,
    isRead: boolean = false
  ) {
    this.type = type;
    this.createdAt = createdAt;
    this.isRead = isRead;
  }
 
  abstract getMessage(): string;
}

추상 클래스를 미리 구현해놓아 해당 클래스의 메서들을 통해 각각이 다른 속성을 가지고 있더라도, 하나의 메서드를 통해서 해당하는 알림의 메시지 내용을 바로 받을 수 있게끔 할 수 있다.