2018년 10월 21일 일요일

OKKY Conference 2018 The Real TDD 세미나 후기


OKKY Conference 2018 The Real TDD - TDD 제대로 알기 -

#1 테스트하기 쉬운 코드로 개발하기

정진욱 / PUBLYTO CPO
  • 테스트하기 쉬운 코드란?
    • 항상 같은 결과 반환
    • 외부상태를 변경하지 않음
  • 테스트하기 쉬운 코드로 개발하기
    • 방법1: 테스트하기 쉬운코드와 어려운 코드 분리
      • 요청한 좌석 수가 확보 가능한지 판단하기 위한 코드를 테스트 하기 위해서는 DB에 테스트 데이터를 설정해야한다.
    • 방법2 : 두 분류의 코드는 어디서 만나야 하나?
      • 두 분류의 코드는 최대한 가장 자리에 위치(에외 : 로깅, 퍼사드)
      • 테스트 하는 메소드에서 테스트 하기 어려운 코드가 제일 안쪽에 있으면 어려움이 전파되서 전체적으로 테스트하기 어려운 메소드가 된다.
    • 방법3 : 두 부류 코드가 만나는 가장자리는 어떻게 테스트 해야 하나?
      • 가장 자리를 테스트하는 방법을 익히자
      • 수동테스트
        • postman 사용
        • DB의 경우 query
      • 자동테스트
        • 작성된 프로덕션 코드의 사용 강제
        • 현 상태의 코드로는 할 수 없다
        • 실제 클래스 대신 목 사용을 위해 이음새가 있어야 한다.
        • 목 사용
          • 작성된 코드 사용을 강제할 수 있다.
          • 목 사용이 큰 장점으로 보이지만, 생각해 볼 점이 있다.
            • 행위 검증
              • 행위가 호출되었는가
              • Mockist
              • 불필요한 추상화 유발 가능성
            • 상태검증
              • 결과 값이 무엇인가
              • Classcist
              • 불필요한 추상화 필요 없음
        • 문제점
          • 목을 남발할 가능성이 크다.
            • 대부분 목 사용 예제는 간단하다. 그래서 장점이 크게 보인다.
            • 실제 프로젝트에 적용하면 한꺼번에 많은 수의 목을 다루면서 곤란을 겪는다.
          • 적당 수의 목 사용에 대한 답을 찾기 어렵다.
          • 상태 검증으로 돌아가보자
        • 상태 검증 - 문제 극복 방안
          • TDD를 통한 사전이 아니라 사후 테스트를 하자
          • 두 부류의 코드가 맞물려 잘 돌아가는 로직이다
          • 난해한 코드가 아니다
          • 구현된 코드를 사용하지 않고 굳이 어려운 길을 택할 이유가 없다
          • 완벽을 추구하면서 목을 사용하는 비용을 들일 필요가 있는가?
  • 끝으로
    • 요즘 저는
      • 두 분류 코드를 분리해서 각각 테스트하고,
      • 가장자리에서 맞물려 돌아가는 코드는 주로 수동테스트
    • 두 부류 코드 섞어 놓고 테스트가 어렵다고 포기하지 마세요
    • 위 내용과 관련된 제 블로그 참조
  • 테스트를 만족하는 만큼만 코드를 작성하라
  • TDD는 점진적인 접근방법을 사용하고 있다.
  • 테스트하기 어렵다는 거는 테스트 할때 값이 필요하다는 뜻이다.
  • Q & A
    • private 코드 테스트 하는 방법?
      • 같은 기능을 테스트해도 적은 메소드를 건드리는 메소드가 좋다
    • 레거시 코드 테스트 하는 방법?
      • 최대한 레거시 코드와 결합도를 낮추자
      • 목업을 할수 있는 seam을 만든다
      • 최대한 새로 생성된 코드에 최대한 테스트를 가한다
      • 기존 레거시 코드에 대한 값을 정의해 놓고 테스트

#2 의식적인 연습으로 TDD, 리팩토링 연습하기

