28
SOLID PHP & Code Smell WrapUp LSP: Liskov subs=tu=on principle ISP: Interface segrega=on principle DIP: Dependency inversion principle 1

SOLID PHP & Code Smell Wrap-Up - WordPress.com · SOLID PHP & Code Smell Wrap-Up Author: Vic Metcalfe Created Date: 3/8/2012 2:42:28 AM

  • Upload
    others

  • View
    2

  • Download
    0

Embed Size (px)

Citation preview

Page 1: SOLID PHP & Code Smell Wrap-Up - WordPress.com · SOLID PHP & Code Smell Wrap-Up Author: Vic Metcalfe Created Date: 3/8/2012 2:42:28 AM

SOLID  PHP  &  Code  Smell    Wrap-­‐Up  

LSP:  Liskov  subs=tu=on  principle  ISP:  Interface  segrega=on  principle  DIP:  Dependency  inversion  principle  

1  

Page 2: SOLID PHP & Code Smell Wrap-Up - WordPress.com · SOLID PHP & Code Smell Wrap-Up Author: Vic Metcalfe Created Date: 3/8/2012 2:42:28 AM

SOLID  PHP  &  Code  Smell    Wrap-­‐Up  

LSP:  Liskov  subs=tu=on  principle  DIP:  Dependency  inversion  principle  ISP:  Interface  segrega=on  principle  

2  

Page 3: SOLID PHP & Code Smell Wrap-Up - WordPress.com · SOLID PHP & Code Smell Wrap-Up Author: Vic Metcalfe Created Date: 3/8/2012 2:42:28 AM

Review  

•  SOLID  is  an  acronym  for  a  set  of  design  principles  by  Robert  “Uncle  Bob”  Mar=n  

•  SRP:  Single  Responsibility  principle  –  Objects  should  only  have  one  responsibility  

•  OCP:  Open/closed  principle  –  Objects  open  for  extension  but  closed  for  modifica=on  

3  

Page 4: SOLID PHP & Code Smell Wrap-Up - WordPress.com · SOLID PHP & Code Smell Wrap-Up Author: Vic Metcalfe Created Date: 3/8/2012 2:42:28 AM

LSP:  Liskov  subs=tu=on  principle  

•  Objects  should  always  be  able  to  stand-­‐in  for  their  ancestors  

•  Named  aTer  Barbara  Liskov  who  first  introduced  the  principal  

4  

Page 5: SOLID PHP & Code Smell Wrap-Up - WordPress.com · SOLID PHP & Code Smell Wrap-Up Author: Vic Metcalfe Created Date: 3/8/2012 2:42:28 AM

DIP:  Dependency  inversion  principle  

•  Define  interfaces  from  the  boVom-­‐up,  not  top-­‐down  

•  Depend  on  interfaces,  not  on  concrete  classes  

5  

Page 6: SOLID PHP & Code Smell Wrap-Up - WordPress.com · SOLID PHP & Code Smell Wrap-Up Author: Vic Metcalfe Created Date: 3/8/2012 2:42:28 AM

ISP:  Interface  segrega=on  principle  

•  “many  client  specific  interfaces  are  beVer  than  one  general  purpose  interface.”  

6  

Page 7: SOLID PHP & Code Smell Wrap-Up - WordPress.com · SOLID PHP & Code Smell Wrap-Up Author: Vic Metcalfe Created Date: 3/8/2012 2:42:28 AM

LSP  Example:  Rectangle  &  Square  

•  The  Rectangle  and  Square  are  the  “standard”  example  of  an  LSP  problem.  

•  A  Square  IS-­‐A  Rectangle  which  happens  to  have  the  same  width  and  height:  

Square   Rectangle  IS-­‐A  

7  

Page 8: SOLID PHP & Code Smell Wrap-Up - WordPress.com · SOLID PHP & Code Smell Wrap-Up Author: Vic Metcalfe Created Date: 3/8/2012 2:42:28 AM

LSP  Example:  Rectangle  &  Square  

•  Lets  look  at  an  implementa=on  and  unit  test  

•  Squares  don’t  BEHAVE  like  rectangles,  so  they  violate  LSP  

Square   Rectangle  BEHAVIOUR  

8  

Page 9: SOLID PHP & Code Smell Wrap-Up - WordPress.com · SOLID PHP & Code Smell Wrap-Up Author: Vic Metcalfe Created Date: 3/8/2012 2:42:28 AM

More  Obvious  LSP  Viola=ons  class  FooMapper  {  

 func)on  fetchAll()  {      return  array(      'a588ea995c5c74827a24d466d14a72101'=>'Alpha',        'z4c853bae4a5e427a8d6b9bf33140bb2e'=>'Omega');    }  

}      class  BarMapper  extends  FooMapper  {  

 func)on  fetchAll()  {      $result  =  new  stdClass();      $result-­‐>a588ea995c5c74827a24d466d14a72101  =  'Alpha';      $result-­‐>z4c853bae4a5e427a8d6b9bf33140bb2e  =  'Omega';      return  $result;    }  

}  9  

