책 10장을 읽고 다양한 의견을 댓글로 남겨 주세요.
책 10장을 읽고 다양한 의견을 댓글로 남겨 주세요.
솔루션 회사를 시작으로 컨설팅 회사 그리고 서비스 회사를 거쳐 지금은 스타트업에서 개발자로 일하고 있습니다. 주로 오픈소스 제품 개발, 기술 자문 및 코칭을 하고 있으며 기술과 인간의 상호작용에 관심이 많습니다.
[yeTi] 예티
2024-10-16 23:38 (수정됨)
실무에서 많은 시간 고민하며 스스로 얻은 결과를 켄트 백이 공감해주는 느낌을 받습니다.
SI 업계에서 개발하던 시절 인터페이스의 매개변수로 MAP 을 사용하던 시기가 있었습니다.
장점은 개발하기가 정말 편했습니다. 매개변수 특성에 따라 클래스를 추가적으로 생성할 필요가 없었고 매개변수의 변경이 필요해도 인터페이스를 변경할 필요가 없어 편했습니다.
단점은 매개변수의 기억이 흐려질수록 유지보수성이 떨어졌습니다. 이러한 환경에서는 API 의 변경이 쿼리의 변경으로 이어지거나 서비스 레이어의 인터페이스의 변경이 API 의 변경으로 이어지는 경우가 있어 변경의 부담이 가중되었습니다.
하지만 제가 경험한 SI 업계의 특성은 MAP 을 활용한 인터페이스가 유용했습니다. 왜냐하면 3개월정도 개발 후 검수만 통과하면 그 코드를 다시 볼 확률은 적었고 유지보수성의 어려움은 유지보수사업을 따내지 못했을 때 최소한의 분풀이로 동작했기 때문입니다.
지금까지의 경험은 다음 인용문을 읽고 떠오른 것들입니다.
코드를 읽으면서도 어떤 데이터가 필요한지 알기 어렵습니다. 또한, 이후에 매개변수를 변경하여 암묵적으로 사용하는 일과 같은 끔찍한 남용의 길이 열립니다. - p.57
이후에 두 가지의 실험을 해봤습니다.
매개변수를 MAP 을 대체하는 VO 객체로 전달하는 실험과 텐트 백의 예시처럼 명시적으로 드러나게 하는 방식입니다.
결론적으로 지금은 처음에는 명시적으로 드러나게 인터페이스를 정의한 후 매개변수가 인지범위를 벗어나기 시작하면 의미단위를 가진 VO 객체로 변경해가는 방식을 사용합니다.
최근에는 IDE 의 지원이나 AI 의 지원이 있어 번거롭지 않게 인터페이스만으로도 의도를 드러낼 수 있어 좋다고 생각합니다.
유영모
2024-10-21 02:38
SI 업계에서 개발하던 시절 인터페이스의 매개변수로 MAP 을 사용하던 시기가 있었습니다.
같은 경험을 공유하고 있는 듯하여 공감했습니다. :)
관련해서는 저도 비슷한 경험을 댓글로 남겼습니다.
nimkoes
2024-10-17 15:29 (수정됨)
흔히 함수(또는 메소드)의 시그니처라고 하면, 이름과 매개변수 리스트를 뜻합니다. 그리고 시그니처는 일반적으로 그것을 대표하는 특징이라고 할 수 있습니다. 다시 말해서 그 함수가 무엇을 하는지 한줄로 표현한 것으로 이해할 수 있습니다. 그렇기 때문에 더욱 명시적인 매개변수를 사용하는 것이 중요하다고 생각 했습니다.
함수(또는 메소드)의 시그니처는 이름과 매개변수 리스트를 의미하며, 이것은 그 함수의 대표적인 특징을 나타냅니다. 즉, 함수가 무엇을 하는지를 한 줄로 설명하기 때문에, 매개변수를 명시적으로 사용하는 것이 무엇을 하는 함수인지 전달하는 데 중요한 역할을 합니다.
명시적인 매개변수의 중요성에 대해 고민하다가, "얼마나 많은 매개변수를 나열해도 괜찮은가?"라는 현실적인 의문이 들었습니다. 호기심에 인간의 인지 능력을 조사하던 중, ‘밀러의 매직 넘버 7’ 이론을 알게 되었습니다.
이 이론에 따르면, 일반적으로 인간은 단기적으로 7±2개의 아이템을 기억할 수 있습니다. 이를 바탕으로 한다면, 최대 9개의 명시적인 매개변수를 사용하는 것이 이상적인 함수 > 시그니처일 수 있습니다. 하지만 이에 대한 반론도 있었습니다.
- 이후 다양한 연구에서 7이 아닌 4라는 결과가 나왔습니다.
- ‘매직 넘버’의 ‘매직’은 비유적인 표현이 와전된 것입니다.
- 절대적 법칙으로 적용하기에는 무리가 있으며, 상황에 맞는 구체적인 고려가 더 중요합니다.
조금 더 찾아보니, "기억의 단위는 단순한 개별 아이템의 개수가 아닌 의미적으로 묶인 하나의 덩어리(chunk)"를 의미했다는 것을 알게 되었습니다.
이로 인해 두 가지 생각을 하게 되었습니다.
마지막으로, 이 내용을 보면서 'PART 01 코드 정리법'에서 언급된 첫 문장이 떠올랐습니다.
저는 구체적인 것에서 출발해 추상적인 것으로 나아가는 학습을 선호합니다.
PART 1 의 세부 챕터의 흐름을 보았을 때, 함수 내부에서 외부로 설명의 시선이 옮겨지고 있다고 느껴져서 꽤나 치밀한 글쓰기를 한다고 생각 했습니다. (드디어 함수 밖으로 나온 느낌..)
유영모
2024-10-21 02:41
우연이네요. 저 역시 같은 의문감을 가지고 조지 밀러의 연구와 청킹에 대해 댓글로 기록했습니다.
Sunghoon Park
2024-10-21 14:55
함수의 시그니처 부분이 굉장히 공감 되네요 ㅎㅎ
자신의 계약과 역할을 제대로 명세하는 곳이 시그니처 특히 public/protected 의 시그니처라고 생각했어요 ㅎㅎ
거기에 더불어서 저는 예외(javadoc에 명세가 되었던, throws로 명세가 되었던)도 굉장히 중요한 시그니처라고 생각합니다.
오호 저는 MAP은 반대라고 생각해봤어요~!
자기 스스로 자신의 스키마를 표현할 수 없는 타입은 그 스스로 명시적인 설명이 불가하기 때문에
주변의 도움이 있어야만 자신을 설명할 수 있다고 생각했습니다 ㅎㅎ
가령 MAP은 그것을 만들고 수정하는 모든 코드들이 존재해야 자신을 표현할 수 있을테니까요~!
유영모
2024-10-21 02:04 (수정됨)
맵에서 매개변수가 블록으로 전달되는 경우가 흔합니다. 이렇게 하면, 코드를 읽으면서도 어떤 데이터가 필요한지 알기 어렵습니다. 또한, 이후에 매개변수를 변경하여 암묵적으로 사용하는 일과 같은 끔찍한 남용의 길이 열립니다.
2010년 초반으로 기억합니다. SI를 주 사업으로하는 모사의 프레임워크를 사용한 적이 있는데요.
함수의 시그니처가 대부분 비슷하더군요.
function foo(param : Map) : List<Map> {
// ...
}
이렇게 하면 뭐가 좋은지 물어 본적이 있습니다.
코드를 바꿀 일이 없다.
그렇습니다. 매개변수가 Map이고 반환하는 타입이 List<Map> 혹은 Map 이니 시그니처가 바뀔일이 거의 없었습니다.
하지만 그것 보다 훨씬 더 큰 문제가 있었습니다. 바로 인지의 문제였습니다.
값을 암묵적으로 사용하고 있었기 때문에 코드에 드러나지 않았습니다.
그렇기에 코드를 읽고 수정하는 것이 어려웠습니다.
또한 코드를 유지보수 할 때에는 변경 영향도 분석이 중요한데
영향도 분석을 매우 어렵게 했습니다.
Sunghoon Park
2024-10-21 14:48
악몽이 떠오르네요..ㅎㅎ
유영모
2024-10-21 02:23
프로젝트에 어떤 분을 만났는데 옆에서 함께 일했던 분이 저 사람이 짜는 코드가 독특해서 유지하기 어렵다는 말을 들었습니다.
그래서 코드를 보았더니 그 이유를 금세 알수 있었습니다.
언어는 자바였는데 메소드 호출 . 매개변수를 객체를 넘기고 있었는데 반환이 void 였습니다.
맙소사. 로직 결과를 매개변수 객체에 값을 다 넣고 있더군요.
객체가 레퍼런스 타입이라는 것을 이용한 것이었습니다.
매개변수로 사용했던 객체는 특정 메소드에서만 사용하는 것이 아니었습니다. 여러군데에서 돌려 쓰고 있더군요.
시간이 흘러 다른 프로젝트에서는 프론트엔드에서 자바스크립트를 이용하여 복잡한 차트를 만들고 있었습니다. 똑같은 패턴을 보았습니다.
버그 하나를 고치는데 일주일을 소비했는데 결과적으로 코드 한줄을 고쳤고.. 나머지는 코드를 분석하는데 시간을 썼습니다. 그 원인은 프로그래밍 방식에 있었습니다.
복잡한 코드에서 값이 어디서 어떻게 바뀌는지 알기 어려웠기에
결과를 예측하기 쉽지 않았기 때문입니다.
Sunghoon Park
2024-10-21 14:50
C, C++ 쪽에서는 이게 또 관례인것 처럼 들은 기억이 있습니다 ㅎㅎ
어쩌면 언어를 잘 안다고 하는건 이런 이디엄과 패턴들을 아는 것도 포함될 것 같아요!
유영모
2024-10-21 02:36 (수정됨)
책 예시 코드를 보자.
function foo(params)
foo_body(params.a, params.b)
function foo_body(a, b)
...a... ...b...
필요한 매개변수를 명시적으로 전달하고 있습니다.
그런데 매개변수가 2개가 아니라 5개, 7개.. 이렇게 많아지면 어떻게 해야 할까요?
애킨슨, 쉬프린의 다중 기억 모형에 따르면 인간의 기억은 감각 기억으로 들어와 주의를 통해 작업 기억으로 오게되고 작업 기억에서 장기 기억으로 넘어가게 된다고 합니다.
문제는 작업 기억 용량에 한계가 있다는 것인데요.
조지 밀러의 연구에서는 7±2 를 제시하고 있습니다. 한번에 인지할 수 있는 양이 7개에서 -2 개 혹은 +2개 라는 것입니다.
그래서 한계를 극복하기 위해 덩이짓기(Chunking)가 필요합니다.
저라면 매개 변수가 5개가 넘게 되면 하나로 다시 묶어 전달할 것 같습니다.
Sunghoon Park
2024-10-21 15:09
저도 공감합니다 ㅎㅎ
너무 많은 인자는 인지 부조화를 만들더라구요.
저도 5개 정도가 마지노선이 아닐까 해요!
Sunghoon Park
2024-10-21 15:25 (수정됨)
메서드 시그니처는 정말 중요한 개념이고, 이것에 따라 가독성이 크게 갈린다고 생각합니다.
그리고 여기에는 프로젝트명, 패키지명, 클래스명/파일명, 함수명, 인자 타입 & 이름, 리턴 타입 그리고 예외들이 모두 그 나름의 역할을 유기적으로 하고 있다고 생각합니다.
행위의 중심인 메서드 이름 기준으로 위의 요소들이 구성 된다고 생각하고, 그런면에서 그에 맞는 인자명은 물론 인자 타입도 고민해볼 필요가 있다고 생각합니다.
(Private Method는 제외)
의미를 가지는 클래스 타입들은(Collection, Pair 등등은 아닙니다.) 스스로 맥락을 잘 설명하지만, 그와 동시에 다른 맥락에서는 존재감으로 인해 오히려 그 맥락을 해치는 것 같기도 합니다.
저는 메서드의 인자를 명령으로 만들었을 때, 그 메서드의 시그니처가 진해진다고 생각합니다.
그래서 그 메서드를 위한 명령 클래스를 정의하고, 사용처들은 자신이 가진 데이터에서 그 명령을 만들어내는 책임을 가집니다.
이런 패턴들은 원래 의존성의 격리를 위해 시도했던 패턴들인데, 부수적으로 좋은 부분들이 보여서 선호하게 되었습니다. 위의 문단에서 언급한 제일 대표적인 장점 외에도, 사용처들이 자신의 데이터를 명령 객체로 바꾸는 과정에서 둘 간의 관계성이 잘 나타나는 것도 좋았구요.
[yeTi] 예티
2024-10-22 04:17
@Sunghoon Park 실무적인 궁금증을 가지고 있던 것을 언급해주셔서 인용해봅니다.
저는 메서드의 인자를 명령으로 만들었을 때, 그 메서드의 시그니처가 진해진다고 생각합니다.
코드적으로 이해했을 때, 메서드의 매개변수를 Command 클래스로 정의하는 것이라고 생각이 되는데요.
이 맥락이 맞다면 Command 클래스로 정의했을 때의 가치를 이해하고 있지 못하여 만남에서 설명 해주시면 감사드리겠습니다.
Sunghoon Park
2024-10-21 15:57
DDD에서는 Domain Entity를 사용하는 위치에 대한 전략으로
정해진 바운더리에서 사용해서 실용성을 높일지,
바운더리 내외부를 잘 격리하고 DTO나 VO를 이용하는 전략을 선택할지 고민을 하는데
그 선택의 기준이 Domain Entity의 오남용 방지가 되기도 합니다.
크게 생각해보지 못한 주제인데, 책 내용을 보니 이게 꼭 Domain Entity에 국한된건 아닌듯 해서 재미있었습니다.