박재성 / SW 교육 전문가 전 NEXT 교수
TDD와 리팩토링을 왜 해야 하는지 알고 있다. 는 가정 하에 진행한다.
TDD와 리팩토링을 비슷한 비중으로 다룬다. 어쩌면 TDD < 리팩토링 일지도 모른다.
개발 현장을 떠난지 오래 되어서 틀린 부분이 있을 수도 있다
  • 의식적인 연습으로 TDD, 리팩토링 연습 과정
  • TDD, 리팩토링을 잘 하려면??
    • 연습..연습..
    • 연습을 많이 한다고 잘할 수 있을까?
    • 6년한 후에 알게된 점
      • 테스트하기 쉬운 코드와 테스트하기 어려운 코드를 보는 눈
      • 테스트하기 어려운 코드를 테스트하기 쉬운 코드로 설계하는 감
  • 의식적인 연습의 7가지 원칙
    • 첫째, 효과적인 훈련 기법이 수립되어 있는 기술 연마
    • 둘째, 개인의 컴포트 존을 벗어난 지점에서 진행, 자신의 형재 능력을 살짝 넘어가는 작업을 지속적으로 시도
    • 셋째, 명확하고 구체적인 목표를 가지고 진행
    • 넷째, 신중하고 계획적이다. 즉, 개인이 온전히 집중하고 '의식적'으로 행동할 것을 요구
    • 다섯째, 피드백과 피드백에 따른 행동 변경을 수반
    • 여섯째, 효과적인 심적 표상을 만들어내는 한편으로 심적 표상에 의존
    • 일곱째, 기존에 습득한 기술의 특정 부분을 집중적으로 개선함으로써 발전시키고, 수정하는 과정을 수반
  • 연습하는 과정
    • 1단계 - 단위 테스트 연습
      • 내가 사용하는 API 사용법을 익히기 위한 학습 테스트에서 시작
        • JAVA API 테스트(split, subString, ArrayLisy ...)
      • 내가 구현하는 메소드중 Input과 Output이 명확한 클래스 메소드(보통Util 메소드)에 대한 단위 테스트 연습
      • 알고리즘을 학습한다면 알고리즘 구현에 대한 검증을 단위 테스트로 한다.
      • 지켜야 할 원칙
        • 회사 프로젝트에 연습하지 말고 장난감 프로젝트를 활용해 연습하자.
        • 실패하는 테스트 소스 -> 성공하는 테스트 소스 - > 리팩토링을 반복
        • 테스트 코드를 먼저 만들고 코드를 만든다.
        • 어려운 문제를 해결하는 것이 아니라 TDD 연습이 목적 난이도가 낮거나 자신에게 익숙한 문제로 시작하는 것을 추천
    • 2단계 - TDD연습
      • 회사 프로젝트 말고 장난감 프로젝트를 활용하자.
      • 의존관계를 가지지 않는 장난감 프로젝트를 활용하자.
      • TDD 사이클

        • 처음에는 1단계, 2단계만 하고 3단게 Refactoring은 안해도 된다.
      • 리팩토링 연습
        • 한 메서드에 오직 한 단계의 들여쓰기만 한다.(메서드로 분리)
        • else 예약어를 쓰지 않는다.
          • return을 중간에 하면 하단 코드를 안봐도 된다.
          • 가독성 증가
        • 메소드가 한 가지 일만 하도록 구현하기
        • 로컬 변수가 정말 필요한가?
        • compose method 패턴 적용
        • 모든 원시값과 문자열을 포장한다.
        • 일급 콜렉션을 쓴다.
        • 3개 이상의 인스턴스 변수를 가진 클래스를 쓰지 않는다.(힘들다)
      • 테스트 코드는 변경하지 말고 테스트 대상 코드를 개선하는 연습을 한다.
      • 읽기 좋게 코드를 변경한다.
      • 추상적인 피드백을 받으면 어느 부분을 작업 해야할지 알기 어렵다.
    • 3단계 - 연습을 과하게 한다
      • 연습을 할때는 극단적으로 해야 느끼는 점이 있다
      • 처음 읽는 사람에게 어느 코드가 더 읽기 좋을까? 리팩토링 전, 후
      • 한번에 모든 원칙을 지키면서 리팩토링하려고 연습하지 마라. 한번에 한 가지 명확하고 구체적인 목표를 가지고 연습하라.
      • 연습을 극단적인 방법으로 연습하는 것도 좋다. 예를 들어 한 메소드의 라인 수 제한을 15라인 -> 10라인으로 줄여가면서 연습하는 것도 좋은 방법이다.
      • 테스트 코드가 있으니 리팩토링 연습이 가능하다.
    • 4단계 - 장난감 프로젝트 난이도 높이기
      • 점진적으로 요구사항이 복잡한 프로그램을 구현한다. 앞에서 지켰던 기준을 지키면서 프로그래밍 연습을 한다.
      • TDD하기 좋은
        • 게임과 같이 요구사항이 명확한 프로그램으로 연습
        • 의존관계가 없이 연습
        • 약간은 복잡한 로직이 있는 프로그램
      • 연습하기 좋은 예
        • 로또
        • 사다리 타기
        • 볼링 게임 점수판
        • 체스 게임
        • 지뢰 찾기 게임
    • 5단계 - 의존관계 추가를 통한 난이도 높이기
      • 웹, 모바일 UI, 데이터베이스의 의존관계를 테스트
      • 필요한 역량
        • 테스트하기 쉬운 코드와 테스트하기 어려운 코드를 보는 눈
        • 테스트하기 어려운 코드를 테스트하기 쉬운 코드로 설계하는 감
      • 앞 단계 연습을 잘 소솨했다면 테스트하기 쉬운 코드와 어려운 코드를 분리하는 역량이 쌓였을 것이다.
      • 한 단계 더 나아간 연습을 하고 싶다면
        • 컴파일 에러를 최소화하면서 리팩토링하기
        • ATDD 기반으로 응용 애플리케이션 개발하기
        • 레거시 애플리케이션에 테스트 코드 추가해 리팩토링하기
      • 유지보수를 잘하는 SW개발자가 몸값이 더 올라갈 것이다

        • 소트웍스 앤솔러지
        • 클린코드
    • TDD, 리팩토링 연습을 위해 필요한 것은?
      • 조급한 대신 마음의 여유
      • 나만의 장난감 프로젝트
      • 같은 과제를 반복적으로 구현할 수 있는 인내력
    • 가장 필요한 것은 가보지 않는 길에 꾸준히 도전할 수 있는 용기
  • Q & A
    • 컴포트존을 극복하는 방법?
      • 삶에 여유와 에너지가 있어야 한다.
      • 회사 말고 집에서 혼자 연습을 하자.
    • 기존 테스트 코드가 있는데 요구사항이 추가, 변경 됐을때 기존 테스트 코드가 에러 났을때 대처
      • 내가 테스트 코드를 잘못 짠 경우가 많다.
      • 나중에 하지 말고 현재에 최대한 테스트 코드를 작성하자.

