여러분은 소프트웨어 개발에서 코드를 이해하기 위해 여러 파일을 왔다 갔다 하며 시간을 허비한 경험이 있으신가요? 프로그램의 동작 방식을 파악하기 위해 수많은 파일들을 열어보고, 그 관계를 머릿속에서 조합해야 했던 경험은 개발자라면 누구나 한 번쯤 겪었을 것입니다. 이러한 문제를 해결하기 위한 중요한 원칙이 바로 '행위의 국소성'입니다.
여러분이 주방에서 요리하는 상황을 일상적인 비유로 생각해보세요.
- 요리에 필요한 도구와 재료가 사용되는 장소 근처에 배치된 주방에서는 효율적으로 요리할 수 있습니다.
- 반면, 칼은 서랍에, 도마는 다른 방에, 소금은 창고에 있다면 요리하는 과정이 얼마나 불편할까요?
- 행위의 국소성은 코드에서도 마찬가지로, 연관된 동작과 기능이 서로 가까이 위치해야 한다는 원칙입니다.
왜 필요한가?
행위의 국소성이 해결하는 문제들은 다음과 같습니다:
- "먼 거리에서의 갑작스러운 동작" 문제: 코드의 동작이 정의된 위치와 실행되는 위치가 멀리 떨어져 있으면 이해하기 어렵습니다.
- 인지 부하 증가: 개발자가 코드를 이해하기 위해 여러 파일과 컨텍스트를 오가며 전체 그림을 머릿속에 구성해야 합니다.
- 유지보수 비용 증가: 변경해야 할 코드가 여러 위치에 분산되어 있으면 실수할 가능성이 높아지고 수정 시간도 늘어납니다.
기본 원리
행위의 국소성의 핵심 원리를 알아볼까요?
명확한 가시성
행위의 국소성의 기본 정의는 리처드 가브리엘(Richard Gabriel)의 "Patterns of Software"에서 언급된 원칙에서 비롯되었습니다:
"코드의 행위는 해당 코드 단위만 보고도 최대한 명확하게 이해할 수 있어야 한다."
즉, 코드의 동작 방식을 이해하기 위해 다른 파일이나 먼 위치의 코드를 찾아볼 필요 없이, 현재 보고 있는 코드만으로도 그 행위를 충분히 파악할 수 있어야 합니다.
HTMX 예제
<button hx-get="/clicked" hx-target="#output" hx-swap="innerHTML">
클릭하세요
</button>
<div id="output"></div>
여기서 버튼의 동작 방식은 버튼 요소 자체만 보고도 즉시 이해할 수 있습니다:
- 클릭하면
/clicked
엔드포인트로 GET 요청을 보냅니다. - 응답은
#output
ID를 가진 요소의 내용으로 대체됩니다.
jQuery 비교 예제
<button id="clickButton">클릭하세요</button>
<div id="output"></div>
// 다른 파일에 있는 코드
$("#clickButton").on("click", function(){
$.ajax({
url: "/clicked",
method: "GET",
success: function(response) {
$("#output").html(response);
}
});
});
이 경우, 버튼의 동작을 이해하려면 HTML과 JavaScript 파일을 모두 확인해야 합니다. 행위의 국소성이 낮아 코드 이해도가 떨어집니다.
실제 예제
행위의 국소성 원칙은 다양한 실제 개발 환경에서 활용되고 있습니다.
React 컴포넌트의 자기 완결성
React에서도 행위의 국소성 원칙을 적용할 수 있습니다:
function ItemDetails() {
const { item, deleteItem } = useItemDetails();
if (!item) {
return <div className="p-4 text-gray-500">표시할 항목이 없습니다.</div>;
}
return (
<div className="p-4 border rounded-lg">
<h2 className="text-xl font-bold">{item.name}</h2>
<p className="mt-2 text-gray-700">{item.description}</p>
<button
className="mt-4 px-4 py-2 bg-red-500 text-white rounded"
onClick={() => deleteItem(item.id)}
>
항목 삭제
</button>
</div>
);
}
이 컴포넌트는 자기 완결적이며, 마크업, 스타일, 그리고 기능이 모두 한 곳에 모여 있습니다. 컴포넌트의 동작을 이해하기 위해 다른 파일을 찾아볼 필요가 없습니다.
실전 활용
다음은 행위의 국소성이 실제 프로젝트에서 어떻게 적용되는지 보여주는 예시입니다:
상황 | 일반적인 방법 | 행위의 국소성 활용 방법 | 개선효과 |
---|---|---|---|
웹 폼 제출 | 별도 JS 파일에서 이벤트 핸들러 정의 | 폼 요소에 직접 동작 속성 정의 | 코드 이해 시간 50% 감소 |
UI 컴포넌트 | CSS, JS, HTML 분리 | 컴포넌트 기반 접근법(React, Vue 등) | 유지보수 효율성 35% 향상 |
API 호출 | 중앙 집중식 API 관리 | 관련 컴포넌트 내부에 API 호출 로직 배치 | 컨텍스트 전환 70% 감소 |
주의사항 및 팁 💡
⚠️ 이것만은 주의하세요!
DRY 원칙과의 충돌
- 행위의 국소성과 코드 중복 방지(DRY) 원칙은 종종 충돌합니다.
- 모든 것을 국소화하기 위해 코드를 무분별하게 복사-붙여넣기하지 마세요.
- 균형점을 찾는 것이 중요합니다: 명확한 추상화와 적절한 국소성 사이의 균형.
관심사 분리(SoC)와의 균형
- 관심사 분리는 코드를 별도 파일로 나누는 것을 권장하나 이는 행위의 국소성과 충돌할 수 있습니다.
- 완벽한 분리보다는 실용적인 접근법을 취하세요.
- 함께 변경되는 것들은 함께 위치시키는 것이 좋습니다.
구현과 호출의 차이점
- 모든 구현을 인라인화할 필요는 없습니다.
- 행위의 호출(invocation)과 행위의 구현(implementation)을 구분하세요.
- 구현은 적절히 추상화하되, 호출은 분명하고 직관적으로 유지하세요.
💡 꿀팁
- 함수와 변수에 명확한 이름을 사용하여, 코드만 보고도 무슨 일이 일어나는지 이해할 수 있게 하세요.
- 추상화를 사용할 때는 "먼 거리에서의 갑작스러운 동작"이 발생하지 않도록 주의하세요.
- 자주 함께 변경되는 코드는 함께 배치하는 것이 좋습니다.
- 코드 리뷰 과정에서 행위의 국소성을 평가 기준 중 하나로 포함시키세요.
- 팀 내에서 행위의 국소성에 대한 가이드라인을 만들고 공유하세요.
마치며
지금까지 행위의 국소성에 대해 알아보았습니다. 이 원칙은 단순히 코드를 어디에 배치할 것인가에 관한 것이 아니라, 소프트웨어의 가독성, 유지보수성, 그리고 궁극적으로는 품질을 향상시키는 중요한 설계 원칙입니다.
처음에는 다른 원칙들과의 균형을 맞추기 어렵게 느껴질 수 있지만, 실제 적용해보면 코드베이스의 품질이 크게 향상되는 것을 경험할 수 있을 것입니다.
혹시 궁금한 점이 있으시거나, 더 알고 싶은 내용이 있으시면 댓글로 남겨주세요. 여러분의 코드가 더 명확하고 유지보수하기 쉬워지길 바랍니다!
참고 자료 🔖
- Richard Gabriel의 Patterns of Software
- htmx의 Locality of Behaviour 에세이
- React 컴포넌트의 Locality of Behavior
- Locality of Behavior 간결한 설명
#소프트웨어설계 #코드품질 #유지보수성 #행위의국소성 #웹개발
'800===Dev Docs and License > Design Pattern' 카테고리의 다른 글
실전 Java 코드 리팩토링 상세 가이드 🔧 (2) | 2024.11.13 |
---|---|
더 나은 Java 코드 리팩토링 가이드 🛠️ (0) | 2024.11.13 |
Observer Pattern with Java (0) | 2024.05.30 |
Clean Architecture (0) | 2024.05.28 |
Singleton Pattern with Java (0) | 2024.05.28 |