일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
- JS
- Router
- codestates
- css in js
- 객체지향
- WAI-ARIA
- 계산기
- OOP
- Prototype
- JavaScript
- 프로토타입
- html
- CDD
- cta button
- self reliance
- 프론트엔드
- 개발자
- css
- Javascript #코드스테이츠
- 원시자료형
- 호스트인식
- condestates
- 회고
- 참조자료형
- cta버튼
- frontend
- codestate
- 코드스테이츠
- 코드스테이스
- 자바스크립트
- Today
- Total
jh.nrtv
라우터 개선 (데이터 영역 != 표현영역) 본문
- 들어가며
프론트엔드 개발을 하면 정말 여러 데이터를 받고, 조작하여 화면에 표시한다.
이 과정에서 여러 성격의 데이터가 섞이는 경험을 할 수 있는데,
데이터의 목적과 성격이 정 반대인 경우에도 그것들을 혼용해서 사용하는 경우가 있다.
최근 사내 여러 프로젝트들에서 프론트엔드 라우터를 개선하는 작업이 많이 이루어졌다.
이 과정에서 팀원분들과 CTO님과 의견을 나누었고,
혼자서는 생각하지 못했을 여러 깨달음을 얻을 수 있었다.
그 과정에서 배운 것들을 공유하고자 한다.
- 상황
기술: vue-router
https://v3.router.vuejs.org/kr/guide/essentials/named-routes.html
우리 팀은 라우팅에서 vue-router를 활용하고 있다.
router은 기본적으로 아래와 같은 형태를 가지고 있는데
수 많은 라우터가 아래의 형태를 유지하며 배열에 추가된다.
여기서 가장 중요한 값은 name이다. name이 라우터를 식별하는 key역할을 하기 때문이다.
const router = new VueRouter({
routes: [
{
path: '/user/:userId',
name: 'user',
component: User
}
]
})
- 문제점 : 데이터 종류의 혼용 , 단일 책임 원칙 위배
우리의 기존 프로젝트는 예를 들자면 아래와 같은 형태를 사용하고 있었다.
vue-router가 고유한 route를 식별하기 위해서 존재하는 name값을 다른 목적( 화면에 표시될 페이지의 이름 )과 혼용해서 나타내는 것이 문제였다.
const router = new VueRouter({
routes: [
{
path: '/users',
name: '사용자 목록',
component: UserList
}
]
})
문제는 여기서 끝나는 것이 아니다. 우리 프로젝트에서는 i18n 을 통해서 이미 2개국어 서비스를 제공하고 있고, 몇 개월 이내 4개국어 이상의 서비스를 예정하고 있었다. 따라서 위의 name값이 그대로 사용되는 것이 아니라 다국어 를 처리하는 key로서 활용하는
다소 복잡한 구조를 이용하고 있었다.
// src/i18n/ja-JP/rouetrs.json
{...
"사용자 목록": "ユーザーリスト",
...}
논의 결과 위와같은 문제가발생한 가장 큰 원인은 예상컨데 아래와 같다.
TF 팀으로 시작한 팀이기에 빠른 개발이 중요했으며, 그 과정에서 아래의 데이터 구분을 명확하게 하지 못했다.
- 문제 1 : 데이터 종류의 혼용
데이터를 크게 두 종류로 보면 다음과 같다.
1. 데이터 영역 : 시스템의 데이터 관리나 비즈니스 로직에 중점을 두는 데이터
2. 표현 영역 : 화면에 표시되는 것에 중점을 두는 데이터
위 두가지는 엄연히 목적이 다르나, 혼용에서 사용하는 경우가 종종 있으며 실제 프로젝트에서도 그렇게 사용되고 있었다.
위의 예시에서 살펴보자면
기존 vue-router에서 제공하는 name은 '데이터 영역'의 데이터다.
물론 데이터 영역의 데이터라고 해서 시스템 식별만 집중해서 정해지지는 않는다.
name: 'aakidd19880' //본래목적(시스템의 식별을 위한 고유한 키)만을 충족
name: 'userList' // 본래 목적과 부가목적(인간 식별에 용이) 모두 충족
위의 예시에서 볼 수 있듯 변수명을 유니크하면서도 시멘틱하게 작성하는 이유는 코드는 시스템과 프로그래머 모두에게 긍정적인 효과를 줄 수 있기 때문이다.
하지만 우리는 name이른 요소를 의도된 원목적(데이터 영역)보다 표현영역에 더 집중해서 사용하고 있었다.
- 문제 2 : 단일 책임 원칙의 위배
객체지향 프로그래밍의 SOLID 원칙 중에
S 에 해당하는 SRP(단일 책임 원칙)에 따르면 하나의 클래스는 오직 하나의 기능이나 역할만을 담당해야 한다.
물론 우리 프로젝트에서는 객체지향 프로그래밍에 완전히 핏한 개발을 하고 있지는 않지만 해당 원칙을 적용해서 문제를 판단할 수는 있다.
현재 우리 구조는 사용자 인터페이스, 시스템 데이터 두 가지의 역할을 하나의 key인 'name'이 담당하고 있으므로 '복수책임'의 문제가 발생한다.
따라서 기존의 우리의 구조는 아래와 같은 잠재적 위험을 가지고 있다.
1. 현재의 형태는 프로그램을 작성하는 프로그래머에게도 혼동을 줄 수 있다.
2. 비즈니스 영역이 표현영역에 의존하고 있다는 것 자체가 오작동을 야기할 수 있는 큰 위험이다.
3. 변경 가능성이 낮은 쪽(데이터 영역)이 변경가능성이 높은 쪽(표현 영역)에 의존하고 있다.
문제점 식별은 완료했으나, 지금 개선할 것인가?
자, 위와 같은 과정을 통해서 문제점은 알겠는데
이를 지금 당장 개선할 것인가?
이것은 문제의 식별과는 별개의 문제이다.
현재 기능상의 문제가 발생한 것이 아닌, 잠재적 위험을 발견한 것이기에 비용 계산을 통해서 이를 당장 개선할 수도, 당분간 개선하지 않기로 결정할 수도 있다.
( 사실 팀 내에서도 위의 문제점을 식별한 지는 오래 되었지만 지금까지는 당장 개선하지 않기로 판단한 것 뿐이다! )
여기서의 가장 큰 '비용'은 프로그래머의 시간이다. 전체 라우터의 구조를 변경해야 하기에 코드 실수로 인한 오류도 발생할 수 있고, 코드 충돌 또한 발생할 수 있다. 이를 잘 고려해서 지금 개선할 것인지를 결정하는 것이 필요하다.
결론
결론적으로 우리는 다음과 같이 프로젝트의 전체 라우터를 수정했다.
1. router의 name은 라우터를 식별하는 역할로만 작동하도록 수정
2. 표현영역 담당하는 키는 아예 별개로 빼서 역할하도록 했다.
느낀 점
1. 데이터를 다룰 때 '이 데이터의 본래 목적이 뭐지?'에 대해서 한 번 더 생각해보게 되었다.
2. 코드에 책임을 부여할 때 '복수책임'인지 혹은 '책임이 상충되지 않는지'에 대해서 재고해보게 되었다.