#3 코드 품질을 위한 테스트 주도 개발

삼성SDS 한성곤 Principal Engineer
  • TDD Cycle
    • Red -> Green -> Refactor 반복
    • 짧은 개발 주기의 반복에 의존하는 개발 프로세스
    • XP의 Test-First 개념을 기반으로, 단순한 설계를 중요시 하는 Pratice
  • TDD 장점
    • FROM Test
      • 동작하는 코드에 대한 자신감
      • 회귀테스트를 통한 자유로은 리팩토링
      • 코드에 대한 지식이 증가
      • 개발 생산성 향상
    • FROM Test-first
      • 과도한 설계를 피하고, 간결한 interface를 가짐
      • 불필요한 기능을 줄임
      • 실행 가능한 문서를 가짐
      • 코드 품질을 높임
      • 테스트 코드가 있으면 디버깅에 대한 시간이 줄어든다.
  • SonarCloud
    • 프로젝트의 코드 퀄리티를 분석
  • 사례
    • Microsoft 사례
      • TDD / Non TDD 팀
        • TDD가 하는 팀이 15% 더 많은 시간 소요
  • 불필요한 주석은 나쁘다. 버그성에 대한 내용을 주석에 담는 경우
  • 코드 퀄리티 매트릭스
    • 복잡도
    • 결합도
    • 응집도
  • MCC 측정 평가
    • 마이크로소프트는 McCabe 수치를 임계치 15, 10이상은 refactoring 교려 대상

