///
Search
⏱️

LastPageInfo Strategy Pattern 적용기

태그
Project
클라썸

Situation

LastPageInfo 란?
lastPageInfo는 유저가 서비스 내에서 마지막으로 방문한 페이지를 얘기합니다. 다음과 같은 형태로 object를 json으로 바꿔서 DB에 그대로 저장합니다. 이 때 다소 당황스러운 점은 LandingStatus 속성들에 따라 lastPageInfo의 property들이 다르다는 것입니다.
user.lastPageInfo = { landingStatus: 'InstituteHome' }
JavaScript
복사
여기서 landingStatus는 여러 갈래로 나뉠 수 있습니다. 기관 홈 / 공간 홈 등으로 나뉠 수도 있고, 관리자라면 관리 콘솔로 들어가야할 수도 있습니다.
landingStatus에 따라서 필요한 id 값들이 다릅니다. 예를 들어 기관 호이라면 현재 기관 id를 공간 홈이라면 현재 공간 id를 주어야할 것입니다.
그렇다고 id라는 이름으로 모든 것을 감싸기엔 다양한 맥락을 표현하지 못하기에 이 형식을 통일하기에는 무리가 있었습니다.
현재 발생한 상황은 lastPageInfo가 잘 업데이트 되지 않는 것입니다.

Task

lastPageInfo가 잘 업데이트 되지 않는 것이 티켓의 메인 문제였지만, 이는 일회성으로도 고칠 수 있었습니다.
그 보다 더 근본적인 방향으로 개선이 필요했습니다.

Action

위와 같은 형식에서 중요한 것은 각각이 담아야할 정보가 다르지만 이것이 추상화되지 않고 있다는 것입니다.
예를 들어 lastPageInfo를 업데이트 해줘야하는 상황에서 하나하나 if,else문을 이용해 분기하면서 object를 만들었습니다.
landingStatus에 따라 조립해야할 object가 다르기 때문에 이 부분을 캡슐화하고자 하였으며 자연스럽게 strategy 패턴을 사용하게 되었습니다.
우선 Strategy에 대한 정의를 아래와 같이 했습니다.
export interface StrategyToLastPageInfo { courseRepo?: CourseRepository courseToUserRepo?: CourseToUserRepository userRepo?: UserRepository instituteRepo?: InstituteRepository instituteMemberRepo?: InstituteMemberRepository update(user: User, course?: Course): Promise<LastPageInfo> }
TypeScript
복사
그리고 이를 구현한 구현체를 각각 만듭니다.
export class CourseStrategyToLastPageInfo implements StrategyToLastPageInfo { ...// } export class InstituteStrategyToLastPageInfo implements StrategyToLastPageInfo { ...// }
TypeScript
복사
그리고 strategy가 해주는 역할 외에, 앞뒤로 해줘야하는 공통 부분을 처리하는 updateLastPageInfo 라는 wrapper 클래스를 만듭니다.
export const updateLastPageInfo = async ( user: User, strategy: StrategyToLastPageInfo, course: Course, manager?: EntityManager, ): Promise<User> => { // strategy에 필요한 param 만들어서 주기 const courseRepo = getCustomRepository(CourseRepository) const courseToUserRepo = getCustomRepository(CourseToUserRepository) const instituteMemberRepo = getCustomRepository(InstituteMemberRepository) const instituteRepo = getCustomRepository(InstituteRepository) const userRepo = getCustomRepository(UserRepository) strategy.courseRepo = courseRepo strategy.courseToUserRepo = courseToUserRepo strategy.instituteMemberRepo = instituteMemberRepo strategy.instituteRepo = instituteRepo strategy.userRepo = userRepo //Delegation const updatedLastPageInfo = await strategy.update(user, course) // user에 lastPageInfo 업데이트 if (updatedLastPageInfo) { await userRepo.update(user.id, { lastPageInfo: updatedLastPageInfo, }) } user = await userRepo.findOne({ id: user.id }) return user }
TypeScript
복사

Result

해당 작업을 통해 updateLastPageInfo를 호출하면 복잡한 if-else 문으로 빠뜨릴 필요 없이 적절한 값으로 lastPageInfo를 호출할 수 있습니다.
또한 어느 로직에서든 다음과 같은 형식으로 1) user와 공간에 대한 값을 입력 2) 업데이트해줘야하는 맥락을 strategy로 제공하면 간편하게 업데이트가 가능합니다.
await updateLastPageInfo(user, new CourseStrategyToLastPageInfo(), course, manager)
TypeScript
복사