Chapter06. 여채현 #32
1000hyehyang
started this conversation in
리뷰
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
🆕 새롭게 알게 된 점
소프트웨어를 설계한다는 것은 단순히 프로그램을 잘 작동하게 만드는 기술의 문제가 아니다. 그것은 세상을 바라보는 방식, 그리고 그 복잡한 세상을 얼마나 이해하기 쉽게 모델링할 수 있는가에 대한 질문이다. 『객체지향의 사실과 오해』 6장은 그 질문에 **"구조를 먼저 보라"**고 말한다. 기능이 아니라 구조, 절차가 아니라 협력, 실행이 아니라 책임이 우선이라고.
이 장의 중심 은유는 바로 ‘지도’다. 저자는 실생활의 지도를 예로 들어 설명한다. 길을 직접 알려주는 방식은 당장의 문제는 해결해 주지만, 상황이 바뀌면 다시 길을 알려줘야 한다. 반면, 지도를 제공하면 사용자는 다양한 목적과 상황에 맞게 스스로 탐색할 수 있는 능력을 갖게 된다.
객체지향 설계도 마찬가지다. 기능(function) 중심으로 시스템을 만들면 기능이 바뀔 때마다 코드 전체가 흔들릴 수밖에 없다. 하지만 구조(structure) 중심으로 설계하면, 기능이 변해도 안정적인 구조 위에서 새로운 기능을 얹을 수 있다. 즉, 기능은 덧붙이는 것이고, 구조는 기반이 된다.
모든 소프트웨어는 두 가지 재료로 만들어진다:
기능은 유스케이스로, 구조는 도메인 모델로 표현된다.
기능은 자주 바뀐다. 고객은 "이 기능을 추가해달라", "저 지표도 보여달라"고 요청한다. 반면 구조는 잘 바뀌지 않는다. 예를 들어, 은행 업무의 본질은 ‘계좌’, ‘고객’, ‘이자’, ‘입출금’과 같은 개념이다. 그 구조는 시간이 지나도 본질적으로 유지된다.
객체지향이 추구하는 설계는 바로 이 안정적인 구조 위에 불안정한 기능을 얹는 것이다.
책에서 소개된 정기예금의 중도 해지 이자 계산 유스케이스는, 객체지향적 설계가 어떻게 현실의 문제를 ‘지도처럼’ 모델링할 수 있는지를 잘 보여주는 사례다.
예금주가 해지를 요청하면 시스템은 해지일을 기준으로 이자를 계산해 보여준다. 이 단순한 기능조차 책임을 나누고 협력하는 객체들로 구성하면 다음과 같이 분해된다:
정기예금: 이자 계산의 시작 책임을 가진다. 해지일을 받아 적절한 이자율 객체를 선택한다.계좌: 예금 금액 정보를 가지고 있으며, 계산 요청을 이자율 객체에 위임한다.이자율: 예금 금액과 해지일을 받아 이자를 계산한다.이자: 결과값 객체로 이자액과 계산 근거 정보를 담는다.이러한 협력 구조는 단지 기능을 수행하는 것만이 아니라, 누가 무엇을 책임지는가, 그리고 서로 어떻게 협력하는가에 초점을 맞춘다. 결국 이 설계는 ‘기능’이 아닌 ‘구조’를 중심으로 이루어진다. 기능이 바뀌더라도 협력 구조는 유지된다.
책에서는 유스케이스를 '기능의 나열'이 아닌, 이야기의 흐름으로 이해할 것을 제안한다. 유스케이스는 다이어그램이 아니라 텍스트이며, 사용자와 시스템 간의 대화를 서술하는 형식이다. 그것은 사용자의 목표 달성 여정을 담은 이야기이며, 이 여정은 시스템 안에서 책임을 가진 객체들이 협력하여 실현된다.
반대로 도메인 모델은 시스템이 작동하는 ‘세계’를 규정한다. 예금과 계좌, 이자율과 해지라는 개념은 사용자에게 친숙하고, 이 구조는 쉽게 변하지 않는다. 객체지향의 강점은 이 도메인의 구조를 소프트웨어로 재현할 수 있다는 점이다.
이 장에서 가장 철학적인 개념은 '표현적 차이'다. 소프트웨어 객체는 현실 객체를 모방한 것이 아니라, 은유와 해석을 통해 재창조한 것이다.
현실에 존재하는 ‘이자’와 소프트웨어에서 구현된
Interest객체는 같지 않지만, 그 의미는 통한다. 이 연결고리는 바로 도메인 모델을 중심으로 설계할 때에만 가능하다.결국...
객체지향의 사실과 오해 6장은 객체지향 설계의 진짜 목적이 **"기능을 빠르게 만드는 것"이 아니라, "변화에 유연하게 대응할 수 있는 구조를 만드는 것"**임을 일깨워준다. 소프트웨어 설계자는 길을 직접 알려주는 사람이 아니라, 지도를 그려주는 사람이어야 한다.
“기능이 아니라, 구조를 보라. 설계란 도메인의 본질을 구조로 옮기는 작업이다.”
📖 핵심 내용 요약
1. '길을 직접 알려주는 방법' vs '지도를 이용하는 방법'
야구장에 처음 방문한 사람이 있다고 가정하자.
[길을 직접 알려주는 방법]
직접 "좌측 매점으로 가려면 3루석을 따라가서 두 번째 출구에서 우회전해라" 같은 구체적인 지침을 제공한다.
→ 구체적이고 기능적인 접근법
→ 그러나 좌석이나 매점의 위치가 바뀌면 정보를 다시 제공해야 한다.
[지도를 제공하는 방법]
전체 야구장 지도를 건네주고 관중이 필요한 정보를 스스로 찾게 한다.
→ 구조적이고 문제 중심의 접근법
→ 사용자의 요구사항(좌석 찾기, 매점 찾기, 화장실 찾기 등)이 변해도 하나의 지도만으로 다양한 요구를 충족할 수 있다.
💡 핵심
2. 기능 중심 설계 vs 구조 중심 설계
야구 기록 프로그램을 만들 때, 단지 현재 필요한 기능인 '오늘의 안타 수'를 표시하는 방식으로 접근하면 기능 중심 설계가 된다. 이때는 오직 현재의 요구사항에만 초점을 맞춰 시스템을 구성하기 때문에 사용자가 갑자기 '투수의 평균자책점(ERA)'을 원한다거나, '타자의 OPS'를 요구하게 되면 전체 프로그램이 크게 흔들릴 가능성이 높다.
반면 구조 중심 설계는 시스템을 더 근본적인 관점에서 바라본다. 예를 들어, 선수(Player), 투수(Pitcher), 타자(Batter), 기록(Record), 경기(Game), 점수판(ScoreBoard)과 같은 야구에서 절대 바뀌지 않을 개념들로 시스템을 설계한다. 야구라는 도메인의 본질적인 구조를 중심으로 시스템을 구축하면, 새로운 기능이 필요해질 때마다 그 구조 위에서 기능만 추가하면 되므로 변화에 안정적이다.
즉, 좋은 소프트웨어는 기능뿐 아니라 변경과 확장이 용이한 안정적인 구조가 뒷받침되어야 한다.
3. 안정적인 재료와 불안정한 재료
소프트웨어 설계에는 두 가지 재료가 있다.
구조: 안정적인 재료다. 야구 경기에서 '선수', '경기', '이닝', '안타', '점수'와 같은 개념은 오랜 기간 거의 변하지 않는다.
기능: 불안정한 재료다. 예를 들어, 사용자가 원하는 경기 분석 방법이나 기록 지표는 언제든지 바뀔 수 있다.
따라서 구조를 중심으로 소프트웨어를 설계하고, 불안정한 기능은 이 구조 위에 얹어서 관리하는 것이 효과적이다.
4. 도메인 모델이란?
도메인은 사용자가 관심을 갖는 특정 분야다. 여기서 야구 경기 자체가 하나의 도메인이다. 이 도메인을 이해하기 쉽도록 선수, 기록, 점수 등으로 나누어 구조화한 것이 바로 도메인 모델이다.
도메인 모델은 사용자(야구 팬, 기록원, 선수)가 야구를 이해하는 방식(사용자 모델), 설계자가 생각하는 야구 시스템의 구조(디자인 모델), 실제로 만들어지는 소프트웨어의 모습(시스템 이미지)을 모두 연결하여 만든 것이다. 도메인 모델이 잘 설계되면 사용자의 멘탈 모델과 소프트웨어의 구조가 매우 흡사해진다. 이것은 곧 사용자가 시스템을 직관적으로 이해할 수 있게 한다.
사용자 모델: 팬들이 야구를 이해하는 방식
디자인 모델: 개발자가 시스템을 구조적으로 보는 방식
시스템 이미지: 실제 만들어진 소프트웨어의 최종 모습
5. 유스케이스(Use Case): 야구 예시
유스케이스는 사용자와 시스템이 어떻게 상호작용하여 사용자의 목표를 만족시키는지를 이야기 형태로 나타낸 것이다. 야구로 예를 들어보자.
사용자(야구 팬)는 앱에서 현재 경기 정보를 실시간으로 확인한다.
기록원(Recorder, 내부 시스템 관리자)은 경기 현장에서 발생한 사건("3번 타자가 2루타를 침")을 시스템에 입력한다.
시스템은 이 요청을 받아 경기(Game) 객체에게 전달한다.
Game 객체는 입력된 정보를 기반으로 새로운 기록(Record)을 생성한다. (이때 기록은 "2루타"라는 타입을 가지며, 선수와 관련 정보를 갖는다.)
Game 객체는 생성된 Record 객체를 자신이 관리하는 기록 목록(List)에 추가하여 저장한다.
ScoreBoard는 새로운 기록(2루타 등)을 기준으로 점수를 업데이트한다.
이 유스케이스는 '안타를 기록하는 것'이라는 사용자 목표와 관련된 모든 시나리오를 담는다. 기능 목록을 단순 나열한 것이 아니라, 사용자가 무엇을 하려는지 이야기의 맥락에서 설명한 것이다.
6. 책임 주도 설계 (객체 협력)
이제 시스템에 들어온 유스케이스("안타를 기록한다")를 객체들의 책임으로 변환해보자.
❓ 어려웠거나 이해가 부족했던 부분
💭 궁금한 점
💡 토론해 보고 싶은 질문
🌟 인상 깊었던 책의 내용
📌 기억에 남는 문장
🔎 적용 방법 고민
📚 관련 아티클 & 추가 자료
🔗 추천 자료
All reactions