#4 테알못 신입은 어떻게 테스트를 시작했을까?

이혜승 / 오마이호텔 Front-End Engineer
  • 방법에 대한 이야기
    • 테스트
      • 1-1 기존 코드에 테스트 추가하기
        • 이미 테스트 하기 쉽게 만들어져 있는 코드로 시작한다(순수함수, 외부 의존성 있는것은 말고)
        • 프로덕션 코드는 수정하지 않고 테스트 한다.
        • 테스트코드는 수정하지 않고 리팩토링을 진행한다.(리팩토링은 테스트가 깨지지 않는 범위 내에서만)
        • 테스트 하기 어렵게 만들어져 있는 코드에서 테스트 하기 쉬운 것만 분리한다.
          • 선택 기준
            • 중요도가 높은 비즈니스 로직이 포함된 부분
            • 버그가 발견된 부분 (과거X)
            • 결합이 낮고 논리는 복잡한 부분(외부 의존도가 낮거나 없고(독립적인 환경을 가지고 있고) 비즈니스 로직은 복잡한)
        • 테스트 가능한 코드를 찾아서 -> 분리하고 -> 테스트 코드를 추가하고 -> 리팩토링
        • 코드가 테스트 하기 어려운 이유(API 요청,응답 결과에 따라 다른 UI)는 테스트 가능한 부분만 분리한다.
          • 외부에 영향을 받지 않는 독립적인 함수로 만들어 준다.
          • 반환 값에 대한 스펙을 추가한다.
    • TDD
      • 1-2 새로운 코드는 TDD로 개발하기
        • 비즈니스 요구 사항 추가
    • 정리
      • 어떻게
        • 기존 코드에 테스트만 추가(+리팩토링)
        • 새롭게 추가 되는 요구 사항은 TDD
      • 무엇을
        • 이미 테스트 하기 쉬운 코드를 만들어서
  • 경험에 대한 이야기
    • 좋은점
      • 새로운 비즈니스가 추가 됐을때 코드를 수정 후 문제 점이 있을때 기존에 있는 오류를 테스트코드가 잡아준다.
      • 진짜로 느낀 것들
        • 스펙 문서 기능
        • 디자인 개선 효과
        • 학습 동기부여
          • 내가 얼마나 디자인을 못하는 지 알게 된다.
          • 안정성과 설계 관심을 가지게 된다.
        • 개발 생산성 향상
          • 버그를 추적하는 시간이 현저하게 줄어든다.
        • 프로젝트 생산성 향상
          • 비즈니스 로직의 허점을 사전(본격적으로 코딩을 시작하기 전에)에 발견하기도 한다.
        • 집중력 향상
          • TDD는 동시에 한 가지 이상의 일을 하지 않도록 통제해준다.
    • 실수
      • 테스트 대상 오류
        • 불필요한 테스트
          • 불필요하다의 기준 : 비즈니스와 관련된 버그를 낼 가능성이 낮거나 없고 테스트를 유지함으로써 얻는 이익 < 테스트 유지와 관리에 드는 비용 일 때, 테스트가 단언하고 있는 내용이 사용자에게 중요한 가치를 주는 것이 아닐때
        • 필요하지만 검증 방식이 잘못된 테스트
          • 특정 위치에 대한 테스트는 변경될 소지가 많다.
          • 검증식을 개선한다.
        • 검증력이 떨어지는 테스트
          • 하나 이상의 가능성을 열어 두고 있다.
        • 테스트 제목과 검증의 불일치
        • 테스트를 앞서가는 프로덕션 코드
          • 프로덕션 코드에서 미리 모든 요소를 만든다.
          • 테스트가 성공할 만큼의 최소한의 프로덕션 코드를 만든다의 원칙을 어긴다.
    • 고민
      • 테스트 관련 코드들의 관리
        • 테스트를 위해 만들어진 데이터(Fixture)
      • 이런방식으로 하다보니 함수가 곳곳에 퍼지게 된다
        • 왠지 모르겠지만 불안하다.
        • 계속 이렇게 함수로 분리하기만 하는 게 맞는 건가?
        • 오히려 전부 분리하는 게 가독성을 더 해치고
        • 추상화 수준이 낮다
          • 아주 구체적인 작은 단위의 함수들로만 분리되어 있고 그들이 조합되어 만들어지는 큰 수준의 기능은 설계되지 않았다. 그래서 추상화 수준이 낮아졌고 클라이언트에서 구체적인 내용을 알아야만 사용될 수 있다.
        • 높은 응집, 낮은 결합

