- Published on
๐ฅ 2024๋ 1์ํ๊ณ
- Authors

- Name
- ์ต์์ค (Youngjun Choi)
1์์๋ ์ค์ฟผ๋์์ ์ฑํฐ๋ก ์์์ด ๋ฐ๋๋ฉด์ ์
๋ฌด๊ฐ ๊ธฐ๋ฅ๊ฐ๋ฐ์์, ์ฑ๋ฅ์ ์ต์ ํํ๊ณ ์์ ์ฑ์ ๋์ด๊ธฐ ์ํ ์
๋ฌด๋ค์ด ์ฃผ๋ฅผ ์ด๋ฃจ๊ฒ ๋์๋ค. ํฌ๊ฒ ์ง์คํด์ ์งํํ๋ ์
๋ฌด๋ App Start์๊ฐ์ ์ต์ ํ์ ์๋ฌ๋ฐ์ด๋๋ฆฌ ์ ์ฉ์ด์๋ค. ๋ ๊ฐ์ง ์ฑํฐ ์
๋ฌด์ ํจ๊ป ๋ถํ์ํ API ํธ์ถ์ ๊ฐ์งํ๋ ๋ฐฉ๋ฒ์ ๋ํด ๊ณ ๋ฏผํ๊ณ ํด๊ฒฐ๋ฐฉ๋ฒ์ ์ฐพ์ ์ ์ฉํด๋ณด์๋ค.
1์ ์ ๋ฌด๋ฅผ ์๋กญ๊ฒ ๋ฐฐ์ฐ๊ฒ ๋ ์ ๊ณผ ๋๊ผ๋ ์ ๋ค์ ๊ฐ๋จํ ์ ๋ฆฌํด๋ณด๋ ค ํ๋ค.
โ ๏ธ ๋ถํ์ํ API ํธ์ถ์ ๊ฐ์งํด๋ณด์
๋ถํ์ํ API๋ฅผ ์ค์ด๋ ๊ฒ์ ์๋น์ค๋ฅผ ์ด์ฉํ๋ ๊ณ ๊ฐ์ ์ฌ์ฉ์ฑ์ ๋์ด๊ณ , ์๋ฒ์ ๋ถํ๋ฅผ ์ค์ผ ์ ์๋ ๋ ๊ฐ์ง ์ฅ์ ์ด ์๋ค. ๊ทธ ์ค์์ฑ์ ์ ๋ฒ ๊ฒฌ์ ๋ฐ์ก ์๊ฐ์ ์ค์ด๋ฉด์ ๋๋ผ๊ณ ๊ฐ๋ฐ๋จ๊ณ์์ ์๋ ๋ฐฉ๋ฒ์ด ์์์ง ๊ณ ๋ฏผํ๊ณ , ์ด๊ฒ์ ํด๊ฒฐํ๋ ๋ฐฉ๋ฒ์ผ๋ก axios interceptor๋ฅผ ์ด์ฉํด๋ณด๊ธฐ๋ก ํ๋ค.
axios interceptor
axios interceptor๋ axios์ ์์ฒญ๊ณผ ์๋ต์ ๊ฐ๋ก์ฑ๋ ๊ธฐ๋ฅ์ด๋ค. ์ด๋ฅผ ์ด์ฉํด ์์ฒญ๊ณผ ์๋ต์ ๋ํ ๋ก์ง์ ์ถ๊ฐํ ์ ์์ด ๊ณตํต์ ์ธ ์์ฒญ๊ณผ ์๋ต์ ๋ํด ์ฒ๋ฆฌ๋ฅผ ํ ์ ์๋ค.
[axios interceptor ๊ณต์๋ฌธ์ ์์ ์ฝ๋]
// Add a request interceptor
axios.interceptors.request.use(
function (config) {
// Do something before request is sent
return config
},
function (error) {
// Do something with request error
return Promise.reject(error)
}
)
// Add a response interceptor
axios.interceptors.response.use(
function (response) {
// Any status code that lie within the range of 2xx cause this function to trigger
// Do something with response data
return response
},
function (error) {
// Any status codes that falls outside the range of 2xx cause this function to trigger
// Do something with response error
return Promise.reject(error)
}
)
์ด๋ฌํ ๊ธฐ๋ฅ์ ์ด์ฉํด ๊ตฌํํ ์ค๋ณต API๋ฅผ ์ฒดํฌํ๊ธฐ ์ํ ์ฝ๋๋ ์๋์ ๊ฐ๋ค.
[axios interceptor๋ฅผ ์ด์ฉํ ์ค๋ณต API ์ฒดํฌ interceptor]
const requestMap = new Map<string, { lastTime: number; count: number }>()
const ์ค๋ณต์ฒดํฌ_request_interceptor = async (
config: InternalAxiosRequestConfig
) => {
const { method, url, params, data } = config
const requestKey = `${method?.toUpperCase()} ${url} ${JSON.stringify(
params
)} ${JSON.stringify(data)}`
const request = requestMap.get(requestKey) ?? { lastTime: 0, count: 0 }
const now = Date.now()
if (request.lastTime === 0 || now - request.lastTime > 1000) {
requestMap.set(requestKey, { lastTime: now, count: 1 })
} else {
requestMap.set(requestKey, { lastTime: now, count: request.count + 1 })
console.warn(
`${method?.toUpperCase()} ${url} ๋ฐ๋ณต ์์ฒญ ${request.count + 1} times`
)
}
return config
}
์์ ๊ฐ์ด interceptor๋ฅผ ํตํด ๋ค์ด์จ ์์ฒญ ์ ๋ณด๋ฅผ key๋ก ํ Map์ ๊ธฐ๋กํ๊ณ ์ค๋ณต API๋ผ๊ณ ๋ณผ ์ ์๋ ๊ฒ์ ๊ธฐ์ค์ ์ฐ์ 1์ด ์ ๋๋ก ์ ํด๋ณด๊ธฐ๋ก ํ๋ค. ์ด๋ ๊ฒ ๊ตฌํํ๊ณ ๋๋ฉด ๋ค์๊ณผ ๊ฐ์ด warning์ด ์ฐํ๋ ๊ฒ์ ๋ณผ ์ ์๋ค.
[warning์ผ๋ก ์ฐํ ์ค๋ณตํธ์ถ ๋ก๊ทธ]

