3주차를 시작하며 - 앞으로는 <할 수 있는 부분>에 집중하기로

 어느덧 프리코스의 절반이 지났다. 2주차 미션이 끝나고 다른 사람들이 제출한 코드들과 회고들을 살펴봤다. 우테코가 선발 과정이 아니라 양성 과정임을 잘 알곤 있지만, MVC패턴이라든지 stream이라던지 내가 잘 모르는 것들을 도입해서 미션을 해결하는 사람들을 보며 조금은 주눅이 들었다. 열정있고 실력있는 사람들과 함께하는 환경에서 공부하고 싶은 맘에 우테코를 지원하기도 했었고, 저런 사람들을 보면서 자극도 받으면서 "자바를 이번에 시작해서 잘 모를 뿐 내가 공부하면 더 예쁘게 코드 짤 수 있어!"라는 나름의 의욕도 생겼지만, 한 편으로는 어찌됐든 나보다 더 실력있어보이는 이 사람들 사이에서 내가 선발될 수 있을까라는 불안감이 들었다.

 

 그러다가 2시에 코수타를 통해 포비 님의 조언을 듣게 됐다. 나처럼 주눅이 든(?) 사람들에게 해주는 말이었는데, 바로 "할 수 있는 것에 집중해서 해봐라!"라는 말이었다. (feat. TDD는 쓰레기다) 괜히 뭐 클린코드를 지향한다고 처음부터 이것저것 좋은 것들을 싹 다 할라고 하지 말고, 우테코 미션에서 요구하는 내용들에만 집중해서 구현하려고 해봐라! 라는 의미였다.

 돌이켜보면, 나 역시 1 ~ 2주차 미션들을 진행할 때 각 미션의 요구사항들 뿐만 아니라 그 외에 추가적으로 이것저것 시도할려고 했었던 것 같다. "있어 보이기 위해" 커밋메시지를 죄다 영어로 작성했고, 잘 할 줄도 모르는 TDD 한 번 해본다고 테스트 먼저 만들고 프로덕션 만들기를 어설프게 시도했었다. 그런데 이것들이 해당 주차에서 우테코가 요구하던 것들이었는가? 커밋메시지 컨벤션을 지키라는 말이 있었을 뿐 한글/영어에 대한 제한은 없었고, TDD를 사용해라 라는 말 역시 없었다. 우테코가 원하던 것은 코치님들이 메일로 명시했던 "함수 분리 연습 및 테스팅 도구에 익숙해지기"이지 영어로 뽀대나게 커밋메시지를 작성하는 것이나 TDD를 도입한 개발에 익숙해지기가 아닐 것이다. 물론 내 딴에는 "이번 기회를 통해 성장하기 위해서, 습관을 들이기 위해서"라는 명목으로 저런 것들을 시도할려고 했던 것이고, 그것들이 결코 안 좋은 일들은 아닐 것이다. 그러나 되려 왠지 모를 조바심에 내가 너무 많은 걸 할려고 했던 게 아닐까.

 생각해봤다. 내가 지금까지 프로그래밍을 공부하면서 함수 분리에 신경을 쓰려 했던 적이 있었나? 테스트란 걸 해볼려고 했던 적이 한 번이라도 있나? 이 질문들은 우테코의 2주차 미션의 목표였다. 함수 분리? 이렇게까지 한 함수가 하나의 기능만 하게 하려고 기를 쓰고 해본건 이번이 처음이다. 테스트? 테스트 코드 자체를 이번에 처음 해봤다. 그리고 이걸 통해서 "한 함수가 하나의 기능만 하게 만드는 걸 통해 좀 더 읽기 좋고 고치기 쉬운 코드가 만들어지는군! " 이란 걸 느낄 수 있었고, "내가 직접 프로그램 수행해서 입력해볼 필요 없이 클릭 한 번으로 테스트가 가능하다고? 너무 편하잖아! "도 느낄 수 있었다. 굳이 뭐 커밋메시지 영어로 쓰고 TDD할려고 하려고 하고 이런 거 필요없이, 우테코에서 제시한 목표를 이루려고 하는 과정에서 조금씩 성장한 내 모습을 볼 수 있었다.

 

 솔직히 말하면, 나는 우테코에서 제시한 목표들을 파고드는 것도 빡세다. 저번 2주차만 해도 내가 함수 분리에 얼마나 많은 시간과 고민을 투자했었는가. 그런데 내가 커밋메시지를 영어로 쓴다고 계속 papago번역기 돌리면서 얼마나 많은 시간을 "날렸는가". (뭐 내가 영어를 잘 못하기 때문인 것 같기도..)  사실 한글로 써도 되는 부분이다. 배보다 배꼽이 더 커지면 안된다. 미션의 목표를 달성하려는 과정에서 성장할 것이고, 거기에 집중해야 한다는 생각이 들었다. 그 외에 집중하는 게 더 많아지면 안 된다.

 

 MVC패턴, stream..다른 사람들의 코드엔 뭐 SOLID의 ocp원칙에 위배된다는 류의 피드백이 달리는 것도 봤다. 지금의 나에겐 다른 차원의 피드백으로 느껴진다. 솔직히 대단하다. 그 정도로 코드를 보는 안목이 있다는 건 그 사람의 실력이 그만큼 엄청나다는 반증이다. 그렇다고 해서, 내가 MVC같은 걸 꼭 써야 한다는 강박은 갖지 말자. 당장 이번 3주차 미션의 목표는 클래스 분리 연습과 도메인 로직에 대한 단위 테스트 작성 연습이다. 이 두 목표를 달성하려는 과정에서도 나는 성장할 거다. 왜? 저런 걸 안 해봤으니까. 그 과정에서 MVC를 도입하는게 더 좋을 것 같다 이런 생각이 들면 써도 되겠지만, 처음부터 "다들 MVC쓰는 거 같으니까 나도 해야 돼!! "라는 생각으로 잘 모르는 MVC를 어설프게 하려고 하지 말자.  그거야말로 배보다 배꼽이 커지는 상황일 것이다.

 

 지금의 내가 할 수 있는 것에 최대한 집중하자. 미션의 목표로 주어진 내용을 달성하려고 하는 것에 집중하자. 저번 2주차에서 느꼈듯이, 그 과정에서 분명히 성장할 것이다. 최대한 우테코가 제시하는 목표를 달성하려고 하다보면, 선발 여부에 관련없이 스스로 돌이켜봤을 때 전에 비해 많은 성장을 했을 것이고, 내가 나아간 방향도 올바른 방향일 것이다.


