본문 바로가기
Log/우아한테크코스

[우아한테크코스 5기] 프리코스 4주차 소감문

by 재영(ReO) 2023. 1. 30.

4주차 미션 소감문


4주간의 프리코스가 오늘로 끝이 납니다. 시작하기 전에는 긴 여정을 예상했는데 막상 이제 와 돌이켜보면 눈 깜짝할 새였습니다. 이 짧은 기간 동안 저의 자바와 객체지향에 대한 이해도는 정말 “환골탈태”라는 단어가 딱 들어맞게 몰라볼 정도로 달라졌습니다. 정말 뼈를 바꾸듯이 가장 기본적인 개념부터 다시 되짚었고, 그 위에 클린한 코드를 작성하는 방법들을 살붙이며 한 달 전의 저와는 아예 다른 사람이 되었습니다.
부끄러운 이야기지만, 혼자서 4주 동안 이만큼의 변화를 이뤄낼 수 있었을까 생각해보면 자신 있게 대답할 수 없을 것 같습니다. 아니, 더 솔직하게 말씀드리자면 불가능했을 것 같습니다. 같은 고민을 하고 서로 응원을 해줬던 수많은 동료, 그리고 매주 수요일마다 일주일의 고민을 속 시원히 해결해주시고 마음을 다독여주셨던 코치님들이 있었기에 가능했던 일입니다. 정말 모든 분께 두고두고 갚아야 할 큰 은혜를 입었습니다. 진심으로 감사드립니다.
이번 주 목요일에도 늘 그랬듯이 지난 미션에 대해 동료들과 스터디를 진행합니다. 프리코스는 끝났지만 프리코스에서 배웠던 것, 해왔던 것들을 꾸준히 유지하려 합니다. 항상 최종 목표가 어디인지 확인하고 방향이 맞는지 확인하며 나아갈 것입니다. 이러한 계획의 시발점이자 길라잡이가 되어준 우아한테크코스에게 진심으로 감사드립니다. 이 길 위에 우아한테크코스 본 과정이 있기를 간절히 바랍니다.



4주 차 미션에서 배운 점


우선은 굴러가게 하자.

프로그래머가 되기로 한 이상, 가장 중요한 것은 어찌 됐든 요구사항을 정확하게 만족시키는 프로그램을 신속하게 만들어내는 것으로 생각했습니다. 그래서 지난 3주간 배워왔던 대로 구현해야 할 기능을 프로그램 진행 과정대로 쭉 적었습니다. 그리고 그 기능에 해당하는 로직들을 도메인 로직과 어플리케이션 서비스 로직으로 분류했습니다. 그 뒤 각 로직에 대한 예외 상황들을 최대한 고려해서 도메인 로직마다 테스트 코드를 작성하고, 그 테스트를 통과시키기 위해서 각 기능 단위로 구현했습니다. 단 두 번의 미션을 진행했을 뿐인데도 숫자 야구 미션을 처음 받았을 때와는 비교도 되지 않는 속도로 이 과정을 진행할 수 있었습니다. 그 후, 요구사항에 맞춰 프로그램을 구현했습니다. 이 과정에서 중요시한 건 정확한 출력과 메소드가 하나의 일만 하도록 분리하는 것, 그리고 그 메소드들을 클래스 별로 분류하여 객체지향적인 프로그램이 되도록 한 것입니다. 그리고 추후 리팩터링할 부분들을 고려하여 체크리스트를 만들며 진행했습니다. 요구 사항을 만족하는 프로그램을 객체를 분리해가며 신속하게 만들 수 있게 된 것이 뿌듯했습니다.

컨트롤러-서비스-도메인의 레이어드 아키텍쳐로 리팩터링 하자.

