SlideShare una empresa de Scribd logo
1 de 82
Descargar para leer sin conexión
초보
개발자의
TDD
체험기
안녕하세요.
비전공자(경영학전공)
현재 취준생(백수)
김세훈입니다..!
저는 튜터링에서 QA인턴을 하다
개발이 하고싶어 도망쳤스ㄴ다..(농담😋)
개발을 잘 하고 싶어 방황하던 저는
개발을
스승님을 만나.
객체 지향적 설계,
TDD, Refactoring을 통한
클린코드 작성법
좋은 프로그래머가 되기 위한
기본 소양을 배울 수 있었습니다.
스승님께서 강조하신 말씀이 있습니다.
TDD와 의식적인 리팩토링을 반복하면, 설계를
개선하고 '품질 높은 코드'를 만들 수 있다.
저는 두 가지 이유로
저 말씀을 완전히 이해하지 못했습니다.
품질 좋은 코드란?
TDD를 사용하면 무엇이 개선되는지?
품질 좋은 코드란 무엇인가?
우선 저는 코드의 품질에 대해
고민해 본적이 없었습니다.
(애초에 코드에 품질 같은게 있다고 생각도 안 했었습니다..)
“코드는 구현하고 싶은 기능만
작동되게 하면 되는 거 아닌가?”
무지함을 해소하고자 정리해본 좋은 코드의 조건
(클린코드는 아직 다 읽지 못했습니다..ㅜ)
1. 잘 동작한다.
2. 읽기(이해하기) 쉽다.
3. 중복이 없다.
3. 확장이 용이하다.
잘 동작한다.
개발의 목적은 잘 작동하는 소프트웨어를 만드는 것
(기본적으로 작동하지 않으면 무슨 소용인가?)
이해하기 쉽다.
가독성 나쁜 코드는
다른 사람(혹은 본인)이 이해하기 힘들고
파악하는데 시간을 쏟게 한다.
이로 인해 추가적인 커뮤니케이션 비용이 발생한다.
중복이 없다.
코드에 중복되는 내용이 많으면 수정이 힘들다.
때문에 중복된 코드는 분리하여 재사용 가능하게 해야 한다.
‘실용주의 프로그래머’ 저자 데이브 토마스
“중복은 해악이다”
확장이 용이하다.
외부의 요구사항은 변하고 기능은 추가되기 마련.
쉽게 기능을 추가,확장 하기 위해서 코드간 의존성을 낮추어야 한다.
객체지향 5원칙 중 OCP
그렇다면 TDD를 통해 어떻게
코드의 품질을 개선할 수 있을까?
TDD(Test Driven Development)는
1. 실제 동작할 프로덕션 코드를 만들기 전에 테스트 코드를 작성하고,
2. 테스트 케이스를 통과할 만큼의 프로덕션 코드를 만들어
3. 리팩토링하는 과정을 반복하는 개발 방식이다.
TDD Cycle
그래 테스트는 좋은거지..
근데 이거 하면 뭐가 달라지나..?
단위테스트랑
뭐가
다른데..
테스트 만드는거 귀찮..
역시 원리만 알아서는 알 수 없죠. ㅋ
저는 레거시 코드를 TDD를 활용해
리팩토링해보기로 결정했습니다.
프로젝트 주제
두 플레이어가 서로 자신의 카드를 모르고 상대방의 카드만 아는
상태에서, 지난 카드들을 통해 유추해 베팅하는 포커게임
리팩토링 전
Before
자바를 공부하며 만들었던 토이 프로젝트
Legacy Code
AutoGamer
Gamer 클래스를 상속받아, 사용자의 카드와 본인의
카드를 기억하여 자동으로 베팅하는 역할
Dealer
턴을 제어하는 로직을 가진 클래스. 턴의 승패를 판단하고,
게이머에게 칩을 분배한다. 매 턴 마다 Dealer의 상태는
초기화된다.
Gamer
칩과 카드라는 상태를 가지며, 베팅이라는 행위를 할 수
있다. 사용자의 입력을 받아 베팅한다.
IndianPoker
게임을 실행하고 종료조건에 따라 게임의 승패를 판단하는
역할. Dealer와 Gamer 객체에 의존성을 가짐
클래스 구성
실제로 코드를 보기 전까진
“나름 객체지향적으로 설계한 거 같은데?”
라고 생각했습니다.
Gamer 클래스의 betting() 메소드
......?
문제가 많으니 하나씩 살펴봅시다.
한 메소드가
너무 많은 일을 하고 있다.
일단 Gamer라는 도메인의 핵심 로직인
betting()이 직접 입출력, 유효성 검사를 하고 있다.
(기능간 의존성 발생)
게다가 배팅의 유효성 검사 부분에는 동일한
기능을 하는 코드가 반복되어 중복이 발생하고
있다.
많은 분기처리로 코드의
복잡성이 높아짐
모든 경우를 한곳에서 판단 하려해
분기처리가 많아졌고, 이로 인해 코드의 흐름이
복잡해졌다.
본인조차 이해하기 힘든 가독성 낮은 코드가 된
것이다..
가장 큰 문제는 모든 클래스의 모든 메소드가
이런 식이라는 것
일단 &%$같은 코드를 개선하기 전
두 가지 목표를 세웠다.
TDD, Pair Programming 방식으로 개발할 것
콘솔 기반으로 개발하되, 웹 프로젝트로 확장할 것을 고려하여 개발 할 것
TDD, Pair Programming 방식으로 개발할 것
개발 방식에 대한 목표
페어 프로그래밍
한 컴퓨터로 파트너와 함께 번갈아 가며 프로그래밍하는 방식
일정, 의견 조율 같은 커뮤니케이션 비용이 많이 들고
둘이서 한 작업을 같이하기 때문에 효율성은 떨어지지만
파트너의 실시간 리뷰를 통해 익숙하지 않은 TDD 방식을 의식적으로 유지하고,
의견 조율 과정을 통해 좀 더 좋은 코드를 만드는데 도움을 준다.
콘솔 기반으로 개발하되, 웹 프로젝트로 확장할 것을 고려하여 개발 할 것
설계에 대한 목표
사실 TDD 방식 자체는 매우 Simple
가장 중요한 부분은 어떤 설계목표를
가지고 “리팩토링“ 하냐는 것
Wine을 숙성시키는
ripening()이라는 로직을 만들어보자
일단 기본 테스트 케이스
절차적
행위(숙성)와 상태(기간)는 분리되어 있어야 한다.
절차적
Wine 클래스는 age라는 상태를 가진다.
(일종의 구조체 역할)
절차적
ripening() 메소드는 실제 숙성시키는 행위를 담당하고 있다.
메소드는 wine 객체의 현재 age를 가져와 숙성 시킬 기간을 더 해
다시 wine 객체에 값을 저장하는 처리를 순차적으로 실행한다.
함수형
함수를 실행하기 전과 후 매개변수로 쓰이는 값은 변하면 안된다.
(Immutable Object로 만들어야 한다)
함수형
Wine 클래스의 age 필드를 외부에서 직접 접근하지 못하도록
private 접근제어자를 주었고, 외부에서는 getAge() 메소드를 통해서
조회만 할 수 있게 하였다.
함수형
함수형 인터페이스 Ripening을 구현하여 apply()를 실행할 때
인자로 넣은 wine의 age와 숙성기간을 더해 새로운 와인을 생성한다.
(매개변수로 들어간 와인과 숙성된 와인은 전혀 다른 객체)
객체지향적
객체는 상태(기간)와 행위(숙성)를 모두 갖는다.
(객체 자신의 상태는 자신이 직접 변화시켜야 한다.)
객체지향적
Wine 클래스의 age는 외부에서 접근하지 못하고,
ripening() 행위를 통해 변화 시킬 수 있다.
객체지향적
이처럼 어떤 설계 목표를 가지고 리팩토링 하는지에 따라
TDD를 사용하더라도 결과물이 달라집니다.
CONSOLE WEB
Our Goal
To
SpringMVC는 MVC 패턴을 기반으로 설계된 프레임워크
가능하다면 핵심 로직을 그대로 사용하고 싶었기에,
객체지향적으로 설계하고 MVC 패턴을 적용하여 개발하기로 결정
페어프로그래밍
1주일에 4시간씩 2회
콘솔 프로젝트 개발기간
약 2개월
+ 웹 프로젝트는 혼자 개발할 때 1개월 정도 걸림
TDD를 하며 느낀 것
처음부터 큰 문제를 한번에 해결하려 하면
어렵게 다가오고 중간에 포기하고 싶어진다.
큰 문제
1. 큰 문제를 작은 단위로 쪼갤 수 있다.
테스트 케이스를 만들다 보면 큰 문제를 해결하기 위한 작은 문제,
그리고 그 작은 문제를 해결하기 위한 더 작은 문제를 찾게 된다.
이렇게 문제를 쪼개다 보면 자신이 감당할 수 있는 범위의 문제를 알게 된다.
큰 문제
중간
중간
작은
1. 큰 문제를 작은 단위로 쪼갤 수 있다.
작은
작은 작은
1. 큰 문제를 작은 단위로 쪼갤 수 있다.
일단 생각나는 문제들을 적고
해결하기 위한 테스트 케이스를
만들었다.
테스트 케이스는 개발을
시작할 포인트가 되어주었고,
시작점에서 점진적으로 필요한
기능에 대한 테스트 케이스를 만들며
문제의 단위를 쪼갤 수 있었다.
2. 개발의 흐름을 쉽게 파악할 수 있다.
아무리 개발을 좋아해도 365일 24시간 같은 것만 개발할 수 없는 법
개발의 흐름
2. 개발의 흐름을 쉽게 파악할 수 있다.
자릴 비울땐 실패하는 테스트 케이스를 만들어 놓아
어디까지 개발했는지 파악할 수 있었다.
Dealer가 Turn의 승패를 판단하는 테스트
2. 개발의 흐름을 쉽게 파악할 수 있다.
테스트 케이스의 이름은 어떤 것이든 상관없다.
때문에 자신이 파악하기 쉽게 만드는게 좋다.
또 테스트 케이스에 작성된 요소(매개변수, 리턴값)
들이 이 메소드가 어떤 일을 하는 지 알려주는 설명서가 되어준다.
BettingState Test
3. 변경에 자신 있게 대처할 수 있다.
좋은 품질의 코드에는
확장이 용의하다는 조건이 있다.
이 조건은 각 기능간 의존성을 낮추어 해결할 수 있다.
A는 B가 없으면 아무것도 못한다..
3. 변경에 자신 있게 대처할 수 있다.
테스트 케이스를 만들면서 자연스럽게 의존관계에 대한 고민을 하고
테스트를 쉽게할 수 있도록 의존성을 낮추는 설계를 하게 된다.
Turn 클래스와 의존관계가 있는 클래스들
3. 변경에 자신 있게 대처할 수 있다.
고민은 결국 변화하는 부분(Player)와 변화하지 않는 부분(Turn의 행위)를
분리 함으로서 해결할 수 있다.
TurnTest의 일부
3. 변경에 자신 있게 대처할 수 있다.
3. 변경에 자신 있게 대처할 수 있다.
테스트 케이스를 만들어 통과시켜 놓으면,
그 테스트 케이스 자체가 입력타입과 출력타입의 표준이 된다.
Input - output
4. 품질이 보장된 코드를 갖게 된다.
테스트를 통해 이미
검증된 도메인 로직을 갖게 된다.
CONSOLE
WEB
5. 테스트를 통과할 때 마다 느끼는 성취감
테스트 케이스를 모두 통과시키면 나름 짜릿
TDD를 활용해 리팩토링한 코드
After
TDD를 활용해 리팩토링한 코드
Refactored
패키지 구성
controller
적절한 행위를 할 수 있도록 입력과 출력을 분기
처리하는 컨트롤러들이 있는 패키지
domain
게임의 핵심로직을 담당하는 클래스들이 모여있는 패키지
dto
도메인 로직의 처리결과를 뷰에서 보여질 수 있도록
가공한 클래스들이 모여있는 패키지
exception
직접 정의한 예외 클래스들이 모여있는 패키지
view
입력과 출력을 담당하는 클래스들이 모여있는 패키지
vo
직접 지정한 상수형 클래스들이 모여있는 패키지
support
프로그램의 실행에 직접적인 연관은 없지만
도움을 줄 수 있는 클래스들이 모여있는 패키지
리팩토링한 Player 클래스의 betting() 메소드
(정확히는 Player 인터페이스를 구현한 추상클래스 AbstractPlayer의 메소드)
......?
일단 리팩토링 전과 달리
메소드 자체의 길이가 매우 짧아졌다.
또한 입출력 로직을 분리하여 입출력 로직에서 직접 입력 값에 대한
유효성을 검사할 수 있게 되었다. (중복제거)
여기서 실제 베팅이라는 행위는 도메인 객체 중 하나인
BettingState라는 클래스가 담당
BettingState로 처리를 분담시켜
분기문이 없어져 가독성이 좋아졌다.
State Pattern 적용
TDD만을 이용해 얻은 성과일까?
“단위테스트”와 “TDD”는 테스트 케이스를 만드는 순서만 다르지,
프로덕션 코드를 검증하기 위한 테스트 케이스가 있다는 것은 같다.
TDD의 다른 점은 리팩토링이라는 설계 개선의 과정이 있다는 것
결국 중요한 것은 의식적인 리팩토링으로
더 나은 설계가 무엇인지 고민하는 과정
TDD란 프로그래밍 의사결정과 피드백 사이의
간극을 의식하고 이를 제어하는 기술이다.
“Test Driven Development by Example” Kent Beck
감사합니다
Github : https://github.com/Sehun-Kim
Blog : https://sehun-kim.github.io/sehun/blog/

