→ 우리의 프로젝트는 미국을 향해 출시할 배달 주문 서비스**입니다.
새롭게 개발하는 앱으로 올해 하반기 9-10월 출시를 목표로 가고 있으며, 현재는 IOS와 안드로이드 모두 출시하는 것을 고려하고 있습니다.
우리 프로젝트에서 중요한 점들이 여러가지가 있겠지만, 저는 그 중에서 서비스 출시
,개발 리소스
,서비스 개선
3가지 키워드를 뽑았습니다.
→ React Native
는
크로스 플랫폼 모바일 애플리케이션을 구축하는 데 널리 사용되는 프레임워크로,
많은 회사에서 성공적인 앱을 구축하는 데 사용되었습니다.
다음은 React Native를 사용하여 앱을 구축한 기업의 몇 가지 예입니다:
- Facebook: React Native를 만든 회사인 Facebook은 Facebook, Instagram, Messenger 등 자체 모바일 앱에서 광범위하게 사용하고 있습니다.
- UberEATS: Uber의 음식 배달 서비스인 UberEATS는 사용자가 지역 레스토랑에서 음식을 주문할 수 있는 모바일 앱을 구축하는 데 React Native를 사용했습니다.
- Airbnb: 인기 있는 휴가 렌탈 플랫폼인 Airbnb는 사용자가 전 세계의 숙소를 검색하고 예약할 수 있는 모바일 앱을 구축하는 데 React Native를 사용했습니다.
- Tesla: 전기 자동차 제조업체인 Tesla는 Tesla 차량을 제어하고 모니터링하기 위한 모바일 앱을 구축하는 데 React Native를 사용했습니다.
- Skype: 영상 및 음성 커뮤니케이션 플랫폼인 Skype는 모바일 앱을 처음부터 재구축하는 데 React Native를 사용하여 사용자 경험이 개선된 더 빠르고 안정적인 앱을 만들었습니다.
이는 React Native를 사용하여 성공적인 앱을 구축한 많은 기업 중 몇 가지 예에 불과합니다. 이 프레임워크의 인기와 유연성 덕분에 전 세계 많은 모바일 앱 개발자가 이 프레임워크를 선택하고 있습니다.
→ 옳소앱의 경우, 현재 Android와 iOS 앱을 동시에 출시하는 것을 목표로 하고 있습니다. 그렇기에 리액트 네이티브를 사용하면 Android와 iOS 앱을 동시에 개발할 수 있기 때문에 더욱 높은 생산성을 보일 것이라 믿습니다. 물론, 코드가 모두 통일되어 있는 것은 아니지만, 기존 네이티브 개발에 비해 높은 생산성을 보이는 것입니다.
Android와 iOS, 높은 생산성
→ 저희의 제한적인 개발 리소스에 리액트 네이티브 사용이 도움이 될 것이라 예상합니다.
일반젹으로 스타트업 기준, IOS 및 안드로이드 앱을 런칭하는데 있어 안드로이드 개발자 1명, IOS 개발자 1명, 프론트엔드 개발자 1명, 백엔드 개발자 2명 이렇게 5명에서부터 앱 개발자 1명, 프론트엔드 개발자 1명, 백엔드 1명 이렇게 3명까지 이루어지게 됩니다.
하지만 우리 프로젝트의 경우, 위와 같은 구성으로 이루어져 있지 않으며 프론트엔드 개발자의 경우 앱 개발 경험이 없습니다. 이런 경우 리액트 기반의 리액트 네이티브를 사용함으로서 러닝 커브를 줄이고 앱 개발에 비교적 빠르게 들어갈 수 있겠습니다.
짧은 러닝 커브
→ 우리 프로젝트에서 중요한 미션 중 하나가 서비스 출시 후 사용자들의 피드백을 받아 서비스를 개선하는 것입니다. 사용자가 필요로 하는 기능을 추가하거나, 단순히 UI의 재배치, 유저 플로우 수정 등이 있을 것입니다. 이런 것들을 위해서는 다양한 테스트를 거쳐야하는데, 리액트 네이티브를 사용했을 때 이러한 테스트를 진행할 때 매우 효율적일 것이라 생각됩니다.
대표적으로 A/B 테스트를 진행한다면, 만약 Android 와 iOS 개발이 따로따로 이뤄져 있는 경우 테스트를 위한 코드를 두 번씩 작성해야 하고,테스트를 마친 후 관련 코드를 제거하는 작업도 두 번씩 해야 합니다. 반면 리액트 네이티브를 사용하는 경우엔 해당 작업들을 한 번씩만 하면 되는 것입니다.
또한 리액트 네이티브에서는 CodePush
라는 기술을 사용하여 앱스토어 검수 없이 바로 배포할 수 있어 수정이 잦을 우리 프로젝트에 적합하다고 봅니다.
테스트 및 수정에 효율적
앱 스토어 검수 없이 바로 배포 가능
→ 리액트 네이티브의 UI 표현에 대해서는 걱정이 없었지만, 학습을 하고 앱에 적용되어야하는 부분들을 서칭하며 우려했던 부분이 있었습니다. 바로 리액트와 다른 써드파티 적용
입니다.
→ 버전 업데이트를 하면 API들이 완전히 바뀌어버리는 리액트 네이티브 라이브러리들이 많다는 점들이 우려가 되었습니다.
리액트 네이티브에 자체적으로 구현되지 않은 기능들의 경우엔 네이티브 코드를 직접 작성하여 구현하거나 관련 써드 파티 라이브러리의 힘을 빌려 구현을 해야 합니다.
기존 리액트의 경우 라이브러리의 개선이 잘 이뤄지고 라이브러리의 버전을 업데이트 해도 코드가 깨지는 일이 많지 않은데, 리액트 네이티브 라이브러리의 경우 버전 업데이트를 하면 코드가 깨지고 호환시키기 위해선 큰 공수가 들어가야 하는 점입니다.
→ npm을 찾아보니 수많은 써드 파티 라이브러리들이 npm에 배포되어 있어서 기능 구현에 사용할 수 있었으나, 대부분이 완성도가 낮고 업데이트가 되지 않아 사용하는 개발자가 2차 수정을 해야하다는 것이 타 앱 개발자들의 평이었습니다.
👉🏻 그럼?
수정이 필요한 라이브러리 프로젝트에 내장시켜서 사용하는 형태?
기존 서드파티 라이브러리를 수정해서 사용할 수 있는 능력 필요
nativebase
react-native-third-party
→ 리액트를 학습하면서 가장 먼저 체감할 수 있던 부분인데, 크로스 플랫폼이나 Android에서 보이는 UI와 iOS에서 보이는 UI가 일관성이 없게 나타날 때가 있습니다.
예를 들어서 iOS에서는 괜찮게 보이는데 Android에서는 스타일이 문제가 있어서 이를 고치기 위한 스타일 코드를 더 추가해야 되는 것입니다.
👉🏻 이 부분은!
개발 이후에는 각 기기에서 잘 작동하는지 확인하는 작업은 필수적
애초에 이 부분을 인지하고 개발
→ 리액트 네이티브를 사용하면 앱 개발을 할 때, 대부분의 경우에 기존보다 빠른 속도로 개발을 할 수가 있습니다.
그런데 문제는, 자바스크립트와 마찬가지로 가끔씩 어떤 이슈가 발생하고 그 이슈가 무엇 때문에 발생하는지 파악을 하기가 어려워 시간 낭비를 엄청나게 하는 상황이 간혹 발생할 수 있다는 것입니다.
👉🏻 이 부분은!
타입 지정이 가능한지 확인 필요
→ 리액트 네이티브 학습시 개발 후, 시뮬레이터 또는 개발용 기기로 개발 모드를 구동을 할 때 대부분의 경우엔 문제없이 잘 작동하지만 브랜치를 변경하여 네이티브 코드에 변동 사항이 발생하거나 하면, 간혹가다가 앱 구동이 제대로 안되는 현상을 경험했습니다.
이럴 땐, Clean Project를 하고, 다시 실행하면 해결할 수 있었습니다.
그래서 이 부분에 대해 서칭을 해보니 앱의 규모가 커져가면서 모든 걸 초기화 하고 앱을 다시 구동하면 3~40분이 넘어가기도 하고, iOS 경우엔 더 오래 걸리고 몇차례 시도해야하는 경우도 있다고 합니다.
👉🏻 이 부분은!
브랜치 관리 어떻게 할 지 고려해야함
빌드 타임에 대해 미리 인지하고 있기
→ 마지막으로, 프론트엔드에서 프로젝트 세팅을 할 지 어느 정도 틀을 잡은 내용을 공유해보려고 합니다.
선택지 : React Native CLI
VS Expo
선택안 : Expo
선택 이유 : 현재까지 학습한 기반이 expo이며, 생성에 있어 초기 세팅이 까다롭기 하지만 React Native CLI
에 비해 비교적 생성이 쉬우며, 앱 설치를 한다면 실시간으로 모바일에서도 확인 가능.
선택지 : Flow
VS TypeScript
선택안 : TypeScript
선택 이유 : 리액트 네이티브 프로젝트에 정적 타입 시스템 Flow가 기본적으로 적용되어 있긴 하지만, 워낙 Flow 쪽 커뮤니티는 너무 작고 적용을 위한 학습 비용이 크다고 생각하여 기존에 사용해본 TypeScript
.
선택지 : React Navigation
VS React Native Navigation
선택안 : 미정
선택 이유 : React Native Navigation를 사용 할 경우 화면 하나 하나가 완전히 다른 별개의 리액트 앱으로 취급.
선택지 : Redux
VS Context API
VS React Query
선택안 : React Query
, Context API
선택 이유 : Context API 를 사용해서 전역적으로 사용 할 수 있게 해주면 컴포넌트에게 함수를 전달해줘야 하는 상황에서 코드가 수월
→ React Query를 사용하면 API 요청 상태 관리 수월
.
const ShinstarrMap = () => {
const { isLoading, isError, data, error } = useQuery("todos", fetchTodoList, {
refetchOnWindowFocus: false, // react-query는 사용자가 사용하는 윈도우가 다른 곳을 갔다가 다시 화면으로 돌아오면 이 함수를 재실행합니다. 그 재실행 여부 옵션 입니다.
retry: 0, // 실패시 재호출 몇번 할지
onSuccess: data => {
// 성공시 호출
console.log(data);
},
onError: e => {
// 실패시 호출 (401, 404 같은 error가 아니라 정말 api 호출이 실패한 경우만 호출됩니다.)
// 강제로 에러 발생시키려면 api단에서 throw Error 날립니다. (참조: https://react-query.tanstack.com/guides/query-functions#usage-with-fetch-and-other-clients-that-do-not-throw-by-default)
console.log(e.message);
}
});
if (isLoading) {
return <span>Loading...</span>;
}
if (isError) {
return <span>Error: {error.message}</span>;
}
return (
<ul>
{data.map(shinstarrmap => (
<li key={shinstarrmap.idx}>{shinstarrmap.list}</li>
))}
</ul>
);
};
→ 이전 프로젝트에서 어려웠던 API 요청 상태, Hook으로 가능하여 코드 재사용
이 수월.
다양한 로직을 한번만 작성하고 재사용 가능.
추후 서버에서 API의 반환 결과에 변동이 있다거나, 비즈니스 로직에 변동이 생기면 쉽게 반영 가능.
const {isLoading, isError, data, error} = useQuery('order', fetchOrdderList);
//결제시 필요한 정보
type PurchaseInfo = {
price: number;
title: string;
isRent: boolean;
menuIds: number[];
}
//Hook 파라미터
type UseMenuSelectorParams = {
optionsId: number;
purchaseCallback: (purchaseInfo : PurchaseInfo) => void;
}
function useEpisodeSelector({optinsId, purchaseCallback} : UseMenuSelectorParams){
const {data, isLoading, refetch} = useMenus(optionsId);
//그 외 다양한 비즈니스 로직 구현들
return {
isLoading, //로딩 상태
toggleId, //단일 항목 토글
toggleAll, //전체 항목 토글
purchase, //결제 시작
reservation, //예약
reservationDays, //예약한 날짜 보여줄 N
refetch, //초기화
}
}
expo를 사용하시면서 네이티브 코드 수정 등 별다른 제한사항은 없으셨나요?