2021.09.08

이짜젠·2021년 9월 8일
0

온보딩 스터디 1주차

인턴분들 및 프론트엔드개발자로 전향하시는 퍼블리셔분들을 위한 팀 내 온보딩 스터디를 진행중이다.
내용은 회사의 페이지하나를 클론코딩해보는것이다.

나는 이미 프론트엔드개발자이긴하지만, 그래도 평소 기초에대한 부족함을 많이 느꼈기에 참여한다고 했다.
그리고 서로의 코드를 리뷰하고 토론해보는시간도 많은 의미가 있을거라고 생각을 했다.


작업순서

SPA는 크게 구조를

  • 앱의 페이지 구성을 위한 라우터 구조
  • 앱의 화면구성을 위한 컴포넌트 구조
  • 앱의 상태관리를 위한 스토어(Redux or Vuex) 구조

3가지로 나눠서 구현을 하고, 이 모두를 아우르는 프로젝트를 스캐폴딩하는것이 프로젝트 구조잡기의 마무리라고 생각했다.


라우터 구조

웹 애플리케이션의 논리적인 흐름, 뼈대를 잡는 작업으로 가장 중요하다.

같은 맥락으로 웹 애플리케이션을 분석할 땐, 라우터 기준으로 분석하면 편하다.

설계문서를 기반으로 페이지를 나누고, url들을 다음으로 정했다.

  • 홈 - /brand/{brandName}/home
  • 판매자 추천 - /brand/{brandName}/recommendation/
  • 전체 - /brand/{brandName}/products
  • 카테고리 - /brand/{brandName}/category?categoryId={categoryId}
  • 검색 - /brand/{brandName}/search?keyword={keyword}

이제 여기에 맞춰서 라우터구조를 잡으면된다.

방법1. 독립적으로 구성

  • 판매자추천
  • 전체상품
  • 카테고리
  • 검색

방법2. url depth 맞춰 분류

url은 기본적으로 /brand/{brandName} 으로 시작하고 뒤에 path가 달라진다.

따라서 아래와 같은 계층으로 나눌 수 있다.

  • 상품목록
    • 전체상품
    • 판매자 추천
    • 카테고리
    • 검색

방법3. 페이지 모양별로 분류

모든 페이지가 공통의 헤더를 갖고있다는 UI적인 공통점이 있다.

따라서 기준은 다르지만 결과는 방법2와 동일하다.

  • 상품목록
    • 전체상품
    • 판매자 추천
    • 카테고리
    • 검색

결정장애가 있는 나는 이런 사소한 것 하나하나 고민이 많이된다.

이럴땐 일단 최대한 현재 상황에 맞춰서 구현을 해보고, 구현한 후 확장성을 고려해서 바꾸면 된다.

모든 조그맣게 시작해서 커지는거다. 처음부터 모든상황을 예측할 순 없다.

방법1은 너무 중복이 많다.

  • 모든 path에 /brand/{brandName} 이라는 path를 붙여야한다.
  • 당장의 구현에는 신경쓸게없어 좋을 수 있으나, 프로그래밍적으로, 그리고 확장성이 없다.

방법3은 너무 구현에 편리성에만 치우쳐있다.

  • UI만 보고 개발자가 판단하기때문에 주관적이고 일관성이 부족하다.
  • 예를들어 홈 페이지의 구성이 다를경우 같은 format의 url임에도 홈만 밖으로 빠져버리는 경우가 발생한다.

방법2가 적당해보였다.

  • url 형태라는 분류의 기준도 명확하다.
  • url의 depth에 따라서 계층구조도 맞춰주면 된다.
    (어차피 Vue의 경우 childeren 으로 라우팅을 구성할경우 <router-view>를 중첩시켜야해서 컴포넌트적으로 계층구조를 가져갈 수 밖에 없다.)
  • ui가 비슷할경우 root path page의 component에서 어느정도의 공통 레이아웃도 구성이 가능하다.

컴포넌트 구조

atomic 디자인 패턴을 사용할 것이다.

컴포넌트를 가장 작은 원자단위부터 쪼개고, 이들을 조합하여 페이지를 구성한다.

어느정도 주관이섞인 기준을 잡아봤다.

  • 원자
    • 더 이상 쪼갤 수 없는 단위.
    • 순수하게 presentational 해야한다.
    • 노출되는 정보와 액션에 대한 정보는 모두 부모로부터 제공받는다.
    • 상태값을 갖지 않는다. 상태값조차 분자로부터 내려받는다.
    • 재사용이되거나, 재사용이 될 확률이 높을경우 분리한다.
    • 한가지 역할만하는 시각적으로 하나인 UI 덩어리
  • 분자
    • 원자들의 집합 또는 (원자컴포넌트 + 부가적인 마크업)
    • 순수하게 presentational 해야한다.
    • 간단한 상태값을 가질 수 있다. (ex. input의 value값)
    • 이벤트에 대한 처리는 모두 부모로부터 제공받는다.
    • 가급적 많은 곳에서 재사용되도록 구성
    • 한가지 일만 해야함
  • 유기체
    • (분자들 | 분자들 + 원자들) + 부가적인 마크업으로 구성한다.
    • 분자들의 집합
      집합이아닌 하나의 분자형태 그대로를 사용할 수 있다.
      (인터렉션과 관련된 내용만 붙여서, dispatch 등)
    • 활동하는 생명체로 상태값을 가질 수 있다.
    • 애플리케이션의 상태관리가 이루어진다.
      • redux, mobex, vuex와 같은 상태관리 라이브러리와의 연동
    • 외부로 노출될 필요없는 모든 액션, 이벤트들은 내부적으로 처리
      외부로 노출되어야 하는 액션: api call과 같은 비동기작업, dispatch 스토어 액션작업
    • 사용자에게 의미있는 정보를 제공 (인터렉션 가능)
    • 재사용성이 별로 없음
  • 템플릿
    • 유기체들 + 부가적인 마크업으로 구성한다.
    • 유기체들의 배치를 담당한다.
    • 아무런 로직을 갖지않는다. 내려받는 props조차 없다.
      (=순수한, presentational)
    • 레이아웃과 비슷한 개념으로 사용한다.
    • 단순 틀만 제공한다.
    • 와이어 프레임
    • 재사용이 가능하다.
  • 페이지
    • 실제 콘텐츠가 배치된 UI의 모습을 보여준다.
    • 대부분의 비동기작업을 이곳에서 처리한다.
      • 사전 초기 데이터 load
      • 유기체의 액션에 의한 action dispatch
    • 하나의 url이 하나의 page가 된다.
      라우트 path와 1:1로 매핑이된다.
      (1:N도 가능하지만 지양하자, redirect 처리를 하는게 낫다.)
    • routes가 계층적일경우 routes 구조에 맞춰서 계층구조로 가져간다.
      (앞서도 말했지만 어차피 를 중첩시켜야 하기 때문에, 계층구조로 가져가는게 편하다.)
    • 사이드 이펙트가 발생할 수 있다.
      즉, 외부의 영향을 받는다. (ex. 네트워크와 관련된 작업)