#5 테스트를 돌보기 위한 매우 간단한 실천 방법들, 그리고 효과

양완수 / 쿠팡 Principal, Software Engineer

테스트 코드의 가독성

  • 질문
    • TDD를 실무에서 많이 하느냐? 아니다.
    • Unit Test를 작성을 하고 있느냐? 할 때도 있고 안 할 떄도 있다.
  • 발표 내용
    • TDD에 대해서 이야기하지 않습니다.
    • 테스트하기 좋은 설계에 대해서 이야기하지 않습니다.
    • 제어할 수 없는 것에 대해서 이야기하지 않습니다.
  • 테스트 코드는 프로젝트 코드가 사용되는 최초의 장소이며 고객이다.
  • 모든 역사는 테스트 코드부터 시작된다.
  • 추상이란?
    • 문맥 위에서 오직 관심 있는 것들에 대해서만 집중하여 명확하게 하는 것
  • 당신이 테스트를 거들떠 보려 하지 않는 이유
    • 귀찮다.
    • 고통스럽게 하는것
      • 숨겨진 본질
        • 낮은 추상화
        • 들쭉날쭉한 추상화
        • 끊어진 논리
        • 알 수 없는 의도
      • 욕심쟁이
        • 테스트가 실패하는 이유는 단 하나
        • 하나의 테스트는 오직 한 가지만 똑바로 검사해야 한다.
      • 인지능력의 과부화
        • 흩어진 코드와 데이터
        • 매직 넘버
      • 꺠지기 쉬운 것들
        • 높은 결합
        • 낮은 응집
  • 백문이 불여 일코
    • 좋은 설계를 가진 코드는 아니다.
    • 다양한 가느성을 가진 코드
    • 실제 팀 내 코드에서 발췌하여 발표에 맞게 수정
    • 불필요한 것에 집착하지 않습니다.(네이밍)
    • 테스트 코드를 위한 프로덕트 코드
    • url작성하기 Git
    • 코드 커밋 순서 설명
      • 무슨 테스트인지 알 수 없는 코드
      • setUp메소드를 통해 응집력이 다른 코드를 분리하고 추상화 레벨을 맞추려고 한다.
      • 객체를 새로 만들어 2가지 객체의 관계를 가깝게 만든다.
      • 테스트 대상을 명확하게 표현한다.(네임변경)
      • 한가지만 확실하게 테스트를 대칭성 있게 하자
      • 응답에는 성공과, 실패가 있다. 의존을 제거하고 불필요한 것을 격리 한다.
      • 테스트명을 처음부터 스트레스 받지 말고 안의 내용을 명확하게 만든 후 수정하자.
      • 하나의 것만 테스트 해라.
  • 테스트 코드를 잘 작성하려고 노력하다보면 좋은 설계를 가진 코드(높은 응집도 낮은 결합도를 가진 코드)를 가지게 된다.
  • 테스트가 쉽도록 코드를 만들어야 한다.
  • 테스트는 과정, 수련, 스승, 거울, 제품이다. 억지로 먼저 하지마라. 건강하게 하라. 두려워 하지마라. 즐거워 해라.
  • 테스트는 우리를 가르쳐준다. 우리를 가이드하고 발전 시켜준다. 프로덕션 코드를 좋게 만들어 준다.

#6 당신들의 TDD가 실패하는 이유(Live Coding)

