Clprolf와 `indef_obj`를 사용한 클래스 리팩토링
Source: Dev.to
대부분의 개발자는 **단일 책임 원칙 (SRP)**에 동의합니다.
실제 어려운 점은 무엇을 해야 하는지가 아니라 언제 해야 하는지입니다.
실제 프로젝트에서는 보통:
- 작동하는 코드를 작성하고,
- 시간이 지나면서 코드를 더 잘 이해하고,
- 책임이 명확해질 때 리팩터링합니다.
Clprolf는 리팩터링을 통해 미뤄진 아키텍처 결정을 지원함으로써 이 워크플로우에 자연스럽게 맞습니다.
1️⃣ 클래식 OOP 클래스에서 시작하기
아주 흔한 예제로 시작해봅시다. 특이한 건 없고, 단지 동작하는 클래스입니다.
public class OrderManager {
public void processOrder(Order order) {
if (order.getTotal() <= 0) {
throw new IllegalArgumentException("Invalid order");
}
saveToDatabase(order);
logOrder(order);
String message = formatConfirmation(order);
sendEmail(message);
}
private void saveToDatabase(Order order) {
System.out.println("Saving order " + order.getId());
}
private void logOrder(Order order) {
System.out.println("Order processed: " + order.getId());
}
private String formatConfirmation(Order order) {
return "Order #" + order.getId() + " confirmed";
}
private void sendEmail(String message) {
System.out.println("Sending email: " + message);
}
}
이 클래스는:
- 비즈니스 규칙을 포함하고,
- 영속성을 처리하며,
- 로깅을 수행하고,
- 메시지를 포맷하며,
- 이메일을 보냅니다.
누구나 이런 코드를 작성해 본 적이 있을 것입니다.
2️⃣ 역할에 대해 고민하지 않고 Clprolf 사용하기
Clprolf에서는 똑같은 방식으로 시작할 수 있습니다. 사전에 아무것도 결정할 필요가 없으며, 단지 아키텍처상의 역할이 아직 명확하지 않음을 인정하면 됩니다.
public indef_obj OrderManager {
public void processOrder(Order order) {
if (order.getTotal() <= 0) {
throw new IllegalArgumentException("Invalid order");
}
saveToDatabase(order);
logOrder(order);
String message = formatConfirmation(order);
sendEmail(message);
}
private void saveToDatabase(Order order) { }
private void logOrder(Order order) { }
private String formatConfirmation(Order order) { return ""; }
private void sendEmail(String message) { }
}
이 단계에서는:
- 강제되는 것이 없고,
- 아키텍처상의 약속도 없으며,
- 코드는 잠시 이렇게 유지될 수 있습니다.
indef_obj는 고전적인 OOP와 하지만 의식적으로 동작합니다.
3️⃣ 코드 이해 후 SRP 적용
Later—exactly like in a classic SRP refactoring—you realize that this class mixes different responsibilities.
| Concern | Nature |
|---|---|
| Business decision | Business |
| Persistence | Technical |
| Logging | Technical |
| Formatting / I/O | Technical |
This is where Clprolf가 유용해집니다.
4️⃣ 명시적 책임으로 리팩터링
Before (indef_obj)
OrderManager
├─ business rule
├─ persistence
├─ logging
└─ notification
After (SRP made explicit)
OrderProcessor (agent)
├─ business decision
OrderRepository (worker_agent)
└─ persistence
OrderNotifier (worker_agent)
├─ logging
└─ messaging
🎯 비즈니스 책임 → agent
public agent OrderProcessor {
private final OrderRepository repository;
private final OrderNotifier notifier;
public OrderProcessor(OrderRepository repository,
OrderNotifier notifier) {
this.repository = repository;
this.notifier = notifier;
}
public void process(Order order) {
if (order.getTotal() <= 0) {
throw new IllegalArgumentException("Invalid order");
}
repository.save(order);
notifier.notify(order);
}
}
agent는:
- 비즈니스 의도를 표현하고,
- 행동을 조정하며,
- 기술적인 세부 사항을 포함하지 않는다.
⚙️ 기술 책임 → worker_agent
public worker_agent OrderRepository {
public void save(Order order) {
System.out.println("Saving order " + order.getId());
}
}
public worker_agent OrderNotifier {
public void notify(Order order) {
log(order);
String message = format(order);
send(message);
}
private void log(Order order) {
System.out.println("Order processed: " + order.getId());
}
private String format(Order order) {
return "Order #" + order.getId() + " confirmed";
}
private void send(String message) {
System.out.println("Sending email: " + message);
}
}
워커는 기술적인 관심사를 자유롭게 혼합할 수 있다:
- I/O,
- 포맷팅,
- 로깅,
- 인프라스트럭처.
이는 비즈니스 의미가 agent에 남아 있기 때문에 허용된다.
5️⃣ 변경된 점 — 그리고 변하지 않은 점
❌ 변경되지 않은 항목
- 알고리즘,
- 동작,
- 성능,
- 표현력.
✅ 변경된 항목
- 책임이 명시적으로 되었다,
- 아키텍처 의도가 가시화되었다,
- 미래의 진화가 쉬워졌다.
이는 단순히 구조적으로 적용된 SRP이다.
🧩 결론
Clprolf는 개발자에게 더 열심히 생각하라고 요구하지 않으며— 특히 더 일찍 생각하라고 요구하지도 않습니다.
그들은 준비가 되었을 때 생각할 수 있게 해줍니다.
당신은:
- 먼저 코드를 작성하고,
- 나중에 이해하고,
- 필요할 때 책임을 리팩터링할 수 있습니다.
indef_obj는 목표가 아니라 — 실제 개발을 지원하는 임시 상태입니다.
그 의미에서, Clprolf는 단순한 언어가 아닙니다.
이는 아키텍처 명료성을 위한 리팩터링 도구입니다.