스토어 구조

스토어의 목적은 애플리케이션의 전역 상태값을 관리/저장하기 위함이다.

내가 생각하는 상태값이라 함은

  • UI: ui 와 관련된 상태값
    • popup, modal 상태
    • 토글의 상태 (여러컴포넌트에서 변경할 수 있는 UI)
    • 기타 등등..
  • DATA: 페이지에서 노출시킬 데이터

로 크게 나눌 수 있다고 본다.

이를 참고로 스토어를 모듈로 나눌 때, 다음방법들이 생각났다.

방법1. 상태의 종류로 나눈다.

  • ui
    • 전역
    • 전체상품
    • 판매자 추천
    • 카테고리
    • 검색
  • data
    • 전역
    • 전체상품
    • 판매자 추천
    • 카테고리
    • 검색

방법2. 페이지별로 나눈다.

  • 전역
    • ui
    • data
  • 전체상품
    • ui
    • data
  • 판매자 추천
    • ui
    • data
  • 카테고리
    • ui
    • data
  • 검색
    • ui
    • data
    • ui
    • data

방법1은 하나의 페이지에서 ui, data 2개의 스토어모듈을 가져다 써야한다는 불편함이 있다.

ui는 저장하는 데이터가 크지도않을텐데 별도의 모듈로 분리하는건 낭비같았다.

그래서 방법2로 정했다.

웹 애플리케이션은 한번에 하나의 페이지만 노출이 가능하다. 

따라서 어떻게보면 현재 노출페이지 상태 = 앱의 상태라고 볼수도 있다.

이러한 맥락에서 페이지단위로 모듈을 나누는게 좋아보였다.
(물론 페이지간의 통신이나, 앱 자체의 전역상태값이 있을수도 있다. 그래서 최상단에 전역상태를 두기로했다.)

결국 스토어의 구조도 routes 구조와 동일하게 가져가는게 용이했다.

페이지 스토어의 하위모듈로 ui, data를 따로 분리할까 고민도 했다.

그러나 ui 상태값의 양이 그렇게 많을 것 같진 않아서 하나의 스토어에서 같이 저장/관리하기로 정했다.


제공받은 스캐폴딩의 수정

  • api를 common 밖으로 뺐다
    common이라는 디렉토리를 두기엔 root에서 common에 해당하는 것들도 많고, 분류가 애매하다고 느꼈다.
  • views 를 page 로 바꾸고 component 파일내부로 이동
  • routes 와 router 구성의 분리
    • router - 뷰 라우터 객체와 관련된 환경설정
    • routes - 순수 path와 관련된 계층데이터를 저장

궁금한 점

라우터

  • 검색페이지의 url을 다른페이지처럼 /store/brand/{brandUrl} 로 시작하지 않은 이유가 있는지?

  • url 을 카멜케이스로 구성하면 안좋은점이 있는지?

  • url 단어선택시 단수형, 복수형 중 선호하는 타입은? 그리고 이유는?

  • url depth 와 router depth를 맞추는지?

    • ex) a/b

      rotues = [
      	{
      		path: '/a'
      		childeren: [
      			{ path: 'b' }
      		]
      	}
      ]

스토어

  • 모듈을 나누는 기준

    • 도메인 기준 (데이터의 주제)
      • 패이지로 나눌 경우 UI와 관련된 상태값은 따로 별도의 UI 상태모듈을 구성?
    • 페이지 기준
      • 상품리스트 패아자의 경우 대부분의 데이터가 비슷한데,, 중복을 허용하더라도 각각 별도로 구성? (확장성을 위해)

리뷰내용

  • 지훈님
    • commit, dispatch 타입스크립트 라이브러리쓰면 깔끔해짐
    • 레이어 컴포넌트 위치는 마크업에 맞춘다.
    • 스토어 또는 이벤트버스를 이용해서 팝업노출상태를 관리
  • 정규님
    • 컨벤션 맞추자
  • 명종
    • 리스너는 vue context 안에서 하기
      리스너를 따로달면 destroy 할때 일일이 제거해주어야된다.
profile
오늘 먹은 음식도 기억이 안납니다. 그래서 모든걸 기록합니다.

0개의 댓글