이규원 / 오마이호텔 CTO
  • TDD가 실패 하는 이유
    • 준비가 되지 않아서
    • 개인
      • 모든 것에 TDD를 하지 않는다.
      • 우리가 보호해야 하는 것
        • 도메인
      • 우리가 제어할 수 없는 것
        • 외부 세상
          • 실 세계
          • 인프라
          • 외부 서비스
          • 레거시
      • 설계
        • 낮은 결합
        • 높은 응집
        • 도메인 모델 보호
      • 설계를 테스트 하라
      • 문제점
        • 정보 숨김(Information Hiding)
          • 어려운 설계 결정과 변경될 가능성이 높은 설계 결정들을 다른 모듈로부터 숨기는 것
        • 구현을 테스트
          • 내부의 코드를 수정하면 테스트가 깨진다.
        • 설계 테스트
          • 내부의 코드를 수정해도 테스트가 깨지지 않는다.
      • 레거시와 함께 살기
        • 새로 작성한 코드를 위해 Adapter로 감싸고 테스트 한다.(System Under Test)

      • 프로세스
        • 점진
        • 반복
        • Fail-Fast
      • 반복 주기
        • 주로 실행만 한다.(코드만 작성)
        • 계획
        • 실행
        • 평가
      • 문화
        • 공유
          • 목표
          • 지식
      • 아키텍처
        • 낮은 결합
        • 높은 응집
        • 도메인 모델 보호
      • 도메인 모델과 플랫폼
        • 도메인 모델과 플랫폼이 강하게 연결되어 있지 말고 서로 분리 해야 한다.
      • 아키텍처 사례(크기가 큰 순서로 나열)
        • 비즈니스로직 - 서비스 -모듈 - 애플리케이션 플랫폼
      • MVVM 아키텍처 패턴
  • 비즈니스에 대한 목적을 정확하고 정리하고 그림을 그리고 얘기를 해야 서로 이해에 대한 오해가 없다
  • ATDD(Acceptance Test) + TDD(Unit Test)로도 테스트 할 수 있다.
  • 코드 설계
    • 작업에는 어떤 코드 변경이 필요한가?
  • 피드백

#7 패널 토의 Q & A

  • 왜 많은 방법론 중에서 TDD인가?
    • 코드에 대한 신중함이 생긴다.
    • 가장 빠른 피드백을 준다.
    • 피드백을 통해 직무 탈진을 하지 않게 된다.
  • 주위 사람들에게 TDD를 어떻게 설득할 수 있을까?
    • TDD를 하는 개발자는 많지 않다. 외롭다.
    • 어떻게 같이 TDD를?
      • 주니어 개발자고 영향력이 크지 않다면 전파하는데 집착하지 말자
      • 나의 만족을 위해서 하자
      • 코드에 대한 자신감이 생긴다.
      • 주위 사람이 리팩토링한 코드에 대해 물어보면 그떄 전파 하자
      • 나중에 영향력이 있을떄 전파 하자
        • 하지만 과연 성공할까?
        • 팀에 대한 문제점을 개인이 인식하게 만든다.
        • 팀원들이 페어링과 TDD를 하자는 환경을 만들어야 한다.
        • 팀원들이 주도적으로 하게 만들어야 한다.
        • 먼저 TDD를 하는게 아니라 필요한 부분에 먼저 작은 변화를 적용한다.
      • 초보일때 남들과 같이 TDD를 하기에 수월할 수도 있다.
    • TDD에서는 테스트의 순서가 중요 하다. 첫 테스트는 작지만 핵심인 부분을 하자
    • TDD를 도입할 때도 핵심을 찾아야 한다.
  • 코드 커버리지의 기준은 어떠한 지표로써 이해를 해야 좋을까?
    • 테스트 커버리지에 집착 하지 말자
    • 프로덕션 코드에 집중 하자
  • 신입의 TDD공부방법 및 도서
    • 페어프로그래밍
    • 테스트 주도 개발(도서)
    • 테스트 및 리팩토링 책을 많이 보자
    • 책만 보지 말고 꾸준히 수련 하
  • 도메인 모델과 스프링의 접점을 줄여야 하는 이유
    • 여러 플랫폼에 종속적이지 않기 위해서
    • 스프링으로 개발하지 말고 순수 코드로 개발 완료 후 스프링에 옮겨 본다.
Share:

2018년 10월 19일 금요일