우아한 테크코스 선발 과정에서 진행되는 1주차 프리코스가 어제 끝났다. 1주차의 미션은 온보딩으로 요구 사항에 맞춰 7문제를 해결하는 것이었다.

나는 7문제를 모두 풀었다. 총 121개의 커밋이 기록됐다.
1주차는 특별히 까다로운 프로그래밍 요구 사항이 없었지만 미리 매를 맞고 싶었다. 그래서 지난 기수의 프리코스 요구 사항을 참고해 이것저것 연습해보았다.
최대한 메소드를 분리하려고 시도했다. 메소드를 분리하기 위해 다음의 명제를 따랐다.
메소드가 한 가지 일만 하도록 구현한다.
이전까지는 메소드의 기능을 분리하려고 노력하지 않았다. 메소드가 내 의도대로 기능하면 그것으로 족했다. 하지만 메소드를 분리하자 전보다 코드의 가독성이 개선되는 것을 느꼈다. 쉽게 읽어지지 않는 코드는 메소드를 분리하자 제법 봐줄만하게 변했다.
하나의 기능만 갖는 메소드는 테스트가 용이했다. 이전에는 테스트를 통과하지 못할 때 디버깅에 오랜 시간을 쏟았다. 반면 메소드를 분리하고 기능 단위로 테스트하니 전보다는 디버깅 할 일이 줄어들었다. 예외 케이스를 찾아 처리하기도 편했다.
메소드를 잘게 분리하는 것이 여러모로 좋은 것 같았다.
하지만 메소드를 분리하는 것은 말처럼 쉽지 않았다. "이런 것까지 분리해야 되는 걸까?" 라는 의문이 들었다. 메소드 분리에 적용되는 명확한 기준이 없었기 때문에 헷갈렸다. 메소드 분리를 연습하면서 코드를 작성하는 시간보다 머릿속으로 고민하는 시간이 더 늘어났다.
메소드 네이밍, 매개변수 설정, 반환값 설정 등에도 오랜 시간이 필요했다. 메소드의 이름을 설정할 때는 메소드의 기능을 알리면서도 매개변수와 반환값에 대한 정보를 전달하는 이름을 짓고 싶었다. 하지만 영어로 간결하게 표현하기 쉽지 않았다. 연습이 필요했다.
한편, 메소드를 분리하자 한 클래스 안에 많은 메소드가 들어가는 일이 생겼다. 그러니 코드를 제대로 읽기 어려웠다. 클래스를 분리할 필요성을 느꼈다. 하지만 어디서부터 어떻게 분리를 해야하는지 알지 못했다. 각 메소드들이 얼기설기 얽혀있었기 때문이다. 클래스를 분리하기 위해서는 기능 설계 단계에서부터 다시 시작해야했다. 결국 효율적인 코드를 위해서는 전체의 설계를 반드시 고려할 줄 알아야 한다고 느꼈다.
메소드 분리는 분명한 장점을 갖는다. 따라서 익숙해지는 시간을 들여야 할 것 같다. 메소드 분리에 대한 나만의 기준이 생기고, 메소드 네이밍에 노하우가 생길 때까지 연습해야겠다. 그리고 앞으로 객체지향 설계 방법을 공부해야겠다. 코드를 메소드로, 클래스로, 패키지로 적절히 분리하는 방법을 깊이 이해하고 싶다.
객체지향 설계를 연습해보고 싶은 마음에 객체지향 생활체조 자료를 찾아 공부했다. 6번, 7번 문제풀이에 적용해보았다.
객체지향 생활체조는 객체지향적 사고 방식을 연습할 수 있는 9가지 원칙이다.
객체지향 프로그래밍을 위해 다음의 9가지 원칙을 지킨다.