Más contenido relacionado

La actualidad más candente

코드 리뷰 시스템 소개
코드 리뷰 시스템 소개코드 리뷰 시스템 소개
코드 리뷰 시스템 소개
Young-Ho Cha
 
TDD&Refactoring Day 02: TDD
TDD&Refactoring Day 02: TDDTDD&Refactoring Day 02: TDD
TDD&Refactoring Day 02: TDD
Suwon Chae
 
E1_Deview nhn애자일개발 tdd_질문답
E1_Deview nhn애자일개발 tdd_질문답E1_Deview nhn애자일개발 tdd_질문답
E1_Deview nhn애자일개발 tdd_질문답
NAVER D2
 

La actualidad más candente (17)

Tdd ver.2
Tdd ver.2Tdd ver.2
Tdd ver.2
 
TDD 발담그기 @ 공감세미나
TDD 발담그기 @ 공감세미나TDD 발담그기 @ 공감세미나
TDD 발담그기 @ 공감세미나
 
C++ 코드 품질 관리 비법
C++ 코드 품질 관리 비법C++ 코드 품질 관리 비법
C++ 코드 품질 관리 비법
 
코드 리뷰 시스템 소개
코드 리뷰 시스템 소개코드 리뷰 시스템 소개
코드 리뷰 시스템 소개
 
