촉촉한 코드, 건조한 코드

오인규·2023년 5월 28일
178
post-thumbnail

WET: DRY(Don't Repeat Yourself)의 반대 단어, Write Everything Twice의 줄임말이다

오늘 할 얘기는 타임머신이 있다면, 과거로 돌아가서 나 자신에게 해주고 싶은 이야기 입니다

중복 코드에 관한 이야기 입니다

공통 모듈 추출

제가 예전에 작업했던 코드에는 빨간색, 보라색 두가지 모듈이 있었습니다

제 친구랑 동료 한명은 빨간 모듈에서 새로운 기능을 개발하고 있었습니다

작업을 하던중에 유사한 기능이 보라색 모듈에 구현되어 있다는 것을 알게 되었습니다

둘의 기능은 거의 유사했기에, 그들은 보라색 모듈의 코드를 복사해서 빨간코드에 붙여 넣었습니다
그리고 저에게 코드 리뷰를 부탁했죠

저는 당시에 실용주의 프로그래머, 클린코더 등의 책에서 DRY 원칙을 배웠기 때문에, 중복을 제거하자고 했습니다

그들은 중복을 제거해 노란 모듈을 만들었고 빨간 모듈과 보라색 모듈이 노란 모듈을 의존하게 만들었습니다
새로운 추상화가 탄생하는 순간이였습니다

모든것이 좋아 보였습니다

공통 모듈 변경

그 코드들을 방치한 채로 시간이 흘렀습니다

우리는 새로운 기능을 개발하게 되었습니다

노란 모듈과 유사한 기능이 필요했는데, 비동기적으로 동작해야 하는 차이점이 있었습니다
기능에 약간의 차이가 있어서 바로 가져다 쓸 수는 없었고, 복붙을 해서 조금만 바꾸는 것은 나쁜 코드처럼 느껴졌습니다.

DRY 원칙을 위반하기 싫어서 두가지를 통합하기로 했습니다

두가지는 통합되었고, 우리는 굉장히 만족했습니다

코드가 기괴해 보이기는 했지만, 현실은 이런거야 하고 넘어갔습니다

공통 모듈에 예외 케이스 추가

새로 만든 기능에서 버그를 발견했습니다

노란색 공통모듈에서 발생하는 것이였습니다
우리는 코드를 통합할때 완전히 같은 기능이라고 생각했지만(async를 제외하고), 사실은 약간 다른 동작이 필요했던 것입니다!

물론 공통 코드에 예외 케이스를 추가해서 해결할 수 있었습니다
남 얘기로 들리지만은 않는 일이죠?

공통 모듈 예외 케이스 제거

며칠뒤 우리는 기존 코드도 문제가 있다는 사실을 발견합니다

처음에 빨간 코드와 보라색 코드를 통합할때, 완전히 같은 코드가 필요하다고 생각했지만 사실은 그들도 약간 차이가 있던것입니다!

그래서 예외 케이스를 하나 더 추가하게 됩니다

이쯤 되니, 추상화가 이상하고 어려워졌습니다

추상화를 더 일반적이게 변경하고 예외처리를 호출하는 곳에서 처리하도록 변경했습니다

우리 추상화는 더이상 예외 케이스를 담당하지 않고, 일반적인 코드가 되었습니다

예뻐지긴 했지만, 아무도 이게 무엇을 나타내는 코드인지 모르게 되었습니다

아 그리고, 보라색 모듈에서도 버그가 발견되어서 예외 케이스를 추가했습니다

결과가 이상하게 느껴질 수 있지만, 앞선 내용들은 점진적으로 이루어 졌고 각 과정에서 아무도 이상함을 말할 수 없었기에 최종적으로 이런 코드가 남게 되었습니다

Many Months Later

그렇게 시간은 흘렀고, 누군가 팀에 들어오고 나가고, 누군가 여기 저기에 버그 픽스를 하기도 하고 기능을 추가하기도 했습니다

최종적으로 코드는 이렇게 되었습니다.

코드가 이렇게 되기까지의 모든 과정은 꽤 납득할만 했습니다.
코드가 거대해지며 맥락을 파악하기 점점 힘들어 지고, 작업자가 변경됨에 따라서 코드의 맥락이 끊어지기도 하고, 순환 참조가 생기기도 하고, 각종 이상한 것들이 추가됩니다.

현실 세계에서는 아마 이 코드가 최종본에 가까울 것입니다.

아무도 이 코드를 건드고 싶어하지 않을것이고 어느날 누군가 코드를 재작성 할지도 모르겠네요.

현실 세계에서는 이렇게 끝나겠지만, 이건 글이니까 우리가 타임머신이 있다고 가정해서 과거로 돌아가서 고칠 수 있습니다.

타임머신

타임머신이 있다면 돌아가고 싶은 시점은 2번째 추상화가 시작되는 시점입니다

공통화할 코드에 약간의 차이가 있지만 현실과 타협을 하고 이상한 추상화를 시작한 시점입니다

이 시점에서 저는 추상화를 깨고 inline 시키자고 말했어야 합니다

inline 시킨다는 뜻은 공통 코드를 없애고 각각의 사용처에 코드를 복붙 하는것을 의미합니다


잠재적 괴물의 예시

복붙은 코드 중복을 만드는 단점이 있습니다, 하지만 우리가 앞서 본 잠재적 괴물을 물리쳐주는 장점도 있습니다

중복은 장기적 관점에서 좋지 않습니다, 그런데 잘못된 추상화 또한 장기적 관점에서 좋지 않습니다
따라서, 두가지를 모두 고려해서 복붙한 코드를 시간을 두고 관찰할 필요가 있습니다

추상화를 깬 세계선에서는 빨간색 모듈에서 버그를 발견하고 사실 다른 동작이 필요하다는 것을 알게 되었을때, 인라인된 구현을 변경할 수 있습니다

그리고 이는 빨간색 모듈에 고립되어 되어있기 때문에 다른 모듈에 영향을 주지 않습니다

유사하게 파란색 모듈에서 버그를 발견했을때도 인라인된 구현을 바꿀 수 있습니다

어느정도 시간이 흘러 코드가 안정화되어서 다시 보고 판단할때, 아마도 전과는 다른 공통점을 추출할 수도 있습니다

결론은, 추상화를 만들기 전에 우연적인 공통점인지, 본질적인 공통점인지를 판단하기 위한 시간을 어느정도 갖고 파악할 필요가 있다는 것입니다
고등학교 때 만난 여자애와 같은 인디밴드를 좋아한다는 사실 하나만으로 공통점이 많고 평생을 함께할 동반자라고 단언할 수는 없으니까요.

References

profile
FE Dev @naver

41개의 댓글

comment-user-thumbnail
2023년 5월 29일

시공간을 넘나드는 오인규 개발자님의 클린 코드를 향한 의지가 잘 드러나는 글이네요. 아직 타임머신이 완성되진 않았지만 과거에서 Approve 미리 눌러드리겠습니다. LGTM!

1개의 답글
comment-user-thumbnail
2023년 5월 31일

개발자의 기본템 타임스톤 보유

2개의 답글
comment-user-thumbnail
2023년 5월 31일

ㄱㅊ

1개의 답글
comment-user-thumbnail
2023년 6월 2일

너무 공감가는 포스팅입니다!
추상화를 과감하게 깨는것 또한 개발자가 갖춰야할 스킬 중 하나인 것 같아요

1개의 답글
comment-user-thumbnail
2023년 6월 2일

haha. fun!
connect 4

답글 달기
comment-user-thumbnail
2023년 6월 2일

혹시 코드 리뷰는 어떻게 하셨나요?

1개의 답글
comment-user-thumbnail
2023년 6월 3일

공감합니다. 결국에는 좋은 코드가 무엇이냐라는 코드관에 따라 다르긴하겠지만, 저도 1차원적인 이유로 모듈화를 진행하기보단 복붙을 하더라도 각 역할별 순수성을 유지하는게 좋다고 생각합니다

1개의 답글
comment-user-thumbnail
2023년 6월 4일

요즘 개발하다보면 자주 마주치는 문제인데 재밌게 읽었습니다. 감사합니다

1개의 답글
comment-user-thumbnail
2023년 6월 5일

공감가네요 ㅋㅋㅋㅋ

1개의 답글
comment-user-thumbnail
2023년 6월 5일

감사히 잘 읽었습니다!
요새 재사용에만 신경쓰다보니 이런 문제들을 마주하는 경우가 많았는데, 생각하는데 도움이 되었습니다!

1개의 답글
comment-user-thumbnail
2023년 6월 5일

잘봤습니다

1개의 답글
comment-user-thumbnail
2023년 6월 5일

저도 저런 상황에 처한 프로젝트가 하나 있는데 정말 건드리기도 싫습니다. ㅠ
설계를 아무리 잘해도 늘 저런 문제는 발생하더라고요. 그때그때 유연한 대응과 판단이 필요한것 같습니다. 천재가 아니고서야 모든 경우의 수를 다 파악할 수는 없으니까요.

1개의 답글
comment-user-thumbnail
2023년 6월 6일

좋은 글 감사합니다.

1개의 답글
comment-user-thumbnail
2023년 6월 7일

시간을 두고 충분히 검토한 뒤에 통합할 것.
성급한 통합은 코드중복보다 나쁠 수도 있다.
많이 공감되네요
좋은 글 감사합니다

1개의 답글
comment-user-thumbnail
2023년 6월 7일

글 재밌게 잘 읽었습니다! ㅋㅋㅋ 너무나 재밌고 간결하게 정리해주셔서 너무 좋은 글이 되었던 것 같습니다.
확실히 저도 추상화를 할 때 이게 맞는건지 항상 의심이되고 결과적으로는 수많은 버전의 중복과 기능의 차이가 발생하는 경우가 많은 것 같습니다. 이를 섣부른 추상화 이전에 알아차리기란 어려운점이고 그래서 시간이 지나고서야 비로소 잘못되었다는 것을 깨닫는 경우가 많은 것 같습니다.
물론 수많은 경험을 통해서 이를 사전에 방지하는것도 좋지만 경험이 없는 프로그래머를 위해 이를 사전에 알아차릴 수 있는 장치가 있으면 어떨까 하는 생각도 드네요. 물론 선택의 연속이 프로그래머의 역할이라고 생각하지만 경험이 적은 저로써 이런 생각을 해봅니다!

1개의 답글
comment-user-thumbnail
2023년 6월 7일

감사합니다 😆

1개의 답글
comment-user-thumbnail
2023년 6월 11일

너무 재밌게 잘 읽었습니다. 쏙쏙 들어오네요

1개의 답글
comment-user-thumbnail
2023년 6월 14일

이런 인사이트를 이렇게 쉽고 재밌게 설명해주시다니..감사합니다!

1개의 답글
comment-user-thumbnail
2023년 10월 22일

저는 이럴때 사수님을 호출하고 턴을 종료합니다.

답글 달기
comment-user-thumbnail
2023년 11월 8일

우연히 왔다가 인규님의 좋은 글 보고 갑니다~ 저도 무턱대고 공통화!! 하면서 합쳐버린 코드들도 많았던 것 같은데 좋은 인사이트 얻어갑니다 ㅎㅎ

한 가지 궁금한 점은.. 공통화된 코드에서 약간의 변경이 필요해지는 시점(이 글에서 세번째 친구가 찾아오는 시점)에 공통화된 코드를 좀 더 아토믹하게 쪼갠 후 재조립해서 사용하는 건 어땠을까요? 아마도 같은 생각을 해보셨을 것 같은데 인규님 경험이 궁금합니다~

1개의 답글
comment-user-thumbnail
2024년 4월 24일

좋은 글 감사합니다! :)

답글 달기