객체는 혼자 일하지 않는다 - 협력 중심의 사고
객체지향은 "책임을 가진 객체가 요청을 받고, 그에 적절한 응답을 하는 것"이라고 이해합니다.
요청과 응답은 곧 전달이며, 메시지를 주고받는 것은 곧 협력의 형태가 됩니다. 즉 중요한 것은 하나하나의 내부 구현이 아닌,
이 객체가 어떤 역할을 맡고 있는가?
책임을 제대로 수행하고 있는가?
다른 객체와 협력을 잘하고 있는가?라는 점입니다.
역할 - 책임 - 협력
주문(Order)라는 하나의 문제를 객체지향적으로 풀어보자면, 하나의 객체가 모든 걸 다 처리해서는 안됩니다.
각 객체는 자신의 역할만 수행하고, 나머지는 다른 객체에 메시지를 보내 협력해야 합니다.
// 주문을 생성하는 역할
@Injectable()
export class OrderService {
constructor(
private readonly paymentService: PaymentService,
private readonly inventoryService: InventoryService,
) {}
async createOrder(orderDto: CreateOrderDto): Promise<string> {
const isAvailable = await this.inventoryService.checkStock(orderDto.itemId);
if (!isAvailable) {
throw new Error('재고 없음');
}
const paymentResult = await this.paymentService.pay(orderDto.userId, orderDto.amount);
if (!paymentResult.success) {
throw new Error('결제 실패');
}
return '주문 완료';
}
}
// 결제 역할
@Injectable()
export class PaymentService {
async pay(userId: number, amount: number): Promise<{ success: boolean }> {
console.log(`유저 ${userId} 결제: ${amount}원`);
return { success: true };
}
}
// 재고 확인 역할
@Injectable()
export class InventoryService {
async checkStock(itemId: number): Promise<boolean> {
console.log(`아이템 ${itemId} 재고 확인`);
return true;
}
}
새 객체는 명확하게 역할과 책임을 가지고 있습니다.
- OrderService: 전체 주문 흐름을 관리하는 역할.
- InventoryService: 재고 확인이라는 책임 수행.
- PaymentService: 결제 요청을 받아서 처리.
중요한 점은 이 객체들 혼자서 모든 문제를 해결하지 않습니다. 신의 영역이라는 뜻이 있었는데 신과 같은 역할을 한다고 해서.. 지금 당장 기억이 나지 않네요. 어쨌든, 각자의 역할을 수행하면서 서로 협력해 주문이라는 비즈니스 문제를 해결합니다.
객체를 어떻게 바라봐야 할까?
대부분의 개발자들은 이러한 구조를 따르고 있을 것 입니다. 일반적인 코드와 비슷하죠. 하지만, 책임을 수행하는 객체라는 관점에서 협력의 흐름을 중심으로 코드를 읽고, 설계할 줄 아는 사고 전환이 필요하다고 생각합니다.
초반 코드를 작성할때 한 곳에 몰아넣고, 이후 하나하나의 책임을 분리 역할을 분리하는 그런 일을 한 적이 있습니다. 그 이유는 한 곳에 모든 코드를 넣다 보니 디버깅에 하루를 쏟고, 어느 개발자가 와도 이해할 수 있는 코드여야 하지만 본인만 이해하는 코드를 작성하는 그런 코드가 작성되고 있었습니다.
즉, 어떻게 동작하느냐가 아니고,
무엇을 요청하고 어떤 책임을 맡고 어떻게 협력하는가? 이것이 중심이 되어야합니다.
객체 지향의 본질은 무엇일까?
협력하는 구조입니다. 객체는 책임을 수행하고, 그 책임은 특정 역할에 적합해야 합니다. 그리고 다른 객체와 협력해 하나의 문제를 해결하게 되죠. 또한, SRP와도 자연스럽게 맞물리게 됩니다.
이러한 구조는 추후 테스트 용이성과 확장성에 이점을 가져왔습니다. bcrypt를 사용해 암호화를 했던 프로젝트가 있는데, 이 내용을 바탕으로 Test Code를 작성하면서 너무 어려웠습니다. bcrypt 또한 역할을 수행하고 있을 뿐 어떤 구체적인 내용을 알 필요는 없습니다. 즉, bcrypt가 아니면 된다는 얘기입니다. 그래서 bcrypt를 Interface화 해서 만들어줘서 Test Code를 쉽게 작성했던 경험이 있습니다.
문제를 분산시키고 협력하는 방식의 사고방식의 틀이 잡혔다고 생각합니다.
앞으로 코드를 작성하며, 이 객체의 역할은 무엇이고, 책임을 과하게 떠안고 있지는 않은지? 그리고 다른 객체와 협력이 자연스러운 구조인지 항상 생각하고 코드를 설계한다면 좀 더 아름다운 코드를 작성할 수 있을 거라 판단됩니다.
'Project > 기록' 카테고리의 다른 글
비동기 아키텍처 전환 (0) | 2025.05.28 |
---|---|
내 API는 실패할 수 있다 (0) | 2025.05.26 |
객체지향의 사실과 오해 - 1 (0) | 2025.05.10 |
회사 코드 문화를 바꾸었다 - 완 (1) | 2025.05.07 |
회사 코드를 바꿔보자 - 3 (0) | 2025.05.07 |