회고록이라는걸 처음써봐서 어떻게 써야할지 잘 모르기에 느낌가는대로 써보려고 한다.
1주차 미션코드 깃허브
https://github.com/woowacourse-precourse/java-baseball-6/pull/2253
[숫자 야구 게임] 신권일 미션 제출합니다. by shin5774 · Pull Request #2253 · woowacourse-precourse/java-basebal
1주차 숫자 야구 게임 미션입니다. 처음이고 여러가지를 시도해봐서 미숙하지만 열심히 해봤습니다.
github.com
서로 코드리뷰 해주면 좋을것 같습니다! 저도 열심히 할게요!
주차 시작전
이번 주차에서의 나의 목표는 '몰입해보자' 였다.
이는 작년 우테코 프리코스에 참가했을때 학업과 겹쳐서 제대로 미션을 수행하지 못한것에 대한 후회로부터 비롯된 것인것 같다.
올해는 졸업학기인 관계로 학교도 거의 안나갔기에 '몰입'에 적절한 환경을 가추고 있었고 남은건 의지뿐! 최선을 다해보자는 생각으로 1주차 미션에 돌입했다.
주차를 진행하며
1주차 미션은 작년 미션중 하나였던 숫자 야구여서 상당히 익숙했다. 이로 인해 어느정도 여유로움이 생겼고, 작년의 성찰점을 하나씩 개선하면서 우테코에 적응하는 과정을 거쳐보기로 했다.
이번주차의 중점 목표
1. TDD(Test-Driven-Development)를 적용해보자
작년 나는 기능구현에 급급해서, 프로덕션 코드를 주구장창 작성하고 이후에 '아! 테스트코드!' 라면서 뒤늦게 채워넣는 느낌으로 미션을 수행했다.
이러다 보니 실제 테스트 코드의 의도를 제대로 지키지 못했다. (실제 테스트도 그냥 main함수 돌리면서 했다.)
올해는 달라진다는 마음으로 시간도 많겠다. TDD를 제대로 경험해보자! 라는 마음으로 기능 구현을 시작했다.
하지만 본인, TDD 처음해보는 늅늅 개발자(희망). 우선 정보부터 찾아보자!
우테코 프리코스 디스코드에 양질의 정보들이 많이 올라왔다.
해당 채널에서는 1주차동안 필요한 정보들을 많이 얻을수 있었다.
추가적으로 TDD를 진행하는데 있어서 도움이된 사이트 링크를 걸어둔다.
1. https://hororolol.tistory.com/518 (TDD에 대한 기본적인 과정이 나와있음)
TDD(Test-Driven Development) 연습해보기 - 예제 1: Money (1) 1~8장
"테스트 주도 개발 Test-Driven Development: By Example" 책에 나오는 예제를 실제로 구현해보자. 프로그래밍 순서 빨강 - 실패하는 작은 테스트를 작성한다. 처음에는 컴파일조차 되지 않을 수 있다. 초록
hororolol.tistory.com
2. https://www.youtube.com/watch?v=bIeqAlmNRrA (TDD에서 리팩토링까지의 상세한 예시.)
2. 객체지향 생활체조 9원칙을 적용하자!
이 단어의 경우는 올해 처음 들었던 원칙이었다. 그래서 이게 뭔가 하고 찾아보니(정확히는 위 영상에 나옴) 어디서 많이 본 조건이었다.
그건 바로..
작년 프리코스 미션의 제약사항이었다..! (이걸 이제 알아버린 나도 대단하네..)
이때는 왜 저렇게 번거로운걸 하는걸까? 라는 의문점만 가지고 흔히 말하는 까라면 까야지라는 생각으로 했다.
이번에는 위의 영상을 먼저 봐서 그런지 이 원칙을 통해 일어나는 효과에 대해 알게되었다.
3. 남들의 방법론에 너무 매몰되지 말자!
엥 앞에서 TDD니 9원칙이니 한다고 해놓고 갑자기 방법론에 매몰되지 말자는 무슨 말이지? 싶을거다.
작년을 되돌아보면, TDD니 MVC니 OOP라는 말을 하는 다른 참가자들을 보면서 멋있다고 생각했다.
나랑 비슷한 나이대에 저런걸 잘 적용할수 있는 사람은 얼마나 대단한거지? 라는 동경이라는 감정이 뒤따라왔다.
동경은 곧 '난 여태까지 뭘한거지..?'라는 자괴감을 만들었고 이를 극복하려고 그들의 개발방법을 무작정 따라가기 시작했다. 그 결과, 코드는 이도 저도 아닌 애매모호한 코드가 되었고, 프리코스가 끝나고 머리속에 남는건 아무것도 없었다.
상당히 후회되는 행동이었다.
올해 프리코스도 디스코드에 들어오자마자 수많은 참가자들이 정보를 공유해주기 시작했다. 당연하게 거기에는 처음들어보는 방법론도 가득했고 생소한 지식들도 많았다.
그러던 중 포비님이 한 글을 올리게 된다.
이 글에 대한 나의 답은 '프리코스 오리엔테이션'에서 이에 대한 포비님이 한 말과 동일하다.
"저런것에 연연하지 않았으면 좋겠다."
"나의 중심을 잘 잡고 나의 속도대로 가야한다."
-포비
이런 말을 들으니 작년보다는 부담감이 상당히 줄어들었다. 작년에는 '잘해야지'라는 강박만 있었다면 올해는 '잘하는것도 좋은데 무언가를 남겨가자'라는 프리코스 과정 전체의 목표가 생겼다. 그러다보니 작년보다는 부담감없이 즐겁게 진행햇던것 같다.
(이런 마인드를 갖게 도와준 포비님(볼지 안볼지 모르겠지만)에게 다시한번 감사드린다.)
문제 충돌과 극복 과정
첫주차고 모든것이 새로운 시도였기에 매번 문제의 연속이었고 깨달음의 연속이었다. 안 힘들었다고 하면 거짓말이겠지만 힘든것 이상으로 재미있었다. 왜 재미있었는가 하면... 뭔가 새로운걸 알고 그걸 내 코드에 적용해서 성공하는거? 그리고 코드가 깔끔해지는거? 뭔가 말로 표현하기가 힘들다. (재밌었는걸 어떡해!)
여러 문제들 중에서 가장 기억에 남는 것들에 대해 해결과정까지 같이 적어보려고 한다.
1. 아니 내 테스트코드가 안돌아간다고요?!
TDD는 처음 해봤지만 너무 재미있었다! (특히 내 머리속을 그대로 쏟아붓는 레드 단계가 너무 재밌었다)
하지만 처음 해봐서 그런지 리팩토링 과정에서 우여곡절이 많았다.
가장 고민점은 리팩토링하는 과정에서 메서드가 분리되고 더 나아가 클래스까지 분리가 되니까 테스트 코드가 안돌아가 는것이었다.
지금에 와서 생각해보니 이는 테스트코드를 제대로 구성을 못하고 억지로 맞춘것이고 이 원인은 기능목록의 내용이 부실해 어느 클래스에 어떤 기능이 있어야하는지 몰랐기에 일어난 문제였던것으로 판단되어진다.
사실 정상적이면 테스트코드가 작동 안할이유는 거의 없다.
Q.아니 그래도 난 테스트코드가 에러가 난다고요..
A.그럼 테스트코드를 수정하자! TDD에서는 테스트코드를 최대한 수정 안하는 방식으로 리팩토링을 수행하라고 하지만 사실 지양일뿐 수정해도 문제될것은 없다! 괜히 테스트코드 지키겠다고 코드가 더 엉망이 되는것보다는 테스트코드를 조금 수정하는게 더 깔끔한 결과를 만들때도 있다 (알잘딱하게)
2. Getter를 사용하지 말라고요?
객체지향 생활체조 원칙중에는 'getter/setter를 사용하지 말라'라는 원칙이 존재한다. 이는 캡슐화를 지키기 위한 원칙이다.
Setter의 경우는 생성자로 만들면 안쓸수 있는데 문제는 Getter였다.
아니 어떻게 Getter를 안쓰고 객체 안의 값을 가져올수 있을까? 난 저 값이 필요한데.. 이에 대해 찾아보니 한 자료를 찾을수 있었다.
https://www.slipp.net/questions/565 (왜 또 포비님 자료인지는 나도 몰?루)
getter 메소드를 사용하지 않도록 리팩토링한다.
오늘 코드 리뷰 주제는 지난 번에 이어 다음 그림과 같은 볼링 게임 점수판을 구현하는 프로그래밍의 일부이다. 볼링 게임을 구현하면서 쓰러진 볼링 핀을 관리하는 클래스를 Pins 클래스로 다음
www.slipp.net
https://tecoble.techcourse.co.kr/post/2020-04-28-ask-instead-of-getter/ (이 자료에 상세하게 설명 되어있다.)
getter를 사용하는 대신 객체에 메시지를 보내자
getter는 멤버변수의 값을 호출하는 메소드이고, setter는 멤버변수의 값을 변경시키는 메소드이다. 자바 빈 설계 규약에 따르면 자바 빈 클래스 설계 시, 클래스의 멤버변수의 접근제어자는 private
tecoble.techcourse.co.kr
여기서 이 문제에 대한 힌트? 예시를 얻을수 있을것이다.
안들어갈 사람들이 위해 한 문장으로 표현하자면 '객체에 메시지를 보내자'라고 할수 있다.
간단하게 말하면 Getter로 값을 가져오는게 아니라 처리를 해당 객체에 보내 객체내부에서 로직을 처리하고 그 결과를 가져오는 식으로 만들면 getter를 안쓰고도 원하는 값을 가져올수 있는것이다!
이를 적용하니까 실제 본인의 1주차 코드에서 getter 사용량을 0개(맞나..?) 로 만들었다.
3.어데.. 패키지십니까..? (by. MVC 패턴)
메서드 분리와 클래스 분리만 하다보니 어느새 클래스가 10개에 근접하게 되었다.
그러다 보니 이를 정리할 필요가 있었고 그때 떠오른게 디자인 패턴이었다.
디자인 패턴에서 나에게 가장 친숙했던건 MVC패턴.. 이었다.
작년의 악몽이 스멀스멀 떠올랐기에 '시험삼아 분류만 해보자'라는 생각으로 클래스를 분류하기 시작했다.
그러자 놀라운 결과가 일어났다.
.
이렇게 아름답게 마치 처음부터 의도한것 마냥 클래스가 이쁘게 분리가 된것이었다.
물론 처음부터 이렇게 깔끔하게 분리되진 않았다. 그래도 어느정도의 적합성을 가지고 분류가 되었기에 아 MVC패턴을 이래서 쓰는건가? 라는 생각을 했고 해당 패턴을 사용해서 리팩토링을 진행하자고 생각했다.
하지만 위 사진처럼 가는데에는 몇몇 의문점이 있었다.
3.1. DTO/VO가 뭔데..?
분류 전의 가장 큰 문제점은 모델이라는 패키지의 클래스가 너무 많은것이었다. 물론 많을수 있지만 현 미션에서는 더 작게 만들수도 있었기에 다른 패키지로 옮겨야 했다. 모델의 대부분은 래퍼 클래스였고 로직을 가지고 값을 전달하는 의도로 만들어진 클래스가 많았다. 이와 비슷한 것이 MVC패턴에 있었다.
바로 DTO(Data Transfer Object) 와 VO(Value Obejct)였다. 둘다 데이터를 가지고 이를 옮긴다는 공통점이 있었기에, 미션의 클래스를 대부분 옮길수 있었는데 여기서 문제가 생겼다. DTO랑 VO의 차이점이 무엇인지에 대한것이었고 이를 알기위해 여러 포스팅을 보았지만 이해가 가지 않았다. 그러던중 현재의 미션의 구조를 만들어준 자료들이 찾았다.
1. https://www.youtube.com/watch?v=z5fUkck_RZM(DTO와 VO의 개념에 대해 알기 쉽게 나와있다.)
2. https://lazymankook.tistory.com/30 (Spring에서의 MVC패턴에 대한 자료. 상세한 설명이 나와있다.)
DAO, DTO, Service
Spring Framework의 MVC에서 Model은 Service, DAO, DTO로 나눌 수 있다. 한 번 살펴보자. DAO Data Access Object의 줄임말이다. DB를 사용해 데이터를 조회하거나 조작하는 기능을 담당하는 것들을 DAO라고 부른다.
lazymankook.tistory.com
위 두 자료를 통해서 DTO와 VO의 차이점에 대해 명확히 알수 있었고 이를 기반으로 내 클래스를 적절히 분배할수 있었다.
이를 통해 나름대로 정리한 내용을 포스팅했다.
3.2. Controller가 너무 뚱뚱해요!
MVC패턴에서 Controller의 역할은 View와 Model을 이어주면서 프로그램의 흐름이나 로직을 수행하는 패키지라고 볼수 있다. 그러다보니 자연스럽게 클래스의 크기가 커질수 밖에 없었고, 이를 분리할 필요가 생겼다.어떻게 분리할지 고민하는 과정에서 프로그램의 전체적인 모델? 구조?를 그려보자고 생각했다.
그리고 나서 현재 컨트롤러가 view와 연결되는 기능을 가진 파트와 Model에서 로직을수행하는 파트로 나뉠수도 있다는것을 발견하였고 이에 대해 떠오른 구조가 있었다.
바로 Spring에서의 MVC 패턴이었다.
Spring에서는 Controller와 Model(Entity?) 사이에 한가지 layer가 더 존재한다. 바로 Service이다.
여기서 Controller는 request를 적합한 Service에 Mapping 해주고 실제 로직 수행은 Service에서 수행하게 된다. 이러한 구조를 이번 미션에 적용할수 있을것이라고 생각하였고 대략적인 구조를 아래와 같이 설계했다.
※각 Layer의 데이터 교환에는 DTO/VO가 사용된다.
이렇게 되는 Controller의 기능 일부가 Service로 넘어가게 되고 이에 따라서 객체지향 생활체조중 하나인 '엔티티를 작게 유지하라'를 준수할수 있었다.
4. 그래서 너가 뭘 한다고..? (feat. 메서드 이름짓기)
메서드를 분리하다보니 메서드가 한가지 기능만을 가지게 되었고, 그러다 보니 코드의 가시성이 보기 힘들어졌다고 생각했다. (코드가 너무 왔다갔다거리니까..)
그래서 메서드명으로라도 해당메서드의 기능을 확실하게 알수 있게 해야 했다.
하지만.. 당신과 나, 우리 모두가 생각하는 가장 어려운일.. 이.름.짓.기.
이와 관련된 게시물이 하나 있길래 이걸 보고 네이밍에 대해 어느정도 감을 잡았다.
https://velog.io/@leeyoungwoozz/Clean-Code-3.-함수#5-서술적인-이름을-사용하라
[Clean Code] 3. 함수
최근 RxSwift를 사용하는 프로젝트를 진행한 경험이 있는데, 최대한 Side Effect 가 없도록 함수를 설계하려고 노력을 했었다. 그리고 코드 리뷰를 진행하며, 함수를 어떤 단위로 쪼갤지... 그리고 함
velog.io
간단하게 메서드명을 서술적으로 마치,한 문장처럼 읽히게끔 지으라는 것이었다. 이게 상당히 많은 도움이 되었다.
(하지만 그래도 창의성의 한계로 gpt를 이용했다는 건 안비밀.. 고마워요 gpt)
5. 아는 친구에 아는 이모의 아는 형의 아는누나의.. (feat. 디미터의 법칙)
클래스를 클래스로 감싸고 이를 호출하고 이런 과정에서 아래와 같은 코드가 나오는경우가 있었다.
Result result=game.play().find().calculate().etc().... //이는 예시코드
즉 dot(.)이 너무 길어져서 흔히 말하는 메서드 체이닝이 되버린거다. 이러다보니 이놈이 누구한테서 이걸 가져오는건지 이런 정보가 다 노출이 되는것이었다. 이는 캡슐화를 위배한것으로 생각되어졌고 이를 막고자 한것이 계속 말하고 있는 객체지향 생활체조 9원칙에 나와있다.
한 줄의 한개의 점만 사용하자
이보다 더욱 상세하게 이 문제에 대한 법칙이 바로 디미터(Demeter)의 법칙이다.
https://dkswnkk.tistory.com/687
디미터 법칙 (Law of Demeter)이란?
최근 클린코드를 읽던 중 디미터 법칙에 대해 알게 되었습니다. 용어 자체는 생소하긴 한데 법칙의 내용 자체는 크게 어렵지 않고, 평상시 개발에서 흔히 마주칠 수 있는 내용을 다룬 법칙이기
dkswnkk.tistory.com
한줄로 말하자면 "친구하고만 대화하라"라는 것이다.
즉 서로 직접적인 클래스에게 통해서 가져오는 것이다.
Result result=game.play().find().calculate().etc().... //before
Result result=game.play() //after
//play() 메서드 안에서 처리된다.
주차 반성점 및 개선사항
첫 주차였고 여러가지를 시도해보는 단계였기에 우여곡절이 상당히 많았다.
1. 기능목록을 활용하지 못했다.
기능 목록을 작성을 했고 1차적으로 수정도 했다. 처음 기능을 구현하는 단계에서는 이를 잘 활용했지만, 후반으로 갈수록 클래스 구조와 프로그램 구조가 바뀌면서 조금씩 소홀했던것 같다.
다음 주차에서는 기능 목록에 더 많은 시간을 써서 이를 활용할수 있도록 해야할것 같다.
2. 주말이 너무 피곤해..
본인은 평일 아침에 헬스장을 가기에 강제로 기상을 하게되어 이른 생활을 진행한다. 하지만 주말에는 헬스장을 안가기에 하루종일 집에만 있게되고 그러다보니 평일에 못잔잠을 주말에 몰아자게 되었다. 이는 지금 생각해보면 시간이 너무 아까웠다고 생각한다.
다음 주차에서는 스터디든 모각코든 뭐든, 주말에 집밖으로 나갈 일정을 만들어서 나를 강제적으로 부지런하게 만들어야 겠다.
주차를 마무리하면서
작년과 다르게 앉으나 서나 누워서나 밥을먹나 헬스를 하나 하루종일 코드에 대해 생각했다.
그저 코드를 좋게 만들고 싶다는 생각. 이 하나로 계속 생각했고 이에 대해 필요한 지식을 찾아나갔다.
작년엔 힘들었던 이과정이 올해는 힘든 것 보다는 재미라는 감정이 생겨났다.(사실 난 이미 미친게 아닐까..?)
이런 느낌은 상당히 새로웠고 이게 우테코에서 말하는 '스스로 찾아서 공부하는 방법'이라는 것일까 라는 생각을 하게 되었다.
주차를 시작하면서 가진 목표였던 '몰입'에 대해 어느정도 경험 했다고 생각한다. 이런 느낌과 열정을 계속 유지해서 4주차까지 성공적으로 마무리 하고싶다.
주차에 포스트한 우테코 관련 정보
1. https://skianything.tistory.com/20 (Indent Depth를 줄이는 방법)
Indent Depth를 줄여보자!
우테코 프리코스에 참가하면서 많은 참가자들이 객체지향 생활체조 9원칙을 지키려고 노력하는 것을 보았다. (본인 포함) 그중에서 아래 원칙을 지키는것이 생각보다 어려웠다. 한 메서드에서
skianything.tistory.com
2. https://skianything.tistory.com/22 (DTO와 VO)
DTO와 VO에 관하여
프리코스 1주차 과정중, MVC를 적용하는 과정에서 DTO와 VO에 대해 알게 되었다. 둘다 얼핏보면 기능이 비슷해 보였고 차이점도 모호해서 매번 헷갈려 하는 자신을 발견하였다. 그래서 이번 기회에
skianything.tistory.com
3. https://skianything.tistory.com/21 (객체지향 생활체조 원칙)
객체지향 생활체조 원칙
우테코 프리코스에 참가하고 디스코드에서 여러 참가자들이 공유해주는 것들중에 [객체지향 생활체조 원칙]이라는 말을 처음 들어봤다. 몇몇 사람들은 이미 알고 있었는지 이에 대해 심도깊은
skianything.tistory.com
기타 잡담
1. 혹시 서울 사시는분들중 저처럼 게으른 주말을 바꾸고 싶다 하시는분 계시면 같이 모각코 할 사람 구합니다. (아직 해본적 없음))
2. 현재 관심사: - 클린코딩(책 빌려볼 예정,스터디 있으면 좋을듯),
- 블로그 포스팅(우테코 과정에서 배운 정보들 정리 + 하다가 그만둔 알고리즘 문제 풀이 정리)
3. 현재 궁금증: Controller 클래스와 OutputView를 단위테스트하는 과정,방법
'우아한테크코스 6기' 카테고리의 다른 글
2주차 미션 [자동차 경주] 회고록 (1) | 2023.11.01 |
---|---|
싱글톤 패턴(Singleton Pattern) 처음부터 끝까지 (0) | 2023.10.27 |
DTO와 VO에 관하여 (0) | 2023.10.25 |
객체지향 생활체조 원칙 (0) | 2023.10.25 |
Indent Depth를 줄여보자! (0) | 2023.10.25 |