3월 17일 날 시작한 후 3주가 지났다. 사실 많으면 매주 회고글을 작성해보고 싶었는데, 아직 초반부라서 그렇게 적을 내용도 많진 않았다.

 

적응 기간도 조금 필요했고, 3주밖에 안 지났지만 나름 루틴에 적응을 해가고 있습니다. 해당 부분에 대해서 짧은 회고를 조금 남겨보려고 합니다.

 

 

🏃🏻 7개월을 꾸준히 참여하기 위해서 필요한 것은 '체력'

월요일부터 금요일까지 오후 1시부터 10시까지 매일 컴퓨터 앞에 앉아있다 보니 몸소 느낀 것이 있다.  '체력'을 키워야 개발자도 꾸준히할 수 있겠구나...

 

처음에는 별로 대수롭지 않게 생각을 했었는데, 요즘은 크게 느껴지고 있는 것 같다. 그래서 하루에 적어도 10분 정도씩은 나가서 뛰는 루틴을 추가해 봤다. 물론...이런 저런 핑계를 대며 안 갔었던 날도 많지만 확실히 작심삼일은 넘겼다. 이것도 나름 대견한 결과이다.

 

물론 10분이 짧을 수도 있지만, 아침에 이렇게 뛰고 오면 나름 오후 1시부터 시작하는 일과 때 정신이 조금 맑아지는 느낌이 난다. 확실히 안 뛰었을 때와는 다른 활력이 조금은 생긴 것 같다. 기회가 된다면 하프 마라톤! 해보고 싶다.

 

작심삼일은 넘긴 나의 도전 😀

 

 

 

🧐 하루에 한 번은 뇌를 돌리자 (알고리즘 문제 풀기)

뇌도 안 쓰다가 쓰려고 하면 저릿한 느낌이 든다. 쉬운 문제라도 조금씩 머리를 돌려보는 것이 중요하다고 느꼈고, Java 언어를 학습하면서 알고리즘 문제를 하루에 적어도 1문제를 해결해보자라는 목표를 정했다.

 

하지만 평소와는 다른 방법으로 알고리즘 문제에 접근해 보기로 했다. 사실 이 부분은 패스트캠퍼스 멘토님이 추천해 주신 방법이다. 

 

항상 알고리즘 문제를 풀 때 고민했었다. 스스로 문제를 푸는 것은 중요한데 이렇게 많은 시간을 쏟는 것이 효율적인 것인가라는 생각이다. 나는 지금껏 알고리즘 문제를 풀 때, 따로 시간을 지정해두지는 않았다. 그래서 어떨 때는 정말 4시간~5시간을 한 문제에 쏟았던 적도 많았다. 

 

근데 문득 이 방법은 그리 효율적인 방법이 아니라는 느낌이 들기 시작했고, 멘토님에게 질문을 드렸다. 멘토님의 의견을 받아들여 내가 정한 알고리즘 문제 풀이 방식은 다음과 같습니다.

1. 문제를 읽자마자 코드를 작성하지 않는다.

이전에는 문제를 읽고난 후 코드를 바로 작성했었다. 이렇게 했을 때의 문제점은 코드를 작성하는 과정 중간에서 막히면 코드를 싹 초기화하고 다시 작성하는 일이 빈번했다. 

그래서 결정한 방법은 처음에 문제를 정독한 후 20~30분 정도는 오직 알고리즘만을 생각하며 종이에 사용할 알고리즘의 방향성에 대해서 적어나간다.

만약 이 과정에서 1시간이 넘게 알고리즘 구상도 못하고 있다면, 그 문제는 모르는 문제로 생각하여 다른 사람의 알고리즘을 참고한다. 이때 코드 답을 바로 보지 않고, 알고리즘 방향만 먼저 참고한 후 해당 알고리즘대로 코드를 작성해봅니다.

알고리즘을 참고하고, 코드를 작성했는데도 계속 풀지 못한다면 다른 사람의 코드도 참고합니다. 이렇게 해결한 문제는 반드시 이해하고 넘어가야 합니다. 그리고 도움을 받은 문제는 따로 깃허브 레포지토리 Readme에 기록해 둡니다.
2. 도움받은 문제는 반드시 다시 풀어보기

일주일 이상이 지난 후 해당 문제를 다시 풀어봅니다. 이 과정은 내가 문제를 정확히 이해하고 넘어갔는지 확인하기 위한 작업입니다.
3. 새롭게 알게 된 알고리즘이나 개념이 있으면 블로그 기록하기

처음 사용해 본 알고리즘이나 기록해뒀으면 하는 과정이 존재하는 알고리즘 문제는 블로그에 따로 기록해 둡니다.

 

 

깃허브 레포지토리 README.md

 

 

 

🙋🏻‍♂️ 일일 계획의 성공률을 높여보자

멘토님을 만나기 전까지는 미친 듯이 달려 나가는 계획을 작성했었다. 물론 결과는 처참했고, 성공률도 저조했다.

성공률이 낮으니깐 뭔가 성취도도 조금 떨어지는 것 같고, 하루 만족도가 많이 떨어졌었다.

 

원인을 생각해 보면 "무리한 계획", "핑계"가 대부분을 차지했다.

 

아 오늘은 조금 힘드니깐 달리기 미뤄야겠다. 강의 듣느냐고 알고리즘 문제 못 풀었다. 내일은 꼭 풀어야지~ 이런 식의 핑계들이었다. 문제점은 파악했으니 해결방안을 생각해 봤다.

 