Page 10: SOLID PHP & Code Smell Wrap-Up - WordPress.com · SOLID PHP & Code Smell Wrap-Up Author: Vic Metcalfe Created Date: 3/8/2012 2:42:28 AM

More  Obvious  LSP  Viola=ons  

class  FooView  {    func)on  display(FooModel  $foo)  {  /*  ...  */  }  

}      class  BarView  extends  FooView  {    func)on  display(BarModel  $bar)  {  /*  ...  */  }  

}  

10  

Page 11: SOLID PHP & Code Smell Wrap-Up - WordPress.com · SOLID PHP & Code Smell Wrap-Up Author: Vic Metcalfe Created Date: 3/8/2012 2:42:28 AM

More  Obvious  LSP  Viola=ons  

•  Removing  func=onality  from  an  ancestor:  

class DecoyDuck extends Duck{ function fly() { throw new Exception( "Decoy ducks can't fly!"); }}

11  

Page 12: SOLID PHP & Code Smell Wrap-Up - WordPress.com · SOLID PHP & Code Smell Wrap-Up Author: Vic Metcalfe Created Date: 3/8/2012 2:42:28 AM

Is  this  an  LSP  Viola=on?  class  Foo  {    func)on  getMapper()  {      return  new  FooMapper();    }  

}      class  Bar  extends  Foo  {    func)on  getMapper()  {      return  new  BarMapper();    }  

}   12  

Page 13: SOLID PHP & Code Smell Wrap-Up - WordPress.com · SOLID PHP & Code Smell Wrap-Up Author: Vic Metcalfe Created Date: 3/8/2012 2:42:28 AM

Preven=ng  LSP  Viola=ons  

•  Design  by  Contract  with  Unit  Tests  

•  Think  in  terms  of  BEHAVES-­‐LIKE  instead  of  IS-­‐A  when  crea=ng  subclasses  

•  Don’t  remove  func=onality  from  ancestors  

13  

Page 14: SOLID PHP & Code Smell Wrap-Up - WordPress.com · SOLID PHP & Code Smell Wrap-Up Author: Vic Metcalfe Created Date: 3/8/2012 2:42:28 AM

Preven=ng  LSP  Viola=ons  

•  Method  parameters  should  be  the  same  or  less  restric=ve  in  what  they  will  accept  (invariant  or  contravariant)  

•  Method  return  values  should  be  the  same  or  more  restric=ve  in  what  is  returned  (invariant  or  covariant)    

14  

Page 15: SOLID PHP & Code Smell Wrap-Up - WordPress.com · SOLID PHP & Code Smell Wrap-Up Author: Vic Metcalfe Created Date: 3/8/2012 2:42:28 AM

Smells  like  an  LSP  Viola=on  

•  Any  =me  you  need  to  know  the  type  of  an  object  (instanceof,  is_a,  etc)  

•  When  the  parameters  or  return  type  of  an  overridden  method  are  different  from  its  ancestor  

•  Throwing  new  excep=ons  

15  

Page 16: SOLID PHP & Code Smell Wrap-Up - WordPress.com · SOLID PHP & Code Smell Wrap-Up Author: Vic Metcalfe Created Date: 3/8/2012 2:42:28 AM

DIP:  What  is  Inversion?  

Conven=onal  MVC  Dependencies:  

Controller  

Model   View  

Storage  

16  

Page 17: SOLID PHP & Code Smell Wrap-Up - WordPress.com · SOLID PHP & Code Smell Wrap-Up Author: Vic Metcalfe Created Date: 3/8/2012 2:42:28 AM

DIP:  What  is  Inversion?  

Inverted  MVC  Dependencies:  

Controller  

Model   View  

Storage  

Model  Service  Interface  

View  Service  Interface  

Storage  Service  Interface  

17  

Page 18: SOLID PHP & Code Smell Wrap-Up - WordPress.com · SOLID PHP & Code Smell Wrap-Up Author: Vic Metcalfe Created Date: 3/8/2012 2:42:28 AM

DIP  Concepts  

•  Concrete  classes  only  have  dependencies  to  interfaces  

•  High  level  components  build  interfaces  for  the  services  they  need  

•  Low  level  components  depend  on  those  high  level  service  interfaces  

18  

Page 19: SOLID PHP & Code Smell Wrap-Up - WordPress.com · SOLID PHP & Code Smell Wrap-Up Author: Vic Metcalfe Created Date: 3/8/2012 2:42:28 AM

Evolving  towards  the  DIP  class  FooControllerConven=onal  {    func)on  indexView()  {      $model  =  new  FooModel();      $viewData  =  $model-­‐>fetchAll();      $view  =  new  FooView();      $view-­‐>render($viewData);    }  

}    