클래스 분리 및 도메인 로직 분리 - 오랜만에 마주한 벽

이번 주 학습 목표는 

  1. 클래스 분리 연습
  2. 도메인 로직에 대한 단위 테스트 연습

이다. 이 둘을 중심으로 파고들기로 맘먹고 클래스 분리부터 해보자고 생각했다.

 

 2주차 미션을 진행하며 야구게임기 / 검증기 / 출력기 라는 3개의 객체로 분리해 코드를 짜긴 했지만, 이것보다 좀 더 심화된 객체분리를 연습해보는 것이 미션 취지에 맞다고 생각했다. 역할에 따라 분리하면 되겠거니 했지만 감이 잘 잡히지 않았다. 해본 적이 없었기 때문이다..그러다가 2주차 피드백에 실려있던 강의영상을 떠올렸다. 제이슨 코치님이 기능 목록을 정의한 후 각 기능들을 어떤 클래스가 수행하게 할지 정하고 클래스를 만드셨는데, 이 방법을 내 기능 목록에도 적용시켜 보기로 한 것이다.

 이 방법을 통해 기능 목록의 각 기능들을 어떤 클래스가 수행하게 할지, 메서드 이름은 뭘로 할지 가닥을 잡을 수 있었나. 크게 입력기 클래스 / 출력기 클래스 / 검증기 클래스/ 생성기 클래스 등으로 역할에 따라 분류했는데, 머지 않아 안개에 가려져 잘 안 보였던 큰 산 하나에 도착하게 됐다. 바로

 

도메인 로직과 UI로직을 분리해 구현하기

이거 구글 쳐서 나오는거 가져왔는데 저작권 문제 걸리나요..그럼 삭제하겠습니다 ㅠ

 정말 그게 뭔데 그 잡채였다. 내가 아는 도메인은 url창에 관련된 그 놈밖에 없는데..분위기상 그걸 말하는 건 아닌 것 같았다. 저번 주에 테스트 코드를 접하면서 테스트 코드에 대해 공부했듯이, 이번에도 도메인 로직이나 UI로직이 뭘 말하는 건지부터 공부해야겠다는 생각이 들었고 구글링부터 시작했다.

 

