μλ νμΈμ dev_writerμ λλ€. μ€λμ [λκ·λͺ¨ 리μ‘νΈ μΉ μ± κ°λ°] μ± μ λν 리뷰λ₯Ό μμ±νκ² μ΅λλ€.
μ± μ λͺ©μ°¨λ λ€μκ³Ό κ°μ΄ μ΄λ£¨μ΄μ Έ μμ΅λλ€.
- μμνλ©°
- μννΈμ¨μ΄ 볡μ‘μ± κ΄λ¦¬νκΈ°
- λͺ¨λμ±
- μ±λ₯
- λμμΈ μμ€ν
- λ°μ΄ν° κ°μ Έμ€κΈ°
- μν κ΄λ¦¬
- κ΅μ ν
- μ½λ μ‘°μ§ννκΈ°
- κ°μΈνμ A/B ν μ€ν
- νμ₯ κ°λ₯ν μΉ μν€ν μ²
- ν μ€ν
- ν΄λ§
- κΈ°μ μ λ§μ΄κ·Έλ μ΄μ
- νμ μ€ν¬λ¦½νΈ
- λΌμ°ν
- μ¬μ©μ μ€μ¬ API λμμΈ
- 리μ‘νΈμ λ―Έλ
- λ§Ίμλ§
λκ·λͺ¨ μΉ μ ν리μΌμ΄μ μ μ μ
κ°μ₯ λ¨Όμ , "λκ·λͺ¨ μΉ μ ν리μΌμ΄μ "μ΄λΌλ μ©μ΄μ μ¬λ°λ₯Έ μ μκ° λ¬΄μμΌκΉμ?
μ± μμλ μμνλ©΄μλΆν° λκ·λͺ¨ μΉ μ ν리μΌμ΄μ μ μ μνκ³ μμ΅λλ€.
μ°λ¦¬λ λκ·λͺ¨ μΉ μ ν리μΌμ΄μ μ μ μνλ κ°μ₯ μ¬μ΄ λ°©λ²μ΄ λ€μκ³Ό κ°λ€κ³ μκ°νλ€. μμ λͺ νΉμ κ·Έ μ΄μμ μμ§λμ΄λ‘ ꡬμ±λ λκ·λͺ¨ νμ μν΄ κ°λ°λμκ±°λ, μκ·λͺ¨ νμ μν΄ κ°λ°λμμ§λ§ μκ°μ΄ μ§λ¨μ λ°λΌ κ³μ μ§ννλ μΉ μ ν리μΌμ΄μ , νΉμ μ΄ λ κ°μ§ μ±κ²©μ λͺ¨λ κ°μ§ μ ν리μΌμ΄μ μ λκ·λͺ¨ μ ν리μΌμ΄μ μ΄λΌ μ μνλ€. μ¦, λκ·λͺ¨ μΉ μ ν리μΌμ΄μ μ μ μ§λ³΄μμ κ°λ°μμ μλΉν λ Έλ ₯μ μꡬνλ, μ¬μνμ§ μμ (non-trival) μ ν리μΌμ΄μ μ΄λΌ ν μ μκ² λ€.
μ΄ λ§μ λ£κ³ , μλΉν λ Έλ ₯κ³Ό μ¬μνμ§ μμ μ ν리μΌμ΄μ μ΄λ 무μμΌμ§ μΆκ°λ‘ κ³ λ―Όν΄ λ³΄μμ΅λλ€. κ·Έλ¬λ€κ° μ± μ μ½μΌλ©΄μ μ± μ λͺ©μ°¨λ‘λΆν° ννΈλ₯Ό μ»μ μ μμλλ°, μ κ° λ΄λ¦° λκ·λͺ¨ μΉ μ ν리μΌμ΄μ μ μ μλ μλμ κ°μ΅λλ€.
λκ·λͺ¨ μΉ μ ν리μΌμ΄μ μ΄λ
μ°¨μμ΄ λ€λ₯Έ μμ€μ μ μ§λ³΄μλ₯Ό κΎΈμ€ν ν΄μΌ νλ, κ³μ μ§νλλ μ ν리μΌμ΄μ μ΄λ€.
μ± μμλ λͺ¨λν, μ±λ₯ μ΅μ ν, ν μ€νΈμ κ°μ μ½λ μμ€μμμ κ°μ λ§κ³ λ κ΅μ ν, κ°μΈν λ° A/B ν μ€ν λ± λΉμ¦λμ€μ κ΄λ ¨λ κΈ°λ²λ€λ μκ°νκ³ μμ΅λλ€. μ΄λ¬ν κΈ°λ²λ€μ λͺ¨λ μ μ©ν΄μΌ ν μ ν리μΌμ΄μ μ΄λΌλ©΄, κ·Έκ²μ΄ κ³§ μ°¨μμ΄ λ€λ₯Έ μμ€μ μ μ§λ³΄μλ₯Ό νκ³ μλ μ ν리μΌμ΄μ μ΄λΌ μκ°ν©λλ€. λ¨μν μ½λλ§ μμ νλ κ² μλλΌ μ¬μ©μ κ²½νκ³Ό λΉμ¦λμ€ μ λ΅κΉμ§ μν₯μ λ―ΈμΉ μ μκΈ° λλ¬Έμ λλ€.
μ²μμ μ λͺ©λ§ λ€μμ λμλ λκ·λͺ¨ μΉ μ ν리μΌμ΄μ μ΄λ "MAUκ° λμ μ ν리μΌμ΄μ "μΌ μ€λ§ μμμλλ° (λ°±μλμμμ "λκ·λͺ¨ νΈλν½"μ²λΌ..), λ³΄λ€ λͺ νν μ μν μ μμ΄ μμλΆν° μ’μ κ³ λ―Όμ ν μ μμμ΅λλ€.
κΈ°μ μ λ¬Έμ λ₯Ό ν΄κ²°νκΈ° μν΄ λ±μ₯ν "λꡬ"μ΄λ€.
μμ¦ λ€μ΄ κ°μ’ κΈ°μ /κΈ°λ²λ€μ μ΄μ©ν λλ§λ€ "μ" μ¨μΌ νλμ§ κ³ λ―Όμ λ§μ΄ νμλλ°, λ³Έ μ± μμλ κ° κΈ°μ λ€μ μκ°ν λλ§λ€ νμν λ°°κ²½, κ³ λ € μμ λ±μ ν¨κ» μ 곡νκ³ μμ΄ μ’μ κ·Όκ±°λ₯Ό μ»μ μ μμμ΅λλ€.
λν, κΈ°μ μ μ νν λ λ¨μν κ·Έ κΈ°μ μ μ΅μνλ€λ μ΄μ λ‘ μΆ©λΆν κ³ λ―Ό μμ΄ κΈ°μ μ μ±ννλ νμλ μ’μ μ κ·Όλ²μ΄ μλμ μλ €μ£Όμμ΅λλ€.
νν€λ λꡬμ (νλ‘κ·Έλλ°) μΈμ΄λ₯Ό μ νν λ μ£Όλ‘ κ³ λ €ν΄μΌ ν μ¬νμ λꡬλ μΈμ΄μ μ¬μ© νΈμμ±μ΄ μλλΌ μ°λ¦¬κ° ν΄λΉ λꡬμ μΈμ΄λ₯Ό μ¬μ©ν΄μ ꡬμΆν μμ€ν μ΄ κ°λ 볡μ‘μ±μ΄μ΄μΌ νλ€κ³ λ§νλ€. μ¬μ©νκΈ° μ¬μ΄ λꡬλ₯Ό μ νΈνλ κ²μ μμ°μ€λ¬μ΄ κ²μ΄μ§λ§, μ¬μ΄ μμ€ν λ³κ²½μ΄λ μ μ§λ³΄μμ λ―ΈμΉλ μ₯κΈ°μ μΈ μν₯μ κ΄ν΄μλ κ³ λ €ν΄μΌ νλ€. μ¬μ©νκΈ° μ¬μ΄ λκ΅¬κ° νμ 볡μ‘μ±μ μΌκΈ°νμ§λ μκ² μ§λ§ μ¬μ΄ μ¬μ©μ±μ λ€λ₯Έ λͺ¨λ κ²λ³΄λ€ μ°μ ν΄μλ μ λλ€. λμ , λ§λ€μ΄μ§λ μμ€ν μ μ λ°μ μΈ λ¨μμ±μ μ΄μ μ λμ΄μΌ νλ€.
μλλ μ± μ λ΄μ©μ ν΅ν΄ κΈ°μ μ λ±μ₯ λ°°κ²½ λ° μ¬μ© μ μ£Όμμ¬νμ λν΄ μ λ¦¬ν΄ λ³Έ λ΄μ©μ λλ€.
리μ‘νΈ μ»΄ν¬λνΈνμ κ³ λ € μμ
λ³΄ν΅ λ¦¬μ‘νΈλ₯Ό 곡λΆν΄ 보μ λΆλ€μ μ»΄ν¬λνΈνλ₯Ό νλ κ² μ¬μ¬μ©μ±κ³Ό μ μ§λ³΄μμ±μ λμ¬μ€λ€λ κ²μ μ μκ³ κ³μ€ κ²λλ€.
κ·Έλ¬λ ννΈμΌλ‘λ, λ§μ½ κ·Ήλ¨μ μΌλ‘ μ»΄ν¬λνΈλ₯Ό μκ² μͺΌκ° λ€κ³ κ°μ νμ λμλ μ μ₯μ μ΄ μ μ§λ κΉλΌκ³ νλ€λ©΄, μλ κ²μ λλ€.
μ± μμλ 리μ‘νΈμμ μ»΄ν¬λνΈνλ₯Ό ν λμλ λͺ κ°μ§ κ³ λ € μ¬νμ μ μνκ³ μμ΅λλ€.
λͺ¨λ κ²μ μ»΄ν¬λνΈλ‘ λ§λ€κ³ μΆμ μλ μκ² μ§λ§ κ· νμ΄ μ€μνλ€. λ무 μκ² λλλ©΄ κ²°κ΅ κ·Έ μ½λλ² μ΄μ€λ₯Ό νμνκΈ° μ΄λ ΅κ² λ κ²μ΄λ€. λ무 μ±κΈ°κ² λλλ©΄ μμμ μ€λͺ ν μ΄μ΅μ ννμ λλ¦¬μ§ λͺ»ν κ²μ΄λ€. μ»΄ν¬λνΈλ‘ λλλ κ²μ κ²°μ ν λλ μ¬λ¬ μμλ€μ κ³ λ €ν΄μΌ νλ€.
- μ¬μ¬μ©μ±: νΉμ ν UI μμ νΉμ κΈ°λ₯μ μ ν리μΌμ΄μ μ μ¬λ¬ λΆλΆμμ λ°λ³΅νκΈ° μνλκ°? κ·Έλ λ€λ©΄ μ체μ μΈ μ»΄ν¬λνΈλ‘ λ§λ€ μ μλ μ’μ ν보μ΄λ€.
- λ¨μμ±κ³Ό κ°λ μ±: μ»΄ν¬λνΈ μ½λμ κ°λ μ±μ μ΄λ€κ°? μ»΄ν¬λνΈλ₯Ό μμ νμ μ»΄ν¬λνΈλ‘ λλκ³ κ°κ°μ μ± μμ μ§μ€νλλ‘ λ§λ€λ©΄ μ½λλ₯Ό λ³΄λ€ μ½κ² μ½κ³ μ΄ν΄ν μ μκ² λλκ°?
- κ°μ λ ν μ€νΈ κ°λ₯μ±: μ»΄ν¬λνΈκ° λ μκ³ μ§μ€λ μ± μμ κ°λλ€λ©΄ μ΄ μ»΄ν¬λνΈλ₯Ό λ³΄λ€ ν¨κ³Όμ μΌλ‘ ν μ€νΈν μ μλκ°? μμ μ»΄ν¬λνΈλ€μ μΌλ°μ μΌλ‘ μ μ λ΄λΆ μνμ μ μ μ¬μ΄λ μ΄ννΈλ₯Ό κ°μ§λ―λ‘ ν μ€νΈμμ 격리νκΈ° μ½κ³ κΈ°λ₯μ κ° μ‘°μ§μ΄ μλν λλ‘ μλν¨μ 보μ₯νλ€.
- μ±λ₯ κ³ λ € μ¬ν: μ»΄ν¬λνΈλ₯Ό λλμΌλ‘μ¨ λ λλ§μ μ΅μ ννκ±°λ λΆνμν μ‘°μ§μ μ€μΌ μ μλκ°? 리μ‘νΈ κ°μ λΌμ΄λΈλ¬λ¦¬μμλ μ’ μ’ μμ μ»΄ν¬λνΈκ° λ³΄λ€ μ μ μμ μ¬λ λλ§μ νλ©° μ»΄ν¬λνΈμ κ³μ°μ λ©λͺ¨ννλ€. μ΄λ λλλ‘ μ±μ μ λ°μ μΈ μ±λ₯μ κ°μ ν μ μλ€.
리μ‘νΈ μΏΌλ¦¬μ νμ κ³κΈ°
리μ‘νΈ μΏΌλ¦¬λ 리μ‘νΈ νκ²½μμμ λΉλκΈ° 쿼리 κ³Όμ μ λμμ£Όλ λΌμ΄λΈλ¬λ¦¬λ‘μ¨, κΈ°λ³Έμ μΌλ‘ μ¬μ©ν μ μλ Fetch APIμ λ λ€λ₯Έ λΌμ΄λΈλ¬λ¦¬μΈ Axiosλ³΄λ€ λ λ°μ΄λ κΈ°λ₯λ€μ μ 곡νκ³ μμ΅λλ€.
μ΄μ μ Axios μΈν°μ ν°μ λν΄ μ‘°μ¬νμ λ Fetch APIλ κΈ°λ³Έμ μΌλ‘ λ΄μ₯λ APIλΌ μ¬μ©μ΄ κ°λ¨νμ§λ§ JSON νμ± κ³Όμ μ΄ λ³λλ‘ μ‘΄μ¬νλ€λ λ¨μ μ΄ μμκ³ , Axiosλ λ³λλ‘ μ€μΉν΄μΌ νλ λΌμ΄λΈλ¬λ¦¬μ΄μ§λ§ μΈν°μ ν° μ 곡, JSON νμ± μ§μ λ± κΈ°λ₯μ΄ λ μλ κΈ°μ λ‘ νμ νμ΅λλ€.
μ΄μ λΉν΄, 리μ‘νΈ μΏΌλ¦¬λ Fetch/Axiosκ° μ§μνλ κΈ°μ μ΄μΈμλ μΊμ±, μ¬μλ λ©μ»€λμ¦ λ± μ ν리μΌμ΄μ μ΄ μ»€μ§κ³ μꡬμ¬νμ΄ λ³΅μ‘ν΄μ§λ©΄μ λ°μν λ¬Έμ λ₯Ό ν΄κ²°νκΈ° μν΄ λ±μ₯νμμ΅λλ€.
λ°λ©΄ 리μ‘νΈ μΏΌλ¦¬λ₯Ό μ΄μ©νλλΌλ μΊμ±μ΄ νμνμ§ μμ μν©, λλ κΈ°μ‘΄μ μ€μΉλ axiosλ§μΌλ‘λ μΆ©λΆν μν© λ±μ΄λΌλ©΄ μ€νλ € 리μ‘νΈ μΏΌλ¦¬λ₯Ό λμ νλ κ² μ μ νμ§ μμ μ μκ² λ€λ μ κ·Όλ ν΄λ³Ό μ μμμ΅λλ€.
μμΈν κ²μ λ νΌλ°μ€λ‘ μ°Ύμλ³Έ μλΉμ€μ React-queryλ₯Ό λμ νλ©° λ§μ£Όν λ¬Έμ λ€ κΈμ μ°Έκ³ ν΄ λ³΄λ©΄ μ’μ΅λλ€.
리μ‘νΈ λ¨μ ν μ€νΈ ν΄ λ³΄κΈ° (feat. AAA ν¨ν΄)
리μ‘νΈλ₯Ό 곡λΆν μ§ μΌλ§ μ§λμ§ μμ μ λ‘μλ ν΄λΉ μΉμ λ λ무 μ’μ μμ μ€ νλμμ΅λλ€.
리μ‘νΈ μ»΄ν¬λνΈλ₯Ό λ§λ€μλ€κ³ νμ λ, μ΄λ»κ² ν μ€νΈν μ μμκΉμ? μλ°λ μ½νλ¦°μ μ΄μ©ν μ€νλ§ λ± λ°±μλ λ¨μμμ ν μ€νΈλ λ§μ΄ μ ν΄λ΄μ μ΅μνμΌλ, 리μ‘νΈ μ»΄ν¬λνΈλ₯Ό ν μ€νΈνλ λ°©λ²μ μ΅μνμ§ μμ μ΄λ €μ΄ μμμΌλ‘λ§ μκ°νμμ΅λλ€.
μ΄κ²μ μ± μμ μκ°ν κ°λ¨ν Counter μ»΄ν¬λνΈ (λ²νΌ λλ₯΄λ©΄ μ«μ μ¦κ°λλ μ»΄ν¬λνΈ) ν μ€νΈ μ½λλ₯Ό 곡μ λ리며 λ§μλλ¦¬κ² μ΅λλ€.
Counter μ»΄ν¬λνΈ
import React, { useState } from 'react';
const Counter = () => {
const [count, setCount] = useState(0);
const increment = () => {
setCount(count + 1);
};
const decrement = () => {
setCount(count - 1);
};
return (
<div>
<button onClick={decrement}>-</button>
<span>{count}</span>
<button onClick={increment}+</button>
</div>
);
};
export default Counter;
μ± μμλ 리μ‘νΈ μ»΄ν¬λνΈ ν μ€νΈλ₯Ό ν λ AAA ν¨ν΄ (Arrange, Act, Assert - μ 리, λμ, νμΈ ν¨ν΄)μ μ μ©νμ¬ μλ €μ£Όκ³ μμ΅λλ€.
import React from 'react';
import {
render,
fireEvent
} from '@testing-library/react';
import Counter from './Counter';
describe('Counter component', () => {
it('renders with initial count of 0', () => {
// μ 리 (Arrange)
const { getByText } = render(<Counter />);
/*
λμ (Act) - μ΄κΈ° λ λλ§μ ν
μ€νΈνλ―λ‘ μλ¬΄λ° λμμ΄ νμνμ§ μλ€.
*/
// νμΈ (Assert)
expect(getByText('0')).not.toBeNull();
});
it('increases count on "+" button click', () => {
// μ 리 (Arrange)
const { getByText } = render(<Counter />);
const incrementButton = getByText('+');
// λμ (Act)
fireEvent.click(incrementButton);
// νμΈ (Assert)
expect(getByText('1')).not.toBeNull();
});
it('decreases count on "-" button click', () => {
// μ 리 (Arrange)
const { getByText } = render(<Counter />);
const decrementButton = getByText('-');
// λμ (Act)
fireEvent.click(decrementButton);
// νμΈ (Assert)
expect(getByText('-1')).not.toBeNull();
});
});
μ΄ν
μ± μ λ€ μ½κ³ λμμΌ μ μ λΆμ λν μ€λͺ μ λ΄€λλ°, κ΅¬κΈ ν¬λ‘¬ μμ§λμ΄λ§ 리λλ₯Ό λ§‘κ³ κ³μ λΆ (Addy Osmani)μ΄μμ΅λλ€. κ΅¬κΈ ν¬λ‘¬μ΄λΌλ©΄ μ± μ μ λͺ©μ²λΌ λκ·λͺ¨ μΉ μ ν리μΌμ΄μ μ΄λΌ ν μ μκ² λ€λ μκ°μ΄ λ€μμ΅λλ€. λ€λ§ 리μ‘νΈμ μμ ν μ’ μμ μΌλ‘ μλ €μ£Όλ μ± μ΄κΈ°λ³΄λ€λ, λκ·λͺ¨ μΉ μ ν리μΌμ΄μ μ ꡬμΆν λ μ΄λ€ λ¬Έμ λ₯Ό μ ν μ μκ³ κ·Έμ λν ν΄κ²°μ± μ μ΄λ»κ² μ μ©νκ³ μλμ§μ λν΄ λ€λ£¨λ μ± μ΄λΌ ν μ μμ΅λλ€.
κ·Έλμ "λκ·λͺ¨ μΉ μ ν리μΌμ΄μ μ 리μ‘νΈλ‘ ꡬμΆνλ λ°©λ²"μ λν΄ μκ³ μΆμΌμ λΆλ€λ³΄λ€λ, "λκ·λͺ¨ μΉ μ ν리μΌμ΄μ μ ꡬμΆνκΈ° μν΄ μ κ·Όν μ μλ ν΄κ²°μ± λ€μ΄ 무μμ΄ μλμ§"λ₯Ό μκ³ μΆμΌμ λΆλ€μκ² μ λ§λ μ± μ λλ€. (λ€λ₯΄κ² λ§νλ©΄, λΆλ΄ μμ΄ μ½κ² μ½μ μ μλ μ± μ΄κΈ°λ ν©λλ€!)
λ λμ νλ°νΈμλ κ°λ°μκ° λκΈ° μν΄ μλν΄ λ³Ό μ μλ μ κ·Όλ²μ΄ 무μμ΄ μλμ§ κΆκΈνμ λΆλ€κ» μ΄ μ± μ μΆμ²ν©λλ€.
λ³Έ κΈμ μ μ΄ν μΆνμ¬λ‘λΆν° λμλ₯Ό μ§μλ°μ μμ±λμμ΅λλ€.