1. 계획은 최대한 구체적으로 작성

원래는 chapter 단위로 크게 크게 묶었었는데, 이번주에는 chapter안에 세부 chapter 단위로 나누어서 계획을 작성해 봤다.
이렇게 했을 때의 결과는 크게 크게 잡았던 계획보다는 확실히 성공률이 많이 늘었다. 그리고 추후에 복습에 대한 계획을 정할 때도 도움이 많이 됐다. 
2. 일과 시작 전에 알고리즘 문제 풀고 시작하기

2주 차까지는 온라인 강의, 실시간 강의 모든 일과를 다 마친 후에 알고리즘 문제를 풀 계획을 잡고 있었다. 근데 문제는 강의 계획이 지켜지지 않은 날은 알고리즘을 풀지 않고 넘어가는 날이 많았다. 사실 핑계다.

그래서 같은 그룹 스터디원의 의견을 수용하여 일과를 시작하기 전에 알고리즘 문제를 먼저 풀고 시작하는 계획으로 변경했다. 이렇게 했을 때 얻을 수 있었던 효과는 알고리즘 문제에 시간을 과도하게 사용하지 않는다는 점과 일과 시작 전에 뇌를 약간 워밍업 하는 느낌으로 시작할 수 있다는 점이 있었다.

 

이렇게 계획을 변경하고 난 후 3주 차 계획 성공률을 많이 높일 수 있었다. 이렇게 계속 적용해보고 점점 계획을 개선해볼 생각이다. 여기까지 3주차 회고를 마치며 다음 회고글은 언제일지 모르겠지만 그때는 지금보다 조금 더 성장해 있을 거라는 확신이 들었다. 🙂

국비교육을 받기로 한 이유

이번에 국민취업지원제도에 등록해서 국비지원 교육을 받게 되었습니다.  작년 초에 대학 동아리에서 처음 개발을 접하게 되었고 백엔드 개발자가 되기로 마음을 먹었습니다. 효율적인 성장을 하기 위해서는 뜻이 같은 사람들과 함께 성장하는 것이 중요하다고 생각합니다. 또한 앞으로 나아가는 법을 잘 모르는 상태이기 때문에 방향을 잡아줄 수 있는 교육 기관의 도움을 받는 것이 좋을 거 같다는 생각을 했고, 국비지원 교육을 받기로 결정했습니다.

 

 

패스트캠퍼스에 지원한 이유

그렇게 선택한 교육이 패스트캠퍼스 백엔드 개발 5기 부트캠프입니다. 많은 부트캠프가 존재하고, 선택의 요소들이 정말 많았습니다. 그중에서 패스트캠퍼스를 선택한 이유는 프로젝트가 많았기 때문입니다.

 

무조건 많은 프로젝트가 좋다는 의견은 아닙니다. 하지만 동아리에서도 그랬었고, 프로젝트를 통해서 협업 능력도 기를 수 있고 사람과 소통하는 법도 배울 수 있었다고 생각합니다. 그리고 프로젝트를 진행하면서 발생한 오류들을 해결하면서 많은 성장을 했고, 무엇보다 함께하는 즐거움을 느껴봤기 때문입니다.

 

패스트캠퍼스 백엔드 부트캠프 과정에서는 총 5번의 프로젝트를 합니다. 토이 프로젝트 3개, 미니 프로젝트 1개, 파이널 프로젝트 1개 이렇게 진행합니다. 이 부분이 저를 조금 끌리게 만들었던 요소였다고 생각합니다.

 

 

지원 과정 & 선발

처음 모집 요강을 봤을 때는 2023년 2월 14일이었습니다. 홈페이지에 들어가 지원을 하게 되면 지원을 할 때 입력했던 이메일로 메일이 도착하고 요구하는 대로 과정을 진행했습니다.

 

자기소개서 제출 -> 기초 소양 테스트 진행 -> 비대면 면접까지 하면 지원 완료입니다. 결과 발표는 3월 10일 날 최종 합격 발표를 받았습니다.

 

선발 메일 내용

 

패스트캠퍼스에서의 첫날

# 과정소개 및 Q&A

3월 17일 오늘 패스트캠퍼스에서 첫 교육이 시작됐습니다. 첫날은 OT를 진행했는데 대면으로는 진행되지 않고, zep이라는 프로그램을 이용해서 비대면으로 진행됐습니다.

zep 컨퍼런스홀

이렇게 캐릭터도 커스터마이징할 수 있고 막 돌아다닐 수도 있었습니다. 눈사람으로 꾸몄는데, 다른 귀여운 옷들도 많습니다. OT는 백엔드만 모여서 진행하는 것이 아닌 프런트엔드도 함께 진행합니다. 사람이 100명 정도로 많았기 때문에 가끔 렉도 걸리기도 합니다. 저는 맥북 M1을 사고 한 번도 발열을 느껴본 적이 없는데 오늘 처음 느껴봤습니다.

 

이렇게 컨퍼런스홀에 모여있으면 매니저분들이 과정에 대한 커리큘럼 설명과 Q&A 과정을 거쳤습니다. 생각보다 많은 사람들이 질문을 해주셨고, 매니저분들이 하나하나 꼼꼼하게 대답을 해주셨습니다. 

 

 

# 아이스브레이킹 시간

이제 과정 설명 및 Q&A가 모두 끝나고 잠시 휴식시간을 가진 후에 백엔드 수강자들끼리 모여서 다양한 나이, 성별, 성격의 사람들이 처음 만났기 때문에 어색한 분위기를 없애기 위해서 아이스브레이킹 시간을 가졌습니다. 이때는 4인에서 5인으로 팀이 랜덤으로 정해졌습니다. 

 