스프링 프레임워크를 아직 공부하지 못해서, 3주차 미션 스터디에서 처음으로 레이어드 아키텍쳐라는 개념을 접했습니다. 컨트롤러는 뷰와 서비스 사이에서 dto들을 교환해주며 프로그램의 흐름을 관리하고, 서비스가 도메인들의 객체를 이용하여 서비스 로직을 실행하는 아키텍쳐라고 공부했습니다. 이번 주 미션의 요구 사항 중 “BridgeGame”의 제약 사항 중에 View들을 사용하지 않아야 한다는 사항이 있었는데, 클래스의 설명이 다리 건너기 게임을 관리한다고 되어 있어서 이 클래스가 서비스 레이어의 역할을 하도록 하면 되겠다고 계획했습니다.
테코블에 올라와 있는 3기 케빈님의 “DTO의 사용 범위에 대하여”라는 글이 큰 도움이 되었습니다. 케빈님이 적으신 대로 저도 서비스 레이어에서 DTO의 변환이 이루어지도록 설계하려 했습니다. 컨트롤러가 DTO의 내부를 모르도록 구현했습니다. 그리고 도메인까지는 DTO가 가지 않고 서비스 레이어에서 값들을 전달해줬습니다. 처음 적용해보는 디자인 구조여서 마지막까지도 리팩터링을 하고 있습니다. Controller가 서비스 로직을 수행하고 있지는 않은지, View와 서비스 레이어가 dto로 값들을 전달받고 있는지 등 배운 내에서 최대한 배운 바를 적용하고 지키려고 해봤습니다. 익숙하지 않아서 방금도 살펴보며 고칠 점을 찾아냈는데, 이렇게 어디까지 DTO를 사용하는지에 대한 나름의 기준을 세우고 이를 지키려고 리팩터링하면서 많은 것을 배웠습니다. 편하게 되는 대로 프로그래밍을 하다 보면 나중에 읽기도 쉽지 않고, 한 기능을 수정하려 하면 엄청 많은 클래스를 건드려야 하는 어려움이 있었는데 이렇게 리팩터링을 진행하면서 점점 더 리팩터링이 수월해지는 걸 느낄 수 있었습니다.

원시값을 포장하고 일급 컬렉션을 사용하고, 유효성 검증의 위치를 결정하자.

스터디에서 일급 컬렉션을 학습해보라는 리뷰를 받고, 테코블에서 2기 오렌지님의 “원시 타입을 포장해야 하는 이유” 글을 봤습니다. 로또 미션에서 이에 대한 개념이 없어서 로또 넘버들의 집합을 관리하고 유효성 검증을 하는 것과 그 위치를 어디로 하는지 결정하는 것이 참 어려웠는데 원시값과 컬렉션을 포장해서 관리하는 방법이 있음을 알았습니다. 도메인 로직에서 중요한 역할을 하는 값들을 전부 포장하려고 했습니다. 입력받는 다리 길이, 사용자의 이동, 게임 재시작 여부를 포장했고 여기서 파생되는 다른 컬렉션과 값 중 도메인 로직에서 특정 역할을 한다고 판단되면 전부 클래스로 만들어 관리를 해봤습니다. 생성자를 호출 시에 유효성 검증이 되기 때문에 이에 대한 고려를 배제하고 편하게 사용할 수 있어서 리팩터링을 하는 데 도움이 많이 됐습니다.
그리고 유효성 검증에 대한 논의가 이번 스터디에서도 진행됐습니다. 제가 내린 결론은 최소한의 검증은 뷰에서 진행하고, 나중에 변경될 수 있는 기준들에 대한 유효성은 도메인에서 처리하는 것입니다. 예를 들어, 사용자가 다리의 길이를 입력하는 경우, 다리의 길이가 극적으로 변하지는 않을 것이라는 가정하에 한자리에서 두 자리의 숫자인지는 view에서 검증하게 했고, 그 범위가 3에서 20인지는 다리의 길이에 대한 입력값을 포장한 BridgeSize 클래스에서 진행하도록 했습니다. 이렇게 하면 다리의 길이 범위가 25로 증가하더라도 view에서는 신경 쓸 필요가 없이 도메인에서만 값을 변경해주면 되므로 편리하리라 생각했습니다. 또, 엄청나게 큰 값이나 숫자가 아닌 입력 등이 주어진 경우 이 값들이 컨트롤러와 서비스 레이어까지 전달되어 돌아다닐 필요 없이 view에서 걸러주기 때문에 프로그램에 예기치 못한 오류가 발생하는 것을 막고 효율적인 작업이 가능할 것이라고 생각했습니다. 실제로 이렇게 관리를 하니까, 클래스를 분리하는 리팩터링을 할 때 객체의 유효성 검증을 고려하지 않고 자유롭게 유지보수를 할 수 있었습니다. 이렇게 또 객체지향적인 설계 방법을 알았다는 것이 뿌듯했습니다.

다양한 테스트 코드로 효율적인 테스트 코드를 작성해보자.