플리토 코드리뷰 - Code Review in Flitto
플리토 코드리뷰 - Code Review in Flitto플리토 코드리뷰 - Code Review in Flitto
플리토 코드리뷰 - Code Review in Flitto
 
Test driven development
Test driven developmentTest driven development
Test driven development
 
깨끗한 코드 (클린 코드, Clean Code)
깨끗한 코드 (클린 코드, Clean Code)깨끗한 코드 (클린 코드, Clean Code)
깨끗한 코드 (클린 코드, Clean Code)
 
애자일 테스트 프랙티스와 사례들 (부제: 협업의 힘)
애자일 테스트 프랙티스와 사례들 (부제: 협업의 힘)애자일 테스트 프랙티스와 사례들 (부제: 협업의 힘)
애자일 테스트 프랙티스와 사례들 (부제: 협업의 힘)
 
TDD
TDDTDD
TDD
 
TDD&Refactoring Day 02: TDD
TDD&Refactoring Day 02: TDDTDD&Refactoring Day 02: TDD
TDD&Refactoring Day 02: TDD
 
간단하게 알아보는 좋은 코드 서영훈
간단하게 알아보는 좋은 코드   서영훈간단하게 알아보는 좋은 코드   서영훈
간단하게 알아보는 좋은 코드 서영훈
 