이렇게 팀원이 정해지면 컨퍼런스 홀과는 다른 공간으로 이동합니다. 이곳에서는 백엔드 수강자들만 모여있었고 팀별로 준비된 장소가 있었습니다.

백엔드 수강자들을 위한 장소

위에 보이는 하얀색 네모에 들어와 있는 사람들하고만 대화가 가능한 독립적인 공간입니다. 채팅을 해도 다른 공간에 있는 사람들은 안 보이는 것 같았습니다. 처음에는 조금 유치하다는 생각을 했는데 캐릭터가 보면 볼수록 매력 있습니다. 스페이스바를 누르면 점프도 가능하고, x를 누르면 앉기도 합니다. 다양한 감정표현도 존재합니다. 이쯤 되면 zep을 홍보하는 사람 같아서 그만하겠습니다.

 

이 공간으로 넘어와서는 팀끼리 팀장을 정했습니다. 저희 팀은 사다리 타기를 해서 팀장을 뽑았는데 저는 사다리에 정말 잘 걸립니다. 가위바위보는 맨날 지면서 이런 건 잘 걸립니다. 그렇게 팀장을 맡았고 팀원 맞추기 퀴즈, 영화 제목 맞추기, 잘린 사진 보고 뭔지 맞추기 등 다양한 활동들을 함께 하면서 아이스브레이킹 시간을 가졌습니다. 그렇게 17시 정도가 되었고 19시부터 있을 강민철 강사님의 특강이 준비되어 있었기 때문에 저녁 식사 시간을 가졌습니다.

 

 

# 개발자 마인드셋 특강

저녁 시간이 끝나고 19시부터 시작된 특강. 강민철 강사님의 특강 시간이었는데, 여기서 신기했던 점은 작년 대학교에서 멋쟁이 사자처럼 대학 10기에서 활동을 했었을 때 파이썬/장고로 개발하는 강의를 해주셨던 분이어서 정말 신기했습니다. 그때는 녹화강의였지만 오늘은...실시간 강의여서 그래서 더 집중해서 들었던 거 같기도 합니다. 

 

2시간 정도 되는 특강의 주제는 다음과 같았습니다. 개발자로서 어떤 마인드와 자세로 성장해야 하는가, 어떻게 효율적인 성장을 할 수 있는가였습니다. 주로 얘기해 주셨던 내용은 무엇을 통해 성장을 할 수 있고, 어떻게 빠르게 성장할 수 있는지에 대한 내용이었습니다. 

 

저는 이 특강을 듣고 "개발자 마인드셋"이라는 강의 이름을 정말 잘 지었다고 생각했습니다. 왜냐하면 제 마인드가 세팅된 거 같기 때문입니다. 사실 약간 정곡을 맞았던 부분이 많았습니다.

 

그중에서 가장 세게 맞은 부분은 블로그를 통한 성장에 대한 내용이었습니다. 저는 지금 성장을 위해 블로그를 하고 있습니다. 제가 작성한 게시글 중에서 토비의 스프링에 대해서 작성한 글들이 몇 개 있습니다. 사실 처음에는 토비의 스프링 책을 읽고 코드도 따라 쳐보면서 발생하는 오류에 대해서 정리를 좀 해볼까라는 생각으로 시작했는데 지금 보니 그냥 거의 책의 모든 내용을 요약해 놨다는 생각이 들었고, 이럴 거면 그냥 책을 보는 게 낫지 않을까라는 생각을 하면서 반성하게 되었습니다.

 

그래서 이제부터는 강의에서 얻은 대로 한번 블로그 글을 작성해 보는 연습을 해보자는 목표가 생겼습니다. 블로그는 제가 성장해 온 길을 증명할 수 있는 가장 강력한 무기가 될 것이기 때문입니다. 이렇게 마인드 세팅을 마무리하고, 이제 다음 주부터 10월 10일까지 긴 여정이 될 거 같습니다. 

 

최대한 1주일에 한 번이나 별다른 내용이 많이 없다면 1달에 한번 정도는 회고글을 남겨볼 생각입니다. 나중에 제가 다시 볼 수도 있고, 누군가 이 글을 읽고 도움을 받을 수 있기 때문입니다. 끝나는 날까지 화이팅입니다. 

 

 

우아한 테크코스 최종 코딩테스트 후기

 

4주간의 프리코스를 마치고 결과를 기다리던 중 12월 14일에 프리코스 합격 메일을 받았다. 4주 동안의 프리코스도 많은 배움이 있었고, 나름 학업보다 우선순위를 더 높게 두고 매주 과제에 임했다.

 

그래서 합격 메일이 더 기쁘게 다가왔다고 생각했다. 어느 교육보다도 우테코에 꼭 입과하고 싶은 마음이 있었기 때문에...

8호선 잠실역에서 9번 출구에서 내리면 조금 직진하다가 오른쪽으로 꺾으면 바로 큰 건물이 하나 있다. 처음에는 어리둥절하면서 어디지 했었는데 들어가서 층별 안내표를 보고 여기구나라고 생각했다.

 


실제로 와서 우아한형제들이라고 써져 있는 걸 보니깐 더 가고 싶어졌다. 😭

 

