4. 1. Place-Site란?
PDP RDP 구매 핸들러 갤러리 캘린더
아래와 같은 화면을 제공하는 Frontend Server
그리고 이를 제공하기위해 많은일을 하고 있다 (하게될 것)
Place-Site란
?
• 야놀자 통합웹에서 PDP, RDP와 같은 야놀자의 핵심 OTA 상품인 숙박 상품(국내)과 관련된 Repositor
y
• 기존 통합웹에 포함되어있던 lagacy PDP, RDP 페이지를 NextPDP 프로젝트를 통해 새로운 Repository로 분리
• 현재 PDP, RDP 단 2개의 페이지로 구성 (추후 PLP 등등 숙박과 관련된 페이지도 올 수 있다고 생각
)
• 그 외는 전부 모달 혹은 바텀시트
• 현재 네이티브앱 구현을 하지 않고 웹뷰로만 제공된다
• 이는 기존 PDP, RDP와 다르고 기존 야놀자의 방향과 다름.
• 추후에 네이티브 구현계획있으나 확정되지 않음
.
• 점점 프론트영역이 웹 프론트엔드로 넘어오고있지않나 생각합니다.
6. 2. Next-PDP?
• RatePlan 노출
• SuperSet Data 출력-> 기존 Text 로 출력되던걸 데이터화 하여 출력
• + UI/UX 개선 (만차정보 개선, ctx, tab구조 등등
)
• 통합웹에서 사용중이던 Joy API 대신 Stay API라는 새로운 BFF(Backend For Frontend) API도 함께 구현
• 여기서 SuperSet, RatePlan Dat
a
• SuperSet이란
?
• 야놀자가 나가야 할 비지니스 확장성을 고려하여, 각 단위별로 갖추어야 할 숙소정보 풀 스펙을 의미
• 그동안 숙소설명등에 text로 작성하던 정보를 메타화해 관리하도록 확장
지금 Place-Site를 만들고 있는 프로젝트
주 목적
7. • SuperSet이란
?
• 야놀자가 나가야 할 비지니스 확장성을 고려하여, 각 단위별로 갖추어야 할 숙소정보 풀 스펙을 의미
• 그동안 숙소설명등에 text로 작성하던 정보를 메타화해 관리하도록 확장
2. Next-PDP?
8. • RatePlan이란
?
• 요금제는 객실을 판매하기 위한 다양한 판매전략을 요금 구성을 비롯한 각종 제한 및 추가 사항들로 설계된 집합
• 공통 조건을 가진 룸타입의 총 재고를 각 개성을 갖춘 복수의 요금제로 구성이 가능
• 모든 객실 타입에는 적어도 하나의 요금제가 있어야 함
2. Next-PDP?
RoomType 1 : N
1 : N
Place
(Property)
RatePlan
RoomType
1 : N
Place
(Property)
9. • StayAPI
?
• PDP / RDP만을 위한 BFF(Backend For Frontend) AP
I
• RatePlan과 SuperSet 등 새롭게 노출되고 정제되어야 하는 국내 숙박 데이터를 제공
• Java로 작성되었다 (Spring Framework
)
• Stay API는 아래와 같은 API를 Mashup해준다
.
• SuperSet API (Product Property API) - 숙소, 객실 정보의 (SuperSet
)
• RatePlan API - rateplan (가격, 캘린더 등
)
• Product Con
fi
g API - 계약에 의해 만들어지는 제어정보 (Badge, 프로모션 정보 등등
)
• Location API - 위치정보
• Review API - 리뷰
• Coupon API - 쿠폰
• Patner API - 판매자 정보
• 상품추천 API - 상품 추천 정보
• 회원-찜하기 API - 찜하기
2. Next-PDP?
10. 3. Place-Site 설계
• Monolithic 구조의 문제
• 특히 빌드 리빌드 시간이...ㅠㅠ
• next도 구버전인데 빌드해야 될 양은 많고
…
• 끝도없이 뻗어나가는 page
기존 통합웹에서의 문제, 불편했던 점 (개인적인 경험도 포함)
11. 3. Place-Site 설계
기존 통합웹에서의 문제, 불편했던 점 (개인적인 경험도 포함)
• 낮은 next 버전 (v9.5.5
)
• getInitialProp
s
• customServe
r
• hot-loader가 없다? → nodemon으로 재실행 (넘 느려)
• routing을 직접 구현
• 직접 커스텀 할 수 있는건 좋은데 매번 nextRoute.ts에 작업하기 번거롭고 트래킹하기 힘들다ㅠ
• 현재 next에서 기본으로 제공해주는 좋은 기능을 이용하지 못함
• next routin
g
• dynami
c
• api route
• Fast Refresh (hot-loader)
• next/image
• next/link
• next1
2
• next 컴파일러가 Rust기반의 SWC로 작동 (vercel 피셜 빌드는 5배, fast refresh(hot-loader?) 는 3배 빨라졌다고 한다)
• SWC: babel, tsc(typescript compiler)를 rust로 포팅
• 추후 css compiler도 포함될 예정
• tsc는 go로 전환예정?
• next v9.5.5는 2020년 10월 10일에 배포
• 약 1년 하고도 반년이 지났다
• 급변하는 프론트 생태계에서 눈에 안보이게 많이 바뀌었을 것 (애러핸들링, 최적화 등등)
12. 3. Place-Site 설계
기존 통합웹에서의 문제, 불편했던 점 (개인적인 경험도 포함)
• Custom Server, Dynamic Router를 직접 구현
• Custom Server는 Express 보일러 플레이트를 따라가야되고, 익숙하지 않으면 힘들다
• 복잡하고 어려운 추상화
• Requester? Action? Builder?
13. 3. Place-Site 설계
기존 통합웹에서의 문제, 불편했던 점 (개인적인 경험도 포함)
• API Validation, Serializatio
n
• schemagen? 번거롭..
.
• 어차피 input값만 validation하는데 그럴거면 joy나 zod같은게 낫지 않을까
?
• Serializer 구현
• BFF가 맞나...
?
• monad 한줌
• 위 코드가 가장 사용이 잘 된 케이스
• 왜 사용되는지 이해한다면 매우 좋은 코드 (railway
)
• 하지만 여기서 크게 벗어나지 않는다.
14. 3. Place-Site 설계
기존 통합웹에서의 문제, 불편했던 점 (개인적인 경험도 포함)
• 모든 상태를 MobX로 관리
• 개인적으로 useState를 활용한 local state도 적절히 사용해야된다고 생각하는데 그냥 모든 state를 MobX Store에 넣은 느낌
• 각 컴포넌트에서 사용하다보니 결합도가 너무 높아졌다
• mobX store가 많아서 불편
globalStore에 대한 Provider도 포함되어있음 (SunnyPage)
Src/pages/places/[place_no]/index.tsx
15. 3. Place-Site 설계
기존 통합웹에서의 문제, 불편했던 점 (개인적인 경험도 포함)
• 너무 많은 코드베이스, 폴더, 파일
• 새로 무언가를 하려고하면 신경쓸 것도 많고 해야할게 많다
• SunnyPage? 페이지별 GetInitialProps
?
• 트래킹 어렵다고 생각. 중복코드 발생.
sunnyPage의 getInitialProps
Place/[place_no] 의 getInitialProps
16. 3. Place-Site 설계
기존 통합웹에서의 문제, 불편했던 점 (개인적인 경험도 포함)
• 분산되어져있는 관심사
• 필요한 파일을 파악하고 찾기가 어려움
• Express 디자인 패턴을 그대로 따라가는게 과연 옳은것일까?
• 통합웹은 Backend API 서버가 아니다
• Joy는 과연 BFF인가? (너무 많은 일을 하는 Joy
)
• ywt verify 하는것도
?
• 타입제공도? (feat. SDM
)
• 데이터 스키마는 과연 프론트앤드를 위한 스키마일까
?
17. 3. Place-Site 설계
기존 통합웹에서의 문제, 불편했던 점 (개인적인 경험도 포함)
• 너무 많은 API를 관리
• 아무래도 Monolithic이기 때문에
• 여기에 API에 대한 보일러플레이트 작업이 많아요 ㅠ
• Model, Action, RequestBuilder, Router, Controller, Serializer, Schemage
n
• api 하나 생기면 x7의 작업
• css Modul
e
• 동적대응이 힘들다
• className 확인의 번거로움
• 모든 요청에 동일한 Middlewar
e
• Ex) API 요청에서는 굳이 channel을 체크할 필요 없음
• Page, API 요청이 아닌데도 모든 middleware를 탄다
18. 3. Place-Site 설계
개인적으로 Sunny를 평가하자면 생각해본다면
• 당시 환경에서는 너무나도 잘 만들었다
.
• 당시 기술환경을 생각해보자
• 내가 직접 추상화 해보려고하니 너무 어렵더라
• place-site를 만들면서 Sunny가 잘 만들어졌다고 생각하였음
• 그리고 시간이 지나면 place-site도 똑같아질거라 생각함
• 문제는 Monolithic구조 + 쌓여갔던 기술부채가 아니었을까…
?
• 크게 리스트럭처링이나 리팩토링을 한 흔적이 안보인다
• 초기 구축에서 개선되지 못하였다
.
• 가장 큰 예시는 기반 기술스택의 틀인 next, react의 버전
• 이는 리소스문제 등등 여러 요인이 있을 수 밖에 없음 ㅠ
• 때문에 기술부채 해결보다는 새로운 기술스택이 쌓여간 느낌
• 결론: 기술부채를 해결하자
• 그것이 바로 place-site
!
• 그리고 앞으로 만들어질 domain frontend server
19. 3. Place-Site 설계
Place-Site는 통합웹의 어떤 문제를 해결하려고 했나?
통합웹의 문제를 완벽히 해결했다고 볼 수 없다. 하지만 해결하려고 노력하였고 개선된 건 확실하다고 생각
Monolithic에서 벗어난 것만으로 상당수 많은 부분이 해결되었을 것이지만, 어떤 고민을 했는지 한번 알아보자
20. 3. Place-Site 설계
Place-Site는 통합웹의 어떤 문제를 해결하려고 했나?
가장 쉬운 기술부채 청산 = Version U
p
• React, Next 최신버전
• React v1
7
• Next v12
22. 3. Place-Site 설계
Place-Site는 통합웹의 어떤 문제를 해결하려고 했나?
구조를 단순화 하자
• Server 코드 분리
src폴더 내에서 server 관련 주요 코드는 다 server 폴더 안으로 (나머지 폴더는 Client)
프론트 컴포넌트 작업할 때에는 서버쪽을 안봐도 된다.
서버관련 소스들의 co-location
23. 3. Place-Site 설계
Place-Site는 통합웹의 어떤 문제를 해결하려고 했나?
구조를 단순화 하자
• Middleware 구조 단순화
• Page 에서만 사용되는 middlewar
e
• API 에서만 사용되는 middleware 구분
27. 3. Place-Site 설계
Place-Site는 통합웹의 어떤 문제를 해결하려고 했나?
place-site의 Middleware 작동방식
PageMiddleware 적용
_app의 getInitialProps
28. 3. Place-Site 설계
Place-Site는 통합웹의 어떤 문제를 해결하려고 했나?
place-site의 Middleware 작동방식
APIMiddleware 적용
Server/tRPCServer 에서 적용
이 tRPCServer가 연결되는 곳은 pages/[trpc].ts
29. 3. Place-Site 설계
Place-Site는 통합웹의 어떤 문제를 해결하려고 했나?
구조를 단순화 하자
• Proxy API 구조 단순화
• Route와 Endpoint의 co-locate
• Endpoint는 Express Controller와 같다
어떤 Route에서 어떤 Endpoint가 있는지 한눈에 확인가능
그리고 Endpoint에서는 무슨일을 하는지 바로 파악이 가능
30. 3. Place-Site 설계
Place-Site는 통합웹의 어떤 문제를 해결하려고 했나?
구조를 단순화 하자
• Proxy API 구조 단순화
그리고 Backend API의 경로를 tRPC Route 네이밍 패턴으로 가져왔다.
예로, [GET] stayAPI/properties/{propertyId}/detail
EndPoint 파일 이름 -> propertiesDetailGet
tRPC Query -> properties.detail.get
[POST] stayAPI/properties/{propertyId}/favorite
EndPoint 파일 이름 -> propertiesFavoritePost
tRPC Mutation. -> properties.favorites.post
Naming Pattern 보이시나요?
31. 3. Place-Site 설계
Place-Site는 통합웹의 어떤 문제를 해결하려고 했나?
구조를 단순화 하자
• Proxy API 구조 단순화
호출은 이렇게
이렇게 하니까 어떤 Backend API를 이용하는지 명확하게 알 수 있다
32. 3. Place-Site 설계
Place-Site는 통합웹의 어떤 문제를 해결하려고 했나?
구조를 단순화 하자
• Proxy API 구조 단순화
Endpoint는 어떻게 생겼나요?
Endpoint에서도 무슨일을 하는지
한 눈에 알 수 있다.
33. 3. Place-Site 설계
Place-Site는 통합웹의 어떤 문제를 해결하려고 했나?
그래서 결국... Backend API 호출할 것이 생긴다면,
tRPC Route를 설정하고 Endpoint만 만들면 끝
(Requester가 없다면 Requester를 만들면 됨. 근데 간단하다) -> BaseRequester 상속받고 Header 세팅하면 끝
34. 3. Place-Site 설계
Place-Site는 통합웹의 어떤 문제를 해결하려고 했나?
Server-side, Client-side의 호출도 tRPC를 이용할 것이기 때문에 너무 간편하다.
Server-side
(getServerSideProps)
Client-side
(React Functional Component)
36. 3. Place-Site 설계
Place-Site는 통합웹의 어떤 문제를 해결하려고 했나?
구조를 단순화 하자
• Atomic Design Pattern 사용
• 크기별 컴포넌트 구분
• 각 단위의 크기 구분이 애매한 부분이 있긴 있지만, 그래도 쓸만하다
.
• atmos < molecules < organisms < templates < page
s
• place-site에서는 더이상의 컴포넌트로 단위를 나눌 수 없으면 atoms로 본다 (ya-com에 존재하지 않는 것
)
• ex) Pictogram
37. 3. Place-Site 설계
Place-Site는 통합웹의 어떤 문제를 해결하려고 했나?
Famework(Next)의 기능을 최대한 활용해서 코드베이스를 줄이자
• Express Boilerplate가 없어짐
• route
r
• middlewar
e
• controller
• _middleware.ts
• API Router (별도 express 관련 코드가 없음)
• Next/images
• Next/Link
• 즉, 관리포인트가 줄었다
38. 3. Place-Site 설계
Place-Site는 통합웹의 어떤 문제를 해결하려고 했나?
서버데이터 상태, 클라이언트데이터 상태를 나누자
• 서버데이터 - tRPC(React-Query
)
• prop drillin
g
• 클라이언트데이터 - recoi
l
• recoil hooks
getServerSideProps에서
recoilState trpcState 나뉜다
recoilState -> Client State
trpcState -> Server State
저는 개인적으로
Server-State는 Prop Drilling하고
Client-State는 Component에 hooks로 꽂아쓰는게 좋은 것 같아요
Client State를 사용하고 싶으면 recoilState를 리턴하자
이유는 Sever State는 현재 프론트 서버 외부에서 얻는 데이터이지만,
Client State는 프론트 서버 내부에서 관리할 수 있어서 좋은 것 같아요
39. 3. Place-Site 설계
Place-Site는 통합웹의 어떤 문제를 해결하려고 했나?
서버데이터 상태, 클라이언트데이터 상태를 나누자
getServerSideProps에서 받은 데이터를
Client-State로 관리하고 싶다면
-> recoilState로
(recoilState를 사용하려면 withRecoilStore 필수)
api를 호출 한 Server-State는
-> trpcState로 degydrate
40. 3. Place-Site 설계
Place-Site는 통합웹의 어떤 문제를 해결하려고 했나?
서버데이터 상태, 클라이언트데이터 상태를 나누자
place-site에서는 recoilState, trpcState 둘 다 prop으로 받아서 Initialize 처리하지 않아도 된다!
-> 요게 place-site의 백미
알아서 다들 잘 들어가요 사용만 하세요
41. 3. Place-Site 설계
Place-Site는 통합웹의 어떤 문제를 해결하려고 했나?
서버데이터 상태, 클라이언트데이터 상태를 나누자
Prop으로 받아서 Initialize하는 과정없이 그냥 사용하면 돼요
기존의 MobX 스토어를 생성하고 초기값을 initialize 하는 과정이 없어졌어요
42. 3. Place-Site 설계
Place-Site는 통합웹의 어떤 문제를 해결하려고 했나?
서버데이터 상태, 클라이언트데이터 상태를 나누자
매직은 Recoil의 특성을 이용한 withRecoilStore라는 HOC을 만들었어요
43. 3. Place-Site 설계
Place-Site는 통합웹의 어떤 문제를 해결하려고 했나?
Stay라는 BFF를 적극 활용하자
place-site에서는 serialize하는 것을 최소화하려고 한다
// Backend Response API
export interface PropertyDetail {
basicInfo: {
propertyId: number;
name: string;
hideWeb: boolean;
vrUrl: string;
hotelStar?: PictogramComponents;
locationDescription: string;
statusMessage: string[];
sellerPhone: string;
representationPhoto: string;
};
badge: {
configBadges: BadgeComponents[];
propertyBadges: string[];
};
review: {
score: number;
scope: number;
reviewCount: number;
limitReviewCount: number;
reviewNotice: boolean;
replyCount: number;
limitReplyCount: number;
};
banner: {
benefitBanners: BannerComponents[];
contentsBanner: BannerComponents[];
plainBanners: BannerComponents[];
};
...
Endpoint의 Backend Response Schema를 바로 사용
왜?
-> Serialize 할 필요 없어서, Normalize 할 필요 없어서
44. 3. Place-Site 설계
Place-Site는 통합웹의 어떤 문제를 해결하려고 했나?
Backend API 호출은 하나의 관리포인트에서
• 하나의 API에 여러 RequestBuilder, Action, Controller는 이제 그만
• Stay API는 StayRequester만
!
• 나머지는 Endpoint에서!
45. 3. Place-Site 설계
Place-Site는 통합웹의 어떤 문제를 해결하려고 했나?
관심사를 표현하자
• 추상화된 클래스를 관심사에 맞게 생성 (추상화된 것을 관심사로
)
• place-site에서 추상화 된 것 → Logger, Requeste
r
• BaseLogger (Abstract Class)
• PageLogger (Page 요청에 대한 로그
)
• APILogger (Proxy API 요청에 대한 로그
)
• RequestLogger (Backend API 요청에 대한 로그)
• BaseRequester (Abstract Class)
• StayRequester. (Stay API 호출
)
• MemberRequester. (Member API 호출)
어떤 일이 어디서 사용되는지 정확히 알 수 있게!
• 어떤 로그가 어느시점에서 로깅되는지
• 어떤 API 호출이 어디서 일어나는지 ex)
• Page logging을 하는 곳? -> PageLogger를 찾으면 됨
• Member API를 호출하는 곳? -> MemberRequester를 찾으면 됨
앞으로 다양한 목적의 로그와 사용하는 다양한 API가 많아질 수록 좋을 것이라고 생각해요
46. 개인정보 마스킹을 하는 추상메서드
3. Place-Site 설계
Place-Site는 통합웹의 어떤 문제를 해결하려고 했나?
관심사를 표현하자
• 그리고 추상 클래스에서 각 관심사에 개별적으로 꼭 필요한 것들을 추상메서드로 만들자
BaseLogger (Abstract Class)
BaseRequester (Abstract Class)
이렇게 구현체에 선언만 해두면 끝!
.log 수행시 자동으로 수행해준다.
47. 3. Place-Site 설계
Place-Site는 통합웹의 어떤 문제를 해결하려고 했나?
Backend API Validation을 간편하게
Endpoint에서 Zod를 이용해서 input validation
48. 3. Place-Site 설계
Place-Site는 통합웹의 어떤 문제를 해결하려고 했나?
Backend API Validation을 간편하게
tRPC로 input이 type 추론된다
.
심지어 response도!
49. 3. Place-Site 설계
Place-Site는 통합웹의 어떤 문제를 해결하려고 했나?
Backend API Validation을 간편하게
개발 편의성 진짜
…
tRPC 짱짱맨
이게 현재 어떤 query가 있고
,
어떤 Mutation이 있는지 파악가능하고,
route도 grouping이 되어있어서
찾기도 쉬움.
52. 3. Place-Site 설계
Place-Site는 통합웹의 어떤 문제를 해결하려고 했나?
부족한 문서화 보완으로 JsDOC을 적극 활용했다
개발 문서가 필요없어도 이해하고 온보딩이 가능해야된다고 생각
추상화가 된 부분이나 복잡한 함수는 JsDoc으로 친절히 설명해두었다
+ Snippet을 사용해보자
typescript react(.tsx
)
• $F
C
• $FC:Storyboo
k
• $PAGE:SS
R
typescript(.ts
)
• $Store:Templat
e
• $Store:Ato
m
• $Store:Selecto
r
• $API:EndPoint_Quer
y
• $API:EndPoint_mutatio
n
• $Requeste
r
• $Middleware
53. 3. Place-Site 설계
Snippet에 관하여
Snippet 한번 보고가세요
▪ 잘 활용하면 개발 생산성을 끌어올리고, 코드 일관성 및 컨벤션을 확립할 수 있을 것
▪ 코드 이해하기가 쉬워질 것
ex)