매번 테스트 코드를 작성하면서 이후 리팩터링을 하는 부분이나 로직을 변경할 때 즉각적으로 피드백을 얻을 수 있어서 정말 편리했습니다. 하지만 같은 메서드에 대해서 서로 다른 예외 사항들에 대하여 매번 테스트코드를 작성하려다 보니 번거로운 부분도 없지 않았습니다. 그래서 테스트 도구를 조금 더 공부해보고 ValueSource, ParameterizedTest, assertTrue, assertFalse, assertDoesNotThrow, assertNotNull 등의 새로운 도구를 이용해봤습니다. 이렇게 더 다양한 도구를 사용하니 제가 확인하고자 하는 바를 더 효율적으로 피드백 받을 수 있어서 편리했습니다.

setter/getter의 최소화, 싱글턴 패턴 적용 등 배운 것을 적용해보자.

setter/getter를 사용하면 값이 호출되고 변경될 수 있어서 이를 최소화하고 객체에 물음을 던지는 식으로 구현해보라는 피드백이 있었습니다. 그래서 이번 미션을 진행하면서는 이에 신경을 많이 쓰고 구현을 해봤습니다. 어쩔 수 없이 getter를 써야 하는 (예를 들면 다리 길이를 BridgeSize 클래스에 담고 유효성 검증을 한 뒤 이 숫자를 다시 가져와서 그 숫자만큼의 길이를 가지는 다리를 만들려는) 상황들을 제외하고는 최대한 getter의 사용을 지양했습니다. 사용자가 입력한 이동에 대한 경우, 입력을 가져오라고 요구하는 대신에 입력이 “U”인지를 물어보는 식으로 구현하는 등 get메서드를 최소화하려고 노력했습니다.
싱글턴 패턴이라는 것 또한 이번 스터디에서 개념을 처음 접했습니다. 프로그램 시작 시에 같이 생성되어 생성자를 호출할 수 없이 인스턴스를 받아오는 형태의 패턴이라고 공부했습니다. 이번 미션의 요구 사항 중 게임 시도 횟수를 반환해야 하는 기능이 필요했는데, 이 요구 사항을 보고 싱글턴 패턴이 떠올랐습니다. 그래서 PlayCount라는 클래스를 초깃값을 1로 가지는 싱글턴 객체로 만들어서 게임을 재시작하는 경우 count에 1을 더하는 addCount메서드를 통해 값이 변경되고, 새로운 생성자를 호출할 수 없게 했습니다. 싱글턴 객체가 객체지향적이지 않아서 사용을 지양해야 한다는 글도 봤지만 배운 것을 적용해보고 실제로 어려움이나 지양해야 하는 이유를 직접 느껴봐야 한다는 것을 프리코스를 진행하며 깨달았기 때문에 적용해봤습니다.



4주 차 미션에서 느낀 점


프리코스가 끝나면 후련할 줄 알았는데 지금 드는 가장 큰 감정은 아쉬움입니다. 지난 과정에 대한 아쉬움이 아니라 내일 미션 메일이 오지 않는 것에 대한 아쉬움입니다. 4주 동안 정말 최선을 다해 몰입해봤습니다. 미션을 하다가 끼니를 까먹은 것을 까먹고 다음 날 깨달을 정도로 집중했습니다. 칠흑 속에서 막막하다가도 손가락을 움직이다 보면 앞에 있는 벽에 금이 가는 듯 순간 빛이 보였습니다. “와 내가 이걸 생각해냈네?”하며 놀랍다가도 그 방법이 잘못된 것이라는 것을 깨닫고 좌절했습니다. 그래도 다시 또 손가락을 움직여봤습니다. 그렇게 올바른 방향으로 향하는 연습을 4주간 후회없이 한 것 같습니다. 전공 21학점 들으며 졸업논문도 준비하면서 프리코스에 참여해서 몸은 정말 힘들었습니다. 하루에 3시간도 못 자고 학교에 올라가면서도 이동시간이 아까워서 어떻게 하면 폰으로 코딩을 할 수 있을까를 고민하는 저를 보면서 아직도 나한테 이런 열정이 있었구나 새삼 놀랐습니다. 정말 알차게 한 달을 보냈다고 자부합니다. 그래서 아쉽지만 후회없이 프리코스를 보내주려 합니다. 정말 고마웠어 프리코스! 본과정으로 다시 만나자!