7층으로 엘리베이터를 타고 올라가서 왼쪽으로 꺾으면 사람들이 줄을 서있었다. 그대로 쭉 들어가서 주시는 볼펜이랑 노트를 챙기고 물도 챙겨서 자리에 앉으면 된다. 다과도 있었지만 아침부터 배가 너무 아팠어서... 아무것도 먹고 싶다는 생각이 안 들어서 그냥 물만 챙겨서 자리에 앉았다.

 

주시는 볼펜 박스를 열어보고 나서 긴장이 많이 풀렸던 거 같다. 볼펜이 귀여워서...ㅎ

 

 

실제로 대면으로 보는 코딩테스트는 처음이어서 많이 긴장하고 갔었는데 생각보다 되게 자유로운 분위기에서 코딩 테스트를 진행했다. 시험은 5시간 동안 진행되는데 중간에 다과를 먹고 싶으면 먹어도 되고, 담배, 화장실 등 자유롭게 이동해도 된다고 하셨다.

 

코딩테스트가 시작되고 예상은 했지만 정말 한두 시간(?) 동안은 아무도 움직이지 않았던 거 같다. 진짜...열정적인 사람들...정말 우테코에 합격해서 가고 싶었다 😢

 

코딩테스트 문제는 4주간의 프리코스를 자신의 힘으로 해결했었다면 풀 수 있을 정도의 문제가 나왔었다. 처음에 시작할 때 말씀하셨던 것이 "먼저 돌아가는 쓰레기를 만들어라. 리펙토링은 그다음이다."라는 말씀을 하셨는데, 제발 돌아가는 쓰레기라도 만들었으면 하는 마음으로 코딩테스트에 임했다.

 

4시간 정도 흘렀을 때 문제에서 제공하는 테스트 코드가 통과되는 것을 확인했고, 가독성을 높이는 작업 또는 주어진 제한조건을 갖추기 위해서 리펙토링을 진행했다. 최종 제출은 30분 전부터 가능했고 제출을 모두 완료하고 코딩테스트에 대한 소감을 남겼다.

 


모든 제출이 끝나고 시간이 15분 정도 남아서 프로그램을 직접 돌려서 한번 확인해 볼까라는 생각을 하고 돌려봤다. 근데....이게...😭.. 분명 잡았던 예외 케이스였는데 왜...이게 안될까... 뭐지라는 걸 10분 남았을 때 발견했다. 괜히 잘못 건들어서 0점짜리가 될까 봐 건들지 못하고 나왔다.

가독성 작업 전에 테스트 코드에 힘을 좀 써봤으면 어땠을까라는 생각이 들면서 테스트가 끝나고 나왔다. 모르고 나왔으면 좋았을 텐데 마지막에 알고 나와서 하루종일 찝찝했다. 그래도 이렇게 좋은 경험할 수 있게 해 준 우테코에 감사하다고 전하고 싶다.

 

 

 

최종 코딩테스트 결과 발표

오늘이 기다리던 최종 코딩테스트 결과 발표를 하는 날이었다. 백엔드가 이번에 지원자가 엄청 많았다고 했던 거 같다. 2000명..?이었나 어쨌든 많은 사람들 중에 200명 조금 넘는 사람을 뽑았고, 최종에서 100명 정도 뽑는 것으로 알고 있다. 200명 안에 들었다는 것도 놀라운데 100명 안에 들면 얼마나 좋을까라는 생각을 하면서 15시를 기다렸다. 우테코에게 15시는 의미 있는 시간일지도 모른다. 우테코하면서 가장 많이 기다렸던 시간이 15시이다. 그렇게 결과는...

 

 


하하하 😭 예상했지만 더 아팠던 결과였던 거 같다. 마지막 두 문장이 크게 와닿았다. "이번의 불합격으로 인해 프로그래머로 성장하는데 좌절하거나 포기하지 말고 지속해서 도전해 나갔으면 합니다. 그것이 여러분을 불합격시킨 우아한테크코스에 복수할 수 있는 가장 좋은 방법입니다."

 

합격하신 분들 떨어지신 분들 모두 좋은 인연으로 다시 만났으면 좋겠습니다. 다들 정말 열정 넘치시는 분들 이어서 에너지 받을 수 있었습니다. 내년에 6기에 또 지원할지 일을 하고 있을지는 모르겠지만 좋은 배움의 기회였다고 생각합니다.

 

📘 4주차 미션을 시작하면서

이번 주차 미션은 “다리 건너기” 미션이었습니다. 처음에 문제를 읽었을 때는 한번에 이해가 안 됐었는데, 오징어게임의 다리 건너기 게임과 유사하다는 얘기를 듣고 찾아보니 한번에 이해가 갔습니다.

마지막 미션에서는 기본적인 클래스의 분리는 우테코에서 이미 만들어놓았고, 각 클래스마다 요구조건이 달려있었습니다.

2, 3주차 미션의 모든 요구 조건을 포함하면서 새롭게 추가된 요구조건을 만족하며 작업을 해야 했기 때문에 요구 사항 정리(README.md)만 엄청 오래 걸렸다는…

이번 미션에서는 ‘View와 Domain의 완벽한 분리”, “메소드의 길이는 10줄 이하”에 많은 집중을 하며 기능을 구현했습니다.

 

 

 

📖 BridgeGame 내부에서 View를 사용할 수 없는 요구조건

이번에 새롭게 추가된 요구조건이었습니다. 저는 BridgeGame 클래스를 Domain으로 주어진 클래스라고 판단을 했습니다. 그래서 UI에 사용되는 InputView와 OutputView를 Domain에서 완벽히 분리하기 위한 요구조건이라고 생각했습니다.