근데 시간이 그리 많이 걸릴 줄 몰랐지..

 

 도메인 로직, 즉 비즈니스 로직이 뭔지 설명하는 글들은 제법 있었지만, "결국 추상적인 말이다"라는 느낌을 세게 받았다. UI로직이 사용자와 상호작용하는 로직, 즉 입출력에 관한 것을 말한다는 건 금방 이해됐지만 도미엔 로직 이 놈이 문제였다. 일단 도메인이란 "해결하고자 하는 문제 영역"이란 의미를 가진다고 한다. 그러면 도메인 로직은 "해결하고자 하는 문제 영역에 대한 로직 주어진 문제에 대한 해결을 이끌어내는 로직"이 된다. 

 처음에는 음~ 이었다. 5초 뒤 응? 이었다. 해결해고자 하는 문제 영역에 대한 로직이란 건 알겠는데, 그 범위를 어디까지 봐야 하는지를 모르겠다. 한 마디로 추상적인 개념이라고 느껴졌다. 유효성 검사 로직을 예로 들면, 유효성 검사 자체가 문제에 대한 해결은 아니니 도메인 로직으로 보면 안 된다고 생각할 수도 있지만 문제에 대한 해결을 이끌어내는데 필요하니 도메인 로직이라고 볼 수도 있다고 느껴졌다. 코에 붙이면 코걸이, 귀에 붙이면 귀걸이처럼 생각하는 관점에 따라 도메인 로직이라고도 아니라고도 부를 수 있는 것 같아 엄청난 혼란이 느껴졌다. 

 개인적으론..이런 추상적인 개념들은 어떻게든 이해를 하고 넘어가야 하는 성격이다. 애시당초에 이 개념에 대한 이해가 없으면 이번 미션 진행이 힘들기도 할 것이다. 이대로는 안된다는 생각이 들어 구글링을 계속 했다..

 

 그러나 답을 찾지 못 했다. 심지어는 도메인을 명사로 부르는 경우도 있는 것 같아 더욱 혼란스러웠다. 해결하고자 하는 문제 영역을 도메인이라 하는 것 같은데, ~~하는 것의 도메인은 OO, OO, OO입니다 이런 식으로 명사로 부르기도 하는 걸 봤다. 혼란은 더욱 가중됐다. 도대체 도메인이라는게 구체적으로 뭘 말하는건지? 도메인 로직은 그럼 구체적으로 뭘 말하는건지?

 

 여기서 끝이 아니었다. MVC패턴 같은 걸 남들 다 쓰니까 나도? 라는 생각으로 쓰지 말자고 다짐했건만, 도메인 로직을 알아보던 중 MVC패턴이 도메인 로직과 UI로직을 분리하기에 좋다는 말을 듣게 됐다. 나도 모르게 무의식적으로 MVC패턴을 써야한다는 생각이 스며들기 시작했다. 그러면 따로 도메인 패키지를 만들어서 클래스들을 넣어야 할 것 같은데, 어떤 파일들을 넣어야 하지? 라는 생각이 들었다. 아직 도메인이 뭔지도 정확히 잘 모르겠는데? 라는 상황이었고, 잘 모르고 써본 적도 없는 MVC패턴을 써야 한다고 생각하니 너무 답답했다.. 

 프로그래밍을 공부하고 얼마 지나지 않아 마주친 포인터의 벽. 알고리즘 공부를 시작하며 느꼈던 재귀의 벽. 그리고 이번에 또 하나의 벽을 마주하게 되는 느낌이었다. 내가 잘 모르는 개념들, 별로 해본 적 없는 구조를 주어진 시간 내에 이해하고 구현할 수 있을까? 라는 생각이 들기 시작했다.

 

 그러다 포비 코치님이 해주신 말씀이 떠올랐다. 1주차가 끝나고 코수타를 진행할 때 해주신 "기능 목록이나 메서드 분리의 답은 없다! 스스로가 자신의 기준을 만들어 나가야 한다!" 라는 말씀이었다. 결국에 추상적인 개념이라면, 스스로의 기준을 만들어 가야 하는 것이고 도메인 로직 역시 내가 나만의 기준을 만들어야 한다는 생각이 들었다. 이게 맞는지 모르겠지만, 물론 맞다 틀리다가 있는지도 모르겠지만, 나름대로 사용자와 상호작용하는 로직을 UI로직으로 분류하고 원하는 것을 도출하는 로직을 도메인 로직으로 분류하기로 일단 기준을 잡아보기로 했다. MVC패턴? 처음에 3주차 미션을 시작하며 했던 다짐인 "할 수 있는 것에 집중하기"를 다시 한 번 상기시켰다. 이번 주 목표인 클래스 분리 연습에 초점을 최대한 두고, 메서드 분리나 함수 네이밍같은 부분(2주차가 끝나고 피어리뷰를 할 때 네이밍을 잘 한 것 같다고 칭찬들을 해주셔서 메서드 네이밍만큼은 남들보다 잘 하고 싶다는 생각이 있기도 했다)을 좀 더 신경쓰자!!라고 생각하며 다시금 멘탈을 잡을 수 있었다.

 

 확실히 느낀 건, 메서드 분리보다 클래스 분리가 훨씬 더 어렵다. 한 메서드가 하나의 기능을 하도록 분리하는 것도 물론 쉽지 않지만, 클래스 분리는 메서드 분리보다 개인의 주관이 좀 더 많이 들어가는 문제라고 느껴졌기 때문이다. 대표적으로 이걸 느꼈던 건 "검증(validation)"이었다. 금액 입력에 대한 유효성 검사, 당첨 번호 및 보너스 번호 입력 시 유효성 검사가 필요해서 나는 이걸 검증기 클래스들을 따로 만들어 구현했었다. 왜냐면 내 클래스 분리의 기준은 "역할"이었으니까. 그러나 이번 미션에서는 Lotto클래스에서 validate메서드를 호출해 검증하는 작업을 해야 했었다.! validate메서드의 내부에서는 실제로 검증을 수행하는 코드가 들어있었다. 내 생각은 검증은 따로 클래스를 만들고 그 클래스를 통해 수행하는 게 맞는 것 같은데, 왜 로또 객체 내부적으로 검증을 수행하게끔 하는거지? 라는 생각이 들었다. "로또 번호 검증"에서 "검증"에 포커스를 두면 검증기 클래스에서 담당하는게 맞고, "로또"에 포커스를 두면 로또 클래스에서 담당하게 할 수도 있다는 생각이 들었다. ..이런 부분에서 개인의 주관이 좀 더 들어가는 문제라고 느껴진 것이다. 이것 역시 나만의 기준을 만들어야 한다는 생각이 들었고, 지금 당장은 역할에 따라 구분하는 게 좋다는 생각이 들었던만큼 검증기 클래스를 따로 만드는 식으로 진행했다. Lotto의 validate는 검증기 객체를 이용한 검증을 하는 식으로 바꾸고.

 