19  

Page 20: SOLID PHP & Code Smell Wrap-Up - WordPress.com · SOLID PHP & Code Smell Wrap-Up Author: Vic Metcalfe Created Date: 3/8/2012 2:42:28 AM

Evolving  towards  the  DIP  class  FooControllerDI  {  

 private  $_model;    private  $_view;        func)on  __construct(FooModel  $model,  FooView  $view)  {      $this-­‐>_model  =  $model;      $this-­‐>_view  =  $view;    }        func)on  indexView()  {      $viewData  =  $this-­‐>_model-­‐>fetchAll();      $this-­‐>_view-­‐>render($viewData);    }  

}  

20  

Page 21: SOLID PHP & Code Smell Wrap-Up - WordPress.com · SOLID PHP & Code Smell Wrap-Up Author: Vic Metcalfe Created Date: 3/8/2012 2:42:28 AM

Evolving  towards  the  DIP  interface  ModelServiceInterface  {    func)on  fetchAll();    //…  Other  required  methods  

}      interface  ViewServiceInterface  {    func)on  render($viewData);    //…  Other  required  methods  

}  

21  

Page 22: SOLID PHP & Code Smell Wrap-Up - WordPress.com · SOLID PHP & Code Smell Wrap-Up Author: Vic Metcalfe Created Date: 3/8/2012 2:42:28 AM

Evolving  towards  the  DIP  class  FooControllerDIP  {  

 private  $_model;    private  $_view;        func)on  __construct(ModelServiceInterface  $model,                ViewServiceInterface  $view)  {      $this-­‐>_model  =  $model;      $this-­‐>_view  =  $view;    }        func)on  indexView()  {      $viewData  =  $this-­‐>_model-­‐>fetchAll();      $this-­‐>_view-­‐>render($viewData);    }  

}  

22  

Page 23: SOLID PHP & Code Smell Wrap-Up - WordPress.com · SOLID PHP & Code Smell Wrap-Up Author: Vic Metcalfe Created Date: 3/8/2012 2:42:28 AM

Smells  like  a  DIP  Viola=on  

•  Any  dependency  by  one  class  on  another  concrete  class:  “Hard  Dependency  Smell”  

23  

Page 24: SOLID PHP & Code Smell Wrap-Up - WordPress.com · SOLID PHP & Code Smell Wrap-Up Author: Vic Metcalfe Created Date: 3/8/2012 2:42:28 AM

Interface  Segrega=on  Principle  

•  Useful  for  “fat”  classes.    These  classes:    – May  violate  SRP  

– May  have  an  “extra”  method  for  a  specific  client  

– May  have  one  responsibility  which  can  be  further  segregated  

24  

Page 25: SOLID PHP & Code Smell Wrap-Up - WordPress.com · SOLID PHP & Code Smell Wrap-Up Author: Vic Metcalfe Created Date: 3/8/2012 2:42:28 AM

ISP  Example:  User  Model  class  UserModel  {  

 /**      *  @param  string  $userId      *  @param  string  $password      *  @return  string  Authen=ca=on  Token;  empty  string  on  failure      */    func)on  doLogin($userId,  $password)  {}    /**      *  @param  string  $token      *  @return  bool      */    func)on  authen=cate($token)  {}  

}  

Most  clients  just  want  to  authen=cate.      

Only  the  login  controller  uses  doLogin().  

25  

Page 26: SOLID PHP & Code Smell Wrap-Up - WordPress.com · SOLID PHP & Code Smell Wrap-Up Author: Vic Metcalfe Created Date: 3/8/2012 2:42:28 AM

ISP  Example:  User  Model  

interface  UserLoginClient  {    func)on  doLogin($userId,  $password);  

}      interface  UserAuthen=ca=onClient  {    func)on  authen=cate($token);  

}  

26  

Page 27: SOLID PHP & Code Smell Wrap-Up - WordPress.com · SOLID PHP & Code Smell Wrap-Up Author: Vic Metcalfe Created Date: 3/8/2012 2:42:28 AM

Smells  Like  an  ISP  Viola=on  

•  Fat  Classes,  “God  Objects”  

•  Methods  only  used  by  a  few  clients  but  pollute  the  interface  used  by  all  clients  

27  

Page 28: SOLID PHP & Code Smell Wrap-Up - WordPress.com · SOLID PHP & Code Smell Wrap-Up Author: Vic Metcalfe Created Date: 3/8/2012 2:42:28 AM

Thanks  Folks!  

•  Thanks  for  joining  me  for  the  SOLID  wrap  up!  

•  If  we  have  =me,  I  have  some  code  we  can  refactor  to  play  with  LSP,  DIP  and  ISP  

•  Slides  and  code  will  be  posted  shortly  

•  Next  week:  CakePHP  and  Facebook  Apps!  

28