Domain과 View를 사용하기 위한 Controlloer를 하나 만들어서 작업했습니다. 요구 조건을 지키면서 작업을 하다보니 메소드의 길이가 10줄이 넘어가는 경우가 정말 많았고, 저번 미션에 주어진 15줄 이하라는 조건은 정말 널널한 조건이었다는 것을 알게되었습니다.

10줄 이하로 메서드를 나누다 보면 정말 작은 단위로 메소드를 자를 수 있게되고, 내가 2주차, 3주차에 작성했던 메소드들이 한 가지 일만 하지 않을 가능성이 높다는 것을 알게되었습니다… 다 끝나고 2주차, 3주차 미션도 한번 다시 풀어보는 시간을 가져야할 거 같습니다.

 

 

 

🙂 4주동안 프리코스를 하며 느낀점

지금까지 많은 자료들을 보면서 공부도 하고 했었지만, 이번 4주가 정말 급성장을 할 수 있었던 기간이었다고 생각됩니다. 만약 프리코스에서 기존처럼 코딩테스트를 진행한 후 붙은 사람들만 프리코스에 참여했었다면 붙지 못했을 거 같습니다.

 

이번 기수부터 프리코스를 확장해서 모두에게 열린 기회를 제공하신거라고 하는데 이번 기수만 3000명이 넘게 참여한 걸로 봐서는 다음 기수는 더 많이 지원할 거 같다는 느낌이 듭니다.

 

그리고 무엇보다도 매주 진행하는 코수타(코치와 수다 타임)가 있는데, 좋은 말도 정말 많이 해주시고 매주 수요일마다 정신 건강을 재정비하는 시간이었다고 생각합니다. 이번에 이것저것 너무 겹치는 일들이 많아서 힘들었는데, 코수타를 통해서 계속 힘내서 했던 거 같아요.

최종 코딩 테스트는 2배수 정도 뽑는다고 들었는데 붙으면 좋겠지만 붙지 못해도 정말 값진 경험했다고 생각합니다. 우테코 프리코스 이전에는 공부 방향을 잡는데 너무 큰 문제를 가지고 있었는데, 프리코스가 끝나고 나니 확실히 달라진 모습을 볼 수 있었습니다.

 

📘 3주차 미션을 시작하면서

3주차 미션을 받은 순간... 추가 요구사항이 더욱 디테일해졌다는 것을 느꼈고, 할 수 있겠지라는 걱정부터 시작되기 시작했었다.
자바를 스스로 공부하기 시작하면서 기본적인 자료형, 문법 등에 대해서는 사용도 해보고 했지만 이번 미션에서는 enum(열거형)을 사용하라는 요구사항이 있었다. 2주차 미션을 하면서 '상수'를 적절하게 사용하면 가독성을 높일 수 있구나라는 것을 느꼈고, 다음 미션에는 꼭 사용해봐야지라는 생각을 하고 있었다. 우테코는 정말 신기한게 마치 내가 하고 있는 생각을 알고 있는 것처럼 새로운 미션에 귀신같이 '열거형'을 사용하라는 요구사항이 있었다. 😦

 

 

 

📖 열거형이 무엇인가?

열거형은 자바에 대해서 공부하면서 들어본적은 많았지만 실제로 코드 개발에서 사용해본적은 없다. 그래서 이번에 미션에서 사용하기 위해서는 혼자 학습을 해봐야겠다고 생각했다. '자바의 정석'이라는 책과 구글링을 통해서 열거형에 대해서 학습하고, 블로그에 정리해놓았다. 간단하게 말하면 '열거형'이란 비슷한 역할을 하는 상수들을 모아서 관리할 수 있도록 도와주는 역할을 한다. static final을 사용하지 않고 비슷한 상수는 모아서 사용한다면 훨씬 가독성을 높일 수 있을 거라고 생각했다.

 

 

 

📖 이번 미션에서 힘들었던 점

솔직히 말하면 다 힘들었다. 클래스 분리도 정말 어려웠고, 함수(메소드)의 길이를 15자 이하로 작성하라는 요구 사항을 의식하면서 코드 작업을 했다. 모든 코드를 작성할 때, 자연스럽게 평소보다 많은 생각을 하게되었다. 그리고 처음에 코드를 작성하면서 이건 엄청난 리펙토링 작업이 필요하겠다는 것을 느끼면서 작업했다. 그 중에서 가장 많이 시간을 쏟았던 삽질을 적어보려고 한다. 한풀이 느낌으로 글을 작성할 것이기 때문에 길어질 수 있다는 것을...ㅠ

 

이번 로또 문제 중에 이런 요구 사항이 있었다.

사용자가 잘못된 값을 입력할 경우 IllegalArgumentException를 발생시키고, "[ERROR]"로 시작하는 에러 메시지를 출력 후 종료한다.

예를 들어 처음에 로또 구입 금액을 입력 받는데, 이때 입력 값이 “1000j”라고 해보자.

  • “1000j” 는 ‘j’라는 문자가 포함되어 있기 때문에 금액이라고 할 수 없다.
  • 잘못된 값을 입력했기 때문에 IllegalArgumentException을 발생한다.
try {
        Integer.valueOf("1000j");
} catch (Exception e) {
        System.out.println("[ERROR] 숫자가 아닌 값을 입력했습니다.");
        throw new IllegalArgumentException();
}

처음에는 이렇게 코드를 작성했다.