E1_Deview nhn애자일개발 tdd_질문답
E1_Deview nhn애자일개발 tdd_질문답E1_Deview nhn애자일개발 tdd_질문답
E1_Deview nhn애자일개발 tdd_질문답
 
S66 goos-w7
S66 goos-w7S66 goos-w7
S66 goos-w7
 
사내 TDD 도입을 위한 설명 문서
사내 TDD 도입을 위한 설명 문서사내 TDD 도입을 위한 설명 문서
사내 TDD 도입을 위한 설명 문서
 
목 오브젝트(Mock Object)의 이해
목 오브젝트(Mock Object)의 이해목 오브젝트(Mock Object)의 이해
목 오브젝트(Mock Object)의 이해
 
테스트 자동화와 TDD(테스트 주도 개발방법론)
테스트 자동화와 TDD(테스트 주도 개발방법론)테스트 자동화와 TDD(테스트 주도 개발방법론)
테스트 자동화와 TDD(테스트 주도 개발방법론)
 
파이썬 TDD 101
파이썬 TDD 101파이썬 TDD 101
파이썬 TDD 101
 

Similar a 초보개발자의 TDD 체험기

홍성우, 게임 프로그래머는 어떻게 가르치나요?, NDC2018
홍성우, 게임 프로그래머는 어떻게 가르치나요?, NDC2018홍성우, 게임 프로그래머는 어떻게 가르치나요?, NDC2018
홍성우, 게임 프로그래머는 어떻게 가르치나요?, NDC2018
devCAT Studio, NEXON
 
