좋은 프로젝트는 기술이 아니라 도메인 이해에서 시작된다
프로젝트를 만들 때 가장 중요한 것은 내가 만들고자 하는 서비스의 도메인을 얼마나 깊이 이해하고 있는가이다.
많은 사람들이 포트폴리오를 만들 때 새로운 기술을 사용하거나 복잡한 기능을 구현하는 것에 집중한다. 하지만 실제 면접에서는 “이 기술을 써봤습니다”보다 “왜 이런 구조로 설계했는가”, “서비스를 얼마나 이해하고 있는가”를 더 중요하게 본다.
자바 문법이나 프레임워크 사용법은 개발자라면 갖추어야 할 기본기일 뿐이다. 결국 회사가 궁금한 것은 다음과 같다.
이 사람이 우리 서비스의 도메인을 이해하고, 비즈니스 요구사항을 코드에 자연스럽게 녹여낼 수 있는가?
따라서 개발 과정에서는 단순히 기술을 적용하는 것이 아니라, 지금 내가 만드는 기능이 서비스에서 어떤 역할을 하는지, 왜 필요한지를 끊임없이 고민해야 한다.
객체지향 개발을 어려워하는 이유
객체지향적으로 설계하지 못하는 이유는 크게 두 가지다.
1. 자바 문법에 대한 이해 부족
클래스, 생성자, 접근 제어자, 캡슐화 같은 기본 문법에 대한 이해가 부족하면 객체의 책임을 나누기 어렵다.
2. 서비스에 대한 이해 부족
서비스 자체를 제대로 이해하지 못하면 객체가 어떤 책임을 가져야 하는지 결정할 수 없다.
결국 객체지향 설계는 문법만의 문제가 아니라 도메인 이해의 문제이기도 하다.
[ 객체지향 행동 지침 ]
클래스는 하나의 일꾼이다
객체지향에서 클래스는 하나의 일꾼이라고 생각하면 이해하기 쉽다.
하나의 일꾼은 하나의 책임만 가져야 한다.
그리고 그 일꾼이 가지고 있는 데이터는 외부에서 함부로 건드릴 수 없도록 private으로 보호한다.
public class Money {
private int amount;
public Money(int amount) {
if(amount < 0) {
throw new IllegalArgumentException("금액은 0보다 작을 수 없습니다.");
}
this.amount = amount;
}
}
위 예제처럼 생성자는 객체가 생성되는 순간부터 올바른 상태를 유지하도록 도와준다.
만약 금액이 음수가 될 수 없는 객체라면 생성자에서 검증하여 애초에 잘못된 객체가 만들어지지 않도록 막을 수 있다.
객체는 직접 데이터를 가져오지 않는다
객체지향의 핵심은 객체 간의 협력이다.
객체가 다른 객체의 데이터를 직접 꺼내서 처리하려고 하면 결합도가 높아지고 책임이 섞이게 된다.
대신 상대 객체에게 일을 요청해야 한다.
account.withdraw(1000);
이처럼 객체 내부의 데이터를 직접 수정하는 것이 아니라, 해당 객체가 제공하는 메서드를 통해 필요한 작업을 요청해야 한다.
즉,
“데이터를 가져와서 내가 처리한다”가 아니라
“그 데이터를 가진 객체에게 일을 시킨다”
라는 관점이 중요하다.
그리고 스프링 역시 궁극적으로는 이러한 객체들의 협력을 조율하는 역할을 한다.
객체는 자신의 책임만 알아야 한다
예를 들어 주문(Order) 객체가 있다고 가정해보자.
주문의 책임은 주문을 처리하는 것이다.
재고 부족 여부를 판단하는 것은 재고가 가진 책임이다.
잔액 부족 여부를 판단하는 것은 계좌나 결제 객체의 책임이다.
따라서 Order가 다음과 같은 내용을 직접 알 필요는 없다.
- 현재 재고가 몇 개인지
- 잔액이 얼마인지
- 결제가 가능한지
Order는 단순히 관련 객체에게 요청만 하면 된다.
inventory.decrease(quantity);
account.pay(price);
재고가 부족하면 Inventory가 예외를 발생시키고,
잔액이 부족하면 Account가 예외를 발생시킨다.
Order는 그 사실만 전달받으면 된다.
즉,
객체는 자신의 책임만 알고 있어야 하며,
다른 객체의 내부 사정까지 알 필요는 없다.
필드는 행동을 위해 존재한다
초보 개발자들은 클래스를 만들 때 흔히 이런 순서로 생각한다.
“무슨 필드를 만들지?”
하지만 객체지향 설계는 반대로 접근해야 한다.
먼저 생각해야 하는 것은 행동이다.
- 이 객체는 어떤 일을 해야 하는가?
- 그 일을 하기 위해 어떤 데이터가 필요한가?
- 그 데이터를 필드로 선언한다.
예를 들어 주문 객체가 주문 취소 기능을 제공해야 한다면, 먼저 “주문 취소”라는 행동을 생각하고,
그 행동을 수행하기 위해 필요한 데이터가 무엇인지 고민해야 한다.
즉, 필드가 행동을 만드는 것이 아니라, 행동이 필드를 결정한다.
마무리
좋은 프로젝트는 새로운 기술을 많이 사용했다고 만들어지는 것이 아니다.
오히려 다음과 같은 질문에 답할 수 있을 때 좋은 프로젝트가 된다.
- 왜 이 객체를 만들었는가?
- 왜 이 책임을 이 객체에게 맡겼는가?
- 왜 이 메서드가 이 클래스에 존재하는가?
- 왜 이 데이터가 필요한가?
- 서비스의 어떤 요구사항을 해결하기 위한 설계인가?
결국 개발자는 코드를 작성하는 사람이 아니라,
도메인을 이해하고 현실의 문제를 객체들의 협력으로 해결하는 사람이다.
기술은 도구일 뿐이고, 좋은 설계는 도메인에 대한 깊은 이해에서 시작된다.
해당 내용은 스파르타 클럽의 [달리기반 수업] 중에 튜터님께서 말씀해주신 내용 중 일부를 참고하여 정리한 글입니다.
'TIL' 카테고리의 다른 글
| [Troubleshooting] 자바 제네릭 T 타입으로 사칙연산이 불가능한 이유 (0) | 2026.06.08 |
|---|---|
| [TIL] 자바 catch문에는 왜 Exception 타입만 들어갈 수 있을까? (0) | 2026.06.08 |
| [TIL] 시간복잡도는 if문 개수보다 반복 횟수가 중요한 이유 (0) | 2026.06.06 |
| [TIL] 문자열에서 숫자를 추출하고 int로 변환하는 방법 (0) | 2026.06.02 |
| [TIL] 코딩테스트에서 Arrays 클래스가 중요한 이유 (0) | 2026.05.28 |