드디어 프리코스 마지막 4주차가 지나가게 되었다..!
개인적으로는 오버를 좀 보태서 천.지.개.벽 수준의 변화가 있다고 느끼는 데 어떤 일들이 있었는지 마지막 회고를 시작해보자!
지난주 회고에도 적은 내용인데, 2주차 때 객체들의 결합관계가 너무 많고 강해서 지난주에는 '의존관계를 최소화'하려고 했었다.
( 당시 고민을 적은 포스트: https://velog.io/@dlguswl936/우테코-6기-프리코스-비전공자-독학러의-3주차-회고#-하루종일-의존성을-고민하고-나온-구상)
하지만 리뷰에서 다른 리뷰어 분들과 논의하다보니
난 '의존성 줄이기'를 정말로 열심히 하기는 했지만, 그 전에 이게 왜 필요한지 고민이 부족했다는 것을 느꼈다.
의존성이 과도하네? 이것에 대한 코멘트도 많고, 리팩토링하기가 어렵네? 오케이! 의존성을 최소화하자!
다시 생각해보니 이 정도의 고민 과정만 거쳤던 것이 느껴졌다.
결국, '의존성을 왜 줄여야하는가?'에 대한 고민을 충분히 하지 않고, '냅다' 의존성 줄이기에 몰입했던 것이다.
'의존성을 과도하게 제거했을 때'의 장단점에 대해 리뷰어 분들과 몇 번에 걸쳐 의견을 주고받고 나니 그제서야 적절한 의존관계에 대해 알 것 같았다.
- 프로그램상 협력하는 객체로 정해 의도적으로 의존관계를 가져야하는 객체들도 있다.
- 의존성을 아예 제거하면, 협력하고 있는 객체가 아무것도 없는 것인데, 절차지향과 다를 바가 없지 않을까?
- 객체 간의 의존성을 줄이기 위해 컨트롤러에서 원시값을 받아와서 다른 객체에 넣어주는 경우, 오히려 컨트롤러가 도메인의 값에 접근하면서 컨트롤러의 깊은 도메인 관여가 생기게 된다.
- 값을 주고 받는 과정에서 안전성이 보장되지 않는다.
불행인지 다행인지 의존성을 최대한으로 줄여보는 방식으로 코드를 한 번 짜보니, 적절하게 의존관계를 부여하는 것은 반대로 어렵지 않았다!
물론, 지난주의 나의 코드가 부끄럽게도 객체 간의 의존성을 극단적으로 제거해 객체별로 조각난 느낌의 조금 이상한 코드였겠지만 의미 없는 시도는 아니었다고 생각한다.
왜냐하면, 틀린 길이어도 끝까지 가보니 아, 이래서 틀린 길이었구나!
를 알 수 있게 된 것이니까!
그 후에 다시 길을 잡아 갈 때는 그 길로 가는 이유가 좀 더 명확한 채로 갈 수 있게 된달까?
지난주 '잘못된' 의존성 줄이기에 몰입하며 'view가 도메인에 의존하지 않도록 도메인 자체를 view로 보내지 않아야 한다'라고 생각하며 해당 방식처럼 구현했었다. 하지만, 이 생각이 MVC 패턴의 원칙에 부합하지 않는다는 것을, 리뷰를 받게 되면서 그 때서야 인지하게 되었다.
그러면서, 프리코스를 진행하며 MVC에 대해 제대로 알아본 적이 있었나?
하고 스스로 질문해 보니 대답할 수 없었다.
실로 충격이었다. MVC 패턴을 잘 알고 기본적으로 지키고 있다고 생각했는데, 잘못 알고 있었다니...
생각해 보니, 프리코스 동안 MVC 패턴에 사용에 대해 피드백을 받은 적이 없었고, model - view - controller로 구분해서 사용하고 있었기 때문에 내가 사용하는 방식이 MVC 패턴이겠거니 생각하고 코드를 짜왔던 것이다.
새삼, 테코톡 등의 정리되어 있는 양질의 자료를 더 찾아보지 않았던 나를 크게 반성하게 되었다.
부끄러워하고 반성하는 시간이 지나가고, 이제부터 제대로 알게 되는 것이 더 중요하다고 생각했고, 그건 나에게 달려있다고 생각했다.
그때부터, MVC 패턴에 대한 그동안의 모든 테코톡 영상을 찾아보며 스스로 MVC 패턴에 대해 잘못 알고 있던 개념을 새로 정립하게 되었다.
- 도메인이 view에 의존하면 안된다.
- view는 도메인에만 의존해야한다. (컨트롤러에 의존하는 것이 아닌)
- view 내부에 모델에 관련된 코드는 있어도 상관이 없다.
- [10분 테코톡] 🧀 제리의 MVC 패턴 해당 영상이 많이 도움이 되었다!
중요한 개념에 대해 잘못 알고 있으면서 그걸 기반으로 코드를 작성하고 미션을 제출했었다는 것이 꽤나 큰 자책감으로 다가왔지만, 프리코스의 의미를 떠올리며 그러지 않으려고 했다. 프리코스 동안 우리는 '미리' 겪어보고 수정할 수 있는 과정
에 놓여있는 것이니까!
지난주 로또 미션을 할 때 로또 매칭 결과에 대한 객체를 enum으로 만들고 매칭 결과가 enum 필드 자체에 반영되게 하였었다.
그러다 보니 초기화 등의 문제가 있어, 일단 해당 방식으로 구현은 했으나 찝찝함이 남아있었던 지난주 미션였다.
그렇게, PR을 올리며 이렇게 고민이었던 점에 대해 코멘트로 해당 부분에 대해 리뷰어분들의 의견을 구했고,
리뷰어 분들의 남겨주신 의견들을 바탕으로 더 찾아보면서, 내가 enum을 사용한 방식의 문제점을 결국 알게 되었다.
일반적으로 enum은 변경 불가능한 상수들의 집합의 정체성을 가지는 것으로 간주되는데,
내가 한 enum 내 상태 변경은 객체 지향 프로그래밍의 기본 원칙과 enum의 사용 목적에 어긋난다
고 볼 수 있던 것이다…!
다시 한번 깨닫는다. 기능을 사용할 때, 그 기능의 정체성을 파악하고 사용해야한다
는 사실!
따라서, 이번 주에는 이 enum의 변경 불가능한 상수들의 집합이라는 정체성을 충분히 이해하고 구현해 봐야겠다고 생각했고 참가자들의 PR을 돌아다니고 리뷰를 하며 enum을 어떻게 제대로 사용할 수 있는지를 소위, 염탐(?)해 보았다. 숱한 코드들을 보다 보니, enum의 정체성과 어떤 활용 등이 있는지 감이 왔던 것 같다!
( 수집 과정 포스팅 : https://velog.io/@dlguswl936/우테코-6기-프리코스-3주차-피드백-정리#-enum-활용-관련 )
- enum 필드에 객체를 넣어주는 방식
- enum 필드에 BiPredicate 등의 함수형 인터페이스를 넣어주는 방식
- enumMap을 생성해서 put해주는 방식
- enumMap 생성과 stream을 하며 Collectors.toMap 으로 put을 한꺼번에 하는 방식
등등 정말 다양한 방식들이 있었다!
그렇게 10 여분의 코드를 통해 enum의 사용법을 수집하다보니 enum의 정체성과 어떤 활용 등이 있는지 감이 왔던 것 같다! 이 활용들을 코드에 이리 저리 적용해보면서 지난주 이상하게 써서 미안했던 enum과 친해지는(?) 시간을 가질 수 있었던 이번주였다!
유효성 검증, 즉 validate 방식은 얼핏 보면 중요 비즈니스 로직으로 보이지는 않지만
난 중요한 부분이라고 생각했고, 4주 동안 정말 많은 방식을 시도해보았다.
돌아보니 4주 동안 같은 적이 없던 검증 방식이었는데, 그 이유는 유효성 검증에 대한 기준이 추가되고 바라보는 시각이 아래의 과정으로 달라졌기 때문
인 것 같다.
방식
: 도메인 안에서 검증, 생성자 안에서 검증이 일어남
생각했던 기준
: 검증 책임을 갖는 도메인에서 검증을 해야한다.
방식
: 도메인 안에서 검증, 부생성자에서 검증을 하고 생성자로 보냄
생각했던 기준: 생성자에는 초기화만 수행하게 부생성자에서 검증이 일어나야한다.
방식
: 도메인에서 검증 로직을 분리함, 팩토리 패턴을 이용한 ValidatorFactory 활용
생각했던 기준: 객체의 비즈니스 로직과 분리해 외부에 있으면서, 상관없는 객체가 검증에 접근할 수 없게 해당 객체에만 검증할 수 있게 제한되면 좋겠다.
3주차 고민 과정 : https://velog.io/@dlguswl936/우테코-6기-프리코스-비전공자-독학러의-3주차-회고#-그동안의-방식-과감히-버리기
방식
: 도메인에서 검증 로직을 분리함, 도메인에 1대1 대응하는 validator에서 직접 정적 호출
생각했던 기준: 프로그램 규모를 고려해 적당한 복잡성을 띄고, 도메인에서 필요한 검증을 확인하기 쉬웠으면 좋겠다
호기롭게 팩토리 패턴도 써봤다가 프로그램 규모를 고려해 보았더니 과도한 복잡성이라는 리뷰들을 받기도 하면서 다시 제거하기도 하며 시행착오가 많았는데,
그렇다고 이것들이 의미 없는 과정이었다고 생각하지 않는다!
물론, 미션과 선발 과정에 몰두하다 보면 그래서 내가 잘 짜여진 코드를 제출했는지
, 프리코스를 통해 내가 선발될 수 있을지
에 매몰기도 하지만, 그럴 때마다 선발
이 아니라 성장
이라는 프리코스의 목적을 다시 떠올리려고 하기 때문이다!
그런 측면에서 4주 동안의 변신을 거쳐서 이번 주에 적용하게 된 나의 유효성 검증 방식에 자신감을 갖고 후회 없이 앞으로의 개선을 더 기대해 보려고 한다!
이번주 미션은 진행하면서 4주 동안 배우게 된 것을 모두 적용해볼 수 있는 프리코스 종합선물세트(?)
를 만드는 기분이 유독 들었다!
자기 역할만 하게 클래스 분리
InputView에서 출력 기능을 하는 부분에 대해 리뷰를 많이 받아왔었기에 Printer, Reader 객체를 생성해 분리함으로써 InputView의 역할만 할 수 있게 해보았고,
유효성 검증 방식
4주 동안 고민한 결과의 방식을 적용해보았고,
enum과 map
이벤트 혜택 내용을 구하면서, 가장 최근에 제대로 알게된 enum과 map을 적용해보았고,
의존성
너무 강한 의존관계도 구현해봤다가, 과도하게 의존성을 제거도 해봤다가 멀리 돌아왔지만 적절한 의존관계를 가질 수 있게 구현해보았고,
확장성과 유지보수
요구사항만을 충족하는 고정된 프로그램과 메소드를 만들 수 있었겠지만, 그동안 미션을 진행하며 느꼈던 유연한 프로그램의 장점들을 마지막 미션에서는 꼭 적용해보고 싶었기에 확장성과 유지보수를 고려한 유연한 프로그램을 만들어보려고 했다!
TDD
첫 주만해도 TDD가 오히려 불편하고 어색했던 나였지만, 이번 미션은 온전히 TDD 기반으로 작성했다고 할 수 있다. 핵심 기능 한 줄을 READ.ME 맨 위에 적어놓고, 가장 중요한 그 핵심 기능을, 가장 작은 단위로 테스트하면서 미션을 진행함으로써 TDD가 주는 빠른 피드백, 코드에 대한 확신이라는 장점을 비로소 온전히 느끼게 되었다!
종합선물세트 속 하나 하나의 선물처럼, 그동안 배웠던 것들 하나하나를 적용하면서 구현하고 작동하는 것을 보니 설레는 기분마저 들었다🎉
그렇게 프로그래밍을 하면서의 몽글몽글하고 뿌듯한 기분을 처음으로 진하게 즐기며 진행한 마지막 미션이었다!
(크리스마스 이벤트라는 미션 주제가 주는 설레임도 한몫 했다🎄)
4주라는 기간이, 흔히하는 말처럼, 바람같이 지나가 버렸다. 그만큼 '몰입'을 했기에 그렇게 느끼는 거겠지?
프리코스를 하기 전과 지금을 비교해보면,
프리코스를 하기 전에는,
비전공자에 독학이기까지한 나의 프로그래밍 공부는 다소 '스스로' 그리고 '혼자'인 측면이 있었던 것 같다.
그러던 중, 프리코스를 통해 180도 다른 개발 공부 방식을 겪어보게 된 것이다.
- 나눔이 가져다 주는 도파민
- 함께였기에 일어난 성장
- 설명할 수 있는 코드를 작성해보기
- 땅 끝까지 파고들어 보는 경험
테스트 코드를 완벽히 이해해보고자 NsTest 코드를 몇 일에 걸려서 파고들고
: https://velog.io/@dlguswl936/우테코-6기-프리코스-우테코-NsTest-코드-땅끝까지-분석해보기
정규식의 적용에서 애매했던 성능 문제에 대해 알아보고자 String.matches를 코드 끝까지 파고드는 등
: https://velog.io/@dlguswl936/공부한-것-String.matches는-왜-성능에-안-좋을까
대충 검색하고 넘어가는 것이 아니라 내가 알아보고 싶은 것에 이렇게까지 미친 듯이 파고들어보는 경험은 처음이었다.
내가 이렇게까지 파고드는 것을 할 수 있는 사람이라는 것 그리고 파고듦은 결국에 성장을 일으킨다는 것을 알게 된 것은 정말 값진 배움이다.
이렇게 비록 프리코스는 끝이 났고, 결과가 어떻게 될지는 모르는 일이지만,
결과를 떠나서 프리코스를 통해 나에게 남은 것들, 그리고 변화한 것들
은 분명히 존재한다고 생각한다.
4주 동안 함께한 참가자, 리뷰어 분들, 중간중간 마음의 불안을 가라앉혀 주셨던 캡틴, 코치분들, 그리고 앞뒤 안 가리고 몰입한 나까지,
모두에게 세상에서 가장 큰 박수를 쳐주고 싶다! 👏
모두모두 그동안 아껴주시고 성원해주시고 후원해주시고 격려해주시고 보태주시고 밀어주시고 염려해주시고 근심해주시고 걱정해주시고 사랑해주시고 은혜를내려주시고 신경써주시고 배려해주시고 두루두루보살펴주시고 많이웃어주시고 박수도쳐주시고 감사합니다^^
현지님 수고하셨습니다! 저도 JUnit에 대해서 끝까지 파본 게 진짜 귀중한 경험이었던 거 같아요 ㅋㅋㅋ 현지님 정도의 몰입이면 진짜 좋은 결과 있을 것 같네요 👍