내가 생각했던 프로그램 진행 방향은 다음과 같다.

  1. “1000j”가 입력 값으로 들어옴.
  2. Interger.valueOf(”1000j”)에서 NumberFormatException이 발생
  3. catch 블럭으로 Exception을 잡아내고, IllegalArgumentException을 발생 시킴.
  4. 프로그램이 종료됨.

생각한대로라면 사용자가 잘못된 값을 입력했고, IllegalArgumentException을 발생했고, “[ERROR]”로 시작하는 에러 메시지도 출력했고, throw new를 통해서 프로그램도 종료되었다.

하지만 ApplicationTest에서 예외_테스트()가 자꾸 실패했다.

@Test
void 예외_테스트() {
    assertSimpleTest(() -> {
        runException("1000j");
        assertThat(output()).contains(ERROR_MESSAGE);
    });
}

왜 실패하지…?;; 이때 부터 삽이 다 닳아서 나무 막대기만 남을 정도로 삽질을 시작했다.

  1. 첫 번째 삽질
    • runException()에 뭔가가 숨어있나보다. 찾아보러 가자.
    • 그렇게 처음으로 woowacourse-projects에 있는 NsTest.java 파일에 가봤다.
    • protected final void runException(final String... args) { try { run(args); } catch (final NoSuchElementException ignore) { } }
    • 코드를 보니 뭔가 저 catch (final NoSuchElementException ignore)이 문제일 거 같다는 생각이 들었다.
    • 그래서 내가 작성한 코드에서 NoSuchElementException을 throw 해보기로 했다.
    • try { Integer.valueOf("1000j"); } catch (Exception e) { System.out.println("[ERROR] 숫자가 아닌 값을 입력했습니다."); throw new NoSuchElementException(); }
    • 이렇게 코드를 작성하고, 다시 ApplicationTest를 돌려봤다. 오…초록불이 들어왔다! 해결한건가?
    • 하지만 문제 요구 조건에서 잘못된 입력이 들어오면 IllegalAegumentException을 발생시키고 라는 요구 조건에 만족하지 못했다.
    • 그래서 혹시나 하는 마음에 미리 만들어놓았던 IllegalArgumentException 발생 여부를 테스트하는 코드를 돌려봤다.
    • @DisplayName("입력된 금액 예외 발생 테스트") @ParameterizedTest @ValueSource(strings = {"3500", "4650", "9080", "10", "100", "1000j"}) void validatePurchaseAmountTest(String money) { assertThatThrownBy(() -> InputException.validatePurchaseAmount(money)) .isInstanceOf(IllegalArgumentException.class); }
    • 역시나 “1000j” 부분에서 빨간불이 들어왔다. ApplicationTest만 통과하면 되는거 아닌가? 라는 생각이 순식간에 지나갔지만 절대…용납할 수 없다. 이런 찝찝한 문제가 발생하면 절대…잠을 잘 수가 없다.
  2. 두 번째 삽질
    • 첫 번째 삽질이 끝나고 ApplicationTest가 통과하려면 일단 NoSuchElementException이 발생되어야 한다는 결론을 무작정 내버렸다.
    • NoSuchElementException 은 발생되어야 하고, IllegalArgumentException도 발생되어야 하고 이게 무슨 혼돈의 카오스인가….
    • “두 개의 예외를 동시에 발생시킬 수 있는가?” 부터 시작해서 정말 모든 키워드는 다 넣어서 구글링을 해봤다.
    • 하지만 어떠한 방법도 ApplicationTest와 내가 만든 테스트가 동시에 통과하는 방법도 없었다.
  3. 결론에 도달
    • 검정색 화면에 있는 코드만 계속 보고 있으니 점점 눈이 흐려질 때쯤 문제를 다시 한번 읽어봐야겠다라는 생각이 들어서 README.md 파일을 다시 천천히 읽어봤다.
    • 잘못된 입력 → IllegalArgumentException 발생 → [ERROR] 출력 → 프로그램 종료….?
    • 갑자기 문득 main 함수가 종료돼도 프로그램이 종료되는 거 아닌가…? 라는 생각이 들었고, 코드를 작성해봤다. 
    • // 프로그램 실행 코드 public void playLottoProgram() { try { savePurchaseAmount(); saveLottoIssueCount(); issueLottoSeveralTimes(lottoIssueCount, myLotto); OutputView.printLottoPurchaseInformation(myLotto, lottoIssueCount); saveWinningNumber(); saveBonusNumber(); setResult(myLotto, winningNumber, bonusNumber); Calculator calculator = new Calculator(); calculator.calculateTotalEarnings(result); calculator.calculateEarningsRate(purchaseAmount); OutputView.printLottoResult(result, calculator.getEarningsRate()); } catch (IllegalArgumentException exception) {} }
    • // 예외 처리 코드 try { Integer.valueOf("1000j"); } catch (Exception e) { System.out.println("[ERROR] 숫자가 아닌 값을 입력했습니다."); throw new IllegalArgumentException(); }
    • 프로그램 실행 코드 전체를 try-catch로 감싸서 IllegalArgumentException이 발생되면 프로그램이 실행이 멈추도록 해봤다.
    • 와…우…. ApplicationTest와 내가 만든 테스트 코드에서 모두 초록색 불이 들어왔다.
    • 정말 간단했던 해결방법인데, 거의 6시간 정도를 빙빙 돌았다. 허무하면서도 이제 잘 수 있다는 안도감에 너무 좋았다. (지금 시간은 오전 2시 24분)
    • 결론은 문제를 잘못 이해했고, woowacourse-projects를 의심했던 벌을 받았다고 생각한다. 틀려도 내가 틀렸지 우테코가 틀렸을리가…없지 역시 😂

 

 

 

