SlideShare a Scribd company logo
1 of 23
Download to read offline
22. I Need to Change a Monster
Method and I Can’t Write Tests
              for It


       ohyecloudy(http://ohyecloudy.com)

                              2008.12.20
Bulleted method
• nearly no indentation
       ___________________________
                 ____________________
       __________________________
       ___________________________
                 ___________________
       ____________________________
       ______________________
                 __________________
                           ____________
       _______________
       __________________
       _______________
Snarled Method
• dominated by a single large, indented
  section
         ____________________________
                   ____________________
                   __________________________
                             ___________________________
                             ___________________
                                       ____________________________
                             ______________________
                             ___________________________
                   _______________________
                             __________________________
                             __________________
                   ______________________________
         _______________
몬스터 함수 격파에 앞서
• refactoring tool이 있고 없고 차이 크다.
• extract method 같은 경우 사용 빈도가
  크기 때문에 대부분의 리팩토링 툴이 지원
  하는데,
• 툴이 안젂하게 extract method를 수행하
  면 테스트 안 해도 된다.
Tackling Monsters with
 Automated Refactoring Support
• key goals
  – dependency가 작은 chunk부터 logic과 분리
    시킨다.
  – 이후 진행될 refactoring의 test를 쉽게 하기
    위해 seam을 삽입한다.
• 리팩토링 툴을 사용하면 extract method
  는 test 없이 진행 가능하다.
class CommoditySelectionPanel
{
   …
   public void update()
   {
        if (commodities.size() > 0
               && commodities.GetSource().equals(“local”))
        {
               listbox.clear();
               for (Iterator it = commodities.iterator();
                       it.hasNext(); )
               {
                       Commodity commodity = (Commodity)it.next();
                       if (commodity.isTwilight()
                              && !commodity.match(broker))
                       {
                              listbox.add(commodity.getView());
                       }
               }
        }
   }
}
class CommoditySelectionPanel   동작이 함수단위로 변경됐을 뿐
{
    …                           구조적으로 바뀐 건 하나도 없다.
    public void update()        이후 Dependency를 제거하고 유닛                     테스트를 진행한다.
    {
          if (commoditiesAreReadyForUpdate())
          {
                    clearDisplay();
                    updateCommodities();
          }
    }

    private boolean commoditiesAreReadyForUpdate()
          { return commodities.size() > 0 && commodities.GetSource().equals(“local”); }

    private void clearDisplay()                  { listbox.clear(); }

    private void updateCommodities()
    {
          for (Iterator it = commodities.iterator(); it.hasNext(); )
          {
                    Commodity commodity = (Commodity)it.next();
                    if (singleBrokerCommodity(commodity))
                    {
                              displayCommodity(commodity.getView());
                    }
          }
    }

    private boolean singleBrokerCommodity(Commodity commodity)
          { return commodity.isTwilight() && !commodity.match(broker); }

    private void displayCommodity(CommodityView view)
          { listbox.add(commodity.getView());     }
}
The Manual Refactoring Challenge

• 유닛 테스트를 진행하면서 리팩토링.
• Extract method에서 실수하는 부분.
 – 변수 젂달을 잊는 경우
 – base class의 method와 동일한 이름을 짓는
   경우
 – 잘못된 type을 패러매터로 선언 혹은 리턴
Introduce Sensing Variable
public class DOMBuilder
{
   …
   void processNode(XDOMNSnippet root, List childNodes)
   {
         if (root != null)
         {
                  if (childNodes != null)
                           root.addNode(new XDOMNSnippet(childNodes));
                  root.addChild(XDOMNSnippet.NullSnippet);
         }
         List paraList = new ArrayList();
         XDOMNSnippet snippet = new XDOMNReSnippet();
         snippet.setSource(m_state);
         for (Iterator it = childNodes.iterator(); it.hasNext(); )
         {
                  XDOMNNode node = (XDOMNNode)it.next();
                  if (node.type() == TF_G || node.type() == TF_H ||
                           (node.type() == TF_GLOT && node.isChild()))
                  {
                           paraList.addNode(node);
                  }
         }
   }
}
public class DOMBuilder
{
   …

    public boolean nodeAdded = false;
    void processNode(XDOMNSnippet root, List childNodes)
    {
         if (root != null)
         {
                  if (childNodes != null)
                           root.addNode(new XDOMNSnippet(childNodes));
                  root.addChild(XDOMNSnippet.NullSnippet);
         }
         List paraList = new ArrayList();
         XDOMNSnippet snippet = new XDOMNReSnippet();
         snippet.setSource(m_state);
         for (Iterator it = childNodes.iterator(); it.hasNext(); )
         {
                  XDOMNNode node = (XDOMNNode)it.next();
                  if (node.type() == TF_G || node.type() == TF_H ||
                           (node.type() == TF_GLOT && node.isChild()))
                  {
                           paraList.addNode(node);
                           nodeAdded = true;
                  }
         }
    }
}
Sensing Variable을 사용한 Unit Test
void testAddNodeOnBasicChild()
{
   DOMBuilder builder = new DomBuilder();
   List children = new ArrayList();
   children.add(new XDOMNNode(XDOMNNode.TF_G));
   builder.processNode(new XDOMNSnippet(), children);
   assertTrue(builder.nodeAdded);
}


void testNoAddNodeOnBasicChild()
{
   DOMBuilder builder = new DomBuilder();
   List children = new ArrayList();
   children.add(new XDOMNNode(XDOMNNode.TF_A));
   builder.processNode(new XDOMNSnippet(), children);
   assertFalse(builder.nodeAdded);
}
public class DOMBuilder
{                                   extract method를 한 후에 unit test를 통과하면
    …                               sensing variables과 test code를 삭제한다.
    public boolean nodeAdded = false;
    void processNode(XDOMNSnippet root, List childNodes)
    {
          if (root != null)
          {
                   if (childNodes != null)
                            root.addNode(new XDOMNSnippet(childNodes));
                   root.addChild(XDOMNSnippet.NullSnippet);
          }
          List paraList = new ArrayList();
          XDOMNSnippet snippet = new XDOMNReSnippet();
          snippet.setSource(m_state);
          for (Iterator it = childNodes.iterator(); it.hasNext(); )
          {
                   XDOMNNode node = (XDOMNNode)it.next();
                   if (isBasicChild(node))
                   {
                            paraList.addNode(node);
                            nodeAdded = true;
                   }
          }
    }
    private boolean isBasicChild(XDOMNNode node)
    {
          return node.type() == TF_G || node.type() == TF_H || node.type() ==
                   TF_GLOT && node.isChild();
    }
}
Break Out a Method Object
• Sensing variable 대신에 사용할 수 있다.
• 메서드의 parameter를 생성자의 parameter로
  받고 run() 또는 execute()와 같은 메서드로 동
  작한다.
• temporary variable을 instance variable로 변
  경할 수 있다.
  – sensing variable 같은 경우 기존에 있는 변수를 사용
    하기에 적합하나 temporary 혹은 local 변수라서
    test에 사용하기 어려운 경우가 있다.
  – Method Object는 좋은 해결책이 된다.
Extract What You Know
• 작은 코드 조각을 테스트 없이 extract한
  다.
 – two or three lines
• 테스트와 다음 작업을 위한 좋은 출발점
• Coupling count가 0일때 사용.
 – # of values that pass into and out
• Coupling count가 0보다 클때는 Sensing
  variable을 사용해라.
Coupling count 예
void process(int a, int b, int c)
{
   int maximum;
   if (a > b) maximum = a;
   else         maximum = b;
}

 void process(int a, int b, int c)
 {
    int maximum = max(a,b);
 }

                         in : a, b
                         out : max return int
                         Coupling count : 3
Gleaning Dependencies
• 보호하고 지켜야 하는 logic에 대해서 test
  를 작성한다.
• 테스트 범위에 들어가지 않는 chuck를 추
  출한다.
• 적어도 중요한 동작이 제대로 돌아갂다는
  확신을 할 수 있다.
void addEntry(Entry entry)
{
   if (view != null && DISPLAY == true)
   {
        view.show(entry);
   }
   …
   if (entry.category().equals(“single”) ||
        entry.category(“dual”))
   {
        entries.add(entry);
        view.showUpdate(entry, view.GREEN);
   }
   else
   {
   …
   }
           • Display code에 관한 실수가 있으면 빨리 알아챌 수 있다.
}
        •   하지만 add login에서 에러가 있으면 찾는데 시갂이 걸릴 것이다.

        •   add login에 관한 테스트를 작성하자.
        •   테스트가 성공하면 display code를 추출한다.
Sensing variables
• 테스트 하는데 사용해서 리팩토링을 돕는
  다.
• sensing variables로 쓰기에 딱인데,
  method의 local variable인 경우가 많다.
  – instance variable인 경우에는 method가 동
    작한 후에도 sense할 수 있다.
• 그래서 local variables into instance
  variable로 고치는데 많이 혺동된다.
Strategy
•   Skeletonize Methods
•   Find Sequences
•   Extract to the Current Class First
•   Extract Small Pieces
•   Be Prepared to Redo Extractions
Skeletonize Methods
if (marginalRate() > 2 && order.hasLimit())
{
  order.readjust(rateCalculator.rateForToday());
  order.recalculate();
}


if (orderNeedsRecalculation(order))
{
  recalculateOrder(order, rateCalculator);
}
                                    메서드만 남아있는 상태
Find Sequences
if (marginalRate() > 2 && order.hasLimit())
{
   order.readjust(rateCalculator.rateForToday());
   order.recalculate();
}

 …
 recalculateOrder(order, rateCalculator);
 …

 void recalculateOrder(Order order, RateCalculator rateCalculator)
 {
    if (marginalRate() > 2 && order.hasLimit())
    {
          order.readjust(rateCalculator.rateForToday());
          order.recalculate();
    }
 }


          chunk가 하나의 메서드가 되서 연산(operation)의 한 순서(sequence)
Skeletonize Methods
         , Find Sequences
• bulleted methods lean me toward
  finding sequences
• snarled methods lean me toward
  skeletonizing
• Extract to the Current Class First
  – 현재 클래스에서 먼저 extract해라.
• Extract Small Pieces
  – 작은 조각을 extract하는 것은 좋은 출발점.
• Be Prepared to Redo Extractions

More Related Content

What's hot

파이썬 namespace Binding 이해하기
파이썬 namespace Binding 이해하기 파이썬 namespace Binding 이해하기
파이썬 namespace Binding 이해하기 Yong Joon Moon
 
파이썬 함수 이해하기
파이썬 함수 이해하기 파이썬 함수 이해하기
파이썬 함수 이해하기 Yong Joon Moon
 
[ETHCon Korea 2019] Park joohyung 박주형
[ETHCon Korea 2019] Park joohyung 박주형[ETHCon Korea 2019] Park joohyung 박주형
[ETHCon Korea 2019] Park joohyung 박주형ethconkr
 
python data model 이해하기
python data model 이해하기python data model 이해하기
python data model 이해하기Yong Joon Moon
 
파이썬 프로퍼티 디스크립터 이해하기
파이썬 프로퍼티 디스크립터 이해하기파이썬 프로퍼티 디스크립터 이해하기
파이썬 프로퍼티 디스크립터 이해하기Yong Joon Moon
 
파이썬 class 및 function namespace 이해하기
파이썬 class 및 function namespace 이해하기파이썬 class 및 function namespace 이해하기
파이썬 class 및 function namespace 이해하기Yong Joon Moon
 
파이썬 class 및 인스턴스 생성 이해하기
파이썬 class 및 인스턴스 생성 이해하기파이썬 class 및 인스턴스 생성 이해하기
파이썬 class 및 인스턴스 생성 이해하기Yong Joon Moon
 
파이썬 반복자 생성자 이해하기
파이썬 반복자 생성자 이해하기파이썬 반복자 생성자 이해하기
파이썬 반복자 생성자 이해하기Yong Joon Moon
 
Effective c++(chapter3,4)
Effective c++(chapter3,4)Effective c++(chapter3,4)
Effective c++(chapter3,4)문익 장
 
프론트엔드스터디 E05 js closure oop
프론트엔드스터디 E05 js closure oop프론트엔드스터디 E05 js closure oop
프론트엔드스터디 E05 js closure oopYoung-Beom Rhee
 
Javascript 완벽 가이드 정리
Javascript 완벽 가이드 정리Javascript 완벽 가이드 정리
Javascript 완벽 가이드 정리ETRIBE_STG
 
파이썬+주요+용어+정리 20160304
파이썬+주요+용어+정리 20160304파이썬+주요+용어+정리 20160304
파이썬+주요+용어+정리 20160304Yong Joon Moon
 
파이썬 iterator generator 이해하기
파이썬 iterator generator 이해하기파이썬 iterator generator 이해하기
파이썬 iterator generator 이해하기Yong Joon Moon
 
자바 테스트 자동화
자바 테스트 자동화자바 테스트 자동화
자바 테스트 자동화Sungchul Park
 
Design patterns
Design patternsDesign patterns
Design patternsdf
 
파이썬 플라스크 이해하기
파이썬 플라스크 이해하기 파이썬 플라스크 이해하기
파이썬 플라스크 이해하기 Yong Joon Moon
 
Processing 기초 이해하기_20160713
Processing 기초 이해하기_20160713Processing 기초 이해하기_20160713
Processing 기초 이해하기_20160713Yong Joon Moon
 
파이썬 Special method 이해하기
파이썬 Special method 이해하기파이썬 Special method 이해하기
파이썬 Special method 이해하기Yong Joon Moon
 

What's hot (20)

파이썬 namespace Binding 이해하기
파이썬 namespace Binding 이해하기 파이썬 namespace Binding 이해하기
파이썬 namespace Binding 이해하기
 
파이썬 함수 이해하기
파이썬 함수 이해하기 파이썬 함수 이해하기
파이썬 함수 이해하기
 
[ETHCon Korea 2019] Park joohyung 박주형
[ETHCon Korea 2019] Park joohyung 박주형[ETHCon Korea 2019] Park joohyung 박주형
[ETHCon Korea 2019] Park joohyung 박주형
 
python data model 이해하기
python data model 이해하기python data model 이해하기
python data model 이해하기
 
파이썬 프로퍼티 디스크립터 이해하기
파이썬 프로퍼티 디스크립터 이해하기파이썬 프로퍼티 디스크립터 이해하기
파이썬 프로퍼티 디스크립터 이해하기
 
파이썬 class 및 function namespace 이해하기
파이썬 class 및 function namespace 이해하기파이썬 class 및 function namespace 이해하기
파이썬 class 및 function namespace 이해하기
 
파이썬 class 및 인스턴스 생성 이해하기
파이썬 class 및 인스턴스 생성 이해하기파이썬 class 및 인스턴스 생성 이해하기
파이썬 class 및 인스턴스 생성 이해하기
 
파이썬 반복자 생성자 이해하기
파이썬 반복자 생성자 이해하기파이썬 반복자 생성자 이해하기
파이썬 반복자 생성자 이해하기
 
파이썬 심화
파이썬 심화파이썬 심화
파이썬 심화
 
Effective c++(chapter3,4)
Effective c++(chapter3,4)Effective c++(chapter3,4)
Effective c++(chapter3,4)
 
프론트엔드스터디 E05 js closure oop
프론트엔드스터디 E05 js closure oop프론트엔드스터디 E05 js closure oop
프론트엔드스터디 E05 js closure oop
 
Javascript 완벽 가이드 정리
Javascript 완벽 가이드 정리Javascript 완벽 가이드 정리
Javascript 완벽 가이드 정리
 
파이썬+주요+용어+정리 20160304
파이썬+주요+용어+정리 20160304파이썬+주요+용어+정리 20160304
파이썬+주요+용어+정리 20160304
 
파이썬 iterator generator 이해하기
파이썬 iterator generator 이해하기파이썬 iterator generator 이해하기
파이썬 iterator generator 이해하기
 
자바 테스트 자동화
자바 테스트 자동화자바 테스트 자동화
자바 테스트 자동화
 
Design patterns
Design patternsDesign patterns
Design patterns
 
Java start01 in 2hours
Java start01 in 2hoursJava start01 in 2hours
Java start01 in 2hours
 
파이썬 플라스크 이해하기
파이썬 플라스크 이해하기 파이썬 플라스크 이해하기
파이썬 플라스크 이해하기
 
Processing 기초 이해하기_20160713
Processing 기초 이해하기_20160713Processing 기초 이해하기_20160713
Processing 기초 이해하기_20160713
 
파이썬 Special method 이해하기
파이썬 Special method 이해하기파이썬 Special method 이해하기
파이썬 Special method 이해하기
 

Similar to [WELC] 22. I Need to Change a Monster Method and I Can’t Write Tests for It

Refactoring - Chapter 8.2
Refactoring - Chapter 8.2Refactoring - Chapter 8.2
Refactoring - Chapter 8.2Ji Ung Lee
 
Droid knights android test @Droid Knights 2018
Droid knights android test @Droid Knights 2018Droid knights android test @Droid Knights 2018
Droid knights android test @Droid Knights 2018KyungHo Jung
 
시작하자 단위테스트
시작하자 단위테스트시작하자 단위테스트
시작하자 단위테스트YongEun Choi
 
Clean code
Clean codeClean code
Clean codebbongcsu
 
Effective unit testing ch3. 테스트더블
Effective unit testing   ch3. 테스트더블Effective unit testing   ch3. 테스트더블
Effective unit testing ch3. 테스트더블YongEun Choi
 
테스트 가능한 소프트웨어 설계와 TDD작성 패턴 (Testable design and TDD)
테스트 가능한 소프트웨어 설계와 TDD작성 패턴 (Testable design and TDD)테스트 가능한 소프트웨어 설계와 TDD작성 패턴 (Testable design and TDD)
테스트 가능한 소프트웨어 설계와 TDD작성 패턴 (Testable design and TDD)Suwon Chae
 
Java mentoring of samsung scsc 2
Java mentoring of samsung scsc   2Java mentoring of samsung scsc   2
Java mentoring of samsung scsc 2도현 김
 
Domain Specific Languages With Groovy
Domain Specific Languages With GroovyDomain Specific Languages With Groovy
Domain Specific Languages With GroovyTommy C. Kang
 
헷갈리는 자바스크립트 정리
헷갈리는 자바스크립트 정리헷갈리는 자바스크립트 정리
헷갈리는 자바스크립트 정리은숙 이
 
ReactJS | 서버와 클라이어트에서 동시에 사용하는
ReactJS | 서버와 클라이어트에서 동시에 사용하는ReactJS | 서버와 클라이어트에서 동시에 사용하는
ReactJS | 서버와 클라이어트에서 동시에 사용하는Taegon Kim
 
나에 첫번째 자바8 람다식 지앤선
나에 첫번째 자바8 람다식   지앤선나에 첫번째 자바8 람다식   지앤선
나에 첫번째 자바8 람다식 지앤선daewon jeong
 
Agd Test Driven Development For Games What, Why, And How)(Game Connect 2006...
Agd   Test Driven Development For Games What, Why, And How)(Game Connect 2006...Agd   Test Driven Development For Games What, Why, And How)(Game Connect 2006...
Agd Test Driven Development For Games What, Why, And How)(Game Connect 2006...Ryan Park
 
NDC11_슈퍼클래스
NDC11_슈퍼클래스NDC11_슈퍼클래스
NDC11_슈퍼클래스noerror
 
목적이 부여된 에이전트 행동
목적이 부여된 에이전트 행동목적이 부여된 에이전트 행동
목적이 부여된 에이전트 행동Hyosung Jeon
 
[2011 04 11]mock_object 소개
[2011 04 11]mock_object 소개[2011 04 11]mock_object 소개
[2011 04 11]mock_object 소개Jong Pil Won
 
안드로이드 설계코드 노하우 및 개발방법
안드로이드 설계코드 노하우 및 개발방법안드로이드 설계코드 노하우 및 개발방법
안드로이드 설계코드 노하우 및 개발방법mosaicnet
 
Agile Test Driven Development For Games What, Why, And How
Agile Test Driven Development For Games What, Why, And HowAgile Test Driven Development For Games What, Why, And How
Agile Test Driven Development For Games What, Why, And HowRyan Park
 
[OKKYCON] 박재성 - 의식적인 연습으로 TDD, 리팩토링 연습하기
[OKKYCON] 박재성 - 의식적인 연습으로 TDD, 리팩토링 연습하기[OKKYCON] 박재성 - 의식적인 연습으로 TDD, 리팩토링 연습하기
[OKKYCON] 박재성 - 의식적인 연습으로 TDD, 리팩토링 연습하기OKKY
 
Legacy code refactoring video rental system
Legacy code refactoring   video rental systemLegacy code refactoring   video rental system
Legacy code refactoring video rental systemJaehoon Oh
 
C++ 프로젝트에 단위 테스트 도입하기
C++ 프로젝트에 단위 테스트 도입하기C++ 프로젝트에 단위 테스트 도입하기
C++ 프로젝트에 단위 테스트 도입하기Heo Seungwook
 

Similar to [WELC] 22. I Need to Change a Monster Method and I Can’t Write Tests for It (20)

Refactoring - Chapter 8.2
Refactoring - Chapter 8.2Refactoring - Chapter 8.2
Refactoring - Chapter 8.2
 
Droid knights android test @Droid Knights 2018
Droid knights android test @Droid Knights 2018Droid knights android test @Droid Knights 2018
Droid knights android test @Droid Knights 2018
 
시작하자 단위테스트
시작하자 단위테스트시작하자 단위테스트
시작하자 단위테스트
 
Clean code
Clean codeClean code
Clean code
 
Effective unit testing ch3. 테스트더블
Effective unit testing   ch3. 테스트더블Effective unit testing   ch3. 테스트더블
Effective unit testing ch3. 테스트더블
 
테스트 가능한 소프트웨어 설계와 TDD작성 패턴 (Testable design and TDD)
테스트 가능한 소프트웨어 설계와 TDD작성 패턴 (Testable design and TDD)테스트 가능한 소프트웨어 설계와 TDD작성 패턴 (Testable design and TDD)
테스트 가능한 소프트웨어 설계와 TDD작성 패턴 (Testable design and TDD)
 
Java mentoring of samsung scsc 2
Java mentoring of samsung scsc   2Java mentoring of samsung scsc   2
Java mentoring of samsung scsc 2
 
Domain Specific Languages With Groovy
Domain Specific Languages With GroovyDomain Specific Languages With Groovy
Domain Specific Languages With Groovy
 
헷갈리는 자바스크립트 정리
헷갈리는 자바스크립트 정리헷갈리는 자바스크립트 정리
헷갈리는 자바스크립트 정리
 
ReactJS | 서버와 클라이어트에서 동시에 사용하는
ReactJS | 서버와 클라이어트에서 동시에 사용하는ReactJS | 서버와 클라이어트에서 동시에 사용하는
ReactJS | 서버와 클라이어트에서 동시에 사용하는
 
나에 첫번째 자바8 람다식 지앤선
나에 첫번째 자바8 람다식   지앤선나에 첫번째 자바8 람다식   지앤선
나에 첫번째 자바8 람다식 지앤선
 
Agd Test Driven Development For Games What, Why, And How)(Game Connect 2006...
Agd   Test Driven Development For Games What, Why, And How)(Game Connect 2006...Agd   Test Driven Development For Games What, Why, And How)(Game Connect 2006...
Agd Test Driven Development For Games What, Why, And How)(Game Connect 2006...
 
NDC11_슈퍼클래스
NDC11_슈퍼클래스NDC11_슈퍼클래스
NDC11_슈퍼클래스
 
목적이 부여된 에이전트 행동
목적이 부여된 에이전트 행동목적이 부여된 에이전트 행동
목적이 부여된 에이전트 행동
 
[2011 04 11]mock_object 소개
[2011 04 11]mock_object 소개[2011 04 11]mock_object 소개
[2011 04 11]mock_object 소개
 
안드로이드 설계코드 노하우 및 개발방법
안드로이드 설계코드 노하우 및 개발방법안드로이드 설계코드 노하우 및 개발방법
안드로이드 설계코드 노하우 및 개발방법
 
Agile Test Driven Development For Games What, Why, And How
Agile Test Driven Development For Games What, Why, And HowAgile Test Driven Development For Games What, Why, And How
Agile Test Driven Development For Games What, Why, And How
 
[OKKYCON] 박재성 - 의식적인 연습으로 TDD, 리팩토링 연습하기
[OKKYCON] 박재성 - 의식적인 연습으로 TDD, 리팩토링 연습하기[OKKYCON] 박재성 - 의식적인 연습으로 TDD, 리팩토링 연습하기
[OKKYCON] 박재성 - 의식적인 연습으로 TDD, 리팩토링 연습하기
 
Legacy code refactoring video rental system
Legacy code refactoring   video rental systemLegacy code refactoring   video rental system
Legacy code refactoring video rental system
 
C++ 프로젝트에 단위 테스트 도입하기
C++ 프로젝트에 단위 테스트 도입하기C++ 프로젝트에 단위 테스트 도입하기
C++ 프로젝트에 단위 테스트 도입하기
 

More from 종빈 오

트위터 봇 개발 후기
트위터 봇 개발 후기트위터 봇 개발 후기
트위터 봇 개발 후기종빈 오
 
적당한 스터디 발표자료 만들기 2.0
적당한 스터디 발표자료 만들기 2.0적당한 스터디 발표자료 만들기 2.0
적당한 스터디 발표자료 만들기 2.0종빈 오
 
페리 수열(Farey sequence)
페리 수열(Farey sequence)페리 수열(Farey sequence)
페리 수열(Farey sequence)종빈 오
 
내가 본 미드 이야기
내가 본 미드 이야기내가 본 미드 이야기
내가 본 미드 이야기종빈 오
 
비트 경제와 공짜
비트 경제와 공짜비트 경제와 공짜
비트 경제와 공짜종빈 오
 
[NDC12] 게임 물리 엔진의 내부 동작 원리 이해
[NDC12] 게임 물리 엔진의 내부 동작 원리 이해[NDC12] 게임 물리 엔진의 내부 동작 원리 이해
[NDC12] 게임 물리 엔진의 내부 동작 원리 이해종빈 오
 
[Windows via c/c++] 4장 프로세스
[Windows via c/c++] 4장 프로세스[Windows via c/c++] 4장 프로세스
[Windows via c/c++] 4장 프로세스종빈 오
 
Intrusive data structure 소개
Intrusive data structure 소개Intrusive data structure 소개
Intrusive data structure 소개종빈 오
 
2011 아꿈사 오전반 포스트모템
2011 아꿈사 오전반 포스트모템2011 아꿈사 오전반 포스트모템
2011 아꿈사 오전반 포스트모템종빈 오
 
[프로젝트가 서쪽으로 간 까닭은] chap 17, 18, 26, 33, 81
[프로젝트가 서쪽으로 간 까닭은] chap 17, 18, 26, 33, 81[프로젝트가 서쪽으로 간 까닭은] chap 17, 18, 26, 33, 81
[프로젝트가 서쪽으로 간 까닭은] chap 17, 18, 26, 33, 81종빈 오
 
[GEG1] 3.volumetric representation of virtual environments
[GEG1] 3.volumetric representation of virtual environments[GEG1] 3.volumetric representation of virtual environments
[GEG1] 3.volumetric representation of virtual environments종빈 오
 
넘쳐나는 정보 소화 노하우
넘쳐나는 정보 소화 노하우넘쳐나는 정보 소화 노하우
넘쳐나는 정보 소화 노하우종빈 오
 
[Domain driven design] 17장 전략의 종합
[Domain driven design] 17장 전략의 종합[Domain driven design] 17장 전략의 종합
[Domain driven design] 17장 전략의 종합종빈 오
 
LevelDB 간단한 소개
LevelDB 간단한 소개LevelDB 간단한 소개
LevelDB 간단한 소개종빈 오
 
[GEG1] 2.the game asset pipeline
[GEG1] 2.the game asset pipeline[GEG1] 2.the game asset pipeline
[GEG1] 2.the game asset pipeline종빈 오
 
[TAOCP] 2.5 동적인 저장소 할당
[TAOCP] 2.5 동적인 저장소 할당[TAOCP] 2.5 동적인 저장소 할당
[TAOCP] 2.5 동적인 저장소 할당종빈 오
 
[GEG1] 24. key value dictionary
[GEG1] 24. key value dictionary[GEG1] 24. key value dictionary
[GEG1] 24. key value dictionary종빈 오
 
[TAOCP] 2.2.3 연결된 할당 - 위상정렬
[TAOCP] 2.2.3 연결된 할당 - 위상정렬[TAOCP] 2.2.3 연결된 할당 - 위상정렬
[TAOCP] 2.2.3 연결된 할당 - 위상정렬종빈 오
 
[TAOCP] 1.3.1 MIX 설명
[TAOCP] 1.3.1 MIX 설명[TAOCP] 1.3.1 MIX 설명
[TAOCP] 1.3.1 MIX 설명종빈 오
 
[GEG1] 10.camera-centric engine design for multithreaded rendering
[GEG1] 10.camera-centric engine design for multithreaded rendering[GEG1] 10.camera-centric engine design for multithreaded rendering
[GEG1] 10.camera-centric engine design for multithreaded rendering종빈 오
 

More from 종빈 오 (20)

트위터 봇 개발 후기
트위터 봇 개발 후기트위터 봇 개발 후기
트위터 봇 개발 후기
 
적당한 스터디 발표자료 만들기 2.0
적당한 스터디 발표자료 만들기 2.0적당한 스터디 발표자료 만들기 2.0
적당한 스터디 발표자료 만들기 2.0
 
페리 수열(Farey sequence)
페리 수열(Farey sequence)페리 수열(Farey sequence)
페리 수열(Farey sequence)
 
내가 본 미드 이야기
내가 본 미드 이야기내가 본 미드 이야기
내가 본 미드 이야기
 
비트 경제와 공짜
비트 경제와 공짜비트 경제와 공짜
비트 경제와 공짜
 
[NDC12] 게임 물리 엔진의 내부 동작 원리 이해
[NDC12] 게임 물리 엔진의 내부 동작 원리 이해[NDC12] 게임 물리 엔진의 내부 동작 원리 이해
[NDC12] 게임 물리 엔진의 내부 동작 원리 이해
 
[Windows via c/c++] 4장 프로세스
[Windows via c/c++] 4장 프로세스[Windows via c/c++] 4장 프로세스
[Windows via c/c++] 4장 프로세스
 
Intrusive data structure 소개
Intrusive data structure 소개Intrusive data structure 소개
Intrusive data structure 소개
 
2011 아꿈사 오전반 포스트모템
2011 아꿈사 오전반 포스트모템2011 아꿈사 오전반 포스트모템
2011 아꿈사 오전반 포스트모템
 
[프로젝트가 서쪽으로 간 까닭은] chap 17, 18, 26, 33, 81
[프로젝트가 서쪽으로 간 까닭은] chap 17, 18, 26, 33, 81[프로젝트가 서쪽으로 간 까닭은] chap 17, 18, 26, 33, 81
[프로젝트가 서쪽으로 간 까닭은] chap 17, 18, 26, 33, 81
 
[GEG1] 3.volumetric representation of virtual environments
[GEG1] 3.volumetric representation of virtual environments[GEG1] 3.volumetric representation of virtual environments
[GEG1] 3.volumetric representation of virtual environments
 
넘쳐나는 정보 소화 노하우
넘쳐나는 정보 소화 노하우넘쳐나는 정보 소화 노하우
넘쳐나는 정보 소화 노하우
 
[Domain driven design] 17장 전략의 종합
[Domain driven design] 17장 전략의 종합[Domain driven design] 17장 전략의 종합
[Domain driven design] 17장 전략의 종합
 
LevelDB 간단한 소개
LevelDB 간단한 소개LevelDB 간단한 소개
LevelDB 간단한 소개
 
[GEG1] 2.the game asset pipeline
[GEG1] 2.the game asset pipeline[GEG1] 2.the game asset pipeline
[GEG1] 2.the game asset pipeline
 
[TAOCP] 2.5 동적인 저장소 할당
[TAOCP] 2.5 동적인 저장소 할당[TAOCP] 2.5 동적인 저장소 할당
[TAOCP] 2.5 동적인 저장소 할당
 
[GEG1] 24. key value dictionary
[GEG1] 24. key value dictionary[GEG1] 24. key value dictionary
[GEG1] 24. key value dictionary
 
[TAOCP] 2.2.3 연결된 할당 - 위상정렬
[TAOCP] 2.2.3 연결된 할당 - 위상정렬[TAOCP] 2.2.3 연결된 할당 - 위상정렬
[TAOCP] 2.2.3 연결된 할당 - 위상정렬
 
[TAOCP] 1.3.1 MIX 설명
[TAOCP] 1.3.1 MIX 설명[TAOCP] 1.3.1 MIX 설명
[TAOCP] 1.3.1 MIX 설명
 
[GEG1] 10.camera-centric engine design for multithreaded rendering
[GEG1] 10.camera-centric engine design for multithreaded rendering[GEG1] 10.camera-centric engine design for multithreaded rendering
[GEG1] 10.camera-centric engine design for multithreaded rendering
 

[WELC] 22. I Need to Change a Monster Method and I Can’t Write Tests for It

  • 1. 22. I Need to Change a Monster Method and I Can’t Write Tests for It ohyecloudy(http://ohyecloudy.com) 2008.12.20
  • 2. Bulleted method • nearly no indentation ___________________________ ____________________ __________________________ ___________________________ ___________________ ____________________________ ______________________ __________________ ____________ _______________ __________________ _______________
  • 3. Snarled Method • dominated by a single large, indented section ____________________________ ____________________ __________________________ ___________________________ ___________________ ____________________________ ______________________ ___________________________ _______________________ __________________________ __________________ ______________________________ _______________
  • 4. 몬스터 함수 격파에 앞서 • refactoring tool이 있고 없고 차이 크다. • extract method 같은 경우 사용 빈도가 크기 때문에 대부분의 리팩토링 툴이 지원 하는데, • 툴이 안젂하게 extract method를 수행하 면 테스트 안 해도 된다.
  • 5. Tackling Monsters with Automated Refactoring Support • key goals – dependency가 작은 chunk부터 logic과 분리 시킨다. – 이후 진행될 refactoring의 test를 쉽게 하기 위해 seam을 삽입한다. • 리팩토링 툴을 사용하면 extract method 는 test 없이 진행 가능하다.
  • 6. class CommoditySelectionPanel { … public void update() { if (commodities.size() > 0 && commodities.GetSource().equals(“local”)) { listbox.clear(); for (Iterator it = commodities.iterator(); it.hasNext(); ) { Commodity commodity = (Commodity)it.next(); if (commodity.isTwilight() && !commodity.match(broker)) { listbox.add(commodity.getView()); } } } } }
  • 7. class CommoditySelectionPanel 동작이 함수단위로 변경됐을 뿐 { … 구조적으로 바뀐 건 하나도 없다. public void update() 이후 Dependency를 제거하고 유닛 테스트를 진행한다. { if (commoditiesAreReadyForUpdate()) { clearDisplay(); updateCommodities(); } } private boolean commoditiesAreReadyForUpdate() { return commodities.size() > 0 && commodities.GetSource().equals(“local”); } private void clearDisplay() { listbox.clear(); } private void updateCommodities() { for (Iterator it = commodities.iterator(); it.hasNext(); ) { Commodity commodity = (Commodity)it.next(); if (singleBrokerCommodity(commodity)) { displayCommodity(commodity.getView()); } } } private boolean singleBrokerCommodity(Commodity commodity) { return commodity.isTwilight() && !commodity.match(broker); } private void displayCommodity(CommodityView view) { listbox.add(commodity.getView()); } }
  • 8. The Manual Refactoring Challenge • 유닛 테스트를 진행하면서 리팩토링. • Extract method에서 실수하는 부분. – 변수 젂달을 잊는 경우 – base class의 method와 동일한 이름을 짓는 경우 – 잘못된 type을 패러매터로 선언 혹은 리턴
  • 9. Introduce Sensing Variable public class DOMBuilder { … void processNode(XDOMNSnippet root, List childNodes) { if (root != null) { if (childNodes != null) root.addNode(new XDOMNSnippet(childNodes)); root.addChild(XDOMNSnippet.NullSnippet); } List paraList = new ArrayList(); XDOMNSnippet snippet = new XDOMNReSnippet(); snippet.setSource(m_state); for (Iterator it = childNodes.iterator(); it.hasNext(); ) { XDOMNNode node = (XDOMNNode)it.next(); if (node.type() == TF_G || node.type() == TF_H || (node.type() == TF_GLOT && node.isChild())) { paraList.addNode(node); } } } }
  • 10. public class DOMBuilder { … public boolean nodeAdded = false; void processNode(XDOMNSnippet root, List childNodes) { if (root != null) { if (childNodes != null) root.addNode(new XDOMNSnippet(childNodes)); root.addChild(XDOMNSnippet.NullSnippet); } List paraList = new ArrayList(); XDOMNSnippet snippet = new XDOMNReSnippet(); snippet.setSource(m_state); for (Iterator it = childNodes.iterator(); it.hasNext(); ) { XDOMNNode node = (XDOMNNode)it.next(); if (node.type() == TF_G || node.type() == TF_H || (node.type() == TF_GLOT && node.isChild())) { paraList.addNode(node); nodeAdded = true; } } } }
  • 11. Sensing Variable을 사용한 Unit Test void testAddNodeOnBasicChild() { DOMBuilder builder = new DomBuilder(); List children = new ArrayList(); children.add(new XDOMNNode(XDOMNNode.TF_G)); builder.processNode(new XDOMNSnippet(), children); assertTrue(builder.nodeAdded); } void testNoAddNodeOnBasicChild() { DOMBuilder builder = new DomBuilder(); List children = new ArrayList(); children.add(new XDOMNNode(XDOMNNode.TF_A)); builder.processNode(new XDOMNSnippet(), children); assertFalse(builder.nodeAdded); }
  • 12. public class DOMBuilder { extract method를 한 후에 unit test를 통과하면 … sensing variables과 test code를 삭제한다. public boolean nodeAdded = false; void processNode(XDOMNSnippet root, List childNodes) { if (root != null) { if (childNodes != null) root.addNode(new XDOMNSnippet(childNodes)); root.addChild(XDOMNSnippet.NullSnippet); } List paraList = new ArrayList(); XDOMNSnippet snippet = new XDOMNReSnippet(); snippet.setSource(m_state); for (Iterator it = childNodes.iterator(); it.hasNext(); ) { XDOMNNode node = (XDOMNNode)it.next(); if (isBasicChild(node)) { paraList.addNode(node); nodeAdded = true; } } } private boolean isBasicChild(XDOMNNode node) { return node.type() == TF_G || node.type() == TF_H || node.type() == TF_GLOT && node.isChild(); } }
  • 13. Break Out a Method Object • Sensing variable 대신에 사용할 수 있다. • 메서드의 parameter를 생성자의 parameter로 받고 run() 또는 execute()와 같은 메서드로 동 작한다. • temporary variable을 instance variable로 변 경할 수 있다. – sensing variable 같은 경우 기존에 있는 변수를 사용 하기에 적합하나 temporary 혹은 local 변수라서 test에 사용하기 어려운 경우가 있다. – Method Object는 좋은 해결책이 된다.
  • 14. Extract What You Know • 작은 코드 조각을 테스트 없이 extract한 다. – two or three lines • 테스트와 다음 작업을 위한 좋은 출발점 • Coupling count가 0일때 사용. – # of values that pass into and out • Coupling count가 0보다 클때는 Sensing variable을 사용해라.
  • 15. Coupling count 예 void process(int a, int b, int c) { int maximum; if (a > b) maximum = a; else maximum = b; } void process(int a, int b, int c) { int maximum = max(a,b); } in : a, b out : max return int Coupling count : 3
  • 16. Gleaning Dependencies • 보호하고 지켜야 하는 logic에 대해서 test 를 작성한다. • 테스트 범위에 들어가지 않는 chuck를 추 출한다. • 적어도 중요한 동작이 제대로 돌아갂다는 확신을 할 수 있다.
  • 17. void addEntry(Entry entry) { if (view != null && DISPLAY == true) { view.show(entry); } … if (entry.category().equals(“single”) || entry.category(“dual”)) { entries.add(entry); view.showUpdate(entry, view.GREEN); } else { … } • Display code에 관한 실수가 있으면 빨리 알아챌 수 있다. } • 하지만 add login에서 에러가 있으면 찾는데 시갂이 걸릴 것이다. • add login에 관한 테스트를 작성하자. • 테스트가 성공하면 display code를 추출한다.
  • 18. Sensing variables • 테스트 하는데 사용해서 리팩토링을 돕는 다. • sensing variables로 쓰기에 딱인데, method의 local variable인 경우가 많다. – instance variable인 경우에는 method가 동 작한 후에도 sense할 수 있다. • 그래서 local variables into instance variable로 고치는데 많이 혺동된다.
  • 19. Strategy • Skeletonize Methods • Find Sequences • Extract to the Current Class First • Extract Small Pieces • Be Prepared to Redo Extractions
  • 20. Skeletonize Methods if (marginalRate() > 2 && order.hasLimit()) { order.readjust(rateCalculator.rateForToday()); order.recalculate(); } if (orderNeedsRecalculation(order)) { recalculateOrder(order, rateCalculator); } 메서드만 남아있는 상태
  • 21. Find Sequences if (marginalRate() > 2 && order.hasLimit()) { order.readjust(rateCalculator.rateForToday()); order.recalculate(); } … recalculateOrder(order, rateCalculator); … void recalculateOrder(Order order, RateCalculator rateCalculator) { if (marginalRate() > 2 && order.hasLimit()) { order.readjust(rateCalculator.rateForToday()); order.recalculate(); } } chunk가 하나의 메서드가 되서 연산(operation)의 한 순서(sequence)
  • 22. Skeletonize Methods , Find Sequences • bulleted methods lean me toward finding sequences • snarled methods lean me toward skeletonizing
  • 23. • Extract to the Current Class First – 현재 클래스에서 먼저 extract해라. • Extract Small Pieces – 작은 조각을 extract하는 것은 좋은 출발점. • Be Prepared to Redo Extractions