SlideShare a Scribd company logo
1 of 88
Day01


        더 나은 코드 작성을 위한

            리팩터링



                         1
학습목표

응용 애플리케이션 작성시 만들어지는 나쁜 코드들을 구별할 수 있다.
나쁜 코드를 객체지향 설계가 적용된 코드로 변경하는 기법을 배우고 적
용할 수 있다.
실제 코드에서 잘못된 부분을 찾아내 이해하기 쉬운 구조로 변경할 수 있
다.




                                              2
                                          디자인패턴
1. 코드개선


 1. 객체지향 특징

 2. 코드 개선 [실습]




                     3
                 디자인패턴
1.객체지향 특징




            4
추상화 Abstraction               객체지향 특징




                  주어진 문제나 시스템 중에서
                  중요하고 관계 있는 부분만을
                  분리하여 간결하고
                  이해하기 쉽게 만드는 작업




                                        5
상속 Inheritance               객체지향 특징




                 직접 구현하지 않고 부모 클래
                 스로부터 물려받은 기능이나
                 데이터를 말하며 재사용을 위
                 한 보편적인 기법




                                    6
캡슐화 Capsulation                  객체지향 특징




                  외부와 통신할 때의 복잡도를
                  줄이고, 내부 상태를 보호하기
                  위해 만들어 놓은 구조




                                           7
다형성 Polymorphism                 객체지향 특징




 polymorphism      하나의 선언으로 여러 개의 타


 多形性               입을 가질 수 있는 것. 혹은 자
                   신이 여러 타입을 가지는 것을
                   지칭
       TYPE

                                        8
2. 코드 개선
   [실습]




           9
2. 리팩터링이란?


 1. 프로젝트 인 더 월드

 2. 리팩터링이란?

 3. 테스트 코드

 4. 리팩터링과 설계

 5. 코드 속의 나쁜 냄새



                    10
                  리팩터링
1. 프로젝트 인 더 월드
 Project in the world




                        11
프로젝트 In IDEAL                  Project in the world



  확정되어 변경되지 않는 고객의 요구 사항

  빈틈없는 시스템 설계

  숙련되고 표준을 따르기를 즐기는 개발자

  하나의 버그도 빠져나갈 수 없는 완벽한 테스트

  정확히 산정된 스케줄과 여유 있는 납기 일자




                                                  12
프로젝트 In REAL                             Project in the world



  파트리더 고미화의 고민
   – 개발자가 모두 동일한 수준의 Skill을 가지고 있지 않다.

   –   고객의 요구는 계속 변화된다.

   –   개발 초기의 디자인이 완벽하지 않는 경우가 많으며,

   –   실제로 설계가 잘못된 경우도 많다.

   –   테스트에 나타나지 않는 버그들이 존재한다

   – 개발 완료로 끝나지 않는다. 유지보수가 뒤 따른다.




                                                            13
프로젝트 In REAL     Project in the world



  개발자 최고수의 고민




                                    14
프로젝트 In REAL                          Project in the world



  개발자 최고수의 고민
   – 코드 이해에 많은 시간이 필요(복잡,다양한 개발자의 취향)

   –   어려운 업무 용어가 많이 들어간 장황한 주석 또는 주석 부재

   –   수정으로 인한 파급 효과에 대한 불안

   –   Copy & Paste 로 신규 기능 작성

   –   고치면 고칠수록 수정이 어려워짐 (땜빵식 코드)




                                                         15
Normal Dejavu                                   Project in the world


      • (어쨌든) 요구사항에 맞춰 동작하는 코드 완성

      • 추가 요구사항을 계속 반영, 반영, 반영

      • 많은 부분에 있어 수정이 가해지고, 개발 속도가 느려지기 시작

      • 가끔은 수정해야 할 부분을 잊어서 에러도 발생 (Iterative)

      • 후임 등장

      • 소스를 보고 기겁, 어떻게 어딜 고쳐야 하나?

      • 언제 시간 내서 통째로 다시 재 작성해야 한다고 믿음

      • 그러나 여전히 부분 부분 수정하며, 필요 시에는 선임자를 전화로 찾음

      • (어쨌든) 요구사항에 맞춰 동작하는 코드 완성

      • and Looping…


                                                                   16
….
     17
2. 리팩터링이란?




             18
리팩터링이란?                          리팩터링이란?



  리팩터링
  – 외견상 보이는 기능 동작은 바뀌지 않는 상태에서

  – 이해하기 쉽고,

  – 수정하기 쉽도록

  – 소프트웨어의 내부적인 구조를 변경하는 것




                                       19