📖 다음 미션을 시작하기 전

다음 미션을 받기 전에 이번 미션 회고록을 작성하면서 공통 피드백을 보며 필요한 부분은 학습하도록 한다. 이번 공통 피드백 내용은 다음과 같습니다. (필요한 부분만 가져왔습니다.)

 

💡 비즈니스 로직과 UI로직을 철저히 분리해라.

비즈니스 로직과 UI 로직이 한 개의 클래스에 있는 것은 단일 책임(SRP)에 위배된다.

View에서 사용해야되는 데이터라면 getter를 만들어서 전달하고, 현재 객체의 상태를 로그에 나타내기 위함이 강하다면 toString()을 사용해서 정의한다.

 

💡 연관있는 상수의 경우는 static final 보다는 enum을 사용한다.

 

💡 final 키워드를 사용해서 값의 변경을 막는다.

최근에 등장하는 프로그래밍 언어들의 기본은 ‘불변’이다. 자바에서는 불변을 위해서 final 키워드를 사용할 수 있다.

final은 상수 선언할 때만 사용하는 줄 알고 있었다. 필드(인스턴스 변수)의 불변을 위해서도 사용할 수 있다는 것을 알아두자.

 

💡 객체의 상태 접근을 제한한다.

인스턴스 변수의 접근 제어자는 private를 사용한다. 객체의 캡슐화를 하기 위한 기본적인 설정.

 

💡 객체는 객체스럽게 사용한다.

객체 내부에 로직을 구현한다. 일반적으로 getter()를 많이 사용하는 경향이 있다. 하지만 객체의 모든 인스턴스 변수를 보내줘야 하는데, 이 모든걸 getter()로 구현한다면 과연 가독성이 좋아질까?

그렇기 때문에 View에서 단순 출력을 하기 위한 데이터 정도는 getter()로 전해줄 수 있지만, 그 이외의 경우에는 getter로 데이터를 보내서 로직을 처리하기 보다는 데이터를 객체로 받아와서 로직을 돌린 후 결과를 날려주는 형식으로 구현하는 것이 좋다.

getter를 사용하는 대신 객체에 메시지를 보내자

 

💡 필드(인스턴스 변수)의 수를 줄이기 위해 노력한다.

객체에 인스턴스 변수가 많을 수록 객체의 복잡도를 높이고, 버그 발생의 가능성을 높일 수 있다. 필드에 중복이 있거나, 불필요한 필드가 있지는 않은지 확인해볼 필요가 있다.

 

💡 성공하는 테스트 뿐만 아니라 예외에 대한 케이스도 테스트 해야 한다.

 

💡 테스트 코드도 코드이다.

즉, 테스트 코드도 중복되는 부분이 존재한다면 줄이는 것이 바람직하다. 예를 들어 단순히 값이 바뀌는 경우라면 @ParameterizedTest를 사용해서 테스트할 수 있다.

 

💡 테스트를 위한 코드는 구현 코드에서 분리되어야 한다.

테스트를 통과하기 위해 구현 코드에 테스트를 위한 코드를 작성해서는 안된다.

  1. 테스트를 위해서 접근 제어자를 바꾸는 경우
  2. 테스트 코드에서만 사용되는 메서드

 

💡 단위 테스트하기 어려운 코드를 단위 테스트 하기

메서드 시그니처를 수정하여 테스트하기 좋은 메서드로 만들기

 

💡 private 함수를 테스트하고 싶다면 클래스(객체) 분리를 고려한다.

가독성을 높이기 위해서 private 함수를 구현한 경우 public으로도 검증 가능하다고 여겨질 수가 있다. 왜냐하면 public 함수가 private 함수를 사용하기 있기 때문에 자연스럽게 테스트 범위에 포함이 된다.

하지만 가독성 이상의 역할을 하는 경우에는 테스트를 쉽게 구현하기 위해서 해당 역할을 수행하는 다른 객체를 만들 타이밍이 아닌지 고민해봐야한다.

다음 단계를 진행할 때는 너무 많은 역할을 하고 있는 함수나 객체를 어떻게 의미 있는 단위로 분할할지에 초점을 맞춰 진행한다.

 

 

 

🔥 다음 미션을 시작하기 전 마음가짐

아직 문제를 자세하게 읽어보진 않았지만, 슬랙 채널에서 다른 분들이 말하는 걸 보면 오징어 게임에 나오는 '다리 건너기' 게임을 구현하는 미션인 것 같다. 최근에 정말 많은 일들이 한번에 몰려와서 체력적으로 딸리는 것이 느껴진다... 그래도 지금까지 해온 것이 있으니깐 포기하지 않고 마무리 잘하고 싶다.

 

2주차 미션의 추가 요구 사항

2주차 미션이 마무리되었다. 온보딩 미션에서와는 다르게 추가적인 요구사항들이 존재했던 미션이었습니다.

추가적인 요구사항은 다음과 같습니다.

  1. indent(인덴트, 들여쓰기) depth를 3이 넘지 않도록 구현한다. 2까지만 허용한다.
  2. 3항 연산자를 쓰지 않는다.
  3. 함수(또는 메서드)가 한 가지 일만 하도록 최대한 작게 만들어라.
  4. JUnit 5와 AssertJ를 이용하여 본인이 정리한 기능 목록이 정상 동작함을 테스트 코드로 확인한다.
  5. 자바 코드 컨벤션을 참고하여 코드를 작성
  6. 커밋 메시지 컨벤션을 참고하여 깃허브 커밋 메시지 작성

 

 

 