๊ตฌํํ๊ณ ๋๋, ์ค์ ๋ก ๋ฐ์ํ๊ณ ์๋ API๋ค์ ์ฐพ์ ์ ์์๋๋ฐ, ์ค๋ณต API๊ฐ ๋ฐ์ํ ๋๋ง๋ค ์ฐํ๋ค ๋ณด๋ ๋ก๊ทธ๊ฐ ๋๋ฌด ๋ง์ด ์ฐํ๋ ๋ฌธ์ ๊ฐ ์์๋ค. ์ด๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด์ ๊ฐ๋จํ๊ฒ debounce๋ฅผ ์ด์ฉํด logging ์ฝ๋๋ฅผ ๊ฐ์ธ์ฃผ์๋ค.
[debounce๋ฅผ ์ ์ฉํ ์ค๋ณต API ์ฒดํฌ interceptor]
const notify = debounce(({ method, url, count }) => {
console.warn(`${method?.toUpperCase()} ${url} ๋ฐ๋ณต ์์ฒญ ${count + 1} times`)
}, 1000)
const requestMap = new Map<string, { lastTime: number; count: number }>()
const ์ค๋ณต์ฒดํฌ_request_interceptor = async (
config: InternalAxiosRequestConfig
) => {
const { method, url, params, data } = config
const requestKey = `${method?.toUpperCase()} ${url} ${JSON.stringify(
params
)} ${JSON.stringify(data)}`
const request = requestMap.get(requestKey) ?? { lastTime: 0, count: 0 }
const now = Date.now()
if (request.lastTime === 0 || now - request.lastTime > 1000) {
requestMap.set(requestKey, { lastTime: now, count: 1 })
} else {
requestMap.set(requestKey, { lastTime: now, count: request.count + 1 })
notify({ method, url, count: request.count })
}
return config
}
[ํ๋๋ง ์ฐํ๋ ๋ก๊ทธ]
๊ตฌํ ํ, ๊ฐ๋ฐ๊ณผ์ ์์ ์ค๋ณต ํธ์ถ๋๋ API๋ค์ ํ์ธํ ์ ์์๊ณ , ์ด๋ฅผ ํตํด ์ค์ ๋ก ์ด๋ค ํ๋ฉด์์ ๋ฐ์ํ๊ณ ์๋์ง ์ ์ ์์๋ค. ์กฐ๊ธ ์์ฌ์ด ์ ์ ๊ฐ๋ฐํ๊ฒฝ์์ ์ธ์งํ๊ณ ์ถ์ด์ ์ถ๊ฐํ ์ฝ๋์ด์ง๋ง ์ฐ๋ฆฌ ํ๋ก์ ํธ ์ฝ๋์ ์ถ๊ฐ๋๊ธฐ๋ณด๋ค debugger์ ํ๊ธฐ๋๋ ๊ฒ ๋ ์ข์ ๋ณด์๋ค.
์ดํ์ RN ๋๋ฒ๊ฑฐ๋ฅผ ๋ถ์ํด๋ณด๋ฉด์ ํด๋น ๊ธฐ๋ฅ์ ๋ง๋ค์ด๋ณด๋ ๊ฒ๋ ์ข์ ๊ฒ ๊ฐ๋ค.
๐ซApp Start ์๊ฐ ์ค์ด๊ธฐ
์ฑํฐ๋ก ์์์ด ๋ณ๊ฒฝ๋๊ณ 24๋ 1๋ถ๊ธฐ ๋ชจ๋ฐ์ผ ์ฑํฐ ๋ชฉํ๋ก App Start ์๊ฐ ๋จ์ถ ์ผ๊ฐ์ ๋ด๋นํ๊ฒ ๋์๋ค. ๊ธฐ์กด์ ์ธก์ ํ๊ณ ์๋ ๊ธฐ์ค์ ์ต์์ ํ์ผ์ธ App.tsx๊ฐ ๋ ๋๋ง ๋ ์ดํ ๋ถํฐ Splash์ ๊ฑฐ์ณ ํํ๋ฉด์ ์ง์ ํ๊ธฐ๊น์ง์๋ค.
์ธก์ ๊ธฐ์ค ์ก๊ธฐ
๊ฐ์ฅ ๋จผ์ ์๋ํ ๋ฐฉ๋ฒ์ ๋คํธ์ํฌ ์ ๋ณ๋ชฉ์ด ์๋์ง ์ฒดํฌํจ์ผ๋ก์จ ๋ถํ์ํ API๋ค์ ์ ๊ฑฐํ๊ณ ์ฐจ๋ก๋ก ์งํ๋๊ณ ์๋ ๋ณ๋ชฉ์ง์ ๋ค์ ๋ณ๋ ฌํํจ์ผ๋ก์จ ์๊ฐ์ ๋จ์ถํ๋ ค ํ๋ค.
ํํ๋ฉด์ ๋ค์ด๊ฐ๊ธฐ ์ ์ ์ฃผ์ํ๊ฒ ์งํํด์ผ ํ ํ๋ก์ธ์ค๋ ์ธ ๊ฐ์ง๋ก ๋ค์๊ณผ ๊ฐ์ด ์ ๋ฆฌํ ์ ์๋ค.
- ์ฑ ๋ฒ์ ์ฒดํฌ ๋ฐ ์ ๋ฐ์ดํธ
- ์ธ์ฆํ ํฐ์ ์ด์ฉํ ๋ก๊ทธ์ธ
- ๋ก๊ทธ์ธ ํ ์ด๊ธฐํ ์์
์ ์ธ ๊ฐ์ง๊ฐ ๋ชจ๋ ์๋ฃ๋๊ณ ๋์ ํ ํ๋ฉด์ผ๋ก ์ด๋ํ ์ ์๊ธฐ ๋๋ฌธ์ ์ด ์ธ ๊ฐ์ง ํ๋ก์ธ์ค๊ฐ ๋ชจ๋ ์๋ฃ๋๋ ๋ฐ๊น์ง ๊ฑธ๋ฆฌ๋ ์๊ฐ์ ์ธก์ ํ๊ธฐ๋ก ํ๋ค. ๊ทธ๋ฆฌ๊ณ ๊ฐ ์คํ ์ ์๋ฃ์ง์ ์ checkpoint๋ฅผ ์ฃผ์ด ์ผ๋ง์ ์๊ฐ์ด ๊ฑธ๋ฆฌ๋์ง ์ ๋ณด๋ฅผ ์ถ๊ฐํ๋ค.
[์ค์ ์ง์ ์ ์ฒดํฌํฌ์ธํธ๋ฅผ ๋ฐ์๋ Splash ํ๋ฉด ์ฝ๋]
const ์ด๊ธฐํ_์คํ = async () => {
try {
await ํ ํฐ๊ฐ์ ธ์ค๊ธฐ()
performanceTracker.addCheckPoint("์ธ์ฆํ ํฐ ๊ฐ์ ธ์ค๊ธฐ")
await ์
๋ฐ์ดํธ๋ฒ์ ์ฒดํฌ()
const deepLink = await ๋ฅ๋งํฌ_์ ๋ณด๊ฐ์ ธ์ค๊ธฐ()
performanceTracker.addCheckPoint("๋ฅ๋งํฌ ์ ๋ณด ๊ฐ์ ธ์ค๊ธฐ")
await ๋ก๊ทธ์ธ()
performanceTracker.addCheckPoint("ํ ํฐ ๊ธฐ๋ฐ ๋ก๊ทธ์ธ")
await tracker.stopTrace("๊ธฐ์กด_trace_์ธก์ _์๋ฃ")
await ํ_ํ๋ฉด์ผ๋ก_์ด๋(deepLink)
performanceTracker.addCheckPoint("ํ ํ๋ฉด ์ด๋")
await ์ด๊ธฐํ์์
1()
// ...
await ์ด๊ธฐํ์์
N()
await tracker.stopTrace("์๋ก์ด trece_์ธก์ _์๋ฃ")
} catch (error) {
์๋ฌํธ๋ค๋ง_๋ฐ_๋ก๊น
()
}
}
์ ์ฝ๋์์ ์๋ก์ด trace๋ฅผ ์ถ๊ฐํ ์ด์ ๋ ์ด๊ธฐํ๊ฐ ๋ชจ๋ ์๋ฃ๋๋ ๋ฐ๊น์ง ์๊ฐ์ ์๊ณ ์ถ์๋ค. ํ ํ๋ฉด์ผ๋ก ์ด๋์ํค๊ณ , ์ดํ์ ์ผ๋ถ ์ด๊ธฐํ ์์ ์ด ์งํ๋๊ณ ์์ด, ํ๋ฉด์ ํ์ด ์๋ต์๋๋ณด๋ค ๋น ๋ฅธ ๊ฒฝ์ฐ๋ ๊น๋นก์ด๊ฑฐ๋ layout shift๊ฐ ๋ฐ์ํ๊ณ ์๋ค๋ ์ ์ ๋ฐ๊ฒฌํ๊ฒ ๋์ด ๋ชจ๋ ์๋ฃํ๋ ๊ฒ ์ ์ ๊ฒฝํ์ ๋ ์ข์ ๊ฒ ๊ฐ์๋ค. ๊ทธ๋์ ์ฐ์ ์ ์ฒด ์ด๊ธฐํ๋ฅผ ์๋ฃํ๋ ๋ฐ ํ์ํ ์๊ฐ์ ํจ๊ป ๋ณด๊ณ ์ ํ๋ค.
ํ์ฌ ์ถ๊ฐํ ์ค๊ฐ์ง์ ๋ค์ ๋ฐ์ดํฐ๋ฅผ IOS 90% ์ ์ ๊ธฐ์ค์ผ๋ก, ๋ค์๊ณผ ๊ฐ์ด ๋ฐ์ดํฐ๋ฅผ ์์๋ณผ ์ ์์๋ค.
- ์ธ์ฆํ ํฐ ๊ฐ์ ธ์ค๊ธฐ: 1.6์ด (์ต์์ App.tsx๋ฅผ ๋ ๋๋งํ ํ๋ถํฐ Splash ํ๋ฉด์ ์ง์ ํ ํ์ ์ธ์ฆํ ํฐ์ ๊ฐ์ ธ์ค๊ธฐ๊น์ง)
- ๋ฅ๋งํฌ ๋ถ๋ฌ์ค๊ธฐ: 3์ด (๋ฒ์ ์ฒดํฌ, ๋ฅ๋งํฌ ์ ๋ณด ๋ถ๋ฌ์ค๊ธฐ๊น์ง)
- ํ ํฐ ๊ธฐ๋ฐ ๋ก๊ทธ์ธ: 5.8์ด (๋ก๊ทธ์ธ+ ์ผ๋ถ ๋ก๊ทธ์ธ ํ ์์ ๊น์ง)
- ํ ํ๋ฉด ์ด๋: 6.3์ด (๋ก๊ทธ์ธ ํ ํ ํ๋ฉด์ผ๋ก ์ด๋ํ๊ธฐ๊น์ง)
์ ์ธก์ ๊ฒฐ๊ณผ๋ฅผ ๋ณด๊ณ ๋จผ์ ๋ฅ๋งํฌ ์ ๋ณด๋ฅผ ๋ถ๋ฌ์ค๊ณ ๋์ ํ๋ฉด ์ด๋๊น์ง์ ์๊ฐ์ ๋จ์ถํด ๋ณด๋ ค ํ๋ค. ์ด๋ฅผ ์ํด์ ์ ์ ํ์ ์ ๊ธฐ์ค์ผ๋ก ์ด๊ธฐํ ์์ ์ ์งํํ ์ ์๊ฒ ๋ฆฌํฉํ ๋งํ๋ค.
์ ์ ํ์ ์ ์ค์ ์ผ๋ก ์๊ฐํ๋ ์ด์ ๋ ๋ ๊ฐ์ง๋ก, ๋จผ์ ์ ์ ํ์ ๋ณ๋ก ์ด๊ธฐํ ์์ ์ ์ํ API ํธ์ถ ํ์๊ฐ ๋ฌ๋๋ค. ๋นํ์/๊ณ ๊ฐ/๊ณ ์ ๋ชจ๋๊ฐ ์ฌ์ฉํ๋ ๊ณตํต ์ด๊ธฐํ ๋ก์ง, ๊ณ ๊ฐ๊ณผ ๊ณ ์๋ง์ ์ํ ์ด๊ธฐํ ๋ก์ง, ๊ณ ์๋ง์ ์ํ ์ด๊ธฐํ ๋ก์ง ์ด ์ธ ๊ฐ์ง๋ก ๊ตฌ๋ถํ ์ ์์๊ณ , ์ ์ ๊ฐ ๊ณ ์๋ผ๋ฉด ์ธ ๊ฐ์ง ๋ชจ๋๋ฅผ ์งํํด์ผ ํด์ ๊ฐ์ฅ ์๊ฐ์ด ์ค๋ ๊ฑธ๋ฆฌ๋ ์ ์ ํ์ ์ผ๋ก ์์๋์๋ค.
๋๋ฒ์งธ๋ก๋ ๊ธฐ์กด์๋ ๋ก๊ทธ์ธ ํจ์ ๋ด๋ถ์ ์ผ๋ถ ์ด๊ธฐํ ์์ ์ด ํฌํจ๋์ด์๊ฑฐ๋ ์ด๊ธฐํ ์์ ๊ฐ๊ฐ ๋ด๋ถ์์ ๋ก๊ทธ์ธ ์ฌ๋ถ ๋๋ ์ ์ ํ์ ์ ์ฒดํฌํด ์คํํ๊ฒ ๋์ด ์์๋ ๊ฒ์ ํ์ ๋ณ๋ก ๋ฌถ์ด ๋ณ๋ ฌ์ฒ๋ฆฌํ ์ ์์ด๋ณด์๋ค.
์ ์ ํ์ ๋ณ ์ด๊ธฐํ ๋ฆฌํฉํ ๋ง
์ค๊ณ๋ฅผ ๋ง์น๊ณ ๋์๋ ํ์ํ์ง ์์ API๋ฅผ ์ฐพ๋ ๊ฒ๊ณผ ํ์ํ API๋ค์ ์์ ์ ํ๊ธฐ๋ ๊ฐ๋ณ API๋ฅผ ๋ถ๋ฅํ๋ ์์ ์ ์งํํ๋ค. ํ์ํ์ง ์์ API๋ฅผ ์ฐพ๋ ์์ ์ ์์ ๊ตฌํํ ์ค๋ณต API ์ฒดํฌ ์ ํธ ๋๋ถ์ ์ด๋ค API๊ฐ ์ค๋ณต๋๋์ง ์ ์ ์์๊ณ , ์ด๋ฅผ ํตํด ํ์ํ์ง ์์ API๋ฅผ ์ฐพ์ ์ ๊ฑฐํ๋ ์์ ์ ์งํํ๋ค.
์ด์ด์ ๋จ์ ํ์ํ API๋ค์ ์๋ก์ ๋ ผ๋ฆฌ์ ์ ํ ๊ด๊ณ๋ฅผ ์ ๋ฆฌํด ํ ํฐ ๋ถ๋ฌ์ค๊ธฐ - ๋ก๊ทธ์ธ -์ ์ ํ์ ๋ณ ์ด๊ธฐํ ์์ผ๋ก ํ๋ฆ์ด ์งํ๋ ์ ์๊ฒ ํ๋ค. ์ด๋ ๊ฒ ์ธ ๊ฐ์ง๋ก ๋ถ๋ฅ๋ ํ๋ฆ ์์์ ์ ์ ํ์ ๋ณ ์ด๊ธฐํ ์์ ๋ค์ ๋ณ๋ ฌ๋ก ์ฒ๋ฆฌํด ์๊ฐ์ ๋จ์ถํ๋ ค ํ๋ค.
[์ ์ ํ์ ์ ๋ค์ด๋ผ ์ ์๊ฒ ๋ฆฌํฉํ ๋งํ ์ด๊ธฐํ ์ฝ๋]
// ์ ์ ํ์
๋ณ ์ด๊ธฐํ
const ์ ์ ํ์
๋ณ_์ด๊ธฐํ = async (userType: UserType) => {
await Promise.all([
๊ณตํต_์ด๊ธฐํ(),
์ ์ _์ด๊ธฐํ(userType),
๊ณ ์_์ด๊ธฐํ(userType),
])
}
const ์ด๊ธฐํ_์คํ = async () => {
try {
await ํ ํฐ๊ฐ์ ธ์ค๊ธฐ()
await ์
๋ฐ์ดํธ๋ฒ์ ์ฒดํฌ()
const deepLink = await ๋ฅ๋งํฌ_์ ๋ณด๊ฐ์ ธ์ค๊ธฐ()
performanceTracker.addCheckPoint("๋ฅ๋งํฌ ์ ๋ณด ๊ฐ์ ธ์ค๊ธฐ")
const userType = await ๋ก๊ทธ์ธ()
performanceTracker.addCheckPoint("ํ ํฐ ๊ธฐ๋ฐ ๋ก๊ทธ์ธ")
await ์ ์ ํ์
๋ณ_์ด๊ธฐํ(userType)
await ํ_ํ๋ฉด์ผ๋ก_์ด๋(deepLink)
performanceTracker.addCheckPoint("ํ ํ๋ฉด ์ด๋")
await ๋ก๊น
()
await tracker.stopTrace("์๋ก์ด_์ธก์ _์๋ฃ")
} catch (error) {
์๋ฌํธ๋ค๋ง_๋ฐ_๋ก๊น
()
}
}
์์ ์ ์๋ฃํ๊ณ ๊ฐ๋ฐํ๊ฒฝ๊ณผ Prodํ๊ฒฝ์ด ๋ค๋ฅด๋ค ๋ณด๋ ์ผ๋ง๋ ์ค์ด๋ค ์ ์์์ง, ์์์ด ๋์ง ์์ง๋ง ์์ ์ด๊ธฐํ ์์ ์ด ํ๋ฉด์ด๋๋ณด๋ค ๋ฆ์ด์ ธ์ layout shift๊ฐ ์ผ์ด๋๋ ๋ฌธ์ ๋ ํด๊ฒฐํ ์ ์์๊ณ , ์์ธ์ฒ๋ฆฌ๋ ์ ์ฉํจ์ผ๋ก์ ๋ณด๋ค ์์ ์ ์ผ๋ก ํํ๋ฉด์ผ๋ก ์ง์ ํ ์ ์๊ฒ ๋์๋ค. ํ์ฌ ๋ฐฐํฌ๋์ง ์์ ์ํฉ์ด๋ผ ๊ฒฐ๊ณผ๊ฐ ์ด๋ป๊ฒ ๋ ์ง ๊ฑฑ์ ๋ฐ, ๊ธฐ๋๋ฐ์ผ๋ก ๊ธฐ๋ค๋ฆฌ๊ณ ์๋ค.
๊ทธ์ธ ์๊ฐ์ ์ค์ด๊ธฐ ์ํ ๋ฐฉ๋ฒ๋ค
์์ ๋๋ ๋์๋ ์ธ๊ฐ์ง ์ธก์ ์ง์ ์ ๋ฐ๋ผ ๋ค์ ๋ฐฉ๋ฒ๋ค์ ๋ํด ๊ณ ๋ฏผํ๊ณ ์ฑํฐ๋ด์์ ๋ ผ์๋ฅผ ์งํํ๋ค. ๋จผ์ ์ ๋ฐ์ดํธ ๋ฒ์ ์ฒดํฌ์ ๋ฅ๋งํฌ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ค๋ ์ง์ ์ ๊ฐ์ ํ ์ ์์ด ๋ณด์๋ค. ์ฌ๊ธฐ์ ๊ฐ์ฅ ํต์ฌ์ด ๋์๋ ๋ถ๋ถ์ ์ฑ๋ฒ์ ์ ๋ฐ์ดํธ ์ฒดํฌ๋ก ์ฝ๋ํธ์์ ์์ฒด ๋ฉ์๋๋ฅผ ์ด์ฉํด์ App center์ ์ฌ๋ผ์์๋ ๋ฒ์ ๊ณผ ํ์ฌ ์ฑ์ ๋ฒ์ ์ ์ฒดํฌํ๊ณ ์๊ณ , ์ฒดํฌํ๋๋ฐ 90ํ๋ก ์ ์ ๊ธฐ์ค์ผ๋ก 1.6์ด๊ฐ ์์๋๊ณ ์์๋ค.
๋จ์ถํ๊ธฐ ์ํ ๋ฐฉ๋ฒ์ผ๋ก ๋ฐฐํฌ๊ณผ์ ์์ ํด๋น ๋ฒ์ ๊ณผ ํ์ ์ ๋ฐ์ดํธ ํ์ ์ฌ๋ถ๋ฑ์ ๊ธฐ๋กํ๋ ์์ฒด ํ๋๊ทธ๋ฅผ ๋ง๋ ๋ค๋ฉด codepush ๋ฉ์๋๋ฅผ ์ฌ์ฉํ์ง ์๊ณ ์ฌ์ฉ์ด ๊ฐ๋ฅํด๋ณด์๋ค. ํ์ง๋ง ์ง์ค์ ์์ฒ์ด๋ผ ํ ์ ์๋ App Center์ ๋ฒ์ ์ ์ฒดํฌํ์ง ์๊ณ ์์ฒด์ ์ผ๋ก ๊ตฌํํ๋ ๊ฒ์ ์์ ์ฑ์ ๋ํ ์ฐ๋ ค๊ฐ ์๊ณ , ๋น์ฉ์ด ํฐ ์์ ์ด ๋ ๊ฒ ๊ฐ์ ์์ ๊ฐ์ ์์ ์ ๊ฒฐ๊ณผ๋ฅผ ๋ณด๊ณ ์์ ํด๋ณด๊ธฐ๋ก ํ๋ค.
๋ง์ง๋ง ๋จ์ ๋ฐฉ๋ฒ์ผ๋ก๋ ์ธ์ฆ ์ด๊ธฐํ ์ ๊น์ง์ ๋จ๊ณ, ์ฑ ๋ฒ๋ค์ ๋ถ๋ฌ์ค๊ณ ์คํํ ๋ ๋ณ๋ชฉ์ง์ ์ ์ฐพ๋ ๊ฒ์ด์๋ค. ์ด๋ถ๋ถ์ ์์ง ์ ํํ ์ง์ ์ ์ฐพ์ง๋ชปํด ๋คํธ์ํฌ์ ์ธ ์ ๊ทผ์ธ์๋ ์ฌ๋ฌ React native ์ต์ ํ์ ๊ด๋ จ๋ ๊ธ๊ณผ ๋ ผ์๋ฅผ ๋ณด๋ฉด์ ๋ฐฉ๋ฒ์ ์ฐพ๊ณ ์๋ค.
Bundle Splitting, Hermes, JSI๋ฑ์ ๋ํด ๊ฒํ ํด ๋ณด์์ง๋ง, ์ด๋ฏธ ์ฐ๋ฆฌ ์ฑ์์๋ Hermes์์ง์ ์ฌ์ฉํ๊ณ ์๊ณ , ํ์ฌ ์ฐ๋ฆฌ๊ฐ ์ธก์ ๊ธฐ์ค์ ๋ง์ถ ์ต์ ํ๊ฐ ์๋๊ธฐ ๋๋ฌธ์ JS ์ค๋ ๋ ์์ฒด์ ๋ถ๋ด์ ์ค์ผ ์ ์๋ ๋ฐฉ๋ฒ์ ๋ํด ๊ณ ๋ฏผ์ด ํ์ํด ๋ณด์๋ค.
๊ฐ์ฅ ๊ธฐ๋ณธ์ ์ธ ๋ถํ์ํ ๋ฆฌ๋ ๋๋ง์ ์ค์ด๋ ์์ ์ ๋จผ์ ์งํํ๊ณ , ์ดํ์ ๋ฒ๋ค์ ํฌ๊ธฐ๋ฅผ ์ค์ด๋ ๋ฑ์ ์์ ์ ์งํํ ์์ ์ด๋ค.
๐ฅ ์๋ฌ๋ฐ์ด๋๋ฆฌ ์ ์ฉ
๋๋์ด ์๋ฌ ๋ฐ์ด๋๋ฆฌ๋ฅผ ์ ์ฉ ์์ ์ ์์ํ๋ค. ๋ด๊ฐ ๊ณํํ ์ ์ฉ๋ฐฉ๋ฒ์ ๊ฐ์ฅ ๋ฐ๊นฅ์ชฝ๋ถํฐ ์์ชฝ์ผ๋ก ์๋ฌ๋ฐ์ด๋๋ฆฌ๋ฅผ ์ ์ฉํ๋ ๊ฒ์ผ๋ก, ์ต์์ ์๋ฌ๋ฐ์ด๋๋ฆฌ๋ฅผ ์์์ผ๋ก ์คํฌ๋ฆฐ๋จ์๋ก ์ ์ฉํด ๋๊ฐ ์์ ์ด์๋ค.
ํ์ํ ์๋ฌ๋ฐ์ด๋๋ฆฌ๋ฅผ ์ต์์์ ์ ์ฉํ๊ธฐ ์ํด App.tsx๋ฅผ ์์ ํ๊ณ , error๋ฅผ ๊ฐ์งํ ์ ์๊ฒ ์ ์ฉํ๋ค.
class App extends Component<{}, State> {
state: State = {
hasError: false,
};
constructor(props: Record<string, never>) {
super(props);
}
componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
์๋ฌ๋ก๊น
()
}
static getDerivedStateFromError() {
return { hasError: true };
}
handleRestartApp = () => {
CodePush.restartApp();
};
render(): ReactElement {
const { hasError } = this.state;
if (hasError) {
return (
<FallabckComponent retry={handleRestartApp} />
);
}
return (
//...
);
}
}
export default App;
์ต์์ ์๋ฌ๋ฐ์ด๋๋ฆฌ์ ์๋ฌ๊ฐ ๋๋ฌํ์ ๋์ ์ฑ์ ์ฌ์์ํ ์ ์๊ฒ ๋์์ฃผ๋ ๊ฒ ์ข์ ๊ฒ ๊ฐ์, Codepush๋ฅผ ์ด์ฉํ restart ๊ธฐ๋ฅ์ ์ถ๊ฐํ๋ค.
๊ตฌํ์์ฒด๋ ์ด๋ ต์ง ์์์ง๋ง, ์กฐ๊ธ ๋ ๊ณ ๋ฏผ์ด ๋์๋ ๊ฒ์ ์ด๋ป๊ฒ ์๋ดํด์ฃผ๋ ๊ฒ ์ ์ ์ ์ฅ์์ ๋์์ด ๋ ์ ์์๊น์๋ค. ํผ์ ๊ณ ๋ฏผํ๋ค๊ฐ ์ฑํฐ์๋ถ๋ค์ ๋์์ ๋ฐ์ ๋ค์ํ ์์์ ๋ง๋ ํ์, UX writer ๋ถ๊ณผ ํ๋ซํผ ๋์์ด๋๋ถ๋ค์ ๋์์ ๋ฐ์ ์์ฑํ๋ค.
์ฑํฐ๋ด์ ์
๋ฌด์ธ๋ฐ ๋ค๋ฅธ ์ฑํฐ๋ถ๋ค๊ป ์ผ์ ๋ง๋ค์ด ๋๋ฆฌ๋ ๊ฑด ์๋๊น๋ผ๋ ๊ณ ๋ฏผ์ด ๋์์ง๋ง ์ค์ ๋ก ์์ฒญ๋๋ ธ์ ๋ ๋๋ฌด ํ์พํ ๋์์ ์ฃผ์
จ๊ณ , ์คํ๋ ค ํ์ฌ ์ด๋ฒ๋
๋ ๋ถ๊ธฐ OKR๊ณผ ์ฐ๊ด๋ ์์
์ด๋ผ ๊ฐ๋ฐ์๋ถ๋ค๊ป ์๋ฌ ๋ฐ์์ ํ๋ฉด๋ค์ ๋ํ ์กฐ์ฌ๋ฅผ ๋ถํ๋๋ฆฌ๋ ค ํ๋ค๋ ์ด์ผ๊ธฐ๋ฅผ ๋ค์ด ํจ๊ป ํ์
ํ๋ ์ข์ ๊ณ๊ธฐ๊ฐ ๋์๋ค.
๋๋ณด๋ค ๋ ์ ์์๊ณ , ์ ํ์๋ ๋ถ๊ป ์ ์ ํ ๋์์ ๋ฐ๋๊ฒ ์ค์ํจ์ ๋ ๋ค์ ๋๋ ์ ์์๋ค.
๐๊ทธ์ธ์ ๋ฐฐ์ด์
App Start๊ฐ์ ์์ ๋ค์ ์งํํ๋ฉด์ ํ์ฌ React Native ์ํคํ ์ณ ์์ฒด์ ๋ํ ๊ณต๋ถ๊ฐ ํ์ํ๋ค. ํด๋น ๋ด์ฉ๋ค์ ๋ฐ๋ก ์ ๋ฆฌํ๋ฉด์ ๋ธ๋ก๊ทธ์ ์ฌ๋ ค๋ณด๊ณ new Architecture, JSI๋ฑ RNํ์์ ๋ง์ ๋ ธ๋ ฅ์ ๊ธฐ์ธ์ด๊ณ ์๋ค๋ ์ ๋ ์ ์ ์์๋ค. ๋ํ ์๋ฌ๋ฐ์ด๋๋ฆฌ๋ฅผ ์ ์ฉํ๋ฉด์ ์ค์ ์ ์ผ๋ก ์ ์ํ๊ณ ์ ์ฉํ๋ฉด์ ์ฑ์ ์์ ์ฑ์๋ ๊ธฐ์ฌํ ์ ์์ด ์ข์๋ ํ๋ฌ์ด์๋ค.
๊ฐ์ธ์ ์ผ๋ก ๊ณ์ํด์ ์๋ํ๋ ์กฐ๊ธ ๋ ์ผ์ ํจ์จ์ ์ผ๋ก ์ฒ๋ฆฌํ๊ธฐ ์ํ ๋ฐฉ๋ฒ๋ค๋ ๊ณ ๋ฏผํ๊ฒ ๋๋ ๊ฒ ๊ฐ๋ค. ์ค๋ณต APIํธ์ถ ๊ฐ์ง ์ ํธ์ ๋ง๋ค๊ธฐ๋ ํ๊ณ , App Start ์๊ฐ์ ์ค์ด๋ ์์ ์ ํ๋ฉด์ JS Bundle ์ต์ ํ๋ฅผ ์ํด Lodash ํจํค์ง ์ ์ฒด๋ฅผ ์ง์ importํ์ง ์๊ฒ ์คํฌ๋ฆฝํธ๋ฅผ ์์ฑํ๊ธฐ๋ ํ๋ค. ์ ์๋ฏธํ ๊ฒฐ๊ณผ๊ฐ ๋ํ๋๊ฒ ๋๋ฉด ๋ธ๋ก๊ทธ์ ๊ธ๋ ์์ฑํด๋ณผ ์์ ์ด๋ค.
์์ง ๋๋ฌด๋๋ฌด ๋ฐฐ์ธ๊ฒ ๋ง๋ค๊ณ ๋๊ปด ๋ฒ๊ฒ๊ฒ ๋๊ปด์ง๊ธฐ๋ ํ์ง๋ง, ๋ ์ข์ ๋ฐฉ๋ฒ์ ๋ํด ์น์ดํ๊ฒ ๊ณ ๋ฏผํ๋ ํ๋ฌ์ด์๋ค. ํฐ ๊ฐ์ ์ด ๋์ง ์๋๋ผ๋, ์น์ดํ๊ฒ ๊ณ ๋ฏผํ๋ ๊ฒ ์์ฒด๊ฐ ๋ด๊ฐ ์ฑ์ฅํด๊ฐ๋ ๊ณผ์ ์ด๊ธธ ๋ฐ๋ผ๋ฉด์ ๋ง์ณ๋ณธ๋ค.