본문은 이곳을 참고
목차
- 의식적인 연습이란?
- TDD, 리팩토링 적용 - 개인
- TDD, 리팩토링 적용 - 개인(주니어) -> 팀
- TDD, 리팩토링 적용 - 내가 리더
1. 의식적인 연습이란?
- 한 단계 발전하기 위해 컴포트존(익숙하고 편안한 수준)에서 벗어나 의식적인 연습을 한다.
- 본인이 자각하는 연습을 꾸준히하며 개발실력을 올리는 것이 중요하다.
- 특히 개발업무와 같이 특정기간이 되면 학습없이, 연습없이 제품을 만들어 낼 수 있지만 이것을 넘어 발전하는 방법을 설명한다.
- 피드백을 받을 수 있는 환경(코드리뷰나 테스트 코드 등)을 만들어서 피드백에 따라 다음 단계를 연습해야 한다.
- 이러한 과정을 통해야만 훌륭한 개발자가 될 수 있다.
- 많은 연습은 역량을 보장하지 않는다. 그렇기에 온전히 집중하고 '의식적' 으로 행동하라.
의식적인 연습의 7가지 원칙(도서 - 1만 시간의 재발견)
- 효과적인 훈련 기법이 수립되어 있는 기술 연마
- 개인의 컴포트 존을 벗어난 지점에서 진행, 자신의 현재 능력을 살짝 넘어가는 작업을 지속적으로 시도
- 명확하고 구체적인 목표를 가지고 진행
- 신중하고 계회적이다. 즉 개인이 온전히 집중하고 '의식적'으로 행동할 것을 요구
- 피드백과 피드백에 따른 행동 변경을 수반
- 효과적인 심적 표상을 만들어내는 한편으로 심적 표상에 의존
- 기존에 습득한 기술의 특정 부분을 집중적으로 개선함으로써 발전시키고, 수정하는 과정을 수반
우아한 테크코스 미션1 부여 => 미션1 완료후 PR => PR 평가 후 공통 피드백 => 미션2 제약사항 추가(리팩토링) -> 미션2 평가 공통피드백 => 미션3 제약사항
리팩토링 자체가 의식적인 연습으로 TDD를 하는 과정, 그
과정에서 극단적인 미션을 추가하여 더욱 의식적인 연습을 돕는다.
ex)
우아한 테크코스 프리코스 피드백 내용
- 1주차 - 프로그래밍 제약사항
- 자바 코드 컨벤션을 지키면서 프로그래밍한다
- indent(인덴트, 들여쓰기) depth 3이 넘지 않도록 구현한다. 2까지만 허용한다
- 함수(또는 메소드)가 한 가지 일만 하도록 최대한 작게 만들어라
- 1주차 - 피드백
- space 도 convention 이다
- 불필요하게 공백 라인을 만들지 않는다
- git commit 메시지를 의미있게 작성한다
- 2주차 - 프로그래밍 제약사항
- 함수(또는 메소드)의 길이가 15라인을 넘어가지 않도록 구현한다
- else 예약어를 쓰지 않는다
- 2주차 - 피드백
- java api 를 적극 활용한다
- 3주차 - 프로그래밍 제약사항
- 함수(또는 메소드)의 길이가 10라인을 넘어가지 않도록 구현한다
- indent(인덴트, 들여쓰기) depth 2이 넘지 않도록 구현한다.
- 함수(또는 메소드)의 인자 수를 3개까지만 허용한다.
- 3주차 - 피드백
- 상태 데이터를 가지는 객체에서 데이터를 꺼내려(get) 하지 말고 객체에 메시지를 보내라
* car.getPosition() == maxDistance;
* car.isMaxPosition(maxDistance);
- 상태 데이터를 가지는 객체에서 데이터를 꺼내려(get) 하지 말고 객체에 메시지를 보내라
- 요구사항 분석
- MD 파일로 구현할 기능 목록을 먼저 작성
2. TDD 리팩토링 (method)
TDD, 리팩토링 == 운동 -> 평생 연습하겠다는 마음가짐을 가져야 한다.
시작하기
- 주변 정리를 통해 꾸준히 연습할 시간을 확보한다.
- 토이 프로젝트 찾기(회사 코드로 하지말라)
- 토이 프로젝트를 시작하여 주변 환경에 영향을 받지 않고 꾸준히 연습한다. 작더라도 꾸준히!
1 단계 - 단위테스트 연습
- 자신이 주로 사용하는 자바 API를 이용해서 단위테스트를 만드는 연습을 하는 것으로 시작.
- api에 대한 이해도, 단위테스트를 만드는 이해도가 증가됨, input, output이 명확한 api로부터 연습
- (ex. 자바 String클래스의 다양한 메소드(함수) 사용법, 자바ArrayList에 데이터를 추가, 수정, 삭제하는 방법)
위와같은 방법으로 자신이 많이쓰는 API를 단위테스트 해 볼것.
연습 효과
- 단위테스트 방법을 학습할 수 있다.
- 단위테스트 도구(xUnit)의 사용법을 익힐 수 있다.
- 사용하는 API에 대한 학습 효과가 있다.
알고리즘을 학습한다면 알고리즘 구현에 대한 검증을 단위 테스트로 한다. (알고리즘은 Input, Output이 명확하기 때문에 연습하기 좋다)
2단계 - TDD 연습
- TDD 연습이 목적이다. 난이도가 낮거나 자신에게 익숙한 문제로 시작한다.
- 엄청 간단한 예제도 많은 연습을 할 수 있으며 요구사항이 복잡할 필요는 없다.(복잡한게 중요하지 않음)
- 의존관계를 가지지 않는 요구사항으로 연습한다. ex) 웹, 모바일, DB
- 위의 의존 관계가 없는 토이프로젝트로부터 시작해라.
문자열 덧셈 계산기 요구사항
쉼표(,) 또는 콜론(;)을 구분자로 가지는 문자열을 전달하는 경우 구분자를 기준으로 분리한 각 숫자의 합을 반환
요구사항
TDD사이클을 지켜라
TDD를 처음에 연습할 때 분리해서 연습할 수 있음.
TDD 사이클(실패 => 패스 => 리팩토링) 과정을 반드시 지킬 것.
테스트 작성
public class StringCalculator{
public static int splitAndSum(String text){
int result = 0;
if(text == null || text.isEmpty()){
result=0;
}else{
String[] values = text.split(",|:");
for(String value : values){
result += Integer.parseInt(value);
}
}
return result;
}
}
3단계 - 메소드 분리 리팩토링
- 테스트 코드의 변경 없이 테스트 대상 코드를 개선하는 연습을 한다.
- 정상적인 기준보다는 정량적인 기준으로 연습한다.
위의 코드를 리팩토링 해보자
1. 한 메서드에 오직 한 단계의 들여 쓰기만 한다.
public class StringCalculator{
public static int splitAndSum(String text){
int result = 0;
if(text == null || text.isEmpty()){
result=0;
}else{
String[] values = text.split(",|:");
result = sum(values);
}
return result;
}
private static int sum(String[] values){
int result = 0;
for(String value : values){
result += Integer.parseInt(value);
}
return result;
}
}
2. else 예약어를 쓰지 않는다.
public class StringCalculator{
public static int splitAndSum(String text){
int result = 0;
if(text == null || text.isEmpty()){
return 0;
}
String[] values = text.split(",|:");
return sum(values);
}
private static int sum(String[] values){
int result = 0;
for(String value : values){
result += Integer.parseInt(value);
}
return result;
}
}
3. 메서드가 한 가지 일만 하도록 구현하기
숫자로 바꾸는 부분과 sum으로 바꾸는 부분을 분리
4. 로컬 변수가 필요한가?
5. compse method 패턴 적용
메소드(함수)의 의도가 잘 드러나도록 동등한 수준의 작업을 하는 여러 단계로 나눈다.
한번에 모든 원칙을 지키면서 리팩토링하려고 연습하지 마라.
한번에 한 가지 명확하고 구체적인 목표를 가지고 연습하라.
연습은 극단적인 방법으로 연습하는 것이 좋다.
예를 들어 한 메소드의 라인 수 제한을 15라인 => 10 라인으로 줄여가면서 연습하는 것도 좋은 방법
기존과 다른 생각이 나올 수 있다.
리팩토링 연습 - 클래스 분리
쉼표(,) 또는 콜론(:)을 구분자로 가지는 문자열을 전달하는 경우 구분자를 기준으로 분리한 각 숫자의 합을 반환
숫자 이외의 값 또는 음수를 전다라하는 경우 RuntimeExcetpion 예외를 throw한다.
그렇다면 test code가 추가될 것.
모든 원시값과 문자열을 포장한다.
항상 양수값을 보장하는 positive 클래스를 만든다.
위의 생성자는 두가지 일을 한다... => 분리
숫자로 바꾸는 부분과 숫자가 0보다 작을때 예외 발생
클래스 분리 연습을 위해 활용할 수 있는 원칙
- 일급 컬렉션을 쓴다. ex) List<Positive>
- 3개 이상의 인스턴스 변수를 가진 클래스를 쓰지 않는다. (극단적 연습)
(이해가 안된다... 다시 살펴 볼 것..)
4단계 - 토이 프로젝트 난이도 높이기
- 점진적으로 요구사항이 복잡한 프로그램을 구현한다. (게임 같은 프로그램들이 명확함)
- 앞에서 지켰던 기준을 지키면서 프로그래밍 연습을 한다.
연습하기 좋은 예: 로또, 사다리 타기, 볼링 게임 점수판, 체스 게임, 지뢰 찾기 게임 etc...
5단계 - 의존관계 추가를 통한 난이도 높이기
웹 UI, 모바일UI, 데이터베이스와 같은 의존 관계를 추가.
- 테스트 하기 쉬운 코드와 테스트하기 어려운 코드를 보는 눈
- 테스트하기 어려운 코드를 테스트하기 쉬운 코드로 설계하는 감
- 앞 단계 연습을 잘 했으면 역량이 쌓인다
한 단계 더 나아간 연습을 하고 싶다면
- 컴파일 에러를 최소화 하면서 리팩토링하기
- ATDD 기반으로 응용 애플리케이션 개발하기
- 레거시 애플리케이션에 테스트 코드 추가해 리팩토링하기
정리
TDD. 리팩토링 적용이 실패하는 이유
TDD, 리팩토링 연습이 충분하지 않는 상태에서
"레거시 어플리케이션에 테스트 코드를 추가해 리팩토링하기" 같은 높은 난이도에 도전한다.
와 같은 높은 난이도에 바로 도전하기 때문이다..
구체적인 목표 찾기 - 객체지향 생활 체조 원칙
- 한 세머드에 오직 한 단계의 들여쓰기만 한다
- else 예약어를 쓰지 않는다
- 모든 원시값과 문자열을 포장한다
- 한 줄에 점을 하나만 찍는다
- 줄여쓰지 않는다 (축약금지)
- 모든 엔티티를 작게 유지한다
- 3개 이상의 인스턴스 변수를 가진 클래스를 쓰지 않는다
- 일급 콜렉션을 쓴다
- 케터/세터/프로퍼티를 쓰지 않는다
도움이 되는 책
객체지향 생활체조 원칙, 클린 코드
TDD. 리팩토링 연습을 위해 필요한 것은?
- 조급한 마음 대신 여유롭게..
- 나만의 토이 프로젝트
- 같은 과제를 반복적으로 구현할 수 있는 인내력, 꾸준함, 성실함