SWDeveloprStory201601
SWDeveloprStory201601SWDeveloprStory201601
SWDeveloprStory201601
Suho Kwon
 
김성훈 - 뛰어난 디버거가 되는 방법
김성훈 - 뛰어난 디버거가 되는 방법김성훈 - 뛰어난 디버거가 되는 방법
김성훈 - 뛰어난 디버거가 되는 방법
성훈 김
 
131 deview 2013 yobi-채수원
131 deview 2013 yobi-채수원131 deview 2013 yobi-채수원
131 deview 2013 yobi-채수원
NAVER D2
 

Similar a 초보개발자의 TDD 체험기 (20)

[FEConf 2018] Front-End 프로젝트의 Test code 작성경험기
[FEConf 2018] Front-End 프로젝트의 Test code 작성경험기[FEConf 2018] Front-End 프로젝트의 Test code 작성경험기
[FEConf 2018] Front-End 프로젝트의 Test code 작성경험기
 
엔지니어의 학습, 그리고 테스트 코드
엔지니어의 학습, 그리고 테스트 코드엔지니어의 학습, 그리고 테스트 코드
엔지니어의 학습, 그리고 테스트 코드
 
TDD - 테스트 주도로 개발하기
TDD - 테스트 주도로 개발하기TDD - 테스트 주도로 개발하기
TDD - 테스트 주도로 개발하기
 
