도메인 주도 설계 3부 독서 후기 Part.2 (feat. DDD)
안녕하세요. yeTi입니다.
오늘은 도메인 주도 설계 의 3부의 읽은 후기를 기록하려고 합니다.
3부의 2편입니다.
선언적 설계
선언적 설계는 대상에 따라 다양한 의미를 지닐 수 있지만 일반적으로 일종의 실행 가능한 명세(executable specification)로서 프로그램 전체 혹은 프로그램의 일부를 작성하는 방식을 의미한다. - p.289
선언적 설계는 프로그램을 생성하는 방법이 일종의 성배
에 해당한다는 구절을 보면서 이전에 안영회 대표님께서 알려주신 MDD
가 떠올랐습니다. (폭포수 방식 설계는 기술 부채를 남긴다)
해당 글에서 다음과 같이 언급합니다.
다양한 맥락을 포용해야하는 비즈니스 시스템에서 마치 '자동화' 결과물이 모든 프로그램을 대체하는 일인 것처럼 생각하면 큰 오산입니다.
결론적으로 MDD 의 결과물을 완전한 구현체로 생각하면 안된다고 말하는데 저도 동의합니다.
개발은 모델, 설계, 코드를 단일한 활동으로 정제하는 반복적인 과정이 된다. - p.50
에릭 에반스가 다양한 구성원간의 피드백 루프와 피드백 루프가 만드는 지식의 축적을 말했는데 MDD 는 피드백 루프에서 모델러와 도메인 전문가만 존재하게 됩니다.
모델을 개선하려면 개발자가 언어를 수정할 수 있어야 한다. 언어를 수정하려면 기반 클래스 라이브러리뿐 아니라 문법을 선언하는 방식과 언어를 번역할 때의 특징까지도 변경해야 할지 모른다. - p.291
에릭 에반스도 모델을 개선하기 위해서는 개발자가 언어를 수정할 수 있어야 한다고 말합니다. 왜냐하면 구현에 특성을 변경할 수 있기 때문입니다.
한편으로 자동화로 만들어진 소프트웨어의 품질은 어떻게 보장할 수 있을까 라는 의문이 듭니다. 왜냐하면 소프트웨어는 경험의 축적 수준에 따라 다른 결과물이 나오기 때문입니다.
여러 선언적인 접근법은 개발자가 의도적이든 의도적이지 않든 이를 우회할 경우 변질될 가능성이 있다. 시스템이 사용하기 어렵거나 과도하게 제한적일 경우 이런 문제가 발생하기 쉽다. - p.290
그리고 실무 경험에서 룰 기반의 자사 프레임워크를 사용하는 회사에서 근무한적이 있었는데 이러한 환경에서 개발자의 자율성이 사라지고 프레임워크에 대한 지식 공유가 제한적이라 오히려 개발을 어렵게 만드는 경험을 한 적이 있습니다.
코드 자동화 프레임워크가 이상향적 성배이지만 유용함을 제공하기에 쉽지 않다는 것을 느꼈던 경험이었습니다. 물론 단점만 있던것은 아니고 대외적으로는 굉장한 홍보 효과가 있긴 했습니다.
개인적으로 선언적인 접근법을 적용해서 가장 큰 가치를 얻었던 경험은 아주 좁은 범위로 한정된 프레임워크를 사용해서 영속성과 객체 관계형 매핑과 같이 매우 지루하고 오류가 발생하기 쉬운 설계 측면을 자동화한 경우였다. - p.290
왠지 하이버네이트를 생각나게하는 구절입니다.
앞서 안영회님의 글에서도 언급됐지만 구체적인 맥락하에서는 의미를 가질 수 있다는 것을 느낍니다.
에릭 에반스도 하이버네이트수준의 자동화는 긍정적으로 보는것처럼 느껴집니다.
선언적인 형식의 설계
타협점을 토대로 현재 여러분이 직면한 상황에 적절한 구현 방법을 찾아야 한다. 동일한 패턴과 모델이라도 구현 방법은 다양할 수 있다. - p.298
앞서 선언적 설계가 완전한 성배가 될수 없다는 얘기를 했습니다. 이를 한번 더 집고 넘어가 주는 느낌이 들어 생각이 연결됐습니다.
Specification 으로 논리연산을 구현하기 위해 Composite 패턴을 적용하기로 설계를 했습니다. 하지만 이를 구현하는 방법은 구현자의 상황이나 수준에 따라 다를 수 있다고 말합니다.
이는 TDD 를 보면서, MSA 를 알아가면서, 기술 부채를 생각해보면서 느꼈던 팀이 처한 상황에 따라 기술적으로 동일한 문제더라도 풀어가는 방법이 다르다는 것입니다.
안영회님께서 언젠지는 모르겠지만 지나가는 말로 해주신 말씀이 떠오릅니다.
현재 코드에서 해결점을 찾아야 합니다.
받음각
받음각이란 항공기 날개의 설계와 바람의 변화간의 상호작용을 표현한 단어입니다.
유연한 설계는 변화와 복잡도에 대처하는 소프트웨어의 능력에 깊은 영향을 미친다. - p.312
소프트웨어도 마찬가지로 설계 수준 따라 변화와 복잡도를 대처하는 능력에 영향을 미칩니다.
하지만 유연한 설계
를 하는 것은 말처럼 쉬운것은 아닙니다.
이에 에릭 에반스는 목표를 선정하라고 말하면서 조금씩 수정하고 역사적으로 정형화 개념들을 활용하라고 조언합니다.
그러나 종국에 소프트웨어를 유연하게 만들 수 있는것은 도메인을 이해하는 통찰력과 기술자가 사용할 수 있는 기법들이라는 생각이 듭니다.
분석 패턴의 적용
항상 부닥치게 되는 현실의 문제를 표현하고자 이런 꼬인 상황을 이야기에 집어넣었다. 우리는 적절한 절충안을 찾아야 하고, 찾아낸 절충안을 바탕으로 MODEL-DRIVEN DESIGN의 길에서 벗어나는 일 없이 앞으로 나아가야 한다. - p.320
계좌의 이자 수익 예제를 보면서 느꼈던 부분이 적절한 절충안을 찾아가는 와중에 모델을 중심으로 커뮤니케이션하는 부분이었습니다.
예제에서 마틴 파울러의 분석 패턴이라는 책에서 괜찮아 보이는 모델을 찾았고 실무에 적용해보니 적합하지 않다는 판단을 했습니다.
흔히 생각하는 도입할것이냐 말것이냐의 이분법적인 사고에서 벗어나 우리에게 적합한 모델을 만들어나가는 과정이 인상깊었습니다.
운 좋게 적용 가능한 분석 패턴을 알고 있더라도 분석 패턴이 현재의 특정 요구사항에 딱 들어맞는 경우는 거의 없다. 그럼에도 분석 패턴은 도메인을 파악하는 과정에서 훌륭한 길잡이 역할을 하며 깔끔하게 추상화된 어휘집을 제공한다. 이뿐만 아니라 구현할 때 고려해야 할 영향력에 대한 지침을 제공함으로써 장차 겪게 될 고통을 덜어주기도 한다. - p.327
다시 한 번, 분석 패턴을 알고 있더라도 해결책과 같이 답안을 제공해주지는 않는다고 말합니다.
이는 패턴을 알면 설계의 문제를 해결할 수 있는 답안을 제공받을 수 있다고 생각해봤던 것을 다르게 생각할 수 있는 계기를 제공해 줬습니다.
따라서 분석 패턴은 도메인 파악을 위한 길잡이로 활용할 수 있고 깔끔하게 추상화된 어휘집을 제공받을 수 있습니다.
그리고 side-effect의 고려도 되어있기 때문에 직접적인 시행착오를 줄일 수 있는 효과를 얻을 수 있습니다.
모델과 디자인 패턴의 연결 - STRATEGY
STRATEGY를 디자인 패턴으로 바라보는 전통적인 관점에서는 각기 다른 알고리즘 간에 상호 대체할 수 있는 능력에 중점을 두는 반면, 도메인 패턴으로 사용하는 관점에서는 프로세스 또는 정책적인 규칙과 같은 하나의 개념을 표현하는 능력에 중점을 둔다. - p.332
TDD에서도 켄트 벡의 관점에서 디자인 패턴을 설명해주던 부분이 실용적으로 다가왔었는데 DDD에서도 에릭 에반스가 도메인 패턴의 관점에서 설명하는게 쉽게 다가왔습니다.
그 동안 디자인 패턴 공부를 수차례 시도했지만 실패했던 이유가 수학 공식처럼 느껴져서 실무에서 어떤식으로 적용하고 활용해야할지 감을 잡기 어려웠기 때문입니다.
이번 장에서 strategy 패턴을 프로세스나 정책적인 규칙을 표현하는 하나의 개념으로 설명을 하니 업무적으로 공감이 되면서 현업 코드상에 표현해보고 싶은 부분이 떠오르기도 했습니다.
라우팅 서비스가 다음과 같이 정책을 표현했을 때 클라이언트 관점에서 분기를 통해 선택해야 합니다.
Routing Service
findFastest(Specification): Itinerary
findCheapest(Specification): Itinerary
하지만 라우팅 서비스를 다음과 같이 정책을 매개변수로 전달한다면 정책이 응집되는 효과도 있고 클라이언트 관점에서 분기문을 사용하지 않을 방법이 생깁니다.
Routing Service
find(Specification, Leg Magnitude Policy): Itinerary
이 설계에는 「디자인 패턴에서 설명하는 STRATEGY 패턴의 장점이 고스란히 담겨 있다. 애플리케이션의 융통성과 유연성 관점에서 보면 적절한 Leg Magnitude Policy를 선택하는 식으로 애플리케이션을 조절하고 확장할 수 있다. - p.333
지금까지 서로 다른 제어로직을 동일한 인터페이스로 제공한다는 기술적 목적을 가지고 strategy 패턴과 template 패턴을 바라봐서 그런지 어렵게 다가왔었습니다.
그러나 이번 기회에 정책을 표현하는 하나의 방식으로 생각하니 실무에도 충분히 적용해볼 수 있겠다고 느낄정도로 쉽게 다가왔습니다.
STRATEGY를 실제 업무 전략이나 정책과 연관시킬 때 패턴은 유용한 구현 기술 이상의 가치를 지닌다. - p.335
Strategy 패턴의 중심 개념은 대체 가능성이었습니다.
더 심층적인 통찰력을 향한 리팩터링 - 타이밍
지속적인 리팩터링은 "우수 실천법"으로서 확고한 지위를 얻어 왔지만 여전히 대부분의 프로젝트 팀에서는 이 부분에 지나치게 신중한 태도를 취한다. 팀에서는 코드 변경에 따르는 위험과 변경에 소요되는 개발자의 시간 비용은 인식하지만 부자연스러운 설계와 그러한 설계를 사용해서 작업하는 데 따르는 비용은 쉽게 깨닫지 못한다. 리팩터링 작업을 원하는 개발자는 종종 리팩터링을 해야 하는 당위성을 설명해야 하는 입장에 처하곤 한다. 리팩터링의 당위성을 묻는 이유가 합당하더라도 이로 인해 이미 어려웠던 작업은 불가능할 정도로 어려워지고 리팩터링 작업을 할 수 없게 되는(또는 공식적인 승인 없이 암암리에 하게 되는) 상황이 초래된다. 소프트웨어 개발은 변경의 이익과 변경을 하지 않음으로써 입게 되는 손실을 정확하게 계산할 수 있는 예측 가능한 프로세스가 아니다. - p.349
리팩토링을 바라보는 현업의 시각을 확하게 묘사하는것 같아 공감되는 문장이었습니다.
팀에서는 코드 변경에 따르는 위험과 변경에 소요되는 개발자의 시간 비용은 인식하지만 부자연스러운 설계와 그러한 설계를 사용해서 작업하는 데 따르는 비용은 쉽게 깨닫지 못한다. - p.349
실무를 진행하다보면 코드의 변경에 따르는 위험과 변경에 소요되는 개발자의 시간 비용은 인식하지만 부자연스러운 설계를 기반으로 제품의 코드를 만들때 발생하는 비효율성은 쉽게 깨닫지 못합니다.
한편으로는 개발팀에서 나가는 피드백 중 가능은 할꺼같다.
가 부자연스러운 설계의 원흉이 된게 아닌가라는 생각도 듭니다.
도메인 모델과 구현을 긴밀하게 소통하며 발전시켜왔다면 부자연스러운 설계가 지속적으로 변경되며 개선되었을것이라고 생각합니다.
리팩터링 작업을 원하는 개발자는 종종 리팩터링을 해야 하는 당위성을 설명해야 하는 입장에 처하곤 한다. - p.349
당연히 무언가를 원하면 당위성을 설명해야합니다. 그러나 켄트 벡이 말한 내 돈이라면 어떻게 할까 운동
처럼 비용기반으로 소통을 하면 당위성을 설명하기 쉬울것입니다.
소프트웨어 개발은 변경의 이익과 변경을 하지 않음으로써 입게 되는 손실을 정확하게 계산할 수 있는 예측 가능한 프로세스가 아니다. - p.349
소프트웨어의 변경에 따른 손익을 정확하게 계산할 수 없다면 투자자 / 관리자 / 운영자는 무엇을 기준으로 의사결정을 해야할까요?
XP에서 말하는 변화를 포용하라 와 TDD에서 말하는 작은 단위의 리팩터링이 떠오릅니다.
불확실한 미래를 인정하고 지금 할 수 있는 작은 단위의 일을 해나가며 피드백 루프를 가지고 있어야 합니다.
소제목이 타이밍인 것처럼 리팩터링이 당위성을 가질 수 있는 타이밍이 존재합니다.
더 심층적인 통찰력을 향한 리팩터링 - 위기를 기회로
리팩터링에 대한 고전적인 설명을 보면 리팩터링이 매우 안정적인 상태로 진행되는 것처럼 보인다. 더 심층적인 통찰력을 향한 리팩터링은 그렇지 않다. - p.350
리팩터링을 막연한 감정으로 느꼈을 때 좋은 것이라는 생각을 가지고 있고 리팩터링을 해나감에 따라 구현의 복잡도가 낮아질것이라는 기대감이 있습니다.
이러한 생각에 일격을 가할 수 있는 문장이라고 생각합니다.
리팩터링을 하다가 통찰력을 얻게 되면 기존 모델의 허점이 많아 보이게 되고 더 나은 이상향을 위해 개해야한다는 포부가 생깁니다.
그러나 어느 결정권자가 기존 잘 돌아가는 서비스의 모델을 변경하는 위험을 감수하겠습니까?
그리고 통찰력을 얻은 모델 위험을 감수하고 반영한다고 정하더라도 이후에 서비스적 이득을 가져올지, 잘못된 판단이었다는 회고를 할지 누가 알 수 있을까요?
역시나 통찰력을 통한 심층 모델로의 도약은 어려운 의사결정이 뒤따를것이라는 생각이 듭니다.
다시 한번 내 돈이라면 어떻게 할까 운동
이 생각납니다.
마무리
이번 장을 보면서 현재의 코드를 기반으로 적절한 해법
을 찾아나가는 것이 중요하다는 것을 느꼈습니다.
선언적 설계
라는 것도 완전한 모델이 코드를 선언한 것이 될 수 없다는 것처럼 선언적 형식을 취하여 코드는 현재 직면한 상황에서 적절한 구현을 찾으라고 말합니다.
받음각
도 날개의 각도에 따라 양력의 크기가 달라지는 것처럼 설계도 필요한 만큼 정의하는 것이 복잡도를 관리하는데 도움이 된다고 느껴졌습니다.
분석 패턴
이나 `디자인 패턴도 마찬가지로 정의된 답을 찾는 것이 중요한 것이 아니고 스스로가 처한 상황에서 필요한것을 취하기 위해 응용을 해보며 우리에게 맞는 구현을 찾아나가는 것이 중요합니다.
마지막으로 리팩토링은 지속적이고 작은 범위에서 진행하는 것이라고 말한다는 느낌이 들었습니다. 그리고 이는 개인 차원에서 하면 안되고 팀 차원에서 우리 서비스의 지속성을 위해 해야하는 업무라는 생각도 이어졌습니다.
이는 켄트 벡도 매일 작은 범위의 변경이라고 말하는 것과 같은 맥락으로 받아들여집니다.