조컴퓨터

[우아한테크세미나] TDD 리팩토링 (자바지기 박재성 님) 본문

공부 방향 설계

[우아한테크세미나] TDD 리팩토링 (자바지기 박재성 님)

챠오위 2022. 7. 4. 14:02

TDD Circle

1. Test Fails

2. Test Passes

3. Refactoring

 

내 경우에는 1번과 2번을 진행하고, 3번을 진행하지 않는 경우가 대다수였다.

박재성 님께서도 3번을 진행하지 않는 경우가 많다고 콕 집어 설명하셨다.

 

-

리팩토링 연습 - 메서드 분리

테스트 코드는 변경하지 말고,

테스트 대상 코드(프로덕션 코드) 를 개선하는 연습에 집중한다.

-

 

예를 들어, else 와 indent 를 줄이는 연습이 이에 해당한다.

 

이것은 의식적인 연습 7가지 원칙 중 2가지에 해당하는 경우이다.

두 번째, 개인의 컴포트존을 벗어난 지점에서 진행, 자신의 현재 능력을 살짝 넘어가는 작업을 지속적으로 시도

세 번째, 명확하고 구체적인 목표를 가지고 진행

 

과거의 나와 현재의 나 둘 다 이것저것 다해보는 상태에 있어 컴포트존에 대한 사항은 잘 모르겠고(있긴 있을 것이다),

명확하고 구체적인 목표 설정이 필요하다는 것은 아주 격렬히 동감하는 바이다. 

 

박재성 님께서 설명하시는 명확하고 구체적인 목표 설정의 예시는 내가 생각하는 것 보다는 좀 더 작은 범위에 속했다.

(물론 큰 범위도 해당하겠지만 일단은 TDD 에 대한 설명 시간이니까 예시는 작고 간결하게..)

 

예시) indent 2 이상인 곳 없애기, else 없애기

 

들여쓰기(indent) 리팩터링

 

else 리팩터링

이 경우 로컬 변수도 만들 필요 없어지고 좋다. 

indent 도 예외적인 상황을 제외하고는 0 이 된다. 

 

indent 1 하나 줄이는 데 목숨 걸라 하신다. 여기에서 희열감을 느낄 정도로 말이다. 

 

이보다 나아가서 정성적인 연습을 한다고 치면

메서드가 한 가지 일만을 하도록 구현하는 방법이 있다.

물론 이 경우에는 for문을 두 번 도는 구조가 되지만, 우리가 구현하는 대부분의 반복문은 데이터 크기가 크지 않기 때문에 프로그램 성능에 영향을 거의 주지 않는다. 그리고 이때 메서드가 한 가지 일만 하게 작성한다면 다시 재활용 될 수 있다.

 

또, 로컬 변수가 정말로 필요한지를 따지는 것도 한 예에 속한다.

변수를 할당하지 않는 것도 좋은 예시에 속한다. 

 

compose method 패턴 적용

메서드(함수)의 의도가 잘 드러나도록 동등한 수준의 작업을 하는 여러 단계로 나눈다.

*compose method : https://dragonq.tistory.com/entry/ComposeMethod

 

ComposeMethod

Compose Method  어떤 메서드의 내부 로직이 한눈에 이해하기 어렵다면, 그 로직을 읟가 잘 드러나며 동등한 수준의 작업을 하는 여러 단계로 나눈다. Composed Method는 다른 메서드들에 대한 호출로 이

dragonq.tistory.com

 

 

compose method 패턴 적용

위와 같은 코드가 완성된다.

 

이때 박재성 님께서는

한 번에 모든 원칙을 지키면서 리팩토링하려고 연습하지 말고,

한 번에 한 가지의 명확하고 구체적인 목표를 가지고 연습하라고 전달하신다.

 

이는 코드숨 과정에서 다른 분들의 PR 을 보면서 느낀 바이기도 하다.

잘하는 다른 분들의 코드를 보면 한 번의 PR 에 구체적인 한 가지 목표를 가지고 리팩터링하고 merge 하는 모습이 많이 목격되었다.

 