문제를 풀면서 원칙들을 지키려고 노력했다. 전보다는 객체 지향적인 코드, 읽기 좋은 코드를 짤 수 있었다.
원시값과 문자열을 객체로 포장했고 그 클래스 내에 필요한 메소드를 구현했다. 해당 클래스는 하나의 역할만 가지면서도 확장성 있는 코드가 되었다.
일급 컬렉션을 만들어 사용했다. 컬렉션 객체를 여러 메소드가 주고 받아 연산을 처리하는 것보다, 일급 컬렉션 클래스에 하나의 메소드를 만들어 사용하는 것이 훨씬 읽기 좋았다.
getter를 사용하지 않는 것은 어려웠다. 가령 일급 컬렉션을 정렬하기 위해 객체의 필드를 불러와야 할 때, getter 외에 다른 방법을 떠올리지 못했다. 결국 getter를 그대로 사용했다. getter를 사용하지 않는 방법을 찾아봐야겠다.
객체지향 생활체조 원칙을 지키면서 객체지향의 느낌을 조금은 이해할 수 있어 좋았다. 알고 싶은 것을 알아갈 수 있어 기뻤다.
하지만 클래스를 단 하나의 책임을 갖도록 분리하는 것은 여전히 어려웠다. 객체지향에 관한 자료를 찾아보고 디자인 패턴 등을 공부해보고 싶다. 클래스에게 어떤 역할과 책임을 부여하는 것이 옳은지, 객체는 서로 어떻게 의존하는 것이 합당한지 알아보아야겠다.
국비학원에서 TDD(Test-Driven Development)의 맛을 아주 살짝 보았다. 이전과는 다른 개발 방식에 나도 직접 TDD를 하고 싶었다. 이번 기회에 도전했다. 이번 미션에서 7번 문제를 제외하고는 TDD를 할 수 있었다.
개발하기 전에 테스트 코드를 먼저 작성한다.
내가 알고 있는 Test 메소드는 Junit5 Assert 메소드들이었다. 하지만 프리코스 테스트에는 AssertJ가 사용되어 있었다. 두 라이브러리의 차이점은 가독성에 있었다.
나도 Junit5 assert 메소드를 사용할 때 매번 참값과 기댓값의 위치가 헷갈렸다. 반면에 AssertJ는 메서드 체이닝으로 매개변수를 하나만 받아 헷갈릴 일이 적었다. AssertJ는 보다 직관적이고 읽기 쉬운 테스트코드에 알맞다고 느꼈다. 따라서 AssertJ를 공부하고 사용하였다.
TDD를 하자 단, 하나의 기능을 개발할 때도 고민이 필요했다. 이전에는 먼저 코드를 짜고 예외를 우연히 발견했다면, TDD는 예외를 생각하게 만들었다. 예외 처리에도 TDD는 긍정적인 면이 많았다.
한편 TDD는 로직을 분명히 이해해야만 가능했다. 프로젝트 전체의 로직을 알아야 테스트 코드를 개발할 수 있었다. 결국 TDD는 생각하고 짜는 코드를 실현할 수 있게 해주었다.
AssertJ를 사용하면서 테스트 코드가 길어지고 테스트하는 메소드가 다양해지자 코드를 알아보기 어려웠다. 테스트 케이스 입력과 테스트 대상을 기준으로 코드를 적절히 분리해야할 필요를 느꼈다. 자료를 찾다가 BDD에 대해 알게 되었다. BDD(Behaviour-Driven Development)는 TDD의 일종으로, 시나리오를 기반으로 테스트 케이스를 작성하는 것이다. 하나의 시나리오는 Given, When, Then 구조를 갖는다.
어떤 메소드를 테스트 할 때 Given, When, Then 구조로 테스트하면, 메소드의 기능을 더욱 자세히 테스트할 수 있었다. 또한 읽고 이해하기에도 훨씬 편한 코드가 되었다.
이러한 연습들로 지식이 쌓였지만 동시에 쉽게 답할 수 없는 궁금증이 생겼다. 차근차근 공부하다보면 하나씩 대답할 수 있는 날이 올 것이다.