Example #1                                          리팩터링이란?




                           void f() {
  void f() {                   ….
      ….                       computeScore();
      // Compute score     }
      score = a * b + c;
      score -= discount;   void computeScore() {
  }                            score = a * b + c;
                               score -= discount;
                           }




                                                          20
Example #2                                              리팩터링이란?



  public String name;




             private String name;

             public String getName(){
                 return name;
             }

             public String setName (String newName) {
                 name = newName;
             }



                                                              21
Example #3                                                 리팩터링이란?



 if (user == null)
     plan = Plan.basic();
 else
     plan = user.getPlan();
                                 plan = user.getPlan();

                              <<interface>>
                                  User

                              +getPlan()




                                NullUser

                              +getPlan()      return Plan.basic();




                                                                     22
왜 리팩터링을 하는가?                                    리팩터링이란?



  설계를 개선 하기 위해

  코드를 이해하기 쉽게 만들기 위해

  버그를 찾아내기 위해

  좀 더 빠르게 프로그래밍 할 수 있도록




                    개발자와 관리자에게 어떤 하나의 대안 될 수 있는가?

                                                      23
구성요소                                 리팩터링이란?



 나쁜냄새(Smells)

 카탈로그(Catalogue)

 자동화된 단위 테스트(Automated Unit Test)




                                           24
문제점                 리팩터링이란?




       데이터 베이스

       인터페이스 변경

       프로젝트 데드라인




                          25
언제 리팩터링할 것인가?                                         리팩터링이란?



  The Rule of Three – DRY(Don’t Repeat Yourself)원칙

  기능을 추가할 때

  버그를 수정 할 때

  코드 리뷰를 할 때




                                                            26
성능의 문제                                 리팩터링이란?



  소프트웨어를 더 이해하기 쉽게 만들기 위해 수정을 하는데, 이때
  종종 프로그램을 더 느리게 작동하도록 하는 원인이 될 수 있다.




  잘 분해된 코드와 프로그램이 주는 이점
   – 새로운 기능 추가가 쉬워 퍼포먼스 튜닝에만 집중하는 것이 가능하다.

   – 세밀한 분석이 가능하다.



                                             27
안전한 리팩터링의 3대 요소                리팩터링이란?



               백업을 만들어 놓거나 형상관
                  리를 사용한다.

               검증된 리팩터링 도구를 사용
                  한다.

               자동화된 단위 테스트 케이스
                  를 만들어 놓는다.




                                     28
리팩터링 도구            리팩터링이란?



  이클립스의 리팩터링 도구




                         29
3.테스트 코드




           30
단위 테스트 Automated Unit Test         테스트 코드



  “리팩터링 작업의 필수 조건은 사전에 탄탄한 테스트를 만들어 놓
   는 것이다.” – 마틴 파울러

  가장 대표적인 자동화된 단위 테스트 프레임워크
   = JUnit




                                         31
테스트 주도 개발 Test-Driven Development   테스트 코드



  자동화된 단위 테스트 케이스를 만들어 내는 가장 훌륭한 방식

  “프로그램을 작성하기 전에 자동화된 테스트 코드를 먼저 작성한다.”

  간결한 설계와 고품질 모듈을 만들어 내는 기법




                                           32
TDD 절차                                    테스트 코드




         질문 Ask
          테스트를 작성함으로써 시스템에 질문한다. (FAIL)


         응답 Respond
          테스트를 통과하는 코드를 작성해서 질문에 대답한다. (PASS)


         정련 Refine
          아이디어를 통합하고, 불필요한 것은 제거하고, 모호한 것은
          명확히 해서 대답을 정제한다. (REFACTORING)


         반복 Repeat
          다음 질문을 통해 대화를 계속 진행한다.

                                                33
4.리팩터링과 설계
Refactoring and Design




                         34
소프트웨어 비용                            리팩터링과 설계



  전체 비용 = 개발 비용 + 유지 비용

  유지 비용 = 이해 비용 + 수정 비용 + 테스트 비용
  + 설치 비용




                                           35
사전 설계 Upfront Design                     리팩터링과 설계



  사전 설계
   – 재 작업 비용을 줄이기 위해서 SW구조에 대해 사전에 고민을 하는 방식

   – 요구사항 변경이 일어날 부분에 대해서 미리 예측한다.

   – 좀 더 유연한 구조의 설계를 지향한다.

  유연한 구조로 솔루션을 구축할 때의 문제점
   – 다양한 유연성을 가진다는 건 다른 의미의 비용으로 이어진다.

   – 좀 더 복잡한 구조가 되기 쉽고, 일반적으로 유지관리하기 더 어려워진다.

   – 그리고 미래를 정확히 예측하기는 것은 대부분의 경우 불가능하다.

                                                36
리팩터링과 설계                                 리팩터링과 설계



  리팩터링은 일부 관점이 사전설계(upfront design)와 충돌하지
  만 결과적으로 리팩터링은 디자인을 보완한다.
   – 리팩터링과 사전 설계는 강조점이 다르다. 완벽한 솔루션을 찾는 것이 아
    니라 납득할만한 수준(reasonable)의 솔루션을 찾는다.

   – 유연성 강조보다 설계를 간결하게 만드는 쪽에 좀 더 관심을 둔다.

   – 간결한 시스템을 좀 더 복잡한 유연한 시스템으로 만드는 것은 매우 쉽지
    만, 그 반대는 훨씬 어렵기 때문이다.




                                                37
5.코드 속의 나쁜 냄새
     Smells




                38
직관 Intuition                                         Smells

               1997년 5월 11일

                 뉴욕의 에퀴터블 센터에서는 IBM이 개발한 수퍼 컴퓨터 딥 블루(Deep
               blue)와 세계 체스 챔피언 ‘게리 카스파로프(Kasparov)’간의 6 차전
               마지막 경기가 진행되고 있었다.


                『딥 블루』는 2m가 채 안되는 키에 1.4 톤이나 나가는 몸무게를
               가지고 있으며 중국인 과학자 츄펑슝 박사 외에 6명의 IBM사 최고
               과학자들이 지난 8년 동안 32개의 마이크로 프로세서와 512개의 특수
               체스 칩을 장착해서 만들은 2백만 달러 상당의 대형 병렬 수퍼 컴퓨터다.
               『딥』은 오로지 『인간을 이겨라』는 특명을 받고 태어난 역사상 최고의
               기계로써 1초당 2억번의 행마(行馬)를 검토해가며 장기를 둘 수 있는
               능력이 있으며, 지난 백 년 동안에 개최되었던 주요 체스 대국의 기보가
               모두 입력되어 있다. 더욱이 슈 박사 팀은 지난번의 패배를 설욕하기 위해
               연산 능력을 2배로 보강했으며 미국의 체스 챔피언 조엘 벤저민과 세계
               유명 체스 선수들의 조언을 추가로 저장하였다. 특히 슈 박사 팀은
               어떠한 경우에도 상대수의 변화에 따라 새로운 수를 개발하여 대처할 수
               있는 자기 조정기능의 유연성을 강화시키는데 초점을 두었다고 한다.
               따라서『딥』은 그야말로 체스에 있어서는 『살아있는 지능을 가지고
               있는 컴퓨터』라고 할 수 있다


               지난 5차전까지 이 두 대국자간의 전적은 1승 3무 1패로 무승부.


               - New York Times 1997.5

                                                              39
코드 속의 나쁜 냄새 #1                                          Smells

                                   “나쁜 냄새가 난다면, 고쳐라!” – 켄트벡

  – 중복코드(Duplicate code)
  – 긴 메소드(Long Method)
  – 거대한 클래스(Large class)
  – 긴 파라미터 리스트(Long Parameter List)
  – 확산적 변경(Divergent Change)
  – 산탄총 수술(Shotgun Surgery)
  – 기능 욕심(Feature Envy)
  – 데이터 덩어리(Data Clumps)
  – 기본형에 대한 강박(Primitive Obsession)
  – 스위치 구문(Switch Statements)
  – 병렬 상속 구조(Parallel Inheritance Hierarchies)


                                                              40
코드 속의 나쁜 냄새 #2                                                        Smells

                    “컴퓨터가 이해할 수 있는 코드는 바보도 작성할 수
                        있다. 사람이 이해할 수 있는 코드를 작성해라”
  – 게으른 클래스(Lazy Class)                    – 마틴 파울러
  – 추측성 일반화(Speculative Generality)
  – 임시 필드(Temporary Field)
  – 메시지 연쇄(Message Chains)
  – 미들맨(Middle Man)
  – 부적절한 친밀관계(Inappropriate Intimacy)
  – 인터페이스가 다른 대체 클래스(Alternative Classes with Different Interfaces)
  – 불완전한 라이브러리 클래스(Incomplete Library Class)
  – 데이터 클래스(Data Class)
  – 거부된 유산(Refused Bequest)
  – 주석(Comments)


                                                                           41
긴 메소드 Long Method                       Smells



  메소드의 길이가 짧은 프로그램이 오래 살아 남는다.
   – 메소드의 길이가 길면 길수록 이해하기 더 어려워 진다.

   – 그럼, 짧은 메소드의 기준은?

      •의미상의 거리(Semantic Distance)를 측정

  대부분 99%에 해당하는 경우
   – Extract Method

  조건문과 반복문들
   – Decompose Conditional

                                             42
긴 메소드 Long Method                    Smells



  Decompose Conditional이 필요한 다른 예




                                          43
이름 짓기 Naming                                             Smells



  addCourse( course );

  getNodesArrayList();

  makeIt();

  getData();

  sort();

  processItem();

                          이름을 잘못 지었다고 확실히 와 닿는 경우도 있다.
                          W44()


                                                              44
이름 짓기 Naming                                                                         Smells


  암기력에 의존하게 되는 학습을 강요하면 안 된다.
  maskClear2( plMoney )

 소스의 난이도를 높이는 형태의 불필요한 오버로딩 금지
 System.out.println(LMoney.toCommaFormat(120000));
 System.out.println(LMoney.toCommaFormat(120000, true)); // () 단위 표시를 추가시킨 스트링 반환
 System.out.println(LMoney.toCommaFormat(070712093801.9283));

  인자(argument)를 줄이기 위한 자기 참조 형태의 생성자 생성 자제
  Money(String a) {
      Money(String a, false); }

  미스터리 소스 생성 금지
    /**
     * basic 한글 화폐단위를 담고 있는 Array
     */
    private static final String basicA[] = { "", "십", "백", "천" };

    /**
     * base 한글 화폐단위를 담고 있는 Array
     */
    private static final String baseA[] = { "", "만", "억", "조", "경" };


                                                                                          45
주석 Comments                         Smells



  코드 블록을 설명하기 위해 주석이 필요하다면?
   – Extract Method

  메소드 이름만으로 이해가 어려워 작성된 주석이라면?
   – Rename Method

  시스템의 상태를 가정하기 위해 기술된 문장이나 사전 조건을 명
   시한 주석의 경우라면?
   – Introduce Assertion




                                         46
주석 Comments                                  Smells



  주석이 나쁘다?
   – 주석은 좋은 것이다.  Sweet Smells

   – But, 무엇(what)을 하는지 설명하는데 쓰여서는 안된다.

   – 이유(why)를 설명하기 위해서 사용해야 한다.

   – 잘못된 주석은 자칫 코드를 장황하게 만들거나 이해하기 어렵게 한다.

  코드 블록을 설명하기 위해 코멘트가 필요하다면?
   – Extract Method




                                                  47
주석 Comments                                         Smells


  작성 가이드
   – 코드가 하는 일을 그대로 주석으로 작성 (비권장)

   – 코드의 설명 : 복잡하거니 미묘한 코드에 대한 내용을 주석으로 작성
     (비권장, 차라리 코드를 수정)

   – 표시기능 : Todo, Release 전에 할 일에 대한 내용을 주석으로 작성
     (비권장, 적어도 배포 전에는 제거)

   – 코드의 요약 : 몇 줄의 코드 뭉치가 하는 일을 요약하는 기능.
     빠르게 코드를 살펴볼 수 있도록 도움을 줌(권장)

   – 코드의 의도 설명 (권장)

   – 코드만으로는 표현할 수 없는 정보: 저작권이나 버전번호, 최적화 내용 등을 기록(권장)
     - from code complete


                                                         48
주석 – Example #1                                                               Smells


  /**
   *
   * laf.xml 파일에 아래와 같이 세팅되어 있다고 가정한다.
   *
   *    1) test-mode
   *      테스트로 메일을 발송 해보고자 할 경우 true로 지정하며, 이 경우 test-receivers 들에게 발송된다.
   *      운영시에는 test-mode를 false로 지정한다.
   *
   *    2) spec
   *      spec 은 메일 발송에 필요한 mailer server정보와 발신자 정보 등을 기록한다.
   *      spec 에 name을 지정하지 않을 경우 default 값이 지정되며,
   *      default 로 지정된 것 중 일부만 변경하여 사용하고 싶을 경우에는 spec 의 name을 example 과 같이 정의한다.
   *      이렇게 해 두면, default에서 지정한 기본값에 새로 지정한 값이 overwrite 된다.
   *      즉, 공통적인 세팅은 default에 두고 변경하고자 할 경우만 spec에 name을 지정하여 사용할 수 있는 장점이 있다.
   *      spec 은 LMail 생성시 인자로서 지정하고, 인자가 없을 경우 default spec이 적용된다.
   *
   *    3) body-template
   *      html 형태로 메일을 보내고자 할 경우 사용한다.
   *      html string 을 직접 만들어서 send할 수도 있으나, 동적으로 html 내부 내용이 세팅되어야 할 경우에 유용하다.
   *      이를 위해 template html 파일을 저장해두는 디렉토리와 html파일을 설정한다.
   *      mail-template 도 spec과 마찬가지로 LMail 생성시 인자로 지정한다.
   *      인자가 없을 경우 default mail-template이 적용되고, sub-directory지정도 가능하다.
   *

                                                                                    49
주석 – Example #2                                              Smells


    public static void writeMail(String[] args) {

       // 메일에 사용할 유저 데이터를 LDATA를 이용하여 생성
       LData ld = new LData("userInfo");

       // 발송자의 이름을 생성한다.
       // 단 발송자는 userName 이라는 항목으로 만들어야 함
       ld.setString("userName", "Jubong, Park");

       // 수신자 목록을 만든다. 수신자 항목은 LData에서 name 으로 설정한다.
       LMultiData lm = new LMultiData("friends");
       lm.add("name", "Hyori, Kim");
       lm.add("name", "Yeesul, Lee");
       lm.add("name", "Dongwook, Park");

       // [ ] 로 수신인을 구분하므로, 스트링 버퍼를 사용하여 구분자가 첨부된 스트링으로 변환
       StringBuffer imsi = new StringBuffer();
       for(int i=0; i<lm.keySize("name"); i++) {
           imsi.append("[");
           imsi.append(lm.getString("name",i));
           imsi.append("] ");
       }
       ld.setString("friends", imsi.toString());

                                                                  50
주석 – Example #2                                      Smells




     public static void writeMail(String[] args) {

            Mail mail = new Mail();

            mail.setSender("Jubong, Park");

            mail.addReceiver("Hyori, Kim");
            mail.addReceiver("Yeesul, Lee");
            mail.addReceiver("Dongwook, Park");

               …
               …



                                                          51
주석 – Example #3                                    Smells




  public static final int LowHandleLength = 400;

  // 일반적인 경우 MaxTilt는 최저조정길이의 절반으로 설정한다.
  public static final int MaxTilt = 200;




                                                        52
기능에 대한 욕심 Feature Envy              Smells



  메소드 자신이 속한 클래스보다 다른 클래스에 대해 관심이 많은
   메소드
   – Move Method

  다른 클래스를 이용해서 기능을 처리하는 특정 부분들
   – Extract Method  Move Method

  함께 변경해야 하는 것들은 한 곳으로 모으자.




                                         53
긴 파라미터 리스트 Long Parameter List               Smells



  프로그래밍 초창기 세대의 규칙
    – 전역변수를 쓰지 말자.  필요한 것들은 모두 파라미터로 넘기자.

  파라미터 리스트가 길어지면?
    – 이해하기 어렵다.

    – 파라미터들의 관련성이나 일관성이 떨어진다.




                                                  54
긴 파라미터 리스트 Long Parameter List         Smells



  OOP의 경우?

  객체(Object)를 통해 필요한 정보들을 전달할 수 있다.
    파라미터 리스트를 줄 일 수 있다!
    – Replace Parameter with Method

    – Preserve Whole Object

    – Introduce Parameter Object




                                            55
확산적 변경 Divergent Change                           Smells



  한 클래스가 어떤 이유로 인해 자주 변경되는 경우
    – 소프트웨어는 변경하기 쉬워야 한다. 그리고 하나의 기능을 변경하기 위해
      서 한 곳만 수정하도록 만들어야 한다. 그런데, 하나의 기능을 위해 한 클
      래스 내부의 여러 곳을 수정해야 한다면?

  특정 원인에 대해 변경해야 하는 부분들을 찾아내 묶자
    – Extract Method




                                                       56
임시 필드 Temporary Fields                    Smells



   특정 상황에 따라 값이 변하게 되는 임시변수는 곧 잘 코드를 이
   해하기 어렵게 만든다.
    – Replace Temp with Query

    – Replace Parameter with Method

   임시 변수 대입이 빈번하다면?
    – Extract Class




                                               57
중복 코드 Duplicate code                                     Smells



  수 많은 버그와 문제의 근원 = 중복 코드!!
    – 중복 코드는 하나로 합치자!

  동일한 표현이 여러 부분에 존재
    – 같은 클래스 내부?  Extract Method

    – 하위 클래스들 사이에서?  Extract Method and Pull Up Field

    – 여러 클래스에 걸쳐서 나타나면? Extract Class




                                                              58
스위치 구문 Switch statements                                            Smells



  잘 작성된 객체지향 프로그램의 확실한 특징 하나!
    – 스위치(switch) 구문이 상대적으로 적다!

  스위치 구문은 곧 잘 코드 중복을 유발하고 프로그램 내부 여러
   곳에 비슷한 형태로 흩어져 존재하게 된다.
    – Extract Method and Move Method
    – Replace Type Code with Subclasses 혹은 Replace Type Code with
      State/Strategy
    – Replace Conditional with Polymorphism
    – Replace Parameter with Explicit Methods
    – Introduce Null Object

                                                                         59
산탄총 수술 Shotgun surgery                     Smells



  하나의 기능 변경 위해 여러 클래스를 고쳐야 하는 경우
    – 찾아내기 어렵고 수정할 부분들을 곧잘 놓치게 된다.

  이상적으로는 추가/변경이 원투원(one-to-one) 링크형태로 이
   뤄져야 한다.
    – Move Method and Move Field

    – Inline Class




                                                60
추측성 일반화 Speculative Generality                 Smells



   “으흠! 이러이러한 기능이 나중에 필요할 걸! 미리 만들어 놓아야
   지!”
    – 하지만, 결과는 곧 잘 이해하기 어렵고 유지보수 하기 어렵게 만든다.

   섣불리 미래를 예측하지 마라! 현재의 복잡도에 집중!
    – 별 볼일없는 추상클래스?  Collapse Hierarchy

    – 불필요한 기능 위임이 발생한다면?  Inline Class

    – 지금 안 쓰는 파라미터라면?  Remove Parameter




                                                    61
기본형에 대한 강박 Primitive Obsession                      Smells



  객체 지향 프로그래밍에서는 기본형과 클래스를 애써 구별 지을
   필요 없다.

  객체지향적인 사고로 전환하자!
    – 이름, 화폐, 통화단위, 전화번호, 우편번호, 주소, 나이 등등 모든 것이 객
      체가 될 수 있다.

    – Replace Data Value with Object

    – Replace Array with Object




                                                         62
3. 리팩터링 카탈로그
1.   Extract Method                   13. Replace Type Code with Subclasses
2.   Rename Method                    14. Replace Type Code with
                                          State/Strategy
3.   Introduce Assertion
                                      15. Replace Conditional with
4.   Move Method
                                          Polymorphism
5.   Decompose Conditional
                                      16. Introduce Null Object
6.   Move Field
                                      17. Preserve Whole Object
7.   Extract Class
                                      18. Collapse Hierarchy
8.   Inline Class
                                      19. Remove Parameter
9.   Replace Temp with Query
                                      20. Introduce Parameter Object
10. Pull Up Field ↔ Pull Down Field
                                      21. Replace Data Value with Object
11. Replace Parameter with Method
                                      22. Replace Array with Object
12. Replace Type Code with Class

                                                                                63
                                                                              리팩터링
리팩터링 카탈로그 #1                                                리팩터링 카탈로그


  – Extract Method                  http://www.refactoring.com/catalog/
  – Decompose Conditional
  – Rename Method
  – Introduce Assertion
  – Move Method
  – Move Field
  – Extract Class
  – Inline Class
  – Replace Temp with Query
  – Pull Up Field
  – Replace Parameter with Method


                                                                          64
리팩터링 카탈로그 #2                                리팩터링 카탈로그


  – Replace Type Code with Class
  – Replace Type Code with Subclasses
  – Replace Type Code with State/Strategy
  – Replace Conditional with Polymorphism
  – Introduce Null Object
  – Preserve Whole Object
  – Collapse Hierarchy
  – Remove Parameter
  – Introduce Parameter Object
  – Replace Data Value with Object
  – Replace Array with Object


                                                    65
Extract Method                                                  리팩터링 카탈로그


   코드 조각이 여기저기 흩어져 있을 때




  - 메소드가 길거나, 주석이 필요할 때 사용하며, 재사용, 가독성을 높여준다.
  - 이름을 잘 지어야 하며, 메소드 추출의 핵심은 “의미상의 거리(Semantic distance)”이다.

                                                                        66
Rename Method                                              리팩터링 카탈로그


   이름만으로 메소드 의도 파악이 잘 안될 때




              Customer                          Customer

       getinvcdtlmt()                  getInvoiceableCreditLimit()




  - 메소드는 작성 의도를 잘 전달해 주는 이름을 가져야 한다.
  - 글로 작성하는 코드는 사람을 이해시키는 것이 목적이지, 컴퓨터를 이해시키는 것이 아니다.
  - 진정으로 뛰어난 프로그래머가 되고 싶은가? 무엇보다 이름을 잘 짓기 위해 노력하고 연습해라!


                                                                     67
Introduce Assertion                                                   리팩터링 카탈로그


   코드의 일부가 프로그램의 특정 상태를 가정하고 있을 때

      double getExpenseLimit() {
         // should have either expense limit or a primary project
         return (_expenseLimit != NULL_EXPENSE) ?
         _expenseLimit:
         _primaryProject.getMemberExpenseLimit();
      }



      double getExpenseLimit() {
         Assert.isTrue (_expenseLimit != NULL_EXPENSE || _primaryProject != null);
         return (_expenseLimit != NULL_EXPENSE) ?
         _expenseLimit:
         _primaryProject.getMemberExpenseLimit();
      }

   - 명시적으로 체크하는 구문을 작성하거나 값을 확인 한다.



                                                                                     68
Move Method                                           리팩터링 카탈로그


  메소드가 자신이 정의된 클래스보다 다른 클래스의 기능을 더 많이 사용할 때




  - 클래스가 너무 많은 동작을 가지고 있거나, 다른 클래스와 공동으로 일하는 부분이 너무 많아서 단단히 결합되어 있
    을 때 메소드 위치를 옮긴다.
  - 만약 메소드를 옮겨야 할지에 대한 확신이 없다면 다른 메소드들을 함께 살펴보자.


                                                                     69
Decompose Conditional                                                 리팩터링 카탈로그


   if-then-else같은 조건문이 복잡하게 존재할 때


      if ( date.before (SUMMER_START) || date.after(SUMMER_END) )
            charge = quantity * _winterRate + _winterServiceCharge;
      else charge = quantity * _summerRate;




      if ( notSummer(date) )
            charge = winterCharge(quantity);
      else charge = summerCharge (quantity);




                                                                              70
Move Field                            리팩터링 카탈로그


   필드가 자신이 정의된 클래스보다 다른 클래스에 의해 더 많이 사용 될 때




                                              71
Extract Class                                            리팩터링 카탈로그


   두 개의 클래스가 해야 할 일을 하나의 클래스가 하고 있는 경우




   - 일반적으로 클래스는 시간이 지날수록 커지게 되며, 크기가 커질 수록 이해하기 어려워진다.
   - 이럴 경우, 쪼갤 수 있다면, 쪼개라!



                                                                 72
Inline Class                                             리팩터링 카탈로그


    클래스가 하는 일이 별로 없을 때




   - 흔히 리팩터링 할 때 메소드를 옮기고 난 다음 살펴보니, 이젠 해당 클래스가 하는 일이 별로 없다는 걸 알게 된다.




                                                                        73
Replace Temp with Query                                              리팩터링 카탈로그


    어떤 수식의 결과값을 저장하기 위해서 임시변수를 사용하고 있을 경우


 double basePrice = _quantity * _itemPrice;
 if (basePrice > 1000)
     return basePrice * 0.95;
 else
     return basePrice * 0.98;                 if (basePrice() > 1000)
                                                  return basePrice() * 0.95;
                                              else
                                                  return basePrice() * 0.98;
                                              ...
                                              double basePrice() {
                                                  return _quantity * _itemPrice;
                                              }


   - 임시 변수는 임시로 사용되고, 특정 부분에서만 의미를 가지므로 문제가 된다.
   - 임시변수가 사용되는 메소드는 보통 길이가 길어진다.



                                                                                   74
Pull Up Field ↔ Pull Down Field   리팩터링 카탈로그


   두 개의 하위 클래스가 같은 필드를 갖고 있을 경우




   - 중복을 제거한다.




                                          75
Replace Parameter with Method                                          리팩터링 카탈로그


   메소드로 받은 결과를 다른 메소드의 파라미터로 넘겨 주는 경우


     int basePrice = _quantity * _itemPrice;
     discountLevel = getDiscountLevel();
     double finalPrice = discountedPrice (basePrice, discountLevel);




     int basePrice = _quantity * _itemPrice;
     double finalPrice = discountedPrice (basePrice);



  - 파라미터로 넘겨주는 메소드에서도 호출 할 수 있는 메소드라면 호출 결과를 받아서 넘겨 줄 필요가 없다.




                                                                               76
Replace Type Code with Class                          리팩터링 카탈로그


   어떤 클래스가 동작에 영향을 미치지 않는 숫자 형식 타입코드를 가졌을 경우




  - 타입 코드가 클래스의 동작에 영향을 주는지 여부를 고려해야 한다.
  - 타입 코드를 나타내는 변수가 단순 별칭이 아니라 컴파일러가 타입을 체크해 줄 수 있도록 만든다.



                                                              77
Replace Type Code with Subclasses                     리팩터링 카탈로그


   클래스의 행위에 영향을 주는 변경 불가능한(immutable) 타입코드를 가질 경우




  - 만약 타입 코드가 클래스의 행위에 영향을 줄 경우, 최선의 방법은 다형성을 이용하는 것이다.
  - 다양한 행위에 대한 지식을 클라이언트 코드에서 특정 클래스로 위임하게 된다는 것이 장점이다.



                                                              78
Replace Type Code with State/Strategy          리팩터링 카탈로그


   행동에 영향을 주는 타입 코드가 있지만 해당 타입 코드를 서브클래스로 만들 수
   없는 경우




   - 객체가 살아있는 동안 타입 코드에 따라 행위가 바뀌도록 만들 수 있다.
   - 컴파일러에 의한 타입 체크 지원을 받을 수 있다.



                                                       79
Replace Conditional with
                                                                       리팩터링 카탈로그
Polymorphism #1
   객체의 타입에 따라 다른 동작을 선택하는 조건문을 가지고 있는 경우

      double getSpeed() {
         switch (_type) {
            case EUROPEAN:
               return getBaseSpeed();
            case AFRICAN:
               return getBaseSpeed() - getLoadFactor() * _numberOfCoconuts;
            case NORWEIGIAN_BLUE:
               return (_isNailed) ? 0 : getBaseSpeed(_voltage);
         }
         throw new RuntimeException ("Should be unreachable");
      }



   - 조건문의 각 부분을 서브클래스에 있는 오버라이딩 메소드로 옮기고 원래 메소드를 abstract로 만든다.




                                                                               80
Replace Conditional with
                                     리팩터링 카탈로그
Polymorphism #2
   객체의 타입에 따라 다른 동작을 선택하는 조건문을 가지고 있는 경우




                                             81
Introduce Null Object                                  리팩터링 카탈로그


    반복적인 널(null) 검사가 이루어지고 있을 경우




       if (customer == null)
          plan = BillingPlan.basic();
       else
          plan = customer.getPlan();




   - null 값을 null 객체로 대체한다.
   - 다형성의 진가는, 객체에 타입을 묻고 그 답을 기초로 하여 어떤 동작을 호출하는 대신에 단지 그 동작을 호출하는
     것이다. 그러면 그 객체는 타입에 따라서 적절히 동작한다.


                                                                      82
Preserve Whole Object                                     리팩터링 카탈로그


   어떤 객체에서 여러 개의 값을 얻은 다음 메소드 호출 시 파라미터로 넘길 경우


        int low = daysTempRange().getLow();
        int high = daysTempRange().getHigh();
        withinPlan = plan.withinRange(low, high);




        withinPlan = plan.withinRange(daysTempRange());



  - 메소드로 넘겨야 하는 값이 변경되는 경우, 해당 메소드들을 다 고쳐야 하는 상황이 발생한다. 관련 데이터를 객체로
    만들어 넘겨주면 이런 상황에도 메소드의 외형을 유지시켜 준다.




                                                                      83
Collapse Hierarchy                리팩터링 카탈로그


   상위 클래스와 하위 클래스가 크게 다르지 않을 경우




   - 리팩터링을 진행하는 과정 도중에 종종 나타난다.




                                          84
Remove Parameter                                  리팩터링 카탈로그


   파라미터가 더 이상 메소드 안에서 쓰이지 않을 경우




  - 쓰지 않는 파라미터를 남겨 놓으면 다른 사용자는 고민한다.
  - 단, 다형성에 사용되는 메소드일 경우, 파라미터 제거에 좀 더 신중해야 한다.



                                                          85
Introduce Parameter Object                             리팩터링 카탈로그


   함께 뭉쳐 다니는 파라미터들의 그룹이 있을 경우




   - 클래스로 도출해 내면 복잡도가 감소된다.
   - 또한, 관련된 동작도 해당 클래스 내부로 옮기는 것이 가능해지므로 중복코드도 줄어들게 된다.



                                                               86
Replace Data Value with Object                            리팩터링 카탈로그


   추가적인 데이터나 행위가 필요한 데이터 항목을 가질 경우




  - 예를 들면, 전화번호를 처음 한동안은 문자열(String)으로 표현 할 수 있지만, 나중에는 포맷팅을 해야 한다든가, 지
    역 코드를 추출해야 하는 등의 특별한 동작이 필요해지는 경우가 발생한다.




                                                                          87
Replace Array with Object                         리팩터링 카탈로그


   배열의 특정 요소가 다른 뜻을 가지고 있을 경우


           String[] row = new String[3];
           row [0] = "Liverpool";
           row [1] = "15";




           Performance row = new Performance();
           row.setName("Liverpool");
           row.setWins("15");




                                                          88

More Related Content

What's hot

Devon 2011-b-5 효과적인 레거시 코드 다루기
Devon 2011-b-5 효과적인 레거시 코드 다루기Devon 2011-b-5 효과적인 레거시 코드 다루기
Devon 2011-b-5 효과적인 레거시 코드 다루기Daum DNA
 
파이썬 TDD 101
파이썬 TDD 101파이썬 TDD 101
파이썬 TDD 101정주 김
 
Legacy code refactoring video rental system
Legacy code refactoring   video rental systemLegacy code refactoring   video rental system
Legacy code refactoring video rental systemJaehoon Oh
 
애자일 테스트 프랙티스와 사례들 (부제: 협업의 힘)
애자일 테스트 프랙티스와 사례들 (부제: 협업의 힘)애자일 테스트 프랙티스와 사례들 (부제: 협업의 힘)
애자일 테스트 프랙티스와 사례들 (부제: 협업의 힘)SangIn Choung
 
테스트 주도 개발 By googletest 1장 다중 통화를 지원하는 money 객체
테스트 주도 개발 By googletest   1장 다중 통화를 지원하는 money 객체테스트 주도 개발 By googletest   1장 다중 통화를 지원하는 money 객체
테스트 주도 개발 By googletest 1장 다중 통화를 지원하는 money 객체Mickey SJ Lee
 
Tdd live spring camp 2013
Tdd live spring camp 2013Tdd live spring camp 2013
Tdd live spring camp 2013beom kyun choi
 
C++ 프로젝트에 단위 테스트 도입하기
C++ 프로젝트에 단위 테스트 도입하기C++ 프로젝트에 단위 테스트 도입하기
C++ 프로젝트에 단위 테스트 도입하기Heo Seungwook
 
IoT 개발자를 위한 Embedded C에서 TDD를 해보자
IoT 개발자를 위한 Embedded C에서 TDD를 해보자IoT 개발자를 위한 Embedded C에서 TDD를 해보자
IoT 개발자를 위한 Embedded C에서 TDD를 해보자Taeyeop Kim
 
테스터가 말하는 테스트코드 작성 팁과 사례
테스터가 말하는 테스트코드 작성 팁과 사례테스터가 말하는 테스트코드 작성 팁과 사례
테스터가 말하는 테스트코드 작성 팁과 사례SangIn Choung
 
테스트자동화와 TDD
테스트자동화와 TDD테스트자동화와 TDD
테스트자동화와 TDDSunghyouk Bae
 
Java performance and trouble shooting
Java performance and trouble shootingJava performance and trouble shooting
Java performance and trouble shootingAnna Choi
 

What's hot (17)

팀장 잔소리
팀장 잔소리팀장 잔소리
팀장 잔소리
 
TDD with JUnit 2
TDD with JUnit 2TDD with JUnit 2
TDD with JUnit 2
 
Devon 2011-b-5 효과적인 레거시 코드 다루기
Devon 2011-b-5 효과적인 레거시 코드 다루기Devon 2011-b-5 효과적인 레거시 코드 다루기
Devon 2011-b-5 효과적인 레거시 코드 다루기
 
파이썬 TDD 101
파이썬 TDD 101파이썬 TDD 101
파이썬 TDD 101
 
Legacy code refactoring video rental system
Legacy code refactoring   video rental systemLegacy code refactoring   video rental system
Legacy code refactoring video rental system
 
애자일 테스트 프랙티스와 사례들 (부제: 협업의 힘)
애자일 테스트 프랙티스와 사례들 (부제: 협업의 힘)애자일 테스트 프랙티스와 사례들 (부제: 협업의 힘)
애자일 테스트 프랙티스와 사례들 (부제: 협업의 힘)
 
테스트 주도 개발 By googletest 1장 다중 통화를 지원하는 money 객체
테스트 주도 개발 By googletest   1장 다중 통화를 지원하는 money 객체테스트 주도 개발 By googletest   1장 다중 통화를 지원하는 money 객체
테스트 주도 개발 By googletest 1장 다중 통화를 지원하는 money 객체
 
TDD
TDDTDD
TDD
 
Tdd live spring camp 2013
Tdd live spring camp 2013Tdd live spring camp 2013
Tdd live spring camp 2013
 
C++ 프로젝트에 단위 테스트 도입하기
C++ 프로젝트에 단위 테스트 도입하기C++ 프로젝트에 단위 테스트 도입하기
C++ 프로젝트에 단위 테스트 도입하기
 
TEST?
TEST?TEST?
TEST?
 
C++과 TDD
C++과 TDDC++과 TDD
C++과 TDD
 
IoT 개발자를 위한 Embedded C에서 TDD를 해보자
IoT 개발자를 위한 Embedded C에서 TDD를 해보자IoT 개발자를 위한 Embedded C에서 TDD를 해보자
IoT 개발자를 위한 Embedded C에서 TDD를 해보자
 
테스터가 말하는 테스트코드 작성 팁과 사례
테스터가 말하는 테스트코드 작성 팁과 사례테스터가 말하는 테스트코드 작성 팁과 사례
테스터가 말하는 테스트코드 작성 팁과 사례
 
Java the good parts
Java the good partsJava the good parts
Java the good parts
 
테스트자동화와 TDD
테스트자동화와 TDD테스트자동화와 TDD
테스트자동화와 TDD
 
Java performance and trouble shooting
Java performance and trouble shootingJava performance and trouble shooting
Java performance and trouble shooting
 

Viewers also liked

Big refactoring #12
Big refactoring #12Big refactoring #12
Big refactoring #12Jay Kim
 
[NEXT] Nextgram Refactoring
[NEXT] Nextgram Refactoring[NEXT] Nextgram Refactoring
[NEXT] Nextgram RefactoringYoungSu Son
 
Refactoring tutorial 1주차[refactoring 개요]
Refactoring tutorial 1주차[refactoring 개요]Refactoring tutorial 1주차[refactoring 개요]
Refactoring tutorial 1주차[refactoring 개요]bbongcsu
 
Refactoring tutorial
Refactoring tutorialRefactoring tutorial
Refactoring tutorialBingu Shim
 
Refactoring to Design Patterns
Refactoring to Design PatternsRefactoring to Design Patterns
Refactoring to Design PatternsEric De Carufel
 
Refactoring vers les design patterns pyxis v2
Refactoring vers les design patterns   pyxis v2Refactoring vers les design patterns   pyxis v2
Refactoring vers les design patterns pyxis v2Eric De Carufel
 

Viewers also liked (8)

Refactoring#9
Refactoring#9Refactoring#9
Refactoring#9
 
Big refactoring #12
Big refactoring #12Big refactoring #12
Big refactoring #12
 
Code Refactoring
Code RefactoringCode Refactoring
Code Refactoring
 
[NEXT] Nextgram Refactoring
[NEXT] Nextgram Refactoring[NEXT] Nextgram Refactoring
[NEXT] Nextgram Refactoring
 
Refactoring tutorial 1주차[refactoring 개요]
Refactoring tutorial 1주차[refactoring 개요]Refactoring tutorial 1주차[refactoring 개요]
Refactoring tutorial 1주차[refactoring 개요]
 
Refactoring tutorial
Refactoring tutorialRefactoring tutorial
Refactoring tutorial
 
Refactoring to Design Patterns
Refactoring to Design PatternsRefactoring to Design Patterns
Refactoring to Design Patterns
 
Refactoring vers les design patterns pyxis v2
Refactoring vers les design patterns   pyxis v2Refactoring vers les design patterns   pyxis v2
Refactoring vers les design patterns pyxis v2
 

Similar to TDD&Refactoring Day 01: Refactoring

Testing & refactoring
Testing & refactoringTesting & refactoring
Testing & refactoringLim Hosung
 
The Cucumber for Java
The Cucumber for JavaThe Cucumber for Java
The Cucumber for JavaJonghwa Lee
 
The roadtocodecraft
The roadtocodecraftThe roadtocodecraft
The roadtocodecraftbbongcsu
 
우아하게 준비하는 테스트와 리팩토링 - PyCon Korea 2018
우아하게 준비하는 테스트와 리팩토링 - PyCon Korea 2018우아하게 준비하는 테스트와 리팩토링 - PyCon Korea 2018
우아하게 준비하는 테스트와 리팩토링 - PyCon Korea 2018Kenneth Ceyer
 
마이크로 프론트엔드 아키텍쳐를 위한 모노레포 관리
마이크로 프론트엔드 아키텍쳐를 위한 모노레포 관리마이크로 프론트엔드 아키텍쳐를 위한 모노레포 관리
마이크로 프론트엔드 아키텍쳐를 위한 모노레포 관리경식 최
 
Dev rookie codecomplete-1
Dev rookie codecomplete-1Dev rookie codecomplete-1
Dev rookie codecomplete-1대영 노
 
프로젝트 Xxx에 적용하고 싶은 개발방법
프로젝트 Xxx에 적용하고 싶은 개발방법프로젝트 Xxx에 적용하고 싶은 개발방법
프로젝트 Xxx에 적용하고 싶은 개발방법도형 임
 
『이펙티브 디버깅』 - 디버깅 지옥에서 탈출하는 66가지 전략과 기법
『이펙티브 디버깅』 - 디버깅 지옥에서 탈출하는 66가지 전략과 기법『이펙티브 디버깅』 - 디버깅 지옥에서 탈출하는 66가지 전략과 기법
『이펙티브 디버깅』 - 디버깅 지옥에서 탈출하는 66가지 전략과 기법복연 이
 
애자일과 애자일 테스트 소개 (테스트기본교육 3장 2절)
애자일과 애자일 테스트 소개 (테스트기본교육 3장 2절)애자일과 애자일 테스트 소개 (테스트기본교육 3장 2절)
애자일과 애자일 테스트 소개 (테스트기본교육 3장 2절)SangIn Choung
 
도메인주도설계
도메인주도설계도메인주도설계
도메인주도설계Wonjun Hwang
 
개발자, 성장하는 '척' 말고, 진짜 성장하기
개발자, 성장하는 '척' 말고, 진짜 성장하기개발자, 성장하는 '척' 말고, 진짜 성장하기
개발자, 성장하는 '척' 말고, 진짜 성장하기Donghyun Cho
 
EMOCON 2015 - 품질과 테스트는 다르다
EMOCON 2015 - 품질과 테스트는 다르다EMOCON 2015 - 품질과 테스트는 다르다
EMOCON 2015 - 품질과 테스트는 다르다이상한모임
 
Clean code 정보통신대학원_2012_spring
Clean code 정보통신대학원_2012_springClean code 정보통신대학원_2012_spring
Clean code 정보통신대학원_2012_spring김진태 Jintae Kim
 
객체지향프로그래밍 특강
객체지향프로그래밍 특강객체지향프로그래밍 특강
객체지향프로그래밍 특강uEngine Solutions
 
Aspect Oriented Programming_SYS4U I&C
Aspect Oriented Programming_SYS4U I&CAspect Oriented Programming_SYS4U I&C
Aspect Oriented Programming_SYS4U I&Csys4u
 
좋은 개발자 되기
좋은 개발자 되기좋은 개발자 되기
좋은 개발자 되기Sunghyouk Bae
 
GraphQL in Action - REST와 이별할 때 생각해야 하는 것들
GraphQL in Action - REST와 이별할 때 생각해야 하는 것들GraphQL in Action - REST와 이별할 때 생각해야 하는 것들
GraphQL in Action - REST와 이별할 때 생각해야 하는 것들Kivol
 
개발 생산성 향상 기법 V1.2
개발 생산성 향상 기법 V1.2개발 생산성 향상 기법 V1.2
개발 생산성 향상 기법 V1.2Daniel Lim
 
9장 도메인 주도 설계
9장 도메인 주도 설계9장 도메인 주도 설계
9장 도메인 주도 설계Hyosung Jeon
 
C Language II
C Language IIC Language II
C Language IISuho Kwon
 

Similar to TDD&Refactoring Day 01: Refactoring (20)

Testing & refactoring
Testing & refactoringTesting & refactoring
Testing & refactoring
 
The Cucumber for Java
The Cucumber for JavaThe Cucumber for Java
The Cucumber for Java
 
The roadtocodecraft
The roadtocodecraftThe roadtocodecraft
The roadtocodecraft
 
우아하게 준비하는 테스트와 리팩토링 - PyCon Korea 2018
우아하게 준비하는 테스트와 리팩토링 - PyCon Korea 2018우아하게 준비하는 테스트와 리팩토링 - PyCon Korea 2018
우아하게 준비하는 테스트와 리팩토링 - PyCon Korea 2018
 
마이크로 프론트엔드 아키텍쳐를 위한 모노레포 관리
마이크로 프론트엔드 아키텍쳐를 위한 모노레포 관리마이크로 프론트엔드 아키텍쳐를 위한 모노레포 관리
마이크로 프론트엔드 아키텍쳐를 위한 모노레포 관리
 
Dev rookie codecomplete-1
Dev rookie codecomplete-1Dev rookie codecomplete-1
Dev rookie codecomplete-1
 
프로젝트 Xxx에 적용하고 싶은 개발방법
프로젝트 Xxx에 적용하고 싶은 개발방법프로젝트 Xxx에 적용하고 싶은 개발방법
프로젝트 Xxx에 적용하고 싶은 개발방법
 
『이펙티브 디버깅』 - 디버깅 지옥에서 탈출하는 66가지 전략과 기법
『이펙티브 디버깅』 - 디버깅 지옥에서 탈출하는 66가지 전략과 기법『이펙티브 디버깅』 - 디버깅 지옥에서 탈출하는 66가지 전략과 기법
『이펙티브 디버깅』 - 디버깅 지옥에서 탈출하는 66가지 전략과 기법
 
애자일과 애자일 테스트 소개 (테스트기본교육 3장 2절)
애자일과 애자일 테스트 소개 (테스트기본교육 3장 2절)애자일과 애자일 테스트 소개 (테스트기본교육 3장 2절)
애자일과 애자일 테스트 소개 (테스트기본교육 3장 2절)
 
도메인주도설계
도메인주도설계도메인주도설계
도메인주도설계
 
개발자, 성장하는 '척' 말고, 진짜 성장하기
개발자, 성장하는 '척' 말고, 진짜 성장하기개발자, 성장하는 '척' 말고, 진짜 성장하기
개발자, 성장하는 '척' 말고, 진짜 성장하기
 
EMOCON 2015 - 품질과 테스트는 다르다
EMOCON 2015 - 품질과 테스트는 다르다EMOCON 2015 - 품질과 테스트는 다르다
EMOCON 2015 - 품질과 테스트는 다르다
 
Clean code 정보통신대학원_2012_spring
Clean code 정보통신대학원_2012_springClean code 정보통신대학원_2012_spring
Clean code 정보통신대학원_2012_spring
 
객체지향프로그래밍 특강
객체지향프로그래밍 특강객체지향프로그래밍 특강
객체지향프로그래밍 특강
 
Aspect Oriented Programming_SYS4U I&C
Aspect Oriented Programming_SYS4U I&CAspect Oriented Programming_SYS4U I&C
Aspect Oriented Programming_SYS4U I&C
 
좋은 개발자 되기
좋은 개발자 되기좋은 개발자 되기
좋은 개발자 되기
 
GraphQL in Action - REST와 이별할 때 생각해야 하는 것들
GraphQL in Action - REST와 이별할 때 생각해야 하는 것들GraphQL in Action - REST와 이별할 때 생각해야 하는 것들
GraphQL in Action - REST와 이별할 때 생각해야 하는 것들
 
개발 생산성 향상 기법 V1.2
개발 생산성 향상 기법 V1.2개발 생산성 향상 기법 V1.2
개발 생산성 향상 기법 V1.2
 
9장 도메인 주도 설계
9장 도메인 주도 설계9장 도메인 주도 설계
9장 도메인 주도 설계
 
C Language II
C Language IIC Language II
C Language II
 

More from Suwon Chae

실패한 프로젝트들의 개발문화_개발방법론
실패한 프로젝트들의 개발문화_개발방법론실패한 프로젝트들의 개발문화_개발방법론
실패한 프로젝트들의 개발문화_개발방법론Suwon Chae
 
Ryan Dahl의 Node.js 소개 동영상 해설 by doortts
Ryan Dahl의 Node.js 소개 동영상 해설 by doorttsRyan Dahl의 Node.js 소개 동영상 해설 by doortts
Ryan Dahl의 Node.js 소개 동영상 해설 by doorttsSuwon Chae
 
Mongo db로 배우는 nosql
Mongo db로 배우는 nosqlMongo db로 배우는 nosql
Mongo db로 배우는 nosqlSuwon Chae
 
테스트 가능한 소프트웨어 설계와 TDD작성 패턴 (Testable design and TDD)
테스트 가능한 소프트웨어 설계와 TDD작성 패턴 (Testable design and TDD)테스트 가능한 소프트웨어 설계와 TDD작성 패턴 (Testable design and TDD)
테스트 가능한 소프트웨어 설계와 TDD작성 패턴 (Testable design and TDD)Suwon Chae
 
잘하면고효율, 못하면가문의원수가되는 짝프로그래밍 (Effective Pair Programming with Lessons Learned)
잘하면고효율, 못하면가문의원수가되는 짝프로그래밍 (Effective Pair Programming with Lessons Learned)잘하면고효율, 못하면가문의원수가되는 짝프로그래밍 (Effective Pair Programming with Lessons Learned)
잘하면고효율, 못하면가문의원수가되는 짝프로그래밍 (Effective Pair Programming with Lessons Learned)Suwon Chae
 

More from Suwon Chae (6)

실패한 프로젝트들의 개발문화_개발방법론
실패한 프로젝트들의 개발문화_개발방법론실패한 프로젝트들의 개발문화_개발방법론
실패한 프로젝트들의 개발문화_개발방법론
 
Refactoring
RefactoringRefactoring
Refactoring
 
Ryan Dahl의 Node.js 소개 동영상 해설 by doortts
Ryan Dahl의 Node.js 소개 동영상 해설 by doorttsRyan Dahl의 Node.js 소개 동영상 해설 by doortts
Ryan Dahl의 Node.js 소개 동영상 해설 by doortts
 
Mongo db로 배우는 nosql
Mongo db로 배우는 nosqlMongo db로 배우는 nosql
Mongo db로 배우는 nosql
 
테스트 가능한 소프트웨어 설계와 TDD작성 패턴 (Testable design and TDD)
테스트 가능한 소프트웨어 설계와 TDD작성 패턴 (Testable design and TDD)테스트 가능한 소프트웨어 설계와 TDD작성 패턴 (Testable design and TDD)
테스트 가능한 소프트웨어 설계와 TDD작성 패턴 (Testable design and TDD)
 
잘하면고효율, 못하면가문의원수가되는 짝프로그래밍 (Effective Pair Programming with Lessons Learned)
잘하면고효율, 못하면가문의원수가되는 짝프로그래밍 (Effective Pair Programming with Lessons Learned)잘하면고효율, 못하면가문의원수가되는 짝프로그래밍 (Effective Pair Programming with Lessons Learned)
잘하면고효율, 못하면가문의원수가되는 짝프로그래밍 (Effective Pair Programming with Lessons Learned)
 

TDD&Refactoring Day 01: Refactoring

  • 1. Day01 더 나은 코드 작성을 위한 리팩터링 1
  • 2. 학습목표 응용 애플리케이션 작성시 만들어지는 나쁜 코드들을 구별할 수 있다. 나쁜 코드를 객체지향 설계가 적용된 코드로 변경하는 기법을 배우고 적 용할 수 있다. 실제 코드에서 잘못된 부분을 찾아내 이해하기 쉬운 구조로 변경할 수 있 다. 2 디자인패턴
  • 3. 1. 코드개선 1. 객체지향 특징 2. 코드 개선 [실습] 3 디자인패턴
  • 5. 추상화 Abstraction 객체지향 특징 주어진 문제나 시스템 중에서 중요하고 관계 있는 부분만을 분리하여 간결하고 이해하기 쉽게 만드는 작업 5
  • 6. 상속 Inheritance 객체지향 특징 직접 구현하지 않고 부모 클래 스로부터 물려받은 기능이나 데이터를 말하며 재사용을 위 한 보편적인 기법 6
  • 7. 캡슐화 Capsulation 객체지향 특징 외부와 통신할 때의 복잡도를 줄이고, 내부 상태를 보호하기 위해 만들어 놓은 구조 7
  • 8. 다형성 Polymorphism 객체지향 특징 polymorphism 하나의 선언으로 여러 개의 타 多形性 입을 가질 수 있는 것. 혹은 자 신이 여러 타입을 가지는 것을 지칭 TYPE 8
  • 9. 2. 코드 개선 [실습] 9
  • 10. 2. 리팩터링이란? 1. 프로젝트 인 더 월드 2. 리팩터링이란? 3. 테스트 코드 4. 리팩터링과 설계 5. 코드 속의 나쁜 냄새 10 리팩터링
  • 11. 1. 프로젝트 인 더 월드 Project in the world 11
  • 12. 프로젝트 In IDEAL Project in the world  확정되어 변경되지 않는 고객의 요구 사항  빈틈없는 시스템 설계  숙련되고 표준을 따르기를 즐기는 개발자  하나의 버그도 빠져나갈 수 없는 완벽한 테스트  정확히 산정된 스케줄과 여유 있는 납기 일자 12
  • 13. 프로젝트 In REAL Project in the world  파트리더 고미화의 고민 – 개발자가 모두 동일한 수준의 Skill을 가지고 있지 않다. – 고객의 요구는 계속 변화된다. – 개발 초기의 디자인이 완벽하지 않는 경우가 많으며, – 실제로 설계가 잘못된 경우도 많다. – 테스트에 나타나지 않는 버그들이 존재한다 – 개발 완료로 끝나지 않는다. 유지보수가 뒤 따른다. 13
  • 14. 프로젝트 In REAL Project in the world  개발자 최고수의 고민 14
  • 15. 프로젝트 In REAL Project in the world  개발자 최고수의 고민 – 코드 이해에 많은 시간이 필요(복잡,다양한 개발자의 취향) – 어려운 업무 용어가 많이 들어간 장황한 주석 또는 주석 부재 – 수정으로 인한 파급 효과에 대한 불안 – Copy & Paste 로 신규 기능 작성 – 고치면 고칠수록 수정이 어려워짐 (땜빵식 코드) 15
  • 16. Normal Dejavu Project in the world • (어쨌든) 요구사항에 맞춰 동작하는 코드 완성 • 추가 요구사항을 계속 반영, 반영, 반영 • 많은 부분에 있어 수정이 가해지고, 개발 속도가 느려지기 시작 • 가끔은 수정해야 할 부분을 잊어서 에러도 발생 (Iterative) • 후임 등장 • 소스를 보고 기겁, 어떻게 어딜 고쳐야 하나? • 언제 시간 내서 통째로 다시 재 작성해야 한다고 믿음 • 그러나 여전히 부분 부분 수정하며, 필요 시에는 선임자를 전화로 찾음 • (어쨌든) 요구사항에 맞춰 동작하는 코드 완성 • and Looping… 16
  • 17. …. 17
  • 19. 리팩터링이란? 리팩터링이란?  리팩터링 – 외견상 보이는 기능 동작은 바뀌지 않는 상태에서 – 이해하기 쉽고, – 수정하기 쉽도록 – 소프트웨어의 내부적인 구조를 변경하는 것 19
  • 20. Example #1 리팩터링이란? void f() { void f() { …. …. computeScore(); // Compute score } score = a * b + c; score -= discount; void computeScore() { } score = a * b + c; score -= discount; } 20
  • 21. Example #2 리팩터링이란? public String name; private String name; public String getName(){ return name; } public String setName (String newName) { name = newName; } 21
  • 22. Example #3 리팩터링이란? if (user == null) plan = Plan.basic(); else plan = user.getPlan(); plan = user.getPlan(); <<interface>> User +getPlan() NullUser +getPlan() return Plan.basic(); 22
  • 23. 왜 리팩터링을 하는가? 리팩터링이란?  설계를 개선 하기 위해  코드를 이해하기 쉽게 만들기 위해  버그를 찾아내기 위해  좀 더 빠르게 프로그래밍 할 수 있도록 개발자와 관리자에게 어떤 하나의 대안 될 수 있는가? 23
  • 24. 구성요소 리팩터링이란?  나쁜냄새(Smells)  카탈로그(Catalogue)  자동화된 단위 테스트(Automated Unit Test) 24
  • 25. 문제점 리팩터링이란?  데이터 베이스  인터페이스 변경  프로젝트 데드라인 25
  • 26. 언제 리팩터링할 것인가? 리팩터링이란?  The Rule of Three – DRY(Don’t Repeat Yourself)원칙  기능을 추가할 때  버그를 수정 할 때  코드 리뷰를 할 때 26
  • 27. 성능의 문제 리팩터링이란?  소프트웨어를 더 이해하기 쉽게 만들기 위해 수정을 하는데, 이때 종종 프로그램을 더 느리게 작동하도록 하는 원인이 될 수 있다.  잘 분해된 코드와 프로그램이 주는 이점 – 새로운 기능 추가가 쉬워 퍼포먼스 튜닝에만 집중하는 것이 가능하다. – 세밀한 분석이 가능하다. 27
  • 28. 안전한 리팩터링의 3대 요소 리팩터링이란?  백업을 만들어 놓거나 형상관 리를 사용한다.  검증된 리팩터링 도구를 사용 한다.  자동화된 단위 테스트 케이스 를 만들어 놓는다. 28
  • 29. 리팩터링 도구 리팩터링이란?  이클립스의 리팩터링 도구 29
  • 31. 단위 테스트 Automated Unit Test 테스트 코드  “리팩터링 작업의 필수 조건은 사전에 탄탄한 테스트를 만들어 놓 는 것이다.” – 마틴 파울러  가장 대표적인 자동화된 단위 테스트 프레임워크 = JUnit 31
  • 32. 테스트 주도 개발 Test-Driven Development 테스트 코드  자동화된 단위 테스트 케이스를 만들어 내는 가장 훌륭한 방식  “프로그램을 작성하기 전에 자동화된 테스트 코드를 먼저 작성한다.”  간결한 설계와 고품질 모듈을 만들어 내는 기법 32
  • 33. TDD 절차 테스트 코드 질문 Ask 테스트를 작성함으로써 시스템에 질문한다. (FAIL) 응답 Respond 테스트를 통과하는 코드를 작성해서 질문에 대답한다. (PASS) 정련 Refine 아이디어를 통합하고, 불필요한 것은 제거하고, 모호한 것은 명확히 해서 대답을 정제한다. (REFACTORING) 반복 Repeat 다음 질문을 통해 대화를 계속 진행한다. 33
  • 35. 소프트웨어 비용 리팩터링과 설계  전체 비용 = 개발 비용 + 유지 비용  유지 비용 = 이해 비용 + 수정 비용 + 테스트 비용 + 설치 비용 35
  • 36. 사전 설계 Upfront Design 리팩터링과 설계  사전 설계 – 재 작업 비용을 줄이기 위해서 SW구조에 대해 사전에 고민을 하는 방식 – 요구사항 변경이 일어날 부분에 대해서 미리 예측한다. – 좀 더 유연한 구조의 설계를 지향한다.  유연한 구조로 솔루션을 구축할 때의 문제점 – 다양한 유연성을 가진다는 건 다른 의미의 비용으로 이어진다. – 좀 더 복잡한 구조가 되기 쉽고, 일반적으로 유지관리하기 더 어려워진다. – 그리고 미래를 정확히 예측하기는 것은 대부분의 경우 불가능하다. 36
  • 37. 리팩터링과 설계 리팩터링과 설계  리팩터링은 일부 관점이 사전설계(upfront design)와 충돌하지 만 결과적으로 리팩터링은 디자인을 보완한다. – 리팩터링과 사전 설계는 강조점이 다르다. 완벽한 솔루션을 찾는 것이 아 니라 납득할만한 수준(reasonable)의 솔루션을 찾는다. – 유연성 강조보다 설계를 간결하게 만드는 쪽에 좀 더 관심을 둔다. – 간결한 시스템을 좀 더 복잡한 유연한 시스템으로 만드는 것은 매우 쉽지 만, 그 반대는 훨씬 어렵기 때문이다. 37
  • 38. 5.코드 속의 나쁜 냄새 Smells 38
  • 39. 직관 Intuition Smells 1997년 5월 11일 뉴욕의 에퀴터블 센터에서는 IBM이 개발한 수퍼 컴퓨터 딥 블루(Deep blue)와 세계 체스 챔피언 ‘게리 카스파로프(Kasparov)’간의 6 차전 마지막 경기가 진행되고 있었다. 『딥 블루』는 2m가 채 안되는 키에 1.4 톤이나 나가는 몸무게를 가지고 있으며 중국인 과학자 츄펑슝 박사 외에 6명의 IBM사 최고 과학자들이 지난 8년 동안 32개의 마이크로 프로세서와 512개의 특수 체스 칩을 장착해서 만들은 2백만 달러 상당의 대형 병렬 수퍼 컴퓨터다. 『딥』은 오로지 『인간을 이겨라』는 특명을 받고 태어난 역사상 최고의 기계로써 1초당 2억번의 행마(行馬)를 검토해가며 장기를 둘 수 있는 능력이 있으며, 지난 백 년 동안에 개최되었던 주요 체스 대국의 기보가 모두 입력되어 있다. 더욱이 슈 박사 팀은 지난번의 패배를 설욕하기 위해 연산 능력을 2배로 보강했으며 미국의 체스 챔피언 조엘 벤저민과 세계 유명 체스 선수들의 조언을 추가로 저장하였다. 특히 슈 박사 팀은 어떠한 경우에도 상대수의 변화에 따라 새로운 수를 개발하여 대처할 수 있는 자기 조정기능의 유연성을 강화시키는데 초점을 두었다고 한다. 따라서『딥』은 그야말로 체스에 있어서는 『살아있는 지능을 가지고 있는 컴퓨터』라고 할 수 있다 지난 5차전까지 이 두 대국자간의 전적은 1승 3무 1패로 무승부. - New York Times 1997.5 39
  • 40. 코드 속의 나쁜 냄새 #1 Smells “나쁜 냄새가 난다면, 고쳐라!” – 켄트벡 – 중복코드(Duplicate code) – 긴 메소드(Long Method) – 거대한 클래스(Large class) – 긴 파라미터 리스트(Long Parameter List) – 확산적 변경(Divergent Change) – 산탄총 수술(Shotgun Surgery) – 기능 욕심(Feature Envy) – 데이터 덩어리(Data Clumps) – 기본형에 대한 강박(Primitive Obsession) – 스위치 구문(Switch Statements) – 병렬 상속 구조(Parallel Inheritance Hierarchies) 40
  • 41. 코드 속의 나쁜 냄새 #2 Smells “컴퓨터가 이해할 수 있는 코드는 바보도 작성할 수 있다. 사람이 이해할 수 있는 코드를 작성해라” – 게으른 클래스(Lazy Class) – 마틴 파울러 – 추측성 일반화(Speculative Generality) – 임시 필드(Temporary Field) – 메시지 연쇄(Message Chains) – 미들맨(Middle Man) – 부적절한 친밀관계(Inappropriate Intimacy) – 인터페이스가 다른 대체 클래스(Alternative Classes with Different Interfaces) – 불완전한 라이브러리 클래스(Incomplete Library Class) – 데이터 클래스(Data Class) – 거부된 유산(Refused Bequest) – 주석(Comments) 41
  • 42. 긴 메소드 Long Method Smells  메소드의 길이가 짧은 프로그램이 오래 살아 남는다. – 메소드의 길이가 길면 길수록 이해하기 더 어려워 진다. – 그럼, 짧은 메소드의 기준은? •의미상의 거리(Semantic Distance)를 측정  대부분 99%에 해당하는 경우 – Extract Method  조건문과 반복문들 – Decompose Conditional 42
  • 43. 긴 메소드 Long Method Smells  Decompose Conditional이 필요한 다른 예 43
  • 44. 이름 짓기 Naming Smells  addCourse( course );  getNodesArrayList();  makeIt();  getData();  sort();  processItem(); 이름을 잘못 지었다고 확실히 와 닿는 경우도 있다. W44() 44
  • 45. 이름 짓기 Naming Smells  암기력에 의존하게 되는 학습을 강요하면 안 된다. maskClear2( plMoney ) 소스의 난이도를 높이는 형태의 불필요한 오버로딩 금지 System.out.println(LMoney.toCommaFormat(120000)); System.out.println(LMoney.toCommaFormat(120000, true)); // () 단위 표시를 추가시킨 스트링 반환 System.out.println(LMoney.toCommaFormat(070712093801.9283));  인자(argument)를 줄이기 위한 자기 참조 형태의 생성자 생성 자제 Money(String a) { Money(String a, false); }  미스터리 소스 생성 금지 /** * basic 한글 화폐단위를 담고 있는 Array */ private static final String basicA[] = { "", "십", "백", "천" }; /** * base 한글 화폐단위를 담고 있는 Array */ private static final String baseA[] = { "", "만", "억", "조", "경" }; 45
  • 46. 주석 Comments Smells  코드 블록을 설명하기 위해 주석이 필요하다면? – Extract Method  메소드 이름만으로 이해가 어려워 작성된 주석이라면? – Rename Method  시스템의 상태를 가정하기 위해 기술된 문장이나 사전 조건을 명 시한 주석의 경우라면? – Introduce Assertion 46
  • 47. 주석 Comments Smells  주석이 나쁘다? – 주석은 좋은 것이다.  Sweet Smells – But, 무엇(what)을 하는지 설명하는데 쓰여서는 안된다. – 이유(why)를 설명하기 위해서 사용해야 한다. – 잘못된 주석은 자칫 코드를 장황하게 만들거나 이해하기 어렵게 한다.  코드 블록을 설명하기 위해 코멘트가 필요하다면? – Extract Method 47
  • 48. 주석 Comments Smells  작성 가이드 – 코드가 하는 일을 그대로 주석으로 작성 (비권장) – 코드의 설명 : 복잡하거니 미묘한 코드에 대한 내용을 주석으로 작성 (비권장, 차라리 코드를 수정) – 표시기능 : Todo, Release 전에 할 일에 대한 내용을 주석으로 작성 (비권장, 적어도 배포 전에는 제거) – 코드의 요약 : 몇 줄의 코드 뭉치가 하는 일을 요약하는 기능. 빠르게 코드를 살펴볼 수 있도록 도움을 줌(권장) – 코드의 의도 설명 (권장) – 코드만으로는 표현할 수 없는 정보: 저작권이나 버전번호, 최적화 내용 등을 기록(권장) - from code complete 48
  • 49. 주석 – Example #1 Smells /** * * laf.xml 파일에 아래와 같이 세팅되어 있다고 가정한다. * * 1) test-mode * 테스트로 메일을 발송 해보고자 할 경우 true로 지정하며, 이 경우 test-receivers 들에게 발송된다. * 운영시에는 test-mode를 false로 지정한다. * * 2) spec * spec 은 메일 발송에 필요한 mailer server정보와 발신자 정보 등을 기록한다. * spec 에 name을 지정하지 않을 경우 default 값이 지정되며, * default 로 지정된 것 중 일부만 변경하여 사용하고 싶을 경우에는 spec 의 name을 example 과 같이 정의한다. * 이렇게 해 두면, default에서 지정한 기본값에 새로 지정한 값이 overwrite 된다. * 즉, 공통적인 세팅은 default에 두고 변경하고자 할 경우만 spec에 name을 지정하여 사용할 수 있는 장점이 있다. * spec 은 LMail 생성시 인자로서 지정하고, 인자가 없을 경우 default spec이 적용된다. * * 3) body-template * html 형태로 메일을 보내고자 할 경우 사용한다. * html string 을 직접 만들어서 send할 수도 있으나, 동적으로 html 내부 내용이 세팅되어야 할 경우에 유용하다. * 이를 위해 template html 파일을 저장해두는 디렉토리와 html파일을 설정한다. * mail-template 도 spec과 마찬가지로 LMail 생성시 인자로 지정한다. * 인자가 없을 경우 default mail-template이 적용되고, sub-directory지정도 가능하다. * 49
  • 50. 주석 – Example #2 Smells public static void writeMail(String[] args) { // 메일에 사용할 유저 데이터를 LDATA를 이용하여 생성 LData ld = new LData("userInfo"); // 발송자의 이름을 생성한다. // 단 발송자는 userName 이라는 항목으로 만들어야 함 ld.setString("userName", "Jubong, Park"); // 수신자 목록을 만든다. 수신자 항목은 LData에서 name 으로 설정한다. LMultiData lm = new LMultiData("friends"); lm.add("name", "Hyori, Kim"); lm.add("name", "Yeesul, Lee"); lm.add("name", "Dongwook, Park"); // [ ] 로 수신인을 구분하므로, 스트링 버퍼를 사용하여 구분자가 첨부된 스트링으로 변환 StringBuffer imsi = new StringBuffer(); for(int i=0; i<lm.keySize("name"); i++) { imsi.append("["); imsi.append(lm.getString("name",i)); imsi.append("] "); } ld.setString("friends", imsi.toString()); 50
  • 51. 주석 – Example #2 Smells public static void writeMail(String[] args) { Mail mail = new Mail(); mail.setSender("Jubong, Park"); mail.addReceiver("Hyori, Kim"); mail.addReceiver("Yeesul, Lee"); mail.addReceiver("Dongwook, Park"); … … 51
  • 52. 주석 – Example #3 Smells public static final int LowHandleLength = 400; // 일반적인 경우 MaxTilt는 최저조정길이의 절반으로 설정한다. public static final int MaxTilt = 200; 52
  • 53. 기능에 대한 욕심 Feature Envy Smells  메소드 자신이 속한 클래스보다 다른 클래스에 대해 관심이 많은 메소드 – Move Method  다른 클래스를 이용해서 기능을 처리하는 특정 부분들 – Extract Method  Move Method  함께 변경해야 하는 것들은 한 곳으로 모으자. 53
  • 54. 긴 파라미터 리스트 Long Parameter List Smells  프로그래밍 초창기 세대의 규칙 – 전역변수를 쓰지 말자.  필요한 것들은 모두 파라미터로 넘기자.  파라미터 리스트가 길어지면? – 이해하기 어렵다. – 파라미터들의 관련성이나 일관성이 떨어진다. 54
  • 55. 긴 파라미터 리스트 Long Parameter List Smells  OOP의 경우?  객체(Object)를 통해 필요한 정보들을 전달할 수 있다.  파라미터 리스트를 줄 일 수 있다! – Replace Parameter with Method – Preserve Whole Object – Introduce Parameter Object 55
  • 56. 확산적 변경 Divergent Change Smells  한 클래스가 어떤 이유로 인해 자주 변경되는 경우 – 소프트웨어는 변경하기 쉬워야 한다. 그리고 하나의 기능을 변경하기 위해 서 한 곳만 수정하도록 만들어야 한다. 그런데, 하나의 기능을 위해 한 클 래스 내부의 여러 곳을 수정해야 한다면?  특정 원인에 대해 변경해야 하는 부분들을 찾아내 묶자 – Extract Method 56
  • 57. 임시 필드 Temporary Fields Smells  특정 상황에 따라 값이 변하게 되는 임시변수는 곧 잘 코드를 이 해하기 어렵게 만든다. – Replace Temp with Query – Replace Parameter with Method  임시 변수 대입이 빈번하다면? – Extract Class 57
  • 58. 중복 코드 Duplicate code Smells  수 많은 버그와 문제의 근원 = 중복 코드!! – 중복 코드는 하나로 합치자!  동일한 표현이 여러 부분에 존재 – 같은 클래스 내부?  Extract Method – 하위 클래스들 사이에서?  Extract Method and Pull Up Field – 여러 클래스에 걸쳐서 나타나면? Extract Class 58
  • 59. 스위치 구문 Switch statements Smells  잘 작성된 객체지향 프로그램의 확실한 특징 하나! – 스위치(switch) 구문이 상대적으로 적다!  스위치 구문은 곧 잘 코드 중복을 유발하고 프로그램 내부 여러 곳에 비슷한 형태로 흩어져 존재하게 된다. – Extract Method and Move Method – Replace Type Code with Subclasses 혹은 Replace Type Code with State/Strategy – Replace Conditional with Polymorphism – Replace Parameter with Explicit Methods – Introduce Null Object 59
  • 60. 산탄총 수술 Shotgun surgery Smells  하나의 기능 변경 위해 여러 클래스를 고쳐야 하는 경우 – 찾아내기 어렵고 수정할 부분들을 곧잘 놓치게 된다.  이상적으로는 추가/변경이 원투원(one-to-one) 링크형태로 이 뤄져야 한다. – Move Method and Move Field – Inline Class 60
  • 61. 추측성 일반화 Speculative Generality Smells  “으흠! 이러이러한 기능이 나중에 필요할 걸! 미리 만들어 놓아야 지!” – 하지만, 결과는 곧 잘 이해하기 어렵고 유지보수 하기 어렵게 만든다.  섣불리 미래를 예측하지 마라! 현재의 복잡도에 집중! – 별 볼일없는 추상클래스?  Collapse Hierarchy – 불필요한 기능 위임이 발생한다면?  Inline Class – 지금 안 쓰는 파라미터라면?  Remove Parameter 61
  • 62. 기본형에 대한 강박 Primitive Obsession Smells  객체 지향 프로그래밍에서는 기본형과 클래스를 애써 구별 지을 필요 없다.  객체지향적인 사고로 전환하자! – 이름, 화폐, 통화단위, 전화번호, 우편번호, 주소, 나이 등등 모든 것이 객 체가 될 수 있다. – Replace Data Value with Object – Replace Array with Object 62
  • 63. 3. 리팩터링 카탈로그 1. Extract Method 13. Replace Type Code with Subclasses 2. Rename Method 14. Replace Type Code with State/Strategy 3. Introduce Assertion 15. Replace Conditional with 4. Move Method Polymorphism 5. Decompose Conditional 16. Introduce Null Object 6. Move Field 17. Preserve Whole Object 7. Extract Class 18. Collapse Hierarchy 8. Inline Class 19. Remove Parameter 9. Replace Temp with Query 20. Introduce Parameter Object 10. Pull Up Field ↔ Pull Down Field 21. Replace Data Value with Object 11. Replace Parameter with Method 22. Replace Array with Object 12. Replace Type Code with Class 63 리팩터링
  • 64. 리팩터링 카탈로그 #1 리팩터링 카탈로그 – Extract Method http://www.refactoring.com/catalog/ – Decompose Conditional – Rename Method – Introduce Assertion – Move Method – Move Field – Extract Class – Inline Class – Replace Temp with Query – Pull Up Field – Replace Parameter with Method 64
  • 65. 리팩터링 카탈로그 #2 리팩터링 카탈로그 – Replace Type Code with Class – Replace Type Code with Subclasses – Replace Type Code with State/Strategy – Replace Conditional with Polymorphism – Introduce Null Object – Preserve Whole Object – Collapse Hierarchy – Remove Parameter – Introduce Parameter Object – Replace Data Value with Object – Replace Array with Object 65
  • 66. Extract Method 리팩터링 카탈로그 코드 조각이 여기저기 흩어져 있을 때 - 메소드가 길거나, 주석이 필요할 때 사용하며, 재사용, 가독성을 높여준다. - 이름을 잘 지어야 하며, 메소드 추출의 핵심은 “의미상의 거리(Semantic distance)”이다. 66
  • 67. Rename Method 리팩터링 카탈로그 이름만으로 메소드 의도 파악이 잘 안될 때 Customer Customer getinvcdtlmt() getInvoiceableCreditLimit() - 메소드는 작성 의도를 잘 전달해 주는 이름을 가져야 한다. - 글로 작성하는 코드는 사람을 이해시키는 것이 목적이지, 컴퓨터를 이해시키는 것이 아니다. - 진정으로 뛰어난 프로그래머가 되고 싶은가? 무엇보다 이름을 잘 짓기 위해 노력하고 연습해라! 67
  • 68. Introduce Assertion 리팩터링 카탈로그 코드의 일부가 프로그램의 특정 상태를 가정하고 있을 때 double getExpenseLimit() { // should have either expense limit or a primary project return (_expenseLimit != NULL_EXPENSE) ? _expenseLimit: _primaryProject.getMemberExpenseLimit(); } double getExpenseLimit() { Assert.isTrue (_expenseLimit != NULL_EXPENSE || _primaryProject != null); return (_expenseLimit != NULL_EXPENSE) ? _expenseLimit: _primaryProject.getMemberExpenseLimit(); } - 명시적으로 체크하는 구문을 작성하거나 값을 확인 한다. 68
  • 69. Move Method 리팩터링 카탈로그 메소드가 자신이 정의된 클래스보다 다른 클래스의 기능을 더 많이 사용할 때 - 클래스가 너무 많은 동작을 가지고 있거나, 다른 클래스와 공동으로 일하는 부분이 너무 많아서 단단히 결합되어 있 을 때 메소드 위치를 옮긴다. - 만약 메소드를 옮겨야 할지에 대한 확신이 없다면 다른 메소드들을 함께 살펴보자. 69
  • 70. Decompose Conditional 리팩터링 카탈로그 if-then-else같은 조건문이 복잡하게 존재할 때 if ( date.before (SUMMER_START) || date.after(SUMMER_END) ) charge = quantity * _winterRate + _winterServiceCharge; else charge = quantity * _summerRate; if ( notSummer(date) ) charge = winterCharge(quantity); else charge = summerCharge (quantity); 70
  • 71. Move Field 리팩터링 카탈로그 필드가 자신이 정의된 클래스보다 다른 클래스에 의해 더 많이 사용 될 때 71
  • 72. Extract Class 리팩터링 카탈로그 두 개의 클래스가 해야 할 일을 하나의 클래스가 하고 있는 경우 - 일반적으로 클래스는 시간이 지날수록 커지게 되며, 크기가 커질 수록 이해하기 어려워진다. - 이럴 경우, 쪼갤 수 있다면, 쪼개라! 72
  • 73. Inline Class 리팩터링 카탈로그 클래스가 하는 일이 별로 없을 때 - 흔히 리팩터링 할 때 메소드를 옮기고 난 다음 살펴보니, 이젠 해당 클래스가 하는 일이 별로 없다는 걸 알게 된다. 73
  • 74. Replace Temp with Query 리팩터링 카탈로그 어떤 수식의 결과값을 저장하기 위해서 임시변수를 사용하고 있을 경우 double basePrice = _quantity * _itemPrice; if (basePrice > 1000) return basePrice * 0.95; else return basePrice * 0.98; if (basePrice() > 1000) return basePrice() * 0.95; else return basePrice() * 0.98; ... double basePrice() { return _quantity * _itemPrice; } - 임시 변수는 임시로 사용되고, 특정 부분에서만 의미를 가지므로 문제가 된다. - 임시변수가 사용되는 메소드는 보통 길이가 길어진다. 74
  • 75. Pull Up Field ↔ Pull Down Field 리팩터링 카탈로그 두 개의 하위 클래스가 같은 필드를 갖고 있을 경우 - 중복을 제거한다. 75
  • 76. Replace Parameter with Method 리팩터링 카탈로그 메소드로 받은 결과를 다른 메소드의 파라미터로 넘겨 주는 경우 int basePrice = _quantity * _itemPrice; discountLevel = getDiscountLevel(); double finalPrice = discountedPrice (basePrice, discountLevel); int basePrice = _quantity * _itemPrice; double finalPrice = discountedPrice (basePrice); - 파라미터로 넘겨주는 메소드에서도 호출 할 수 있는 메소드라면 호출 결과를 받아서 넘겨 줄 필요가 없다. 76
  • 77. Replace Type Code with Class 리팩터링 카탈로그 어떤 클래스가 동작에 영향을 미치지 않는 숫자 형식 타입코드를 가졌을 경우 - 타입 코드가 클래스의 동작에 영향을 주는지 여부를 고려해야 한다. - 타입 코드를 나타내는 변수가 단순 별칭이 아니라 컴파일러가 타입을 체크해 줄 수 있도록 만든다. 77
  • 78. Replace Type Code with Subclasses 리팩터링 카탈로그 클래스의 행위에 영향을 주는 변경 불가능한(immutable) 타입코드를 가질 경우 - 만약 타입 코드가 클래스의 행위에 영향을 줄 경우, 최선의 방법은 다형성을 이용하는 것이다. - 다양한 행위에 대한 지식을 클라이언트 코드에서 특정 클래스로 위임하게 된다는 것이 장점이다. 78
  • 79. Replace Type Code with State/Strategy 리팩터링 카탈로그 행동에 영향을 주는 타입 코드가 있지만 해당 타입 코드를 서브클래스로 만들 수 없는 경우 - 객체가 살아있는 동안 타입 코드에 따라 행위가 바뀌도록 만들 수 있다. - 컴파일러에 의한 타입 체크 지원을 받을 수 있다. 79
  • 80. Replace Conditional with 리팩터링 카탈로그 Polymorphism #1 객체의 타입에 따라 다른 동작을 선택하는 조건문을 가지고 있는 경우 double getSpeed() { switch (_type) { case EUROPEAN: return getBaseSpeed(); case AFRICAN: return getBaseSpeed() - getLoadFactor() * _numberOfCoconuts; case NORWEIGIAN_BLUE: return (_isNailed) ? 0 : getBaseSpeed(_voltage); } throw new RuntimeException ("Should be unreachable"); } - 조건문의 각 부분을 서브클래스에 있는 오버라이딩 메소드로 옮기고 원래 메소드를 abstract로 만든다. 80
  • 81. Replace Conditional with 리팩터링 카탈로그 Polymorphism #2 객체의 타입에 따라 다른 동작을 선택하는 조건문을 가지고 있는 경우 81
  • 82. Introduce Null Object 리팩터링 카탈로그 반복적인 널(null) 검사가 이루어지고 있을 경우 if (customer == null) plan = BillingPlan.basic(); else plan = customer.getPlan(); - null 값을 null 객체로 대체한다. - 다형성의 진가는, 객체에 타입을 묻고 그 답을 기초로 하여 어떤 동작을 호출하는 대신에 단지 그 동작을 호출하는 것이다. 그러면 그 객체는 타입에 따라서 적절히 동작한다. 82
  • 83. Preserve Whole Object 리팩터링 카탈로그 어떤 객체에서 여러 개의 값을 얻은 다음 메소드 호출 시 파라미터로 넘길 경우 int low = daysTempRange().getLow(); int high = daysTempRange().getHigh(); withinPlan = plan.withinRange(low, high); withinPlan = plan.withinRange(daysTempRange()); - 메소드로 넘겨야 하는 값이 변경되는 경우, 해당 메소드들을 다 고쳐야 하는 상황이 발생한다. 관련 데이터를 객체로 만들어 넘겨주면 이런 상황에도 메소드의 외형을 유지시켜 준다. 83
  • 84. Collapse Hierarchy 리팩터링 카탈로그 상위 클래스와 하위 클래스가 크게 다르지 않을 경우 - 리팩터링을 진행하는 과정 도중에 종종 나타난다. 84
  • 85. Remove Parameter 리팩터링 카탈로그 파라미터가 더 이상 메소드 안에서 쓰이지 않을 경우 - 쓰지 않는 파라미터를 남겨 놓으면 다른 사용자는 고민한다. - 단, 다형성에 사용되는 메소드일 경우, 파라미터 제거에 좀 더 신중해야 한다. 85
  • 86. Introduce Parameter Object 리팩터링 카탈로그 함께 뭉쳐 다니는 파라미터들의 그룹이 있을 경우 - 클래스로 도출해 내면 복잡도가 감소된다. - 또한, 관련된 동작도 해당 클래스 내부로 옮기는 것이 가능해지므로 중복코드도 줄어들게 된다. 86
  • 87. Replace Data Value with Object 리팩터링 카탈로그 추가적인 데이터나 행위가 필요한 데이터 항목을 가질 경우 - 예를 들면, 전화번호를 처음 한동안은 문자열(String)으로 표현 할 수 있지만, 나중에는 포맷팅을 해야 한다든가, 지 역 코드를 추출해야 하는 등의 특별한 동작이 필요해지는 경우가 발생한다. 87
  • 88. Replace Array with Object 리팩터링 카탈로그 배열의 특정 요소가 다른 뜻을 가지고 있을 경우 String[] row = new String[3]; row [0] = "Liverpool"; row [1] = "15"; Performance row = new Performance(); row.setName("Liverpool"); row.setWins("15"); 88