클래스 분리를 이번에 연습하며 느낀 장점? 일단 확실히 한 파일의 길이가 짧아진다. 그리고 나중에 기능을 수정할 땐 그 역할에 맞는 클래스만 수정하면 됐다. 근데 이런 장점보다도 솔직히 고통스러웠던 시간의 임팩트가 훨씬 길었다..고통이 장점으로 얻는 달콤함을 압도하는 느낌..


도메인 로직에 대한 단위 테스트 작성 - private vs public..이거 뭔가 잘못됐다..?

 저번 주 미션에서는 TDD를 한 번 해보겠다고 설치면서 테스트 코드를 먼저 만들고 프로덕션 코드를 나중에 만드는 식으로 진행했었다. 그러나 이번 주부터는 "할 수 있는 것에 집중하기"를 다짐한 만큼 어설픈 TDD를 잘 해보겠다고 깝치지 말고 우테코에서 제시하는 요구사항과 목표들에 포커스를 맞추기로 했다. 즉 테스트 코드 먼저 만들고 프로덕션 코드 만들기라는 방식을 쓰지 않았다.

 

근데 문제는, 그렇다고 내가 아예 테스트 코드를 모든 기능의 구현이 다 끝날 때까지 한 개도 만들지 않았다는 것..

 

"안 돼!! 멈춰!! 돌아가서 테스트 코드를 짜!!"

 

 모든 기능의 구현이 끝나고 나서야 테스트 코드의 작성을 시작했다. 1주차 미션을 통해서 기능 목록을 정의하는 나만의 기준을 세웠었는데, 그건 바로 목록의 각 기능들이 하나의 메서드 또는 코드에 대응하도록 만드는 것이었다. 2주차 때 이런 식으로 기능 목록을 세우는 걸 연습했던 만큼, 이번 3주차 역시 기능목록의 각 항목들이 하나의 메서드에 대응하는 구조였다. 즉 이 메서드들을 테스트 코드로 테스트하는 식으로만 만들면 그것이 단위 테스트가 될 것이다!

 

 라고 생각하고, 내가 생각한 도메인에 해당하는 각 클래스별로 테스트클래스를 만들면서 테스트코드들을 만들었지만..문제에 봉착했다. 테스트를 진행할 수 없었다. 왜냐하면..2주차 미션의 피어리뷰 당시 죄다 public으로 작성한 점을 지적받았어서, 이번엔 외부에서 호출할 수 있는 메서드말고 내부적으로 쓰는 메서드들은 죄다 private로 만들었기 때문이다.. 물론 다시 public으로 돌리면 될 일이다. 다 public으로 돌린다고 본 미션에서의 지장은 없다. 그러나 죄다 public으로 할 때 드러나는 단점이 너무나도 명확하지 않은가. 외부에서 함부로 다 쓸 수 있게 하는 건..좋지 않다. 내가 채택한 클래스 분리가 이런 결과를 도출해낸 건가? 다른 식으로 클래스 분리를 해야했던 걸까? 라는 생각들이 들었다. 그러나 시간이 충분하지 않았다. 클래스 분리 과정에서 그 죽일 놈의 도메인이 뭔지 따지던 과정에서 시간을 너무 많이 한 탓일까..팀플이 너무 많았던 탓일까....암튼, 다시 다 뒤엎고 처음부터 새 판을 짤 수 있을 시간은..솔직히 없었다..  할 수 없이 울며 겨자먹기로 public으로 돌리기를 선택했다. 단 멤버변수들은 private로 그대로 둬서 나름대로의 양심(?)은 챙겼다. 그럼에도 불구하고 메서드 단위로 테스트할 수 없는 부분이 존재했다. 예를 들어 LottoGameResult의 멤버변수로 earningRate(수익률) 변수를 뒀는데, calcaulateEarningRate를 수행한 다음 수익률을 확인할 수 있는 방법이 없었다. 왜냐면 내가 멤버변수들의 접근지정자마저 public으로 돌릴 순 없었서 private로 남겨뒀으니까!! 내 마지막 자존심이니까!! ㅠㅜ.. 이 부분은 할 수 없이 calculateEarningRate의 수행을 포함하는 더 큰 메서드를 수행하고 내가 원하는 로직이 이뤄지는지 확인하는 식으로 코드를 짰다.

 

 도메인 로직에 대한 단위 테스트 작성에 대한 연습이라..클래스 별로 단위 테스트를 진행하도록 만들면서 테스트 코드가 좀 더 깔끔해지는 느낌을 받았고, 도메인 로직들에 대해서만 테스트하며 중요한 로직에 대한 테스트 위주로 진행하는 게 중요하겠다라는 느낌도 받았지만..결국 아쉬운 감정이 크게 남는다. 좀 더 클래스 분리를 잘했더라면 어땠을까. 기능 구현 중간중간에 지금까지 만든 기능에 대한 테스트 코드를 작성하는 식으로 했으면 어땠을까. 등등과 같은..


