RORO 패턴이란?
RORO는 "Receive an Object, Return an Object"의 약자로, 함수의 매개변수와 반환값을 모두 객체로 사용하는 JavaScript 패턴이다.
이 패턴은 TypeScript와 함께 사용할 때 특히 유용하다고 한다. RORO 패턴의 주요 이점은 다음과 같다:
- 매개변수의 순서에 구애받지 않음
- 선택적 매개변수를 쉽게 처리
- 함수 시그니처의 변경이 용이
- 코드의 가독성과 유지보수성 향상
- TypeScript와 함께 사용 시 타입 안정성 강화
RORO 패턴 예시
예시1
기존의 함수:
function createUser(name: string, age: number, email: string, isAdmin: boolean = false) {
// 사용자 생성 로직
}
createUser("John Doe", 30, "john@example.com");
RORO 패턴 적용 함수:
interface CreateUserParams {
name: string;
age: number;
email: string;
isAdmin?: boolean;
}
interface User {
id: string;
name: string;
age: number;
email: string;
isAdmin: boolean;
}
function createUser({ name, age, email, isAdmin = false }: CreateUserParams): User {
const id = generateUniqueId(); // 고유 ID 생성 함수라고 가정
return { id, name, age, email, isAdmin };
}
const newUser = createUser({
name: "John Doe",
age: 30,
email: "john@example.com",
// isAdmin은 선택적이므로 생략 가능
});
적용 컴포넌트:
interface ButtonProps {
text: string;
onClick: () => void;
color?: 'primary' | 'secondary';
size?: 'small' | 'medium' | 'large';
}
const Button: React.FC<ButtonProps> = ({ text, onClick, color = 'primary', size = 'medium' }) => {
return (
<button className={`btn btn-${color} btn-${size}`} onClick={onClick}>
{text}
</button>
);
};
// 사용
<Button text="Click me" onClick={() => console.log('Clicked')} color="secondary" />
예시2
기존의 함수:
function calculateTotalPrice(productPrice: number, quantity: number, discountRate: number, taxRate: number) {
const discountedPrice = productPrice * (1 - discountRate);
const priceBeforeTax = discountedPrice * quantity;
const totalPrice = priceBeforeTax * (1 + taxRate);
return totalPrice;
}
const total = calculateTotalPrice(100, 2, 0.1, 0.08);
RORO 패턴 적용 함수:
interface PriceCalculationParams {
productPrice: number;
quantity: number;
discountRate: number;
taxRate: number;
}
interface PriceCalculationResult {
totalPrice: number;
priceBeforeTax: number;
discountAmount: number;
taxAmount: number;
}
function calculateTotalPrice({
productPrice,
quantity,
discountRate,
taxRate
}: PriceCalculationParams): PriceCalculationResult {
const discountAmount = productPrice * discountRate * quantity;
const priceBeforeTax = (productPrice * quantity) - discountAmount;
const taxAmount = priceBeforeTax * taxRate;
const totalPrice = priceBeforeTax + taxAmount;
return {
totalPrice,
priceBeforeTax,
discountAmount,
taxAmount
};
}
const result = calculateTotalPrice({
productPrice: 100,
quantity: 2,
discountRate: 0.1,
taxRate: 0.08
});
console.log(`Total Price: $${result.totalPrice.toFixed(2)}`);
적용 컴포넌트:
interface ProductCardProps {
name: string;
price: number;
imageUrl: string;
inStock?: boolean;
onAddToCart: () => void;
}
const ProductCard: React.FC<ProductCardProps> = ({
name,
price,
imageUrl,
inStock = true,
onAddToCart
}) => {
return (
<div className="product-card">
<img src={imageUrl} alt={name} />
<h3>{name}</h3>
<p>Price: ${price.toFixed(2)}</p>
{inStock ? (
<button onClick={onAddToCart}>Add to Cart</button>
) : (
<p>Out of Stock</p>
)}
</div>
);
};
// 사용
<ProductCard
name="Wireless Headphones"
price={79.99}
imageUrl="/images/headphones.jpg"
onAddToCart={() => console.log('Added to cart')}
/>
팁
- 일관성 유지: 프로젝트 전체에서 RORO 패턴을 일관되게 사용하세요. 이는 코드의 예측 가능성을 높인다.
- 기본값 활용: 선택적 매개변수에 대해 기본값을 제공하여 사용의 유연성을 높이는 것이 좋다.
- 구조 분해 할당 사용: 함수 내부에서 매개변수 객체를 구조 분해 할당하여 사용하면 코드가 더 깔끔해진다.
- 타입 정의 분리: 매개변수와 반환값의 타입을 별도의 인터페이스로 정의하면 재사용성과 유지보수성이 향상된다.
- 과도한 사용 주의: 매우 간단한 함수의 경우 RORO 패턴이 오히려 복잡성을 증가시킬 수 있으므로 상황에 맞게 사용하는 것이 좋다.
- 문서화: JSDoc 주석을 사용하여 각 매개변수의 목적과 사용법을 문서화하면 더욱 좋다.
- 중첩 객체 주의: 매개변수 객체가 너무 깊게 중첩되면 복잡성이 증가할 수 있으므로 적절한 수준으로 유지하는 것이 좋다.