구현 기능 목록 정리

이때부터 확실히 뭔가 배워간다는 것을 느꼈습니다. 1주차 때는 기능을 구현하면서 기능목록을 명세했었습니다. 하지만 이번 2주차 미션 때는 구현하고자 하는 기능들을 먼저 작성했습니다.

주로 저는 노션을 자주 사용하고, 제가 정리한 기능 목록도 노션에 먼저 기록해서 README.md 파일에 저장해서 커밋을 했습니다.

기능 구현을 시작하기 전에 기능 목록을 정리를 해보니 어떤 순서대로 구현을 해야겠고, 얼마나 작은 기능까지 나눌 수 있을까라는 고민을 많이 하게되었습니다. 그리고 이렇게 정리해둔 기능 목록에 따라서 기능 구현을 하다보니 내가 구현해야되는 기능에 대해서 더 확실히 알고 있는 상태에서 구현할 수 있었고, 개발 속도도 더 빠르게 진행되었다고 체감으로 느꼈습니다.

 

 

 

기능을 구현하면서 느꼈던 점

이번 2주차 미션에서는 자바 컨벤션 코드도 지키면서 메소드를 최대한 작게 나누어 기능을 구현하는 것에 초점을 맞추고 기능 구현을 시작했습니다.

 

메소드의 기능을 최소한(1개)으로 나누고 작업을 시작하니 신기하게 메소드 이름을 작명할 때도 이전보다 더 쉽게 작명할 수 있다는 것을 느꼈습니다. 메소드 이름은 동사로 시작하게 짓는 것이 컨벤션 내용에 있었지만, 지금까지 구현하던 메소드들은 기능이 2개 이상이었기 때문에 동사를 2개 써야돼서 메소드 이름 작명에 어려움을 느꼈던 거 같습니다. 그래서 기능을 최소한으로 나누고 보니 동사 1개만 사용해서 이름을 작명할 수 있었습니다. 하지만 아직 아쉽다고 느껴지는 것이 메소드의 기능을 표현할 적절한 동사를 찾는 것이 어려웠고, 동사 뒤에 붙는 이름을 작명하는 것이 어려웠습니다.

 

이렇게 메소드 이름을 신경쓰면서 작업함으로써 얻은 효과는 주석을 많이 줄일 수 있었습니다. 이전 미션에서는 기능을 가지고 있는 메소드 뒤에는 무조건 주석을 작성했었습니다. 이때까지만 해도 주석으로 설명을 추가해주는 것이 좋은 코드를 작성하는 방법이라고 생각했었습니다. 어떤 분의 글을 제가 읽었는데 최고의 주석은 잘 만들어진 메소드 이름이라는 글을 봤었습니다. 메소드 이름을 잘 만들어주면 쓸데없는 주석을 다 지워도 무방하다는 것을 의미합니다. 그래서 2주차 미션에서 가장 시간을 많이 썼던 것이 “메소드는 하나의 기능만을 하게 만들어라”“메소드의 이름만 봐도 어떤 기능인지 알게 만들어라” 였습니다.

 

두 번째는 이번에 추가된 요구사항 중 Test에 관련된 내용이었습니다. 단위 테스트가 중요한 이유에 대해서 찾아보고 Junit5에 관련된 내용을 공부했던 거 같습니다. 저는 이번에 리펙토링 과정에서 코드 변경이 많았었습니다. 하지만 신기하게도 코드 리펙토링을 하더라도 그 메소드의 기능은 바뀌지 않습니다. 그렇기 때문에 제대로된 테스트 코드를 작성해뒀다면 리펙토링을 한 코드도 같은 기능에 대해서 빠르게 테스트해볼 수 있었습니다. 이게 아마도 단위테스트의 맛이지 않을까 싶습니다. 초록색 글자는 언제 봐도.. 짜릿합니다.

 

 

 

 

2주차 미션을 마무리하며

이번 미션을 진행하면서 얻었던 내용을 다시 정리하면 다음과 같습니다.

  1. 기능 목록을 먼저 작성해라.
    • 오히려 개발 속도를 증가시킬 수 있다.
    • 내가 구현하고 있는 구현을 정확하게 알고 구현할 수 있다.
  2. 메소드를 최소한의 기능단위로 나누어라.
    • 메소드 이름 작명을 하기 편해진다.
    • 단위 테스트를 할 때, 메소드별로 적용시킬 수 있다.
  3. 메소드 이름과 변수 이름 작명에 힘을 쓰고, 쓸데없는 주석은 지워라.
    • 난잡한 주석을 지울 수 있고, 코드의 가독성을 높여준다.
  4. 정확한 단위 테스트 코드를 하나 만들어둬라.
    • 코드 리펙토링 후 테스트에 드는 비용(시간)을 최소화할 수 있다.

 

이 4가지에 대해서는 이제 알고 학습하기 시작했고, 앞으로 코드 개발에서 꾸준히 신경써야하는 요소들이라고 생각합니다. 다음 3주차 미션에서도 꾸준히 적용되어야 하는 사항이라고 생각하고, 프리코스가 끝나는 시점에서는 모든 요구사항들을 적용시켜 기능 구현을 할 수 있는 능력을 키우고 싶습니다. 남은 2주도 화이팅.

 

+ Recent posts