그래도 성장했고, 배운 건 많다. 

 정말 힘든 고통의 1주일을 보낸 것 같다. 4개의 팀플, 가족모임, 알바를 제외한 모든 시간을 쏟아부었고 학교 개인과제는 전부 버리면서까지 시간을 투자했지만, 벽을 느끼는 순간들이 있었다고 할 수 있을 정도로 고통스러웠고 마무리한 후 뒤돌아보는 지금 이 시점에서도 개운함보다는 아쉬움과 찝찝함이 더 남는다. 지금 이 순간조차도 도메인에 대한 스스로의 기준이 구체적이지 않다. 이 죽일 놈의 도메인..

 

 그러나 뒤를 천천히 돌아보면, 물론 고통스러웠지만 그럼에도 배운 게 많다. 새로 배운 개념부터만 해도 enum이란 것이 있다. 열거형 이런 거 내가 3주차 미션을 시작하기 전까지는 잘 모르던 놈이었다. 그래도 이번 미션을 통해 enum이 뭔지를 알게 되고, 능숙하진 않아도 다루는 법을 알게 됐다. 클래스 분리를 통해 좀 더 읽기 좋고 재사용성이 좋은 코드를 짤 수 있다는 것도 알게 됐고, 구현이 다 끝나고 테스트 코드를 만드는 게 아니라 중간중간 만드는게 좀 더 좋다는 것도 느낄 수 있었다.

 

 고통스러운 시간이었고, 깨지고 부셔지는 시간들이었다. 그러나 전에 비해 성장한 게 느껴지고, 이 깨지고 부셔지는 것도 성장하는 과정에 포함되는 요소일거다. 성장하는 시간들이 달콤함만 있지는 않고 고통을 많이 수반할 거다. 그럼에도 포기하지 말고 나아가면, 더 큰 성장 더 맛있는 달콤함을 느낄 수 있을 것이다.

 

  이번 년도 롤드컵에서 DRX라는 팀이 우승했고, 데프트라는 선수가 데뷔 10년만에 우승하면서 "중요한 건 꺾이지 않는 마음"이라는 말을 했었다. 나도 꺾이지 않는 맘을 가지고 계속해서 나아가야겠다.

 

음..뭔가 오글거리는 것 같기도..

+ Recent posts