4 Weeks Project Diary
#Sprint2 - Day 4.
Javascript를 배우고 있습니다.
현재는 길고양이들을 돌보는 모바일 앱을 제작하는 4주 프로젝트 중입니다.
1. Sprint2
1. 목표(40%) vs 달성(25%)
- 이번 4주 프로젝트는 총 5개의 스프린트로 구성하였다. 첫 번째 스프린트는 기획과 구조 설계, 새로운 스택 학습에 시간이 많이 필요할 듯 하여 5일을 잡았고, 다른 스프린트들은 워킹데이 기준으로 4일씩 구성하였다.(물론 주말이 껴있는 스프린트도 있지만...)
- 2번째 스프린트의 목표는 기본 기능으로 기획했던 mvp를 100%으로 보았을 때 40% 가량을 구현하는 것이었다. 스프린트를 마치며 팀원들과 의견을 나누어보니 달성도는 mvp 100% 기준으로 25%이 달성인 것 같다.
- 25% 달성 중에서도 서버 단의 데이터 스키마 작성, 데이터베이스 작성, api 라우터 작성이 대부분이고 내가 맡은 프런트엔드는 정말 진도가 느렸다. React와 비슷하게 생겼지만 하나 하나 실행환경이 다른 React Native 때문에 적잖이 당황했던 스프린트였다.
2. To-do와 회고
1. to-do: 프로젝트 기본 설정
1. 린트와 프리티어
- 드디어 긴 긴 구조 기획과 학습을 마치고 레포지토리를 열었다.
- 린트 설정은 이번에도 air-bnb였는데, 리액트와 같은 줄 알았더니 리액트 네이티브는 플러그인과 바벨을 깔아서 설정하는 점들이 달랐다. 대부분의 블로깅들이 리액트 기반으로 설명을 하다 보니 package.json에서 린트 설정과 룰을 적용하는 것들이 대부분이었는데, 우리는 이번에 .eslintrc.json에서 플러그인 설정과 룰 설정을 하였다. 프리티어 또한 lint 룰과 부딪히지 않도록 설정하였다.
- vs code에 보이는 코드 구조가 리액트와 너무 비슷하다고 생각하여 당연히 설정도 비슷할 거라 생각했는데 그렇지 않았다. 리액트 네이티브는 사용자가 "리액트처럼" 다룰 수 있는 것이지, 리액트는 아니다. 바벨로 컴파일 하기 위한 설정들이 달랐다.
2. mobx babel 셋팅
- 지난 스프린트에서 학습한 mobx를 프로젝트 구조에 안착시키기 위해서 mobx babel 셋팅에 들어갔다. 그리고 온갖 에러와 추측성 reference 사이에서 반나절 이상을 혼돈으로 보냈다.
- 결론부터 말하자면, mobx에서 사용할 수 있는 decorator(@), 정적 클래스 형성 방법들을 다루는 바벨들에서 에러가 발생했었고, 몇 몇 필요 없는 패키지들을 지우고 vscode의 lint 규칙을 고치고 나서야 앱 초기 가동이 가능했고, 코드 상에서도 에러 인식 없이 정상 작동을 했다.
- 우리는 애초에 mobx를 시작할 때 observable이나 action 등 앞에 줄임말처럼 쓸 수 있는 데코레이터(@)를 사용하지 않고 기본 모델인 decorate 함수를 사용할 계획이었다. 이유는 나중에 누가 코드를 보더라도 '@, 이건 뭐지?'하고 의아해하지 않고, '아! class로 store를 구현했구나. 그리고 mobx로 decorate을 했구나.' 하고 깨닫게 할 수 있도록 하기 위해서였다. class 자체를 집중해서 볼 수 있도록...
- 어쨌거나 그런 이유에서 우리는 decorate나 static class 등에 필요한 바벨은 필요가 없었고, 하루 종일 시뮬레이터의 빨간 화면을 마주한 후에 계속 충돌을 일으키는 바벨 셋팅을 과감히 지워버리고 환경 설정을 완료할 수 있었다.
- 나를 혼돈으로 이끈 @babel/plugin-proposal-class-properties 페이스북 버그 신고 커뮤니티나 스택오버플로우를 봐도 이 플러그인 자체적으로 버그가 있다는 사람이 너무 많았다... ㅜ
2. to-do: 프로젝트 큰 틀 작성
1. React navigation을 이용한 구조 완성
- 지난 스프린트에서 개념을 익혔던 navigation 구조도 완성하였다.
- '스택 안에 스택을 쌓는다'는 개념을 코드로 구현했을 때쯤 마주한 문제는, nested stack의 화면에서는 header 부분이 계속 넓어진다는 것이었다.
- 이런 식으로 회색으로 처리된 헤더 부분이 계속 불필요한 공간을 차지했다
- 문제 해결을 위해서 react navigation 공식 문서와 스택오버플로우 등을 참고해서 navigatio option이라는 부분을 적용해 header를 감추는 방향으로 진행을 했다. header를 감추게 되면 back button이 같이 지워질 수 있으므로 일부는 하단의 tab navigation으로 이 문제를 해결했고, 스크린의 특성에 따라 modal 창으로 변경한 후 임의로 customized back button을 좌측 상단에 심기도 했다.
- 우리 프로젝트에서 사용한 mobx와 navigation 구조
2. Mobx stores 작성
- 바벨 설정에 한참 힘을 쓴 후 바로 mobx store 작성에 들어갔다.
- store는 velopert님의 mobx 학습 블로깅에서 나온 예시와 비슷하게 구성했다.
- Root store > 2개의 store 구성(cat, store)
- 그런 다음 observable과 action을 정의했다. observable은 리액트에서 state와 같은 개념인데 한 store 안에 몰아 넣다 보니 엄청나게 많은 state들이 모인 격이 되었다. 그대로 observable을 관리하기 힘들 것 같아서 관련된 내용들을 한 객체로 묶어서 2~3개 내지의 observable로 구성하였다.
import CatStore from './CatStore';
import UserStore from './UserStore';
class RootStore {
constructor() {
this.cat = new CatStore(this);
this.user = new UserStore(this);
}
}
export default RootStore;
const defaultCredential = { withCredentials: true };
class CatStore {
constructor(root) {
this.root = root;
}
spot = {
followCatNum: 0,
list: null,
selectedSpot: null,
};
addCatBio = {
location: { latitude: 0, longitude: 0 },
photoPath: null,
nickname: '',
description: '',
species: '',
gag: '',
cutClicked: { Y: false, N: false, unknown: false },
catCut: { Y: 0, N: 0, unknown: 0 },
};
생략....
action 함수들 구성
생략 ....
}
decorate(CatStore, {
spot: observable,
addCatBio: observable,
catInfo: observable,
getMapInfo: action,
getSelectedSpotInfo: action,
getSelectedCatInfo: action,
... 생략
})
export default Catstore;
- 컨벤션을 찾기 힘들어서 임의로 구성한 구조인데,
장점은 observable이 적어졌기 때문에 하단에 decorate에서 observable로 정의할 것들이 적고 시각적으로 유사 필드를 묶었다는 것이다.
단점은 각 컴포넌트에서 세부내용을 불러올 때 this.cat.addCatBio.nickName처럼 객체 깊숙이 있는 객체를 불러오기 때문에 타이포가 발생할 경우 찾기가 힘들고, 변수 사용을 위해 destructuring도 복잡한 점이 있겠다.
3. UI 작성: 기본 인증, 길고양이 등록 UI
- 위의 작업을 다 하고 나서야, 계획했던 UI 작성에 들어갔다. 실전으로 RN 코드를 작성해보는 것이었는데, 바벨 설정이나 실행환경이 리액트와 달라 고생한 것에 비해 코드 작성 자체는 RN에서 사용하는
<TouchbleOpacity>
나 <View>, <Text>, <Image>
등이 이미 많은 기능을 내포하고 있는 뷰들이라서 만족스러웠다.
- 구현 환경이 각 사람들의 모바일 기기이기 때문에 flex 기반으로 레이아웃이 짜이고 max length 같은 개념들이 각 기기에 따라 명확해서 좋기도 했고, 또 안 좋기도 했다. 좋았던 점은 css layout 부분이 웹에 비해 절제되어 있다는 점이었고 안 좋은 점은 그렇다 하더라도 기기별로 상황이 너무 달라서 안드로이드, 아이폰... 아이폰 중에서도 8과 11의 차이 등으로 미세하게 view가 틀어지는 점들이 그러했다.
- 가장 처음 구현한 것은 회원가입, 로그인 화면이었다. RN은 코드 상 문제가 있을 때 컴파일링 단계에서부터 에러가 나기 때문에 에러 메시지를 자세히 보지 않으면 혹은 자세히 보더라도 어느 부분에서 에러가 났는지 캐치하는 것이 쉽지 않았다. 코드 작성 5분과 에러 처리 1시간이 오가는 괴로운 시간이었다.
- 에러 처리는 정말 한 땀 한 땀이었다. mobx 값을 못 불러오거나, arrow function이 아닌 함수에서 this 설정을 잘못 읽어오거나... 지금 정리해보니 너무 당연한 것들인데 저 빨간 화면을 마주하는 순간에는 머리가 아득해졌다.
- 가장 먼저는 Input을 마련하고 mobx의 observable에 onChange 할 때마다 값을 주고 받을 수 있는지부터 구현했다. 리액트에선 너무 당연했던 것이... 리액트 네이티브와 처음 써 보는 상태관리 라이브러리 때문에 다시 걸음마 단계로 돌아갔었다. 그런 다음 하나씩 화면 구성을 시작했다.
- 지난번 프로젝트에서는 웹 UI 구성에서 ant design의 도움을 많이 받아 회원가입이나 로그인에 필요한 메소드들이 이미 구현된 컴포넌트들을 받아서 왔는데, RN은 그런 것들이 많이 없는 것 같아 손수 validation 함수를 짰다. 어딘가에는 이런 컴포넌트가 있을 것 같은데 내가 못 찾는 것 같기도 하다...
- 아무튼 그렇게 조금씩 화면이 구성되고 expo앱을 통해 다룰 수 있게 되니 성취감이 매우 컸다. 내가 들고 다니는 폰에서 결과물들을 본다는 점에서 웹 시연보다 더 성취감이 큰 것 같다.
3. 회고
- 어려움을 느꼈던 부분들
- 4일 간의 스프린트 내내 에러와 마주한 순간이 너무 많았다. 그리고 에러의 원인을 찾기 힘든 경우가 너무 많았다. 간신히 에러의 이유를 찾아내고 리액트에 비해 리액트 네이티브의 공식문서를 통해 해결 할 수 있는 것들이 적었다. 스택오버플로우 같은 개발자 커뮤니티 내에도 해결 방법은
이렇게 하면 된다
보다 나는 이렇게 했더니 문제가 풀렸다. 그런데 확실한지는 모르겠다
식의 답변이 많다 보니 여러 방법을 시도해보는데 너무 많은 시간이 들었다.
- 당연히 계획한 것을 수행하는 시간보다 디버깅 시간이 x2, x3배 잡아 먹어 기운도 많이 빠지고 갈 길이 먼데 에러 때문에 정체되는 느낌이 많이 들었다.
- 극복을 위한 노력들
- 스택오버플로우를 정말 많이 찾아 보았다.
- 스택오버플로우도 정답을 담고 있는 것은 아닌지라 해결이 되지 않으면 거기서 나온 키워드를 중심으로 다시 공식문서에서 검색을 진행했다. 공식문서에서 단서가 나오면 또 다시 그 키워드를 중심으로 스택오버플로우나 페이스북 버그 신고 커뮤니티를 찾았다.
- 이렇게 키워드 파도타기를 하면서 내게 맞는 에러 해결 방법을 찾으려고 노력했다.
- 배움
- 초반에도 언급했지만 웹과 모바일의 실행 환경은 너무나도 다르다. 단순히 컴파일링을 떠나서도 모바일 기기에서의 사용자 특성이나 섬세한 설정의 문제들은 결코 만만하게 볼 수 없는 것들이다. 그래서 네이티브로 앱을 개발하는구나 싶다.
- 그럼에도 자바스크립트만으로 (바벨의 도움을 엄청 받아야 하지만) 안드로이드와 ios 모바일 앱 개발이 가능하다는 것은 엄청난 기회이자 자바스크립트 개발자에게 주어진 혜택인 것 같다. 만약 빠르게 검증해보고 싶은 모바일 환경 기반 mvp가 있다면 리액트 네이티브를 사용할 것이다.
- 다음 스프린트 계획
- 주말 포함 5일 진행 예정인 다음 스프린트에서는 이번 스프린트에서 만든 길고양이 등록 화면을 보완하고, 서비스의 핵심인 고양이 정보와 커뮤니티 화면 구현을 할 것이다.
- 그 외에도 프런트에서는 동료가 구현한 google map 화면과 통합, 서버와의 토큰 인증 등의 굵직굵직한 계획이 잡혀있다.