그리고 연습은 극단적인 방법으로 연습하는 것도 좋다고 전달하신다. 

예를 들어, 한 메서드의 라인 수 제한을 15 라인에서 10 라인으로 줄여가면서 연습하는 것도 좋은 방법이다.

 

 

-

클래스 분리 - 리팩터링 연습

-

 

숫자 이외의 값 또는 음수 값을 전달하는 경우 RuntimeException 예외를 throw 한다.

 

음수 값에 해당하는 테스트 코드 작성

 

음수 값을 RuntimeException 예외를 throw 하는 메서드 작성

 

모든 원시값과 문자열을 포장한다.

 

+ 추가적으로

 

-

클래스 분리 연습을 위해 활용할 수 있는 원칙

1. 일급 콜렉션을 쓴다.

2. 3개 이상의 인스턴스 변수를 가진 클래스를 쓰지 않는다.

-

 

1. 일급 콜렉션 사용

 

 

-

4단계 - 장난감 프로젝트 난이도 높이기

점진적으로 요구사항이 복잡한 프로그램을 구현한다.

앞에서 지켰던 기준을 지키면서 프로그래밍 연습을 한다.

 

5단계 - 의존관계 추가를 통한 난이도 높이기

테스트하기 쉬운 코드와 테스트하기 어려운 코드를 보는 눈

테스트하기 어려운 코드를 테스트하기 쉬운 코드로 설계하는 감

앞 단계 연습을 잘 소화했으면 분리하는 역량이 쌓인다.

 

한 단계 더 나아가기

컴파일 에러를 최소화 하면서 리팩토링하기

ATDD 기반으로 응용 애플리케이션 개발하기

레거시 애플리케이션에 테스트 코드 추가해 리팩토링하기

 

구체적인 연습 목표 찾기

객체지향 생활 체조 원칙

- 규칙 1 : 한 메서드에 오직 한 단계의 들여쓰기만 한다.

- 규칙 2 : else 예약어를 쓰지 않는다.

- 규칙 3 : 모든 원시값과 문자열을 포장한다.

- 규칙 4 : 한 줄에 점을 하나만 찍는다.

- 규칙 5 : 줄여쓰지 않는다(축약 금지).

- 규칙 6 : 모든 엔티티를 작게 유지한다.

- 규칙 7 : 3개 이상의 인스턴스 변수를 가진 클래스를 쓰지 않는다.

- 규칙 8 : 일급 콜렉션을 쓴다.

- 규칙 9 : 게터/세터/프로퍼티를 쓰지 않는다.

-

 

 

Q&A

답변 : 리팩토링을 하다보면, 클린 코드를 만들고 쪼개다 보면 성능의 이슈가 생기는 경우가 있다.

근데 잘 생각해보면 서비스를 오픈했을 때 아무도 사용하지 않으므로 상당 시간 동안은 문제가 되지 않는다.

과거에는 하드웨어가 비싸고 느렸다. 현재에는 하드웨어가 싸졌고, 인건비가 올라갔다.

 

그렇기 때문에 가독성이 좋은 방향으로 작성하는게 맞다.

운영을 하다가 사용자가 많아지고 성능이 떨어지는 때가 생기는데,

그때 분석을 하다 보면 nosql, 내부 API call 의 문제인 경우가 대다수일 것이다.

코드에서 문제가 생기는 경우는 극히 드물다.

 

그러나 간혹 인스턴스가 너무 많이 생성되는 경우가 있다. 

그러면 이때 거꾸로 상황을 정리하면 된다. 

우형이나 네이버 급의 사용자가 많은 상황이면 지금부터 고려하는게 맞다. 

그렇지 않는 경우는 읽기 좋은 코드를 작성하는 게 맞다. 

 

 

-

중요한 것은 어떤 Practice 를 하느냐가 아니다.

현재보다 조금씩 나아지고 있다는 방향성이 중요하다.

-