홍성우, 게임 프로그래머는 어떻게 가르치나요?, NDC2018
홍성우, 게임 프로그래머는 어떻게 가르치나요?, NDC2018홍성우, 게임 프로그래머는 어떻게 가르치나요?, NDC2018
홍성우, 게임 프로그래머는 어떻게 가르치나요?, NDC2018
 
[TECHCON 2019: MOBILE - iOS]2.들숨에 협업 날숨에 클린코드
[TECHCON 2019: MOBILE - iOS]2.들숨에 협업 날숨에 클린코드[TECHCON 2019: MOBILE - iOS]2.들숨에 협업 날숨에 클린코드
[TECHCON 2019: MOBILE - iOS]2.들숨에 협업 날숨에 클린코드
 
SWDeveloprStory201601
SWDeveloprStory201601SWDeveloprStory201601
SWDeveloprStory201601
 
프로젝트 Xxx에 적용하고 싶은 개발방법
프로젝트 Xxx에 적용하고 싶은 개발방법프로젝트 Xxx에 적용하고 싶은 개발방법
프로젝트 Xxx에 적용하고 싶은 개발방법
 
김성훈 - 뛰어난 디버거가 되는 방법
김성훈 - 뛰어난 디버거가 되는 방법김성훈 - 뛰어난 디버거가 되는 방법
김성훈 - 뛰어난 디버거가 되는 방법
 
클린코드와 테스트코드
클린코드와 테스트코드클린코드와 테스트코드
클린코드와 테스트코드
 
청강대 특강 - 프로젝트 제대로 해보기
청강대 특강 - 프로젝트 제대로 해보기청강대 특강 - 프로젝트 제대로 해보기
청강대 특강 - 프로젝트 제대로 해보기
 
NHN 게임서버엔진팀 리빌딩과 운영 방침.pdf
NHN 게임서버엔진팀 리빌딩과 운영 방침.pdfNHN 게임서버엔진팀 리빌딩과 운영 방침.pdf
NHN 게임서버엔진팀 리빌딩과 운영 방침.pdf
 
NDC2019 - 게임플레이 프로그래머의 역할
NDC2019 - 게임플레이 프로그래머의 역할NDC2019 - 게임플레이 프로그래머의 역할
NDC2019 - 게임플레이 프로그래머의 역할
 
행복한 개발을 위한_테스트_케이스
행복한 개발을 위한_테스트_케이스행복한 개발을 위한_테스트_케이스
행복한 개발을 위한_테스트_케이스
 
[H3 2012] 행복한 개발을 위한 테스트 케이스
[H3 2012] 행복한 개발을 위한 테스트 케이스[H3 2012] 행복한 개발을 위한 테스트 케이스
[H3 2012] 행복한 개발을 위한 테스트 케이스
 
131 deview 2013 yobi-채수원
131 deview 2013 yobi-채수원131 deview 2013 yobi-채수원
131 deview 2013 yobi-채수원
 
Code Review - DevOn2013
Code Review - DevOn2013Code Review - DevOn2013
Code Review - DevOn2013
 
애자일 하라
애자일 하라애자일 하라
애자일 하라
 
프로젝트 관리 및 지켜야 할 사항들
프로젝트 관리 및 지켜야 할 사항들프로젝트 관리 및 지켜야 할 사항들
프로젝트 관리 및 지켜야 할 사항들
 
애자일과 애자일 테스트 소개 (테스트기본교육 3장 2절)
애자일과 애자일 테스트 소개 (테스트기본교육 3장 2절)애자일과 애자일 테스트 소개 (테스트기본교육 3장 2절)
애자일과 애자일 테스트 소개 (테스트기본교육 3장 2절)
 
테스트 기발 개발, TBD(Test based developement)
테스트 기발 개발, TBD(Test based developement)테스트 기발 개발, TBD(Test based developement)
테스트 기발 개발, TBD(Test based developement)
 

초보개발자의 TDD 체험기