Dependency Breaking Techniques
            Working Effectively with LegacyCode
                                             Ver 1.0




               아키텍트를 꿈꾸는 사람들 cafe.naver.com/architect1
                            현수명 soomong.net
                                                #soomong
before           after




24   dependency breaking techniques
1. Adapt Parameter



                                        Interface A’

   Method (   A   ){
     ...
   }



                         Concrete A’                   Concrete A’
                       for production                    for test
When to use?
 - parameter is difficult to test.
 - can’t use Extract Interface on a parameter’s class.
2. Break Out Method Object


  Class


     longMethod A() {
       …
       …
       …                New Class A
     }

                          longMethod () {
                            …
                            …
                            …
                          }
When to use?
- method is too large

- use instance data and methods
3. Definition Completion


                       Definition for
       Definition          Test




     Concrete Class    Concrete Class
When to use?
 - language supplies that can declare a type in on place and
define it another.

- to break dependencies in procedural language like C.
4. Encapsulate Global References



    Class               New Class A


     Global reference      Global reference
When to use?
- to separate dependencies on global references.
5. Expose Static Method


                          Class


    Class
                             Static Method () {
                               …
        Method () {          }
          …
        }
When to use?
- trying to test code that can’t be instantiated.
6. Extract and Override Call

Class               Class               Class for test


   Method ( ) {        Method ( ) {
    …                   …

            logic           call A();
        …                   …
   }                   }
                                         @Override

                       Method A ( ) {      Method A( ) {
                         logic               test logic
                       }                   }
When to use?
- trying to test only single method call.
7. Extract and Override Factory Method


Class                Class                   Class for test


constructor( ) {      constructor( ) {
  …                     …
  object = new A()      object = call A();
  …                     …
}                     }

                                             @Override

                      Factory method A(){    Factory method A(){
                        return new A()         …
                      }                      }
When to use?
- trying to test code that creates objects in constructor.
8. Extract and Override Getter

Class                Class                     Class for test


constructor( ) {      constructor( ) {
  …                     …
  object = New A()      object = null;
  …                     …
}                     }

                                                @Override
object
                      Getter Method getA(){     Getter Method getA(){
                        if A is null              …
           object           return new A();     }
                        return A;
                      }


                      getA()
                                   getA()




                                              Lazy initialize
When to use?
  - trying to test code that creates objects in constructor
  - language doesn’t support virtual function call in a derived class
from base class’s constructor
9. Extract Implementer


                Duplicated Class

                 Method A() {      Interface
Class              …
                 }                  virtual Method A()
 Method A() {
   …             Method B() {       virtual Method B()
 }                 …
                 }
 Method B() {
   …
 }
When to use?
- hard to naming the interface
10. Extract Interface


                Interface

                 virtual Method A()   Concrete Class
Class
                                       Method A() {
                 virtual Method B()
 Method A() {                            …
   …                                   }
 }

                                       Method A() {
 Method B() {                            …
   …                                   }
 }
When to use?
- trying to test code that break dependency
11. Introduce Instance Delegator

Class                    Class                     Class for test

Static Method A( ) {      Static Method A( ) {
  …                         …
}                         }

                                                    @Override
                           Method A’(){              Method A’(){
 Class.A()
                             A();                      …
                           }                         }
             Class.A()


                         instance.A’()


                                   instance.A’()
When to use?
- static method has logic that hard to test

- it’s weird

- 더 큰 리팩토링의 시작
12. Introduce Static Setter

Class                           Class                           Class for test

Static instance                 Static instance

private constructor( ) {        protected constructor( ) {
}                               }




Static Method getInst(){        Static Method getInst(){
  if instance is null             if instance is null
      instance = new Class();         instance = new Class();
  return instance;                return instance;
}                               }

                                                                @Override

                                Method setInstance(…) {         Method setInstance(…) {
                                  instance = …                    test logic
                                                                }
                                }
When to use?
 - Singleton test

 - Protected constructor = can subclassing = 구리다

 - singleton을 코드로 강제하는 것보다는 팀원들이
모두 이해하는게 더 중요하다?
13. Link Substitution


                        Global reference for test
                          Call history
                          Value history



    Method A() {
      …
    }
                        Method A() {
                          record call history
                          record value history
                          …
                        }
When to use?
- to break dependencies in procedural language like C.
14. Parameterize Constructor

Class                 Class                Class for test


constructor( ) {      constructor( ) {
  …                     this( new A() );
  object = new A();   }
  …
}




                      constructor( A ) {   constructor( A ) {
                        …                    …
                        object = A;          object = test;
                        …                    …
                      }                    }
When to use?
- to separate the object that created in constructor.

has dependencies on parameter’s class.
but it’s a small concern.
15. Parameterize Method


    Class                 Class


    Method( ) {           Method( A ) {
      …                     …
      object = new A();     object = A;
      …                     …
    }                     }
When to use?
 -to separate the object that created in method.

dependency issue?
Extract and Override Factory Method is alternative way.
16. Primitivize Parameter

Class          Class                     TestClass


Method ( ) {   Method ( ) {              TEST( ) {
 …               …                         …
    logic        call free function();     call free function();
    …            …                       }
}              }




                free function( ) {
                    logic

                }
When to use?
- work to get a class under test is too large.

- what the…
17. Pull Up Feature
                                  New Abstract Class

                                        Method A( ) {
                                          …
                                        }

                                        abstract Method B
                                        abstract Method C




  Class
     Method A( ) {
       …             Class                              Class for test
     }
                        Method B( ) {                       TEST( ) {
     Method B( ) {        …                                   CHECK(A());
       …                }                                   }
     }
                       Method C( ) {
     Method C( ) {       …
       …               }
     }
When to use?
- to test just one method that clustered with other methods.
18. Push Down Dependency

                     Abstract Class
Class
                       Method A( ) {
 Method A( ) {           …
   …                   }
 }

                       Method B( ) {
 Method B( ) {           …
   …                   }
 }
                      abstract drawUI()

Method drawUI( ) {
  …
}
                     New Concrete Class    Concrete Class for test




                      Method drawUI( ) {    Method drawUI( ) {
                        …                     // do nothing
                      }                     }
When to use?
 - dependencies are pervasive like drawing UI.
19. Replace Function with Function Pointer



   Method main( ) {   Method main( ) {
     …                  …
     A();               *pointer
     …                  …
   }                  }
                                         *Method testA( ) {
                                           test logic
                                         }
   Method A( ) {
     …
   }                  *Method A( ) {
                        …
                      }
When to use?
- to break dependencies in procedural language like C.

Different points of view
- horribly unsafe VS useful tool
20. Replace Global Reference with Getter



Class                  Class                    Class for test

 Global references A     Global references A



A                       getA

                A                     getA
                                                @Override
                       Getter Method getA() {   Getter Method getA() {
                         return A;                …
                       }                        }
When to use?
- separate dependencies on global references
21. Subclass and Override Method

  Class                 Class



  private Method A(){   protected Method A(){
    …                     …
  }                     }




                                            subClass for test


                                                @Override

                                                protected Method A(){
                                                  …
                                                }
When to use?
 - break dependencies in object-oriented language.

Many of the other dependency-breaking techniques
are variations on it.
22. Supersede Instance Variable

 Class              Class                    Class for test

 variable           variable

 constructor( ) {   constructor( ) {
   variable;          variable;
 }                  }


                                             @Override
                    supersedeVariable(A) {   supersedeVariable(A) {
                      variable = A;            …
                    }                        }
When to use?
 - separate objects that created in constructor.
 - language disallows overrides of virtual function calls
in constructors.


Use uncommon prefix : supersede

개발자들이 잘못 사용할지도 모르니
잘 모르는 uncommon 한 단어를 prefix 로 사용하자??
23. Template Redefinition


                                        generics
   Method (   A   ){
     ...
   }



                       Concrete type           Concrete type
                       for production             for test
When to use?
 - language supplies generics and a way of aliasing types.
24. Text Redefinition

                        TestClass


      Class                Class

                           def Method A()
      def Method A()       end
        …
        logic
        …
      end




                        TEST( ) {
                          …
                          test Class
                        }
When to use?
- break dependencies in interpreted language like Ruby.
전체 정리하면서 느낀 점

- 억지스러운 면이 자주 보인다.

- dependency 는 깨질지 몰라도 Readability는 더 낮아진다.

- 코드가 잘못 사용될 수 있으니 개발자가 더 주의 깊게 살펴봐야 한다.

- 아무래도 LegacyCode 와의 싸움이 힘겹긴 한가보다. 이해하자.

- 억지스럽고 지저분한 방법일지라도 대안이 없다면
  그게 바로 최선의 방법이다.

- 원문이 훨씬 보기 쉽다. (번역 X)
Reference



            레거시코드 활용 전략
            http://www.yes24.com/24/goods/3092523
감사합니다

Dependency Breaking Techniques

  • 1.
    Dependency Breaking Techniques Working Effectively with LegacyCode Ver 1.0 아키텍트를 꿈꾸는 사람들 cafe.naver.com/architect1 현수명 soomong.net #soomong
  • 2.
    before after 24 dependency breaking techniques
  • 3.
    1. Adapt Parameter Interface A’ Method ( A ){ ... } Concrete A’ Concrete A’ for production for test
  • 4.
    When to use? - parameter is difficult to test. - can’t use Extract Interface on a parameter’s class.
  • 5.
    2. Break OutMethod Object Class longMethod A() { … … … New Class A } longMethod () { … … … }
  • 6.
    When to use? -method is too large - use instance data and methods
  • 7.
    3. Definition Completion Definition for Definition Test Concrete Class Concrete Class
  • 8.
    When to use? - language supplies that can declare a type in on place and define it another. - to break dependencies in procedural language like C.
  • 9.
    4. Encapsulate GlobalReferences Class New Class A Global reference Global reference
  • 10.
    When to use? -to separate dependencies on global references.
  • 11.
    5. Expose StaticMethod Class Class Static Method () { … Method () { } … }
  • 12.
    When to use? -trying to test code that can’t be instantiated.
  • 13.
    6. Extract andOverride Call Class Class Class for test Method ( ) { Method ( ) { … … logic call A(); … … } } @Override Method A ( ) { Method A( ) { logic test logic } }
  • 14.
    When to use? -trying to test only single method call.
  • 15.
    7. Extract andOverride Factory Method Class Class Class for test constructor( ) { constructor( ) { … … object = new A() object = call A(); … … } } @Override Factory method A(){ Factory method A(){ return new A() … } }
  • 16.
    When to use? -trying to test code that creates objects in constructor.
  • 17.
    8. Extract andOverride Getter Class Class Class for test constructor( ) { constructor( ) { … … object = New A() object = null; … … } } @Override object Getter Method getA(){ Getter Method getA(){ if A is null … object return new A(); } return A; } getA() getA() Lazy initialize
  • 18.
    When to use? - trying to test code that creates objects in constructor - language doesn’t support virtual function call in a derived class from base class’s constructor
  • 19.
    9. Extract Implementer Duplicated Class Method A() { Interface Class … } virtual Method A() Method A() { … Method B() { virtual Method B() } … } Method B() { … }
  • 20.
    When to use? -hard to naming the interface
  • 21.
    10. Extract Interface Interface virtual Method A() Concrete Class Class Method A() { virtual Method B() Method A() { … … } } Method A() { Method B() { … … } }
  • 22.
    When to use? -trying to test code that break dependency
  • 23.
    11. Introduce InstanceDelegator Class Class Class for test Static Method A( ) { Static Method A( ) { … … } } @Override Method A’(){ Method A’(){ Class.A() A(); … } } Class.A() instance.A’() instance.A’()
  • 24.
    When to use? -static method has logic that hard to test - it’s weird - 더 큰 리팩토링의 시작
  • 25.
    12. Introduce StaticSetter Class Class Class for test Static instance Static instance private constructor( ) { protected constructor( ) { } } Static Method getInst(){ Static Method getInst(){ if instance is null if instance is null instance = new Class(); instance = new Class(); return instance; return instance; } } @Override Method setInstance(…) { Method setInstance(…) { instance = … test logic } }
  • 26.
    When to use? - Singleton test - Protected constructor = can subclassing = 구리다 - singleton을 코드로 강제하는 것보다는 팀원들이 모두 이해하는게 더 중요하다?
  • 27.
    13. Link Substitution Global reference for test Call history Value history Method A() { … } Method A() { record call history record value history … }
  • 28.
    When to use? -to break dependencies in procedural language like C.
  • 29.
    14. Parameterize Constructor Class Class Class for test constructor( ) { constructor( ) { … this( new A() ); object = new A(); } … } constructor( A ) { constructor( A ) { … … object = A; object = test; … … } }
  • 30.
    When to use? -to separate the object that created in constructor. has dependencies on parameter’s class. but it’s a small concern.
  • 31.
    15. Parameterize Method Class Class Method( ) { Method( A ) { … … object = new A(); object = A; … … } }
  • 32.
    When to use? -to separate the object that created in method. dependency issue? Extract and Override Factory Method is alternative way.
  • 33.
    16. Primitivize Parameter Class Class TestClass Method ( ) { Method ( ) { TEST( ) { … … … logic call free function(); call free function(); … … } } } free function( ) { logic }
  • 34.
    When to use? -work to get a class under test is too large. - what the…
  • 35.
    17. Pull UpFeature New Abstract Class Method A( ) { … } abstract Method B abstract Method C Class Method A( ) { … Class Class for test } Method B( ) { TEST( ) { Method B( ) { … CHECK(A()); … } } } Method C( ) { Method C( ) { … … } }
  • 36.
    When to use? -to test just one method that clustered with other methods.
  • 37.
    18. Push DownDependency Abstract Class Class Method A( ) { Method A( ) { … … } } Method B( ) { Method B( ) { … … } } abstract drawUI() Method drawUI( ) { … } New Concrete Class Concrete Class for test Method drawUI( ) { Method drawUI( ) { … // do nothing } }
  • 38.
    When to use? - dependencies are pervasive like drawing UI.
  • 39.
    19. Replace Functionwith Function Pointer Method main( ) { Method main( ) { … … A(); *pointer … … } } *Method testA( ) { test logic } Method A( ) { … } *Method A( ) { … }
  • 40.
    When to use? -to break dependencies in procedural language like C. Different points of view - horribly unsafe VS useful tool
  • 41.
    20. Replace GlobalReference with Getter Class Class Class for test Global references A Global references A A getA A getA @Override Getter Method getA() { Getter Method getA() { return A; … } }
  • 42.
    When to use? -separate dependencies on global references
  • 43.
    21. Subclass andOverride Method Class Class private Method A(){ protected Method A(){ … … } } subClass for test @Override protected Method A(){ … }
  • 44.
    When to use? - break dependencies in object-oriented language. Many of the other dependency-breaking techniques are variations on it.
  • 45.
    22. Supersede InstanceVariable Class Class Class for test variable variable constructor( ) { constructor( ) { variable; variable; } } @Override supersedeVariable(A) { supersedeVariable(A) { variable = A; … } }
  • 46.
    When to use? - separate objects that created in constructor. - language disallows overrides of virtual function calls in constructors. Use uncommon prefix : supersede 개발자들이 잘못 사용할지도 모르니 잘 모르는 uncommon 한 단어를 prefix 로 사용하자??
  • 47.
    23. Template Redefinition generics Method ( A ){ ... } Concrete type Concrete type for production for test
  • 48.
    When to use? - language supplies generics and a way of aliasing types.
  • 49.
    24. Text Redefinition TestClass Class Class def Method A() def Method A() end … logic … end TEST( ) { … test Class }
  • 50.
    When to use? -break dependencies in interpreted language like Ruby.
  • 51.
    전체 정리하면서 느낀점 - 억지스러운 면이 자주 보인다. - dependency 는 깨질지 몰라도 Readability는 더 낮아진다. - 코드가 잘못 사용될 수 있으니 개발자가 더 주의 깊게 살펴봐야 한다. - 아무래도 LegacyCode 와의 싸움이 힘겹긴 한가보다. 이해하자. - 억지스럽고 지저분한 방법일지라도 대안이 없다면 그게 바로 최선의 방법이다. - 원문이 훨씬 보기 쉽다. (번역 X)
  • 52.
    Reference 레거시코드 활용 전략 http://www.yes24.com/24/goods/3092523
  • 53.