SlideShare a Scribd company logo
Refactoring	
  an	
  unmaintainable	
  mess	
  of	
  nested	
  
condi3onals	
  to	
  the	
  Open/Closed	
  principle	
  	
  
	
  
-­‐	
  using	
  OO	
  inheritance	
  -­‐	
  
	
  
-­‐	
  an	
  example	
  -­‐	
  
Inheritance	
  is	
  not	
  always	
  evil!	
  
©	
  2014	
  Philip	
  Schwarz	
  
hHps://twiHer.com/philip_schwarz	
  
philip.johann.schwarz@gmail.com	
  
	
  
	
  
	
  
This	
  work	
  is	
  licensed	
  under	
  a	
  
Crea3ve	
  Commons	
  AHribu3on-­‐NonCommercial-­‐NoDerivs	
  3.0	
  Unported	
  License.	
  
This	
  talk	
  complements	
  and	
  extends	
  some	
  aspects	
  of	
  my	
  OCP	
  talk:	
  
Downloadable	
  at	
  hHps://github.com/philipschwarz/presenta3ons	
  
Shortly	
  aVer	
  giving	
  the	
  OCP	
  talk	
  I	
  watched	
  the	
  following:	
  
Sandi’s	
  talk	
  complements	
  and	
  extends	
  parts	
  of	
  mine	
  so	
  well	
  	
  
	
  
hHp://www.poodr.com/	
  
that	
  I	
  just	
  HAVE	
  TO	
  show	
  you	
  the	
  video!	
  
So	
  this	
  is	
  not	
  your	
  regular	
  talk.	
  	
  
I’ll	
  wrap	
  my	
  slides	
  around	
  her	
  talk	
  
‱  slides	
  at	
  the	
  beginning:	
  
‱  to	
  give	
  you	
  addi3onal	
  background	
  that	
  
helps	
  you	
  follow	
  the	
  video	
  
‱  to	
  link	
  back	
  to	
  the	
  topics	
  of	
  my	
  other	
  
presenta3on	
  
‱  slides	
  at	
  the	
  end:	
  to	
  recap	
  and	
  elaborate	
  
some	
  of	
  Sandi’s	
  key	
  points	
  
What	
  I’ll	
  actually	
  be	
  doing	
  is	
  
showing	
  you	
  the	
  video	
  of	
  Sandi’s	
  
talk	
  (A	
  talk	
  within	
  a	
  talk!).	
  
OO Inheritance - Not Always Evil - Refactoring to Open-Closed with Inheritance
The	
  Open-­‐Closed	
  Principle	
  
Modules	
  should	
  be	
  both	
  open	
  and	
  closed	
  
Bertrand	
  Meyer	
  Object	
  Oriented	
  
SoVware	
  Construc3on	
  
1988	
  
We	
  want	
  modules	
  to	
  be	
  both	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  for	
  extension	
  and	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  for	
  modiïŹca3on	
  
the	
  two	
  goals	
  of	
  	
  
openness	
  and	
  closedness	
  
	
  
with	
  tradiEonal	
  
techniques	
  
are	
  incompaEble	
  
With	
  non-­‐OO	
  methods,	
  	
  
there	
  seem	
  to	
  be	
  only	
  2	
  soluEons,	
  	
  
equally	
  unsaEsfactory	
  
If	
  non-­‐OO	
  methods	
  are	
  all	
  we	
  have,	
  then	
  
Meyer	
  says	
  we	
  face	
  a	
  change	
  or	
  copy	
  
dilemma	
  
CHANGE	
   COPY	
  
A	
  B	
   C	
  
D	
  
E	
  
A	
  module	
  and	
  its	
  clients	
  
A’	
  F	
  
G	
   H	
   I	
  
New	
  clients	
  which	
  need	
  A’,	
  an	
  adapted	
  or	
  extended	
  version	
  of	
  A	
  
Typical	
  situa3on	
  where	
  the	
  needs	
  for	
  Open	
  and	
  Closed	
  
modules	
  are	
  hard	
  to	
  reconcile	
  
=	
  	
  client	
  of	
  
Analysability	
   Stability	
   Reliability	
  
soluEon	
  
-­‐ -­‐ -­‐
Analysability	
   Stability	
   Reliability	
  
soluEon	
  
-­‐	
   -­‐	
   -­‐	
  
With	
  non-­‐OO	
  methods,	
  there	
  are	
  only	
  only	
  2	
  soluEons	
  available	
  to	
  us,	
  	
  
BOTH	
  UNSATISFACTORY	
  
mulEple	
  maintenance	
  problem	
  
Change	
  by	
  	
  
ModiïŹca3on	
  
CHANGE	
  
COPY	
  
A	
  B	
   C	
  
D	
  
E	
  
A’	
  F	
  
G	
   H	
   I	
  
So	
  how	
  can	
  we	
  have	
  modules	
  that	
  are	
  both	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  and	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  ?	
  
How	
  can	
  we	
  keep	
  A	
  and	
  everything	
  in	
  the	
  top	
  part	
  of	
  the	
 Â ïŹgure	
  unchanged,	
  
	
  

while	
  providing	
  A’	
  to	
  the	
  boHom	
  clients,	
  and	
  avoiding	
  duplicaEon	
  of	
  soTware?	
  	
  
A	
  B	
   C	
  
D	
  
E	
  
A’	
  F	
  
G	
   H	
   I	
  
With	
  the	
  OO	
  concept	
  of	
  inheritance	
  
Inheritance	
  allows	
  us	
  to	
  get	
  out	
  of	
  the	
  CHANGE	
  OR	
  COPY	
  dilemma
	
  

because	
  inheritance	
  allows	
  us	
  to	
  deïŹne	
  a	
  new	
  module	
  A'	
  in	
  terms	
  of	
  an	
  exisEng	
  
module	
  A,	
  
by	
  staEng	
  only	
  the	
  diïŹ€erences	
  between	
  the	
  two	
  	
  
A’	
  deïŹnes	
  new	
  features,	
  and	
  redeïŹnes	
  (i.e.	
  modiïŹes)	
  
one	
  or	
  more	
  of	
  A’s	
  features	
  
inherits	
  from	
  
Change	
  by	
  	
  
Addi3on	
  
Hacking = Slipshod approach to building and
modifying code
Slipshod = Done poorly or too quickly; careless.
The	
  Hacker	
  	
  
may	
  seem	
  	
  
bad	
  
but	
  oVen	
  his	
  	
  
heart	
  is	
  pure.	
  
He	
  sees	
  a	
  useful	
  piece	
  of	
  soVware,	
  which	
  is	
  almost	
  able	
  to	
  address	
  the	
  needs	
  of	
  the	
  	
  
moment,	
  more	
  general	
  than	
  the	
  soVware’s	
  original	
  purpose.	
  	
  
Hacker	
  	
  
Spurred	
  by	
  a	
  laudable	
  desire	
  not	
  to	
  redo	
  what	
  can	
  be	
  reused,	
  our	
  hacker	
  starts	
  	
  
modifying	
  the	
  original	
  to	
  add	
  provisions	
  for	
  new	
  cases	
  
soluEon	
  
The	
  impulse	
  is	
  good	
  but	
  the	
  eïŹ€ect	
  
is	
  oVen	
  to	
  pollute	
  the	
  soVware	
  
with	
  many	
  clauses	
  of	
  the	
  form	
  	
  
if	
  that_special_case	
  then
	
  
if	
  (<special	
  case	
  D>)	
  
then 
	
  
if	
  (<special	
  case	
  C>)	
  
then 
	
  
if	
  (<special	
  case	
  B>)	
  
then 
	
  
if	
  (<special	
  case	
  A>)	
  
then 
	
  
switch!
Open-Closed Principle = 	
  
One	
  way	
  to	
  describe	
  the	
  OCP	
  and	
  the	
  consequent	
  OO	
  techniques	
  is	
  to	
  think	
  of	
  them	
  
as	
  organised	
  hacking	
  
Hacking	
  
The	
  organised	
  form	
  of	
  hacking	
  will	
  enable	
  us	
  to	
  cater	
  to	
  the	
  variants	
  	
  
without	
  aïŹ€ecEng	
  the	
  consistency	
  of	
  the	
  original	
  version.	
  
Inheritance	
  
Change	
  by	
  	
  
ModiïŹca3on	
  
Change	
  by	
  	
  
Addi3on	
  
extends	
  is	
  evil!!!!!	
  
But,	
  using	
  inheritance	
  is	
  no	
  longer	
  the	
  main	
  approach	
  
to	
  sa3sfying	
  the	
  OCP	
  
Allen	
  Holub	
   2004	
  
2003	
  
Using	
  inheritance	
  is	
  s3ll	
  one	
  of	
  the	
  ways	
  of	
  saEsfying	
  the	
  OCP,	
  	
  
and	
  was	
  considered	
  THE	
  approach	
  for	
  a	
  long	
  while	
  
Why	
  extends	
  is	
  evil	
  
1988	
  -­‐	
  1st	
  ed.	
  	
   1997	
  –	
  2nd	
  ed.	
  	
  
1995	
  	
  
That	
  started	
  changing	
  with	
  the	
  	
  emergence	
  of	
  the	
  	
  
design	
  techniques	
  presented	
  in	
  Design	
  Paerns	
  
2003	
  
mulEple	
  maintenance	
  problem	
  
Change	
  by	
  	
  
ModiïŹca3on	
  
CHANGE	
  
soluEon	
  
COPY	
  	
  
soluEon	
  
Hacker	
  	
  
Change	
  by	
  	
  
Addi3on	
  
OCP	
  
soluEon	
  
Chooses	
  
Chooses	
  
switch!
extends	
  	
  
is	
  evil!!!!!	
  
But
	
  
OO Inheritance - Not Always Evil - Refactoring to Open-Closed with Inheritance
Sandi	
  deals	
  with	
  a	
  perfect	
  
example	
  of	
  the	
  
unmaintainable	
  mess	
  that	
  
you	
  end	
  up	
  with	
  when	
  you	
  
keep	
  extending	
  code	
  by	
  
adding	
  condi3onals	
  
switch!
The	
  CondiEonal	
  Sandi	
  	
  
will	
  be	
  dealing	
  with	
  
switch!
REFACTOR	
  
Sandi	
  deals	
  with	
  the	
  43-­‐line	
  condi3onal	
  by	
  refactoring	
  it	
  	
  
so	
  it	
  sa3sïŹes	
  the	
  Open	
  Closed	
  Principle	
  
switch!
Inheritance	
  
	
  
	
  
	
  
	
  
Sandi	
  uses	
  the	
  original	
  approach	
  to	
  sa3sfying	
  the	
  OCP:	
  	
  
using	
  OO	
  inheritance	
  
	
  
	
  
	
  
	
  
	
  
	
  
	
  
So	
  we	
  get	
  a	
  nice	
  example	
  of	
  the	
  technique	
  
inheritance	
  is	
  not	
  evil,	
  	
  
and	
  I	
  can	
  tell	
  you	
  exactly	
  when	
  it	
  
is	
  safe	
  to	
  use	
  it	
  
switch!
Sandi’s	
  talk	
  also
	
  	
  
looks	
  a	
  liHle	
  bit	
  at	
  why	
  	
  
switch	
  creep	
  takes	
  root	
  
acts	
  as	
  an	
  example	
  of	
  
refactoring	
  from	
  procedural	
  
code	
  to	
  OO	
  code	
  
contains	
  other	
  bits	
  of	
  	
  
her	
  design	
  wisdom	
  
Refactoring	
  
Sandi’s	
  talk	
  is	
  centered	
  around	
  the	
  Gilded	
  Rose	
  Kata	
  
A	
  code	
  kata	
  is	
  an	
  exercise	
  in	
  programming	
  
which	
  helps	
  a	
  programmer	
  hone	
  their	
  skills	
  
through	
  prac3ce	
  and	
  repe33on	
  
A	
  kata	
  is	
  an	
  exercise	
  in	
  karate	
  where	
  you	
  
repeat	
  a	
  form	
  many,	
  many	
  3mes,	
  making	
  liHle	
  
improvements	
  in	
  each	
  
The	
  intent	
  behind	
  a	
  code	
  kata	
  is	
  similar	
  
The	
  Gilded	
  Rose	
  Inn	
  
An	
  Inn	
  is	
  where	
  travellers	
  can	
  seek	
  lodging	
  and,	
  usually,	
  food	
  and	
  drink	
  
The	
  Gilded	
  Rose	
  Kata	
  centers	
  around	
  a	
 Â ïŹc3onal	
  Inn	
  in	
  a	
  game	
  called	
  World	
  of	
  WarcraT	
  	
  	
  
Hi	
  and	
  welcome	
  to	
  team	
  Gilded	
  Rose.	
  As	
  you	
  know,	
  we	
  are	
  a	
  
small	
  inn	
  with	
  a	
  prime	
  loca3on	
  in	
  a	
  prominent	
  city	
  ran	
  by	
  a	
  
friendly	
  innkeeper	
  named	
  Allison.	
  	
  
	
  
hHp://iamnotmyself.com/2011/02/13/refactor-­‐this-­‐the-­‐gilded-­‐rose-­‐kata/	
  
The	
  Original	
  Gilded	
  Rose	
  Kata	
  
Aged	
  Brie	
  
Sulfuras,	
  Hand	
  of	
  Ragnaros	
  
Backstage	
  Pass	
  to	
  a	
  	
  
TAFKAL80ETC	
  concert	
  
+5	
  Dexterity	
  Vest	
  
Elixir	
  of	
  the	
  	
  
Mongoose	
  
	
  
We	
  also	
  buy	
  and	
  sell	
  only	
  the	
 Â ïŹnest	
  goods.	
  Unfortunately,	
  our	
  
goods	
  are	
  constantly	
  degrading	
  in	
  quality	
  as	
  they	
  approach	
  
their	
  sell	
  by	
  date.	
  We	
  have	
  a	
  system	
  in	
  place	
  that	
  updates	
  our	
  
inventory	
  for	
  us.	
  It	
  was	
  developed	
  by	
  a	
  no-­‐nonsense	
  type	
  
named	
  Leeroy,	
  who	
  has	
  moved	
  on	
  to	
  new	
  adventures.	
  
Your	
  task	
  is	
  to	
  add	
  the	
  new	
  feature	
  to	
  our	
  system	
  so	
  	
  
that	
  we	
  can	
  begin	
  selling	
  a	
  new	
  category	
  of	
  items.	
  
	
  
	
  
First	
  an	
  introduc3on	
  to	
  our	
  system
	
  
‘sellIn’	
  denotes	
  the	
  number	
  of	
  days	
  we	
  have	
  to	
  sell	
  the	
  Item	
  
int sellIn = 4;!
All	
  items	
  have	
  a	
  	
  
sellIn	
  value	
  	
  
‘quality’	
  denotes	
  how	
  valuable	
  the	
  item	
  is	
  
int quality = 7;!
All	
  items	
  have	
  a	
  	
  
quality	
  value	
  	
  
At	
  the	
  end	
  of	
  each	
  day	
  the	
  system	
  lowers	
  both	
  values	
  for	
  every	
  item	
  
for (Item item : items) !
{!
!
!
!
!
!
}!
sellIn -= X! quality -= Y!
PreHy	
  simple,	
  right?	
  	
  
!
!
!
!
!
!
quality -= Y!
Once	
  the	
  sell	
  by	
  date	
  has	
  passed
	
  

quality	
  degrades	
  twice	
  as	
  fast	
  
x	
  2	
  
‱  Once	
  the	
  sell	
  by	
  date	
  has	
  passed,	
  Quality	
  degrades	
  twice	
  as	
  fast	
  
‱  The	
  Quality	
  of	
  an	
  item	
  is	
  never	
  nega3ve	
  
‱  “Aged	
  Brie”	
  actually	
  increases	
  in	
  Quality	
  the	
  older	
  it	
  gets	
  
‱  The	
  Quality	
  of	
  an	
  item	
  is	
  never	
  more	
  than	
  50	
  
‱  “Sulfuras”,	
  being	
  a	
  legendary	
  item,	
  never	
  has	
  to	
  be	
  sold	
  or	
  decreases	
  in	
  Quality	
  
‱  “Backstage	
  passes”,	
  like	
  aged	
  brie,	
  increases	
  in	
  Quality	
  as	
  it’s	
  SellIn	
  value	
  	
  
approaches;	
  	
  
	
  Quality	
  increases	
  by	
  2	
  when	
  there	
  are	
  10	
  days	
  or	
  less	
  and	
  by	
  3	
  when	
  there	
  are	
  	
  
	
  5	
  days	
  or	
  less	
  but	
  Quality	
  drops	
  to	
  0	
  aVer	
  the	
  concert	
  
That’s	
  just	
  the	
 Â ïŹrst	
  of	
  several	
  addi3onal	
  ‘rules’	
  aïŹ€ec3ng	
  items:	
  
It	
  is	
  not	
  hard	
  to	
  
imagine	
  developers	
  
implemen3ng	
  those	
  
requirements	
  one	
  
at	
  a	
  3me,	
  each	
  3me	
  
adding	
  one	
  or	
  more	
  
branches	
  to	
  the	
  
condi3onal.	
  
switch!
We	
  have	
  recently	
  signed	
  a	
  supplier	
  of	
  conjured	
  
items.	
  	
  
	
  
Feel	
  free	
  to	
  make	
  any	
  changes	
  to	
  the	
  
UpdateQuality	
  method	
  and	
  add	
  any	
  new	
  code	
  
as	
  long	
  as	
  everything	
  s3ll	
  works	
  correctly.	
  
However,	
  do	
  not	
  alter	
  the	
  Item	
  class	
  or	
  Items	
  
property	
  as	
  those	
  belong	
  to	
  the	
  goblin	
  in	
  the	
  
corner	
  who	
  will	
  insta-­‐rage	
  and	
  one-­‐shot	
  you	
  as	
  
he	
  doesn’t	
  believe	
  in	
  shared	
  code	
  ownership	
  
Conjured	
  Item	
  
Conjured	
  	
  
Mana	
  Cake	
  
X	
  
This	
  requires	
  an	
  update	
  to	
  our	
  system:	
  
	
  
“Conjured”	
  items	
  degrade	
  in	
  Quality	
  twice	
  as	
  
fast	
  as	
  normal	
  items	
  
That	
  was	
  the	
  original	
  kata	
  (in	
  C#)	
  
Emily	
  Bache	
  
This	
  is	
  designed	
  as	
  a	
  refactoring	
  kata,	
  where	
  you	
  take	
  this	
  less	
  than	
  clean	
  code,	
  and	
  
transform	
  it	
  via	
  small	
  steps	
  into	
  something	
  that	
  can	
  be	
  maintained	
  and	
  extended.	
  
Conjured	
  Item	
  
When	
  you	
  have	
  the	
  code	
  under	
  control,	
  it	
  
should	
  be	
  easy	
  to	
  add	
  the	
  new	
  feature	
  for	
  
“Conjured”	
  items.	
  
Two	
  approaches	
  to	
  this	
  Kata	
  
‱  In	
  the	
  original	
  version	
  of	
  this	
  Kata,	
  there	
  were	
  no	
  tests	
  provided,	
  
only	
  a	
  textual	
  descrip3on	
  of	
  the	
  requirements.	
  	
  
‱  In	
  a	
  later	
  addiEon,	
  I	
  added	
  Text-­‐Based	
  (aka	
  Approval)	
  tests.	
  	
  
	
  
Emily	
  Bache	
  
So	
  you	
  can	
  do	
  this	
  kata	
  in	
  two	
  ways,	
  	
  
‱  either	
  wriEng	
  your	
  own	
  tests,	
  and	
  prac3ce	
  wri3ng	
  really	
  good	
  ones	
  	
  
‱  or	
  just	
  jump	
  straight	
  to	
  the	
  refactoring	
  part,	
  leaning	
  on	
  the	
  text-­‐based	
  tests.	
  
Sandi	
  takes	
  neither	
  of	
  these	
  approaches:	
  	
  
https://github.com/jimweirich/gilded_rose_kata
The	
  original	
  had	
  no	
  tests.	
  Since	
  this	
  is	
  a	
  refactoring	
  kata,	
  I	
  feel	
  the	
  
tests	
  are	
  important	
  and	
  provide	
  a	
  fairly	
  complete	
  test	
  suite.	
  Just	
  
delete	
  the	
  tests	
  if	
  you	
  wish	
  to	
  "go	
  it	
  alone".	
  
she	
  uses	
  a	
  Ruby	
  version	
  of	
  the	
  kata	
  that	
  already	
  has	
  tests	
  
Sandi	
  also	
  ignores	
  the	
  restric3on	
  we	
  saw	
  earlier:	
  	
  
‘do	
  not	
  alter	
  the	
  Item	
  class	
  or	
  Items	
  property’	
  	
  
	
  	
  
In	
  fact	
  she	
  goes	
  further:	
  she	
  
doesn’t	
  even	
  look	
  at	
  the	
  
explana3on	
  of	
  the	
  problem.	
  
She	
  just	
  takes	
  the	
  code	
  and	
  tries	
  to	
  	
  
add	
  the	
  required	
  new	
  func3onality	
  
X	
  
“But	
  I	
  didn’t	
  do	
  that	
  [look	
  at	
  the	
  
problem	
  explana3on].	
  I	
  wanted	
  to	
  
treat	
  this	
  problem	
  as	
  if	
  it	
  was	
  a	
  real	
  
produc3on	
  problem,	
  and	
  that	
  my	
  only	
  
source	
  of	
  informa3on	
  was	
  the	
  tests	
  
and	
  the	
  code”	
  
Watch	
  ‘All	
  the	
  LiHle	
  Things’	
  
(just	
  under	
  40	
  minutes	
  long)	
  
hHps://www.youtube.com/watch?v=8bZh5LMaSmE	
  
	
  
hHp://www.confreaks.com/videos/3358-­‐railsconf-­‐all-­‐the-­‐liHle-­‐things	
  
Let’s Recap and Elaborate
Some of Sandi’s
Take Home Points
RailsConf	
  2014	
  
Ruby	
  on	
  Ales	
  2014	
  
There	
  are	
  two	
  versions	
  of	
  Sandi’s	
  Talk:	
  
In	
  recapping,	
  I’ll	
  sample	
  from	
  both	
  versions.	
  
Your	
  task	
  is	
  to	
  add	
  the	
  new	
  feature	
  to	
  our	
  system	
  so	
  	
  
that	
  we	
  can	
  begin	
  selling	
  a	
  new	
  category	
  of	
  items.	
  
	
  
	
  
I	
  went	
  and	
  I	
  tried.	
  	
  
I	
  tried	
  really	
  hard,	
  but	
  I	
  failed	
  
miserably.	
  I	
  could	
  not	
  do	
  it.	
  	
  
I	
  spent	
  hours	
  trying
	
  	
  
I	
  found	
  it	
  impossible	
  
if 
 !
then 
 !
else 
!
IMPOSSIBLE	
  
ALL	
  
If	
  it	
  is	
  so	
  hard,	
  if	
  it	
  is	
  impossible	
  to	
  
change	
  that	
  if	
  statement,	
  	
  
and	
  I	
  am	
  supposed	
  to	
  be	
  all	
  OOP,	
  	
  	
  
then	
  you	
  have	
  to	
  wonder	
  why	
  I	
  even	
  tried.	
  	
  
What	
  made	
  me	
  choose	
  as	
  my	
  strategy,	
  
changing	
  that	
  if	
  statement?	
  
Well	
  it	
  is	
  because	
  I	
  felt	
  	
  
I	
  was	
  supposed	
  to	
  do	
  it.	
  
And	
  here	
  is	
  what	
  happens,	
  right?	
  
you	
  write	
  some	
  code	
  
someone	
  asks	
  for	
  a	
  change	
  	
  
What	
  do	
  we	
  do?	
  You	
  go	
  looking	
  around	
  the	
  
codebase	
  for	
  code	
  that	
  is	
  the	
  closest	
  thing	
  to	
  
the	
  	
  thing	
  that	
  you	
  are	
  trying	
  to	
  do.	
  You	
  put	
  
the	
  new	
  code	
  there	
  
if 
 !
then 
 !
else 
!
if 
 !
then 
 !
else 
!
Maybe	
  the	
 Â ïŹrst	
  person	
  that	
  wrote	
  it	
  put	
  an	
  if	
  
statement	
  in.	
  	
  
And	
  if	
  statements	
  exert	
  gravita3onal	
  pull.	
  
	
  
and	
  if	
  that	
  thing	
  already	
  has	
  an	
  if	
  statement,	
  
well	
  they	
  just	
  put	
  in	
  another	
  branch	
  on	
  it,	
  
right?	
  that’s	
  how	
  it	
  works.	
  
Novices	
  especially,	
  they	
  are	
  afraid	
  to	
  make	
  
new	
  objects	
  so	
  the	
  just	
  go	
  put	
  more	
  code	
  in	
  	
  
where	
  they	
  can	
 Â ïŹnd	
  the	
  thing	
  they	
  are	
  trying	
  
to	
  add	
  	
  
So,	
  the	
  natural	
  tendency	
  of	
  code	
  is	
  to	
  grow	
  
bigger	
  and	
  bigger	
  and	
  bigger,	
  and	
  there	
  comes	
  
a	
  point	
  when	
  it	
  gets	
  big	
  enough	
  that	
  it	
  3ps	
  
DIS	
  
and	
  it	
  feels	
  like	
  even	
  if	
  you	
  are	
  the	
  kind	
  
of	
  person	
  who	
  would	
  normally	
  make	
  a	
  
new	
  class,	
  	
  
	
  
	
  
	
  
	
  
	
  
	
  
that	
  you	
  would	
  be	
  doing	
  the	
  past	
  and	
  the	
  
future	
  a	
  disservice	
  by	
  pu|ng	
  the	
  code	
  
anywhere	
  else.	
  
at	
  that	
  point	
  it	
  is	
  	
  
so	
  big	
  that	
  you	
  cannot	
  
imagine	
  pu|ng	
  code	
  
anywhere	
  else.	
  
if 
 !
then 
 !
else 
!
if 
 !
then 
 !
else 
!
when	
  you	
  have	
  a	
  5000	
  line	
  in	
  
an	
  ac3ve	
  record,	
  you	
  do	
  not	
  
make	
  a	
  20	
  line	
  service	
  object	
  
that	
  goes	
  with	
  it	
  when	
  you	
  
have	
  a	
  new	
  requirement,	
  
you	
  feel	
  like	
  you	
  have	
  to	
  put	
  
the	
  code	
  where	
  it	
  is	
  
Service	
  
X	
  
Let’s	
  take	
  a	
  2	
  minute	
  detour	
  to	
  see	
  a	
  real-­‐world	
  example	
  of	
  a	
  condi3onal	
  
that	
  has	
  grown	
  well	
  beyond	
  the	
  3pping	
  point.	
  	
  	
  
OO Inheritance - Not Always Evil - Refactoring to Open-Closed with Inheritance
switch!
Detour	
  over.	
  
Now	
  back	
  to	
  
Sandi’s	
  talk	
  
Ăšïƒš	
 Â Ăšïƒš	
 Â Ăšïƒš	
  
If	
  the	
  paHern	
  is	
  a	
  good	
  one	
  
then	
  the	
  code	
  gets	
  beHer,	
  and	
  
if	
  the	
  paHern	
  is	
  a	
  bad	
  one,	
  we	
  
exacerbate	
  the	
  problem.	
  
We	
  have	
  a	
  bargain	
  to	
  
follow	
  the	
  paHern.	
  	
  
	
  
And	
  so	
  the	
  	
  
paHern	
  	
  
failed	
  me.	
  	
  
That	
  if	
  statement,	
  it	
  
felt	
  like	
  it	
  had	
  
evolved,	
  	
  
evolu3onarily,	
  	
  
	
  
	
  
if 
 !
then 
 !
else 
!
if 
 !
then 
 !
else 
!
and	
  that	
  any	
  
change	
  I	
  made	
  I	
  
was	
  supposed	
  to	
  
make	
  there	
  
But	
  fortunately	
  I	
  couldn’t	
  do	
  it.	
  	
  
And	
  so	
  I	
  decided	
  I	
  would	
  make	
  a	
  new	
  paHern:	
  	
  
I	
  am	
  not	
  going	
  to	
  try	
  
to	
  add	
  Conjured,	
  I	
  
am	
  going	
  to	
  refactor	
  
the	
  code	
  so	
  that	
  it	
  is	
  
simpler	
  and	
  so	
  that	
  I	
  
can	
  then	
  add	
  
Conjured.	
  	
  
Conjured	
  Item	
  
inheritance	
  
But,	
  but
extends	
  is	
  evil!!!!	
  
Sandi	
  sa3sïŹed	
  the	
  OCP	
  using	
  inheritance	
  
Despite	
  the	
  fact	
  that	
  people	
  
tell	
  you	
  ‘never	
  ever	
  ever	
  use	
  
inheritance’
	
  
inheritance	
  	
  
is	
  not	
  evil!!!!!	
  
X	
  
1.	
  The	
  hierarchy	
  is	
  shallow	
  and	
  narrow,	
  it	
  is	
  not	
  deep	
  and	
  wide	
  
If	
  those	
  condi3ons	
  are	
  all	
  true	
  for	
  the	
  thing	
  that	
  you	
  are	
  doing	
  
I	
  will	
  give	
  you	
  dispensa3on	
  to	
  
use	
  it	
  in	
  a	
  very	
  speciïŹc	
  case	
  
	
  
2.	
  The	
  subclasses	
  use	
  every	
  bit	
  of	
  code	
  that	
  is	
  in	
  the	
  superclass	
  
	
  
3.	
  If	
  you	
  draw	
  a	
  mental	
  image	
  of	
  your	
  object	
  graph,	
  this	
  lile	
  hierarchical	
  cluster	
  is	
  at	
  	
  	
  	
  	
  
	
  	
  	
  	
  the	
  edge	
  of	
  the	
  graph	
  (it	
  is	
  on	
  a	
  leaf	
  node	
  of	
  your	
  object	
  hierarchy)	
  
then	
  it	
  is	
  hard	
  to	
 Â ïŹnd	
  another	
  more	
  intenEon-­‐revealing	
  way	
  to	
  write	
  this	
  code.	
  
1.  The	
  hierarchy	
  is	
  shallow	
  and	
  narrow,	
  it	
  is	
  not	
  deep	
  and	
  wide	
  
2.  The	
  subclasses	
  use	
  every	
  bit	
  of	
  code	
  that	
  is	
  in	
  the	
  superclass	
  
Let’s now look at how Sandi
elaborates on her first two
conditions
In her book:
POODR
1.	
  The	
  hierarchy	
  is	
  shallow	
  and	
  narrow,	
  it	
  is	
  not	
  deep	
  and	
  wide	
  
A	
  hierarchy’s	
  shape	
  is	
  deïŹned	
  by	
  its	
  overall	
  breadth	
  and	
  depth	
  
It	
  is	
  this	
  shape	
  that	
  determines	
  ease	
  of	
  use,	
  maintenance,	
  and	
  extension.	
  
Here	
  are	
  a	
  few	
  of	
  the	
  possible	
  variaEons	
  of	
  shape:	
  
Easy	
  to	
  understand	
   Slightly	
  more	
  complicated.	
  
A	
  bit	
  more	
  challenging	
  
Have	
  a	
  tendency	
  to	
  get	
  wider	
  
DiïŹƒcult	
  to	
  understand	
  	
  
and	
  costly	
  to	
  maintain	
  
SHOULD	
  BE	
  AVOIDED	
  
The	
  problems	
  with	
  deep	
  hierarchies	
  
They	
  have	
  a	
  very	
  long	
  search	
  	
  
path	
  for	
  message	
  resolu3on	
  
They	
  provide	
  numerous	
  opportuni3es	
  for	
  objects	
  in	
  that	
  path	
  to	
  add	
  behavior	
  as	
  the	
  
message	
  passes	
  by.	
  
Objects	
  depend	
  on	
  everything	
  above	
  them,	
  so	
  a	
  deep	
  hierarchy	
  has	
  	
  
a	
  large	
  set	
  of	
  built-­‐in	
  dependencies,	
  each	
  of	
  which	
  might	
  someday	
  change.	
  
Programmers	
  tend	
  to	
  be	
  familiar	
  with	
  just	
  the	
  classes	
  at	
  their	
  tops	
  and	
  boHoms;	
  
*	
  They	
  tend	
  to	
  understand	
  only	
  the	
  behavior	
  implemented	
  at	
  the	
  boundaries	
  	
  
	
  	
  	
  of	
  the	
  search	
  path	
  
*	
  The	
  classes	
  in	
  the	
  middle	
  get	
  short	
  shriT.	
  
*	
  Changes	
  to	
  these	
  vaguely	
  understood	
  middle	
  classes	
  stand	
  a	
  greater	
  chance	
  of	
  	
  	
  	
  	
  
	
  	
  	
  	
  introducing	
  errors.	
  
1.	
  The	
  hierarchy	
  is	
  shallow	
  and	
  narrow,	
  it	
  is	
  not	
  deep	
  and	
  wide	
  
2.	
  “The	
  subclasses	
  use	
  every	
  bit	
  of	
  code	
  that	
  is	
  in	
  the	
  superclass”	
  
What	
  does	
  she	
  mean?	
  Let’s	
  look	
  at	
  how	
  she	
  elaborates	
  this	
  in	
  POODR	
  	
  
Subclasses	
  are	
  specializaEons	
  of	
  their	
  superclasses.	
  	
  
A	
  MountainBike	
  should	
  be	
  everything	
  a	
  Bicycle	
  is,	
  plus	
  more.	
  
Any	
  object	
  that	
  expects	
  a	
  Bicycle	
  should	
  be	
  able	
  to	
  interact	
  with	
  a	
  
MountainBike	
  in	
  blissful	
  ignorance	
  of	
  its	
  actual	
  class.	
  
These	
  are	
  the	
  rules	
  of	
  inheritance;	
  break	
  them	
  at	
  your	
  peril.	
  	
  
For	
  inheritance	
  to	
  work
the	
  objects	
  that	
  you	
  are	
  
modeling	
  must	
  truly	
  have	
  a	
  generalizaEon–specializaEon	
  
rela3onship.	
  	
  
[When]	
  subclasses
are	
  not	
  
truly	
  specializaEons	
  of	
  their	
  	
  
superclasses,	
  the	
  hierarchy	
  	
  
becomes	
  untrustworthy.	
  
IS-­‐A	
  
__	
  
trust	
  
Untrustworthy	
  hierarchies	
  
force	
  objects	
  that	
  interact	
  
with	
  them	
  to	
  know	
  their	
  
quirks	
  
trust	
  
Inexperienced	
  programmers	
  	
  
do	
  not	
  understand	
  and	
  
cannot	
 Â ïŹx	
  a	
  faulty	
  hierarchy	
  
Knowledge	
  of	
  the	
  structure	
  	
  
of	
  the	
  hierarchy	
  leaks	
  into	
  	
  
the	
  rest	
  of	
  the	
  applica3on,	
  	
  
creaEng	
  dependencies	
  that	
  	
  
raise	
  the	
  cost	
  of	
  change.	
  	
  
if (bicycle instanceof MountainBike)
{
// do XYZ
}
if (bicycle instanceof MountainBike)
{
// do XYZ
}
if (bicycle instanceof MountainBike)
{
// code that knows about
}
oTen	
  by	
  explicitly	
  	
  
checking	
  the	
  classes	
  
of	
  objects.	
  	
  
when	
  asked	
  to	
  use	
  	
  
one	
  they	
  will	
  embed	
  	
  
knowledge	
  of	
  its	
  	
  
quirks	
  into	
  their	
  own	
  	
  
code,	
  
All	
  of	
  the	
  code	
  in	
  an	
  
abstract	
  superclass	
  	
  
should	
  apply	
  to	
  every	
  	
  
class	
  that	
  inherits	
  it	
  
Superclasses	
  should	
  not	
  
contain	
  code	
  that	
  applies	
  	
  
to	
  some,	
  but	
  not	
  all,	
  
subclasses.	
  
=======	
  
=======	
  
=======	
  
=======	
  
	
  
=======	
  
	
  
=======	
  
=======	
  
=======	
  
=======	
  
=======	
  
=======	
  
=======	
  
=======	
  
=======	
  
=======	
  
=======	
  
 
When	
  interac3ng	
  with	
  
these	
  awkward	
  objects,	
  
programmers	
  are	
  forced	
  
to	
  know	
  their	
  quirks	
  and	
  
into	
  dependencies	
  that	
  
are	
  beHer	
  avoided.	
  
Faulty	
  abstracEons	
  cause	
  
inheri3ng	
  objects	
  to	
  
contain	
  incorrect	
  behavior;	
  
aHempts	
  to	
  work	
  around	
  
this	
  erroneous	
  behavior	
  
will	
  cause	
  your	
  code	
  to	
  
decay.	
  	
  
subclasses	
  agree	
  to	
  a	
  
contract	
  	
  
they	
  promise	
  to	
  be	
  	
  
subsEtutable	
  	
  
for	
  their	
  superclasses.	
  
Subclasses	
  that	
  fail	
  to	
  honor	
  	
  
their	
  contract	
  are	
  diïŹƒcult	
  to	
  	
  
use.	
  They’re	
  “special”and	
  	
  
cannot	
  be	
  freely	
  subsEtuted	
  	
  
for	
  their	
  superclasses.	
  	
  
	
  
	
  These	
  subclasses	
  are	
  declaring	
  that	
  	
  
they	
  are	
  not	
  really	
  a	
  kind-­‐of	
  their	
  	
  
superclass	
  and	
  cast	
  doubt	
  on	
  the	
  	
  
correctness	
  of	
  the	
  en3re	
  hierarchy.	
  
They	
  are	
  not	
  permied	
  	
  
to	
  do	
  anything	
  that	
  	
  
forces	
  others	
  to	
  check	
  	
  
their	
  type	
  in	
  order	
  to	
  	
  
know	
  how	
  to	
  treat	
  them	
  	
  
or	
  what	
  to	
  expect	
  of	
  them.	
  
	
  
if (bicycle instanceof MountainBike)
{
// code that knows
}
trust	
  
IS-­‐A	
  
__	
  
Let’s	
  look	
  in	
  more	
  detail	
  at	
  the	
  LSP	
  to	
  	
  
beHer	
  understand	
  what	
  Sandi	
  means	
  	
  
by	
  contract,	
  and	
  subsEtutability	
  
When	
  you	
  honor	
  the	
  contract,	
  you	
  are	
  
following	
  the	
  Liskov	
  SubsEtuEon	
  
Principle,	
  which	
  is	
  named	
  for	
  its	
  
creator,	
  Barbara	
  Liskov,	
  and	
  supplies	
  
the	
  “L”	
  in	
  the	
  SOLID	
  design	
  principles	
  
Barbara	
  Liskov	
  
The	
  Liskov	
  SubsEtuEon	
  Principle	
  (LSP)	
  -­‐	
  1988	
  
Let	
  q(x)	
  be	
  a	
  property	
  provable	
  about	
  
objects	
  x	
  of	
  type	
  T.	
  	
  
	
  
Then	
  q(y)	
  should	
  be	
  provable	
  for	
  objects	
  y	
  
of	
  type	
  S	
  where	
  S	
  is	
  a	
  subtype	
  of	
  T.	
  
[in	
  a	
  Type	
  hierarchy]	
  the	
  supertype’s	
  behavior	
  must	
  be	
  supported	
  by	
  the	
  subtypes:	
  
subtype	
  objects	
  can	
  be	
  subsEtuted	
  for	
  supertype	
  objects	
  without	
  aïŹ€ecEng	
  the	
  
behavior	
  of	
  the	
  using	
  code.	
  	
  
Behaviour	
  of	
  -­‐-­‐-­‐-­‐>	
  
supported	
  	
  
by	
  -­‐-­‐-­‐-­‐>	
  
2000	
  
[the	
  LSP]	
  allows	
  using	
  code	
  to	
  be	
  wrien	
  in	
  terms	
  of	
  the	
  supertype	
  	
  
speciïŹcaEon,	
  yet	
  work	
  correctly	
  when	
  using	
  objects	
  of	
  the	
  subtype.	
  	
  
For	
  example,	
  code	
  can	
  be	
  wriHen	
  in	
  terms	
  of	
  the	
  Reader	
  type,	
  yet	
  work	
  correctly	
  
when	
  using	
  a	
  BuïŹ€eredFileReader.	
  
private void foo(BufferedReader bufferedReader) throws IOException
{


bar(bufferedReader);


}
private void bar(Reader reader) throws IOException
{


System.out.println( reader.read() );


}
the	
  subsEtuEon	
  principle	
  requires	
  that	
  the	
  subtype	
  
speciïŹca3on	
  support	
  reasoning	
  based	
  on	
  the	
  supertype	
  
speciïŹca3on.	
  	
  
	
  
Three	
  proper3es	
  must	
  be	
  
supported:	
  
	
  
1. Signature	
  Rule	
  	
  
2. Methods	
  Rule	
  	
  
3. ProperEes	
  Rule	
  	
  
The	
  subtype	
  objects	
  must	
  have	
  all	
  the	
  methods	
  of	
  the	
  supertype,	
  and	
  the	
  signatures	
  of	
  
the	
  subtype	
  methods	
  must	
  be	
  compaEble	
  with	
  the	
  signatures	
  of	
  the	
  corresponding	
  
supertype	
  methods.	
  
This	
  rule	
  is	
  enforced	
  by	
  the	
  compiler,	
  so	
  we	
  are	
  all	
  familiar	
  with	
  it.	
  
#1	
  The	
  Signature	
  Rule	
  	
  
1. Signature	
  Rule	
  	
  
2. Methods	
  Rule	
  	
  
3. ProperEes	
  Rule	
  	
  
Before	
  we	
  can	
  cover	
  the	
  other	
  two	
  rules	
  we	
  	
  
must	
  brieïŹ‚y	
  look	
  at	
  Design	
  by	
  Contract	
  
The	
  other	
  two	
  rules	
  cannot	
  be	
  checked	
  by	
  a	
  	
  
compiler	
  because	
  they	
  require	
  reasoning	
  about	
  	
  
the	
  meaning	
  of	
  speciïŹca3ons	
  
Viewing	
  the	
  rela3onship	
  between	
  a	
  class	
  and	
  
its	
  clients	
  as	
  a	
  formal	
  agreement	
  ,	
  expressing	
  
each	
  party’s	
  rights	
  and	
  obligaEons	
  
DbC	
  uses	
  precondiEons,	
  postcondiEons	
  and	
  class	
  invariants	
  	
  
to	
  document	
  (or	
  beHer,	
  programma3cally	
  assert)	
  	
  
the	
  contract	
  between	
  classes,	
  methods	
  and	
  their	
  callers.	
  
1986	
  
Bertrand	
  Meyer	
  
Design	
  by	
  Contract	
  (DbC)	
  	
  
DbC	
  
Condi3ons	
  that	
  must	
  always	
  be	
  true	
  of	
  a	
  class.	
  
They	
  are	
  implicitly	
  added	
  to	
  the	
  precondiEons	
  and	
  postcondiEons	
  of	
  every	
  method.	
  
DbC	
   Object	
  Oriented	
  
SoTware	
  ConstrucEon	
  
Condi3ons	
  that	
  must	
  be	
  true	
  before	
  a	
  method	
  can	
  execute.	
  	
  
if	
  the	
  condi3ons	
  are	
  not	
  met,	
  it	
  is	
  a	
  bug	
  in	
  the	
  client.	
  
Condi3ons	
  that	
  must	
  be	
  true	
  when	
  a	
  method	
  is	
 Â ïŹnished	
  execuEng.	
  	
  
if	
  the	
  condi3ons	
  are	
  not	
  met,	
  it	
  is	
  a	
  bug	
  in	
  the	
  method.	
  
hHp://www.cs.olemiss.edu/~hcc/soVArch/notes/iContract/OW_Berlin99_web.pdf	
  
https://code.google.com/p/cofoja/wiki/AddContracts
Open-­‐source	
  library	
  released	
  by	
  Google	
  to	
  bring	
  DbC	
  to	
  Java	
  
#2	
  The	
  Methods	
  Rule	
  	
  
Calls	
  of	
  these	
  subtype	
  methods	
  must	
  “behave	
  like”	
  calls	
  to	
  the	
  corresponding	
  
supertype	
  methods.	
  
The	
  subtype	
  objects	
  must	
  have	
  all	
  the	
  methods	
  of	
  the	
  supertype,	
  and	
  the	
  signatures	
  of	
  
the	
  subtype	
  methods	
  must	
  be	
  compaEble	
  with	
  the	
  signatures	
  of	
  the	
  corresponding	
  
supertype	
  methods.	
  
#1	
  The	
  Signature	
  Rule	
  	
  
What	
  does	
  Liskov	
  mean	
  by	
  “behave	
  like”?	
  
Let’s	
  look	
  at	
  Meillir-­‐Jones’	
  explana3on,	
  in	
  terms	
  of	
  	
  
precondi3ons	
  and	
  postcondi3ons	
  	
  
‱  Every	
  opera3on’s	
  precondiEon	
  is	
  no	
  stronger	
  than	
  
the	
  corresponding	
  opera3on	
  in	
  the	
  superclass	
  	
  	
  
‱  Every	
  opera3on’s	
  postcondiEon	
  is	
  at	
  least	
  as	
  
strong	
  as	
  the	
  corresponding	
  opera3on	
  in	
  the	
  
superclass	
  	
  	
  	
  
a	
  subtype	
  method	
  can	
  
‱  expect	
  the	
  same	
  or	
  less	
  	
  
‱  promise	
  the	
  same	
  or	
  more	
  
Explana3on	
  of	
  “methods	
  must	
  ‘behave	
  
like’	
  calls	
  to	
  the	
  corresponding	
  supertype	
  
methods”	
  
Meillir-­‐Jones	
  
A	
  subtype	
  method	
  can	
  
weaken	
  the	
  precondiEon	
  
and	
  can	
  strengthen	
  the	
  
postcondiEon	
  
1999	
  
#2	
  The	
  Methods	
  Rule	
  	
  
Calls	
  of	
  these	
  subtype	
  methods	
  must	
  “behave	
  like”	
  calls	
  to	
  the	
  corresponding	
  
supertype	
  methods.	
  
The	
  subtype	
  objects	
  must	
  have	
  all	
  the	
  methods	
  of	
  the	
  supertype,	
  and	
  the	
  signatures	
  of	
  
the	
  subtype	
  methods	
  must	
  be	
  compaEble	
  with	
  the	
  signatures	
  of	
  the	
  corresponding	
  
supertype	
  methods.	
  
#1	
  The	
  Signature	
  Rule	
  	
  
The	
  subtype	
  must	
  preserve	
  all	
  properEes	
  that	
  can	
  be	
  proved	
  about	
  
supertype	
  objects.	
  
#3	
  The	
  ProperEes	
  Rule	
  	
  
The	
  class	
  invariant	
  of	
  a	
  subclass	
  must	
  be	
  equal	
  to	
  or	
  
stronger	
  than	
  that	
  of	
  its	
  superclass	
  
An	
  Example	
  of	
  a	
  subclass	
  viola3ng	
  
the	
  contract	
  of	
  its	
  superclass	
  
Robert	
  MarEn	
  (aka	
  Uncle	
  Bob)	
   Agile	
  SoTware	
  Development	
  
Principles,	
  Paerns	
  and	
  PracEces	
  
2002	
  
public class Rectangle
{
private Point topLeft;
private double width;
private double height;
public void setWidth(double width)
{
this.width = width;
}
public double getWidth()
{
return width;
}
public void setHeight(double height)
{
this.height = height;
}
public double getHeight()
{
return height;
}


}
Imagine	
  that	
  this	
  applica3on	
  works	
  well	
  
and	
  is	
  installed	
  in	
  many	
  sites.	
  
One	
  day,	
  the	
  users	
  demand	
  the	
  ability	
  to	
  
manipulate	
  squares	
  in	
  addi3on	
  to	
  
rectangles.	
  
It	
  is	
  oVen	
  said	
  that	
  inheritance	
  
is	
  the	
  IS-­‐A	
  relaEonship.	
  	
  
In	
  other	
  words,	
  if	
  a	
  new	
  kind	
  
of	
  object	
  can	
  be	
  said	
  to	
  fulïŹll	
  the	
  
IS-­‐A	
  relaEonship	
  with	
  an	
  old	
  kind	
  of	
  
object,	
  the	
  class	
  of	
  
the	
  new	
  object	
  should	
  be	
  derived	
  
from	
  the	
  class	
  of	
  the	
  old	
  object.	
  
public class Rectangle!
{!
!
!
!!
!public void setWidth(double width)!
!{ !
! !this.width = width; !
!} !!
!
!
!
public void setHeight(double height)
{
this.height = height;
}

!
}!For	
  all	
  normal	
  intents	
  and	
  purposes,	
  a	
  square	
  is	
  a	
  rectangle.	
  
So	
  it	
  is	
  logical	
  to	
  view	
  the	
  Square	
  class	
  as	
  	
  
being	
  derived	
  from	
  the	
  Rectangle	
  class.	
   IS-­‐A	
  
!
public class Square extends Rectangle!
{ !!
}!
public class Rectangle!
{!
!
!
@Ensures({“getWidth() = width”})!
!public void setWidth(double width)!
!{ !
! !this.width = width; !
!} !!
!
!
!@Ensures({“getHeight() = height”})!
public void setHeight(double height)
{
this.height = height;
}

!
}!
@Invariant(“getWidth() = getHeight()”)!
public class Square extends Rectangle!
{ !!
}!
A	
  square	
  has	
  the	
  invariant	
  that	
  its	
  width	
  and	
  height	
  are	
  idenEcal,	
  	
  
but	
  Square	
  inherits	
  Rectangle’s	
  seHers,	
  which	
  do	
  not	
  preserve	
  the	
  invariant.	
  
public void f(Square square)
{
square.setWidth(5);
assert square.getHeight() == 5;
}
There	
  is	
  a	
  problem	
  though	
  
The	
  asserEon	
  fails	
  
To	
  see	
  why,	
  let’s	
  make	
  the	
  contract	
  explicit	
  
public class Rectangle!
{!
!
!
@Ensures({“getWidth() = width”})!
!public void setWidth(double width)!
!{ !
! !this.width = width; !
!} !!
!
!
!@Ensures({“getHeight() = height”})!
public void setHeight(double height)
{
this.height = height;
}

!
}! We	
  can	
  sidestep	
  the	
  problem	
  by	
  overriding	
  the	
  seHers.	
  
@Invariant(“getWidth() = getHeight()”)!
public class Square extends Rectangle!
{!
@Ensures({“getWidth() = width”})!
!public void setWidth(double width)!
!{ !
! !this.width = width; !
! !this.height = width; !
!} !!
!
@Ensures({“getHeight() = height”})!
public void setHeight(double height)
{
this.height = height;
! !this.width = height;
} !!
}!
Now	
  Square	
  and	
  Rectangle	
  appear	
  to	
  work.	
  No	
  maHer	
  what	
  you	
  do	
  to	
  a	
  Square	
  object,	
  it	
  
will	
  remain	
  consistent	
  with	
  a	
  mathema3cal	
  square,	
  and	
  regardless	
  of	
  what	
  you	
  do	
  to	
  a	
  
Rectangle	
  object,	
  it	
  will	
  remain	
  a	
  mathema3cal	
  rectangle.	
  
public class Rectangle!
{!
!
!
@Ensures({“getWidth() = width”})!
!public void setWidth(double width)!
!{ !
! !this.width = width; !
!} !!
!
!
!@Ensures({“getHeight() = height”})!
public void setHeight(double height)
{
this.height = height;
}

!
}!
@Invariant(“getWidth() = getHeight()”)!
public class Square extends Rectangle!
{!
@Ensures({“getWidth() = width”})!
!public void setWidth(double width)!
!{ !
! !this.width = width; !
! !this.height = width; !
!} !!
!
@Ensures({“getHeight() = height”})!
public void setHeight(double height)
{
this.height = height;
! !this.width = height;
} !!
}!
The	
  asserEon	
  now	
  passes.	
  
The	
  invariant	
  of	
  the	
  Square	
  is	
  now	
  sa3sïŹed.	
  
public void f(Square square)
{
square.setWidth(5);
assert square.getHeight() == 5;
}
Moreover,	
  you	
  can	
  pass	
  a	
  Square	
  into	
  a	
  
func3on	
  that	
  accepts	
  a	
  Rectangle,	
  and	
  the	
  
Square	
  will	
  s3ll	
  act	
  like	
  a	
  square	
  and	
  will	
  
remain	
  consistent.	
  
public class Rectangle!
{!
!
!
@Ensures({“getWidth() = width”})!
!public void setWidth(double width)!
!{ !
! !this.width = width; !
!} !!
!
!
!@Ensures({“getHeight() = height”})!
public void setHeight(double height)
{
this.height = height;
}

!
}!
So	
  we	
  might	
  conclude	
  that	
  the	
  design	
  is	
  now	
  self-­‐consistent	
  and	
  correct.	
  	
  
@Invariant(“getWidth() = getHeight()”)!
public class Square extends Rectangle!
{!
@Ensures({“getWidth() = width”})!
!public void setWidth(double width)!
!{ !
! !this.width = width; !
! !this.height = width; !
!} !!
!
@Ensures({“getHeight() = height”})!
public void setHeight(double height)
{
this.height = height;
! !this.width = height;
} !!
}!
However,	
  this	
  conclusion	
  would	
  be	
  amiss.	
  A	
  design	
  that	
  is	
  self-­‐consistent	
  is	
  not	
  
necessarily	
  consistent	
  with	
  all	
  its	
  users!	
  	
  
public class Rectangle!
{!
!
!
@Ensures({“getWidth() = width”})!
!public void setWidth(double width)!
!{ !
! !this.width = width; !
!} !!
!
!
!@Ensures({“getHeight() = height”})!
public void setHeight(double height)
{
this.height = height;
}

!
}!
public void g(Rectangle rectangle)
{
rectangle.setWidth(5);
rectangle.setHeight(4);
assert rectangle.getArea() == 20;
}
Consider	
  a	
  client’s	
  func3on	
  g:	
  
@Invariant(“getWidth() = getHeight()”)!
public class Square extends Rectangle!
{!
@Ensures({“getWidth() = width”})!
!public void setWidth(double width)!
!{ !
! !this.width = width; !
! !this.height = width; !
!} !!
!
@Ensures({“getHeight() = height”})!
public void setHeight(double height)
{
this.height = height;
! !this.width = height;
} !!
}!
public class Rectangle!
{!
!
!
@Ensures({“getWidth() = width”})!
!public void setWidth(double width)!
!{ !
! !this.width = width; !
!} !!
!
!
!@Ensures({“getHeight() = height”})!
public void setHeight(double height)
{
this.height = height;
}

!
}!
public void g(Rectangle rectangle)
{
rectangle.setWidth(5);
rectangle.setHeight(4);
assert rectangle.getArea() == 20;
}
This	
  func3on	
  sets	
  the	
  width	
  and	
  height	
  of	
  	
  
what	
  it	
  believes	
  to	
  be	
  a	
  Rectangle.	
  	
  
@Invariant(“getWidth() = getHeight()”)!
public class Square extends Rectangle!
{!
@Ensures({“getWidth() = width”})!
!public void setWidth(double width)!
!{ !
! !this.width = width; !
! !this.height = width; !
!} !!
!
@Ensures({“getHeight() = height”})!
public void setHeight(double height)
{
this.height = height;
! !this.width = height;
} !!
}!
	
  
The	
  func3on	
  works	
 Â ïŹne	
  for	
  a	
  Rectangle	
  but	
  
fails	
  if	
  passed	
  a	
  Square.	
  	
  
	
  
Problem:	
  The	
  author	
  of	
  g	
  assumed	
  that	
  
changing	
  the	
  width	
  of	
  a	
  Rectangle	
  leaves	
  its	
  
height	
  unchanged.	
  
@Invariant(“getWidth() = getHeight()”)!
public class Square extends Rectangle!
{!
@Ensures({“getWidth() = width”})!
!public void setWidth(double width)!
!{ !
! !this.width = width; !
! !this.height = width; !
!} !!
!
@Ensures({“getHeight() = height”})!
public void setHeight(double height)
{
this.height = height;
! !this.width = height;
} !!
}!
public class Rectangle!
{!
!
!
@Ensures({“getWidth() = width”})!
!public void setWidth(double width)!
!{ !
! !this.width = width; !
!} !!
!
!
!@Ensures({“getHeight() = height”})!
public void setHeight(double height)
{
this.height = height;
}

!
}!
Clearly,	
  it	
  is	
  reasonable	
  to	
  assume	
  that	
  changing	
  the	
  width	
  of	
  a	
  rectangle	
  does	
  not	
  
aïŹ€ect	
  its	
  height!	
  	
  
In	
  fact	
  it	
  is	
  so	
  obviously	
  right	
  that	
  we	
  didn’t	
  even	
  bother	
  explicitly	
  adding	
  it	
  as	
  a	
  
postcondi3on	
  of	
  Rectangle’s	
  seHers,	
  we	
  leV	
  it	
  implicit!	
  	
  
Let’s	
  make	
  it	
  explicit.	
  
public class Rectangle!
{!
!
!
@Ensures({!
“getWidth() = width!
getHeight() = old(getHeight())”})!
!public void setWidth(double width)!
!{ !
! !this.width = width; !
!} !!
!
!
!@Ensures({!
“getHeight() = height!
getWidth() = old(getWidth())”})!
public void setHeight(double height)
{
this.height = height;
}
!
}!
Clearly,	
  it	
  is	
  reasonable	
  to	
  assume	
  that	
  changing	
  the	
  width	
  of	
  a	
  rectangle	
  does	
  not	
  
aïŹ€ect	
  its	
  height!	
  
@Invariant(“getWidth() = getHeight()”)!
public class Square extends Rectangle!
{!
@Ensures({“getWidth() = width”})!
!public void setWidth(double width)!
!{ !
! !this.width = width; !
! !this.height = width; !
!} !!
!
@Ensures({“getHeight() = height”})!
public void setHeight(double height)
{
this.height = height;
! !this.width = height;
} !!
}!
	
  
In	
  fact	
  it	
  is	
  so	
  obviously	
  right	
  that	
  we	
  didn’t	
  even	
  bother	
  explicitly	
  adding	
  it	
  as	
  a	
  
postcondi3on	
  of	
  Rectangle’s	
  seHers,	
  we	
  leV	
  it	
  implicit!	
  	
  
Let’s	
  make	
  it	
  explicit.	
  
public class Rectangle!
{!
!
!
@Ensures({!
“getWidth() = width”!
getHeight() = old(getHeight())”})!
!public void setWidth(double width)!
!{ !
! !this.width = width; !
!} !!
!
!
!@Ensures({!
“getHeight() = height”!
getWidth() = old(getWidth())”})!
public void setHeight(double height)
{
this.height = height;
}
!
}!
@Invariant(“getWidth() = getHeight()”)!
public class Square extends Rectangle!
{!
@Ensures({“getWidth() = width”})!
!public void setWidth(double width)!
!{ !
! !this.width = width; !
! !this.height = width; !
!} !!
!
@Ensures({“getHeight() = height”})!
public void setHeight(double height)
{
this.height = height;
! !this.width = height;
} !!
}!
Clearly,	
  the	
  postcondi3on	
  of	
  Square’s	
  setWidth	
  is	
  weaker	
  than	
  the	
  postcondi3on	
  of	
  	
  
Rectangle’s	
  setWidth,	
  since	
  it	
  does	
  not	
  enforce	
  the	
  constraint	
  
(getHeight() = old(getHeight()).	
  Similarly	
  for	
  Square’s	
  setHeight.	
  
Square’s	
  setWidth	
  and	
  setHeight	
  methods	
  violate	
  the	
  contract	
  of	
  the	
  Rectangle	
  base	
  class.	
  
‱  Every	
  opera3on’s	
  precondiEon	
  is	
  no	
  stronger	
  than	
  the	
  
corresponding	
  opera3on	
  in	
  the	
  superclass	
  	
  	
  
‱  Every	
  opera3on’s	
  postcondiEon	
  is	
  at	
  least	
  as	
  strong	
  as	
  the	
  
corresponding	
  opera3on	
  in	
  the	
  superclass	
  	
  	
  	
  
“methods	
  must	
  ‘behave	
  like’	
  calls	
  to	
  the	
  
corresponding	
  supertype	
  methods”	
  
#2	
  The	
  Methods	
  Rule	
  	
  
Square’s	
  seers	
  don’t	
  	
  
behave	
  like	
  Rectangle’s	
  
Seers!	
  
The	
  postcondiEons	
  
of	
  Square’s	
  seers	
  	
  
are	
  weaker	
  than	
  
those	
  of	
  
Rectangle’s	
  
seers!	
  
1.  Signature	
  Rule	
  	
  
2.  Methods	
  Rule	
  	
  
3.  ProperEes	
  Rule	
  	
  
Square	
  Violates	
  
Rectangle’s	
  contract	
  
It	
  is	
  oVen	
  said	
  that	
  inheritance	
  is	
  the	
  IS-­‐A	
  rela3onship.	
  	
  
	
  
e.g.	
  a	
  square	
  is	
  a	
  rectangle,	
  therefore	
  
Square	
  should	
  be	
  derived	
  from	
  the	
  
Rectangle.	
  
ISA	
  
If	
  a	
  new	
  kind	
  of	
  object	
  can	
  be	
  said	
  to	
  fulïŹll	
  the	
  IS-­‐A	
  rela3onship	
  with	
  an	
  
old	
  kind	
  of	
  object,	
  the	
  class	
  of	
  the	
  new	
  object	
  should	
  be	
  derived	
  from	
  the	
  
class	
  of	
  the	
  old	
  object.	
  
Flawed	
  reasoning	
  –	
  recap	
  
But	
  IS-­‐A	
  is	
  about	
  behaviour.	
  
In	
  OOD,	
  a	
  square	
  IS-­‐A	
  rectangle	
  only	
  if	
  it	
  behaves	
  like	
  a	
  rectangle,	
  if	
  it	
  honours	
  
Rectangle’s	
  contract,	
  if	
  it	
  sa3sïŹes	
  the	
  LSP.	
  	
  
The	
  contract	
  may	
  be	
  implicit	
  (not	
  so	
  good).	
  	
  
A	
  square	
  is	
  a	
  rectangle,	
  but	
  only	
  in	
  a	
  
geometrical	
  sense,	
  not	
  in	
  a	
  behavioural	
  sense.	
  	
  
In	
  OOD,	
  Square	
  violates	
  Rectangle’s	
  contract,	
  it	
  violates	
  
the	
  LSP,	
  therefore	
  it	
  does	
  not	
  behave	
  like	
  a	
  Rectangle:	
  it	
  
is	
  not	
  true	
  that	
  a	
  Square	
  IS-­‐A	
  Rectangle	
  and	
  therefore	
  	
  
Square	
  should	
  not	
  inherit	
  from	
  Rectangle.	
  	
  
IS-­‐A	
  
__	
  
X	
  
X	
  
It	
  may	
  be	
  expressed	
  in	
  comments	
  (beHer).	
  	
  
It	
  may	
  be	
  expressed	
  as	
  automated	
  unit	
  tests	
  (much	
  beHer).	
  	
  
Or	
  it	
  may	
  be	
  expressed	
  using	
  a	
  DbC	
  framework	
  (rare?).	
  	
  
 
	
  
	
  
	
  
	
  
	
  
	
  
To	
  adhere	
  to	
  LSP	
  in	
  Java,	
  we	
  must	
  make	
  sure	
  that	
  developers	
  deïŹne	
  precondi3ons	
  and	
  
postcondi3ons	
  for	
  each	
  of	
  the	
  methods	
  on	
  an	
  abstract	
  class.	
  	
  
	
  
X	
  
In	
  order	
  to	
  take	
  advantage	
  of	
  LSP,	
  we	
  must	
  
adhere	
  to	
  OCP	
  because	
  violaEons	
  of	
  LSP	
  also	
  
are	
  violaEons	
  of	
  OCP,	
  but	
  not	
  vice	
  versa.	
  
X	
  X	
  
When	
  deïŹning	
  our	
  subclasses,	
  we	
  must	
  adhere	
  to	
  these	
  precondi3ons	
  and	
  
postcondi3ons.	
  	
  
	
  
If	
  we	
  do	
  not	
  deïŹne	
  precondiEons	
  and	
  postcondiEons	
  for	
  our	
  methods,	
  it	
  becomes	
  
virtually	
  impossible	
  to	
 Â ïŹnd	
  violaEons	
  of	
  LSP.	
  
Kirk	
  	
  
Knoernschild	
  
The	
  Liskov	
  SubsEtuEon	
  Principle	
  is	
  one	
  of	
  the	
  
prime	
  enablers	
  of	
  OCP.	
  
We	
  can	
  think	
  of	
  the	
  Liskov	
  Subs3tu3on	
  
Principle	
  (LSP)	
  as	
  an	
  extension	
  to	
  OCP.	
  	
  
2002	
  
When	
  interac3ng	
  with	
  
these	
  awkward	
  objects,	
  
programmers	
  are	
  forced	
  
to	
  know	
  their	
  quirks	
  
and	
  into	
  dependencies	
  
that	
  are	
  beHer	
  avoided.	
  
when	
  asked	
  to	
  use	
  one	
  
they	
  will	
  embed	
  
knowledge	
  of	
  its	
  quirks	
  
into	
  their	
  own	
  code	
  
if (bicycle instanceof MountainBike)
{
// do XYZ
}
if (bicycle instanceof MountainBike)
{
// do XYZ
}
if (bicycle instanceof MountainBike)
{
// code that knows about
}
oVen	
  by	
  explicitly	
  	
  
checking	
  the	
  classes	
  
of	
  objects.	
  	
  
Recap:	
  Sandi	
  on	
  consequences	
  of	
  	
  
untrustworthy	
  Hierarchies	
  
every	
  viola3on	
  of	
  the	
  
LSP	
  is	
  a	
  latent	
  viola3on	
  
of	
  the	
  OCP	
  	
   X	
   X	
  
because	
  in	
  order	
  to	
  
repair	
  the	
  damage	
  
	
  
we	
  are	
  going	
  to	
  have	
  
to	
  add	
  if	
  statements	
  
and	
  hang	
  
dependencies	
  upon	
  
subtypes	
  
if (bicycle instanceof MountainBike)
{
// do XYZ
}
if (bicycle instanceof MountainBike)
{
// do XYZ
}
if (bicycle instanceof MountainBike)
{
// code that knows about
}
Uncle	
  Bob	
  on	
  violaEons	
  of	
  LSP	
  
Next	
  Eme	
  you	
  are	
  faced	
  with	
  adding	
  logic	
  to	
  a	
  non-­‐trivial	
  condiEonal,	
  
don’t	
  just	
  follow	
  the	
  paern	
  and	
  add	
  another	
  branch.	
  
See	
  if	
  the	
  condi,onal	
  is	
  one	
  of	
  those	
  that	
  can	
  be	
  refactored	
  to	
  the	
  OCP,	
  	
  
using	
  inheritance	
  if	
  necessary.	
  	
  
Next	
  Eme	
  you	
  consider	
  introducing	
  an	
  inheritance	
  hierarchy,	
  ask	
  yourself	
  if	
  it	
  
meets	
  Sandi’s	
  criteria	
  for	
  using	
  inheritance.	
  	
  
If	
  not,	
  consider	
  the	
  consequences	
  of	
  going	
  ahead	
  (if	
  you	
  decide	
  to	
  do	
  so).	
  
Next	
  Eme	
  you	
  create	
  a	
  base	
  class,	
  spend	
  some	
  Eme	
  thinking	
  about	
  how	
  its	
  contract	
  
	
  needs	
  to	
  be	
  expressed.	
  	
  
Is	
  it	
  really	
  acceptable	
  to	
  leave	
  it	
  implicit?	
  Is	
  it	
  so	
  obvious?	
  	
  
Is	
  it	
  workable	
  and	
  eïŹ€ecEve	
  to	
  express	
  the	
  contract	
  using	
  unit	
  tests?	
  
	
  
	
  If	
  not,	
  maybe	
  explore	
  the	
  possibility	
  of	
  using	
  a	
  DbC	
  framework.	
  
	
  If	
  not,	
  express	
  the	
  contract	
  using	
  unit	
  tests.	
  
Next	
  Eme	
  you	
  create	
  a	
  derived	
  class,	
  verify	
  that	
  it	
  saEsïŹes	
  the	
  contract	
  of	
  its	
  superclass.	
  
Next	
  Eme	
  you	
  come	
  across	
  instanceof	
  usages,	
  see	
  if	
  they	
  are	
  the	
  smell	
  of	
  	
  
an	
  untrustworthy	
  hierarchy.	
  	
  
If	
  it	
  doesn’t,	
  take	
  remedial	
  ac,on.	
  
If	
  so,	
 Â ïŹx	
  the	
  hierarchy.	
  
OO Inheritance - Not Always Evil - Refactoring to Open-Closed with Inheritance
References	
  	
  
All	
  images	
  sourced	
  from	
  hHp://www.google.co.uk/advanced_image_search,	
  so	
  see	
  
there	
  for	
  details	
  of	
  which	
  are	
  	
  subject	
  to	
  copyright	
  
	
  
PracEcal	
  Object-­‐Oriented	
  Design	
  in	
  Ruby:	
  An	
  Agile	
  Primer	
  –	
  by	
  Sandi	
  Metz	
  |	
  
Publica3on	
  Date:	
  September	
  15,	
  2012	
  |	
  ISBN-­‐10:	
  0321721330	
  	
  |	
  ISBN-­‐13:	
  
978-­‐0321721334	
  
	
  
Agile	
  SoTware	
  Development,	
  Principles,	
  Paerns,	
  and	
  PracEces	
  –	
  by	
  Robert	
  C.	
  
MarEn	
  |	
  Publica3on	
  Date:	
  	
  October	
  25,	
  2002	
  |	
  ISBN-­‐10:	
  0135974445	
  |	
  ISBN-­‐13:	
  
978-­‐0135974445	
  
	
  
Object-­‐Oriented	
  SoTware	
  ConstrucEon	
  –	
  by	
  Bertrand	
  Meyer	
  |	
  Publica3on	
  Date:	
  3	
  
April	
  1997	
  |	
  ISBN-­‐10:	
  0136291554	
  |	
  ISBN-­‐13:	
  978-­‐0136291558	
  |	
  Edi3on:	
  2	
  
	
  
Program	
  Development	
  in	
  Java	
  –	
  AbstracEon,	
  SpeciïŹcaEon	
  and	
  OO	
  Design	
  –	
  by	
  
Barbara	
  Liskov,	
  with	
  John	
  Guag	
  |	
  Publica3on	
  Date:	
  6	
  Jun	
  2000	
  |	
  ISBN-­‐10:	
  
0201657686	
  |	
  ISBN-­‐13:	
  978-­‐0201657685	
  
	
  
	
  
 
Java	
  Design:	
  Objects,	
  UML,	
  and	
  Process	
  –	
  by	
  Kirk	
  Knoernschild	
  |	
  Publica3on	
  Date:	
  
December	
  18,	
  2001	
  |	
  	
  ISBN-­‐10:	
  0201750449	
  |	
  ISBN-­‐13:	
  978-­‐0201750447	
  
	
  
The	
  Coding	
  Dojo	
  Handbook	
  -­‐	
  a	
  pracEcal	
  guide	
  to	
  creaEng	
  a	
  space	
  where	
  good	
  
programmers	
  can	
  become	
  great	
  programmers	
  –	
  by	
  Emily	
  Bache	
  |	
  Publica3on	
  Date:	
  
29	
  October	
  2013	
  |	
  hHps://leanpub.com/codingdojohandbook	
  
	
  
Fundamentals	
  of	
  Object	
  Oriented	
  Design	
  in	
  UML	
  –	
  by	
  Meilir	
  Page-­‐Jones	
  |	
  Publica3on	
  
Date:	
  November	
  13,	
  1999	
  |	
  ISBN-­‐13:	
  978-­‐0201699463	
  	
  ISBN-­‐10:	
  020169946X	
  	
  
	
  
The	
  AnE-­‐IF	
  Campaign	
  -­‐	
  hHp://an3ifcampaign.com/	
  
	
  
The	
  Gilded	
  Rose	
  Kata	
  -­‐	
  hHp://iamnotmyself.com/2011/02/13/refactor-­‐this-­‐the-­‐gilded-­‐rose-­‐kata/	
  
	
  
	
  
	
  
	
  
References	
  (con3nued)	
  	
  	
  

More Related Content

PDF
The Open-Closed Principle - the Original Version and the Contemporary Version
PDF
The Open Closed Principle - Part 1 - The Original Version
ODP
Open Close Principle
PPTX
Open Closed Principle kata
PPTX
Refactoring Applications using SOLID Principles
PPTX
Soild principles
PPTX
SOLID Software Principles with C#
PPTX
Learning solid principles using c#
The Open-Closed Principle - the Original Version and the Contemporary Version
The Open Closed Principle - Part 1 - The Original Version
Open Close Principle
Open Closed Principle kata
Refactoring Applications using SOLID Principles
Soild principles
SOLID Software Principles with C#
Learning solid principles using c#

What's hot (20)

PPTX
Design principle vs design patterns
PDF
Object Oriented Design Principles
PDF
Object-oriented design principles
PDF
SOLID Design Principles applied in Java
ODP
Geecon09: SOLID Design Principles
PPT
DesignPrinciples-and-DesignPatterns
PDF
Solid principles of oo design
 
PDF
Are You a SOLID Coder?
PDF
Software design principles - jinal desai
PDF
Solid principle
PPT
Refactoring Tips by Martin Fowler
PDF
Solid OO & Clean Coding is essential to successful Agile development
PPTX
SOLID Principles
PPT
Design poo my_jug_en_ppt
PPT
Principle of OOD
PDF
Refactoring: Improve the design of existing code
PDF
Big code refactoring with agility
PPTX
Combating software entropy 2-roc1-
PPTX
The Solid Principles
PPT
Scrum and Test-driven development
 
Design principle vs design patterns
Object Oriented Design Principles
Object-oriented design principles
SOLID Design Principles applied in Java
Geecon09: SOLID Design Principles
DesignPrinciples-and-DesignPatterns
Solid principles of oo design
 
Are You a SOLID Coder?
Software design principles - jinal desai
Solid principle
Refactoring Tips by Martin Fowler
Solid OO & Clean Coding is essential to successful Agile development
SOLID Principles
Design poo my_jug_en_ppt
Principle of OOD
Refactoring: Improve the design of existing code
Big code refactoring with agility
Combating software entropy 2-roc1-
The Solid Principles
Scrum and Test-driven development
 
Ad

Similar to OO Inheritance - Not Always Evil - Refactoring to Open-Closed with Inheritance (20)

PPT
Object Oriented Concepts and Principles
PPTX
Data Science Salon: Deep Learning as a Product @ Scribd
PPT
The OO Design Principles
PPT
All we like sheep: Cloning as an Engineering Tool
 
PDF
Deploying node.js at scale - Maraschi, Collina - Codemotion Amsterdam 2016
PPTX
The software design principles
PDF
Effect systems in scala: beyond flatmap
PDF
Owaspeutour2013lisbon pedrofortunaprotectingjavascriptsourcecodeusingobfuscat...
PDF
Protecting JavaScript source code using obfuscation - OWASP Europe Tour 2013 ...
PDF
The Open-Closed Principle - Part 2 - The Contemporary Version - An Introduction
PDF
Adobe Photoshop 2025 Free crack Download
PDF
Adobe Photoshop Lightroom Classic Crack Free Download
PDF
Adobe Photoshop 2025 Free crack Download
PPTX
How to not suck at JavaScript
 
PPTX
How have we developed product without bugs
PDF
Fantastic Design Patterns and Where to use them No Notes.pdf
PDF
AOMEI Backupper Crack Latest Version 2025
PDF
CorelDraw X7 Crack Latest Version 2025 ?
PDF
Download- Enscape Crack + Activvation key
PDF
The Open-Closed Principle - Part 1 - The Original Version
Object Oriented Concepts and Principles
Data Science Salon: Deep Learning as a Product @ Scribd
The OO Design Principles
All we like sheep: Cloning as an Engineering Tool
 
Deploying node.js at scale - Maraschi, Collina - Codemotion Amsterdam 2016
The software design principles
Effect systems in scala: beyond flatmap
Owaspeutour2013lisbon pedrofortunaprotectingjavascriptsourcecodeusingobfuscat...
Protecting JavaScript source code using obfuscation - OWASP Europe Tour 2013 ...
The Open-Closed Principle - Part 2 - The Contemporary Version - An Introduction
Adobe Photoshop 2025 Free crack Download
Adobe Photoshop Lightroom Classic Crack Free Download
Adobe Photoshop 2025 Free crack Download
How to not suck at JavaScript
 
How have we developed product without bugs
Fantastic Design Patterns and Where to use them No Notes.pdf
AOMEI Backupper Crack Latest Version 2025
CorelDraw X7 Crack Latest Version 2025 ?
Download- Enscape Crack + Activvation key
The Open-Closed Principle - Part 1 - The Original Version
Ad

More from Philip Schwarz (20)

PDF
ApplicativeError functions handling and recovering from errors: A mnemonic to...
PDF
Folding Cheat Sheet Series Titles - a series of 9 decks
PDF
Folding Cheat Sheet # 9 - List Unfolding 𝑱𝑛𝑓𝑜𝑙𝑑 as the Computational Dual of ...
PDF
List Unfolding - 'unfold' as the Computational Dual of 'fold', and how 'unfol...
PDF
Drawing Heighway’s Dragon - Part 4 - Interactive and Animated Dragon Creation
PDF
The Nature of Complexity in John Ousterhout’s Philosophy of Software Design
PDF
Drawing Heighway’s Dragon - Part 3 - Simplification Through Separation of Con...
PDF
Drawing Heighway’s Dragon - Part II - Recursive Function Simplification - Fro...
PDF
Drawing Heighway’s Dragon - Recursive Function Rewrite - From Imperative Styl...
PDF
Fibonacci Function Gallery - Part 2 - One in a series
PDF
Fibonacci Function Gallery - Part 1 (of a series) - with minor corrections
PDF
Fibonacci Function Gallery - Part 1 (of a series)
PDF
The Debt Metaphor - Ward Cunningham in his 2009 YouTube video
PDF
Folding Cheat Sheet Series Titles (so far)
PDF
From Subtype Polymorphism To Typeclass-based Ad hoc Polymorphism - An Example
PDF
Folding Cheat Sheet #8 - eighth in a series
PDF
Function Applicative for Great Good of Leap Year Function
PDF
Folding Cheat Sheet #7 - seventh in a series
PDF
Folding Cheat Sheet #6 - sixth in a series
PDF
Folding Cheat Sheet #5 - fifth in a series
ApplicativeError functions handling and recovering from errors: A mnemonic to...
Folding Cheat Sheet Series Titles - a series of 9 decks
Folding Cheat Sheet # 9 - List Unfolding 𝑱𝑛𝑓𝑜𝑙𝑑 as the Computational Dual of ...
List Unfolding - 'unfold' as the Computational Dual of 'fold', and how 'unfol...
Drawing Heighway’s Dragon - Part 4 - Interactive and Animated Dragon Creation
The Nature of Complexity in John Ousterhout’s Philosophy of Software Design
Drawing Heighway’s Dragon - Part 3 - Simplification Through Separation of Con...
Drawing Heighway’s Dragon - Part II - Recursive Function Simplification - Fro...
Drawing Heighway’s Dragon - Recursive Function Rewrite - From Imperative Styl...
Fibonacci Function Gallery - Part 2 - One in a series
Fibonacci Function Gallery - Part 1 (of a series) - with minor corrections
Fibonacci Function Gallery - Part 1 (of a series)
The Debt Metaphor - Ward Cunningham in his 2009 YouTube video
Folding Cheat Sheet Series Titles (so far)
From Subtype Polymorphism To Typeclass-based Ad hoc Polymorphism - An Example
Folding Cheat Sheet #8 - eighth in a series
Function Applicative for Great Good of Leap Year Function
Folding Cheat Sheet #7 - seventh in a series
Folding Cheat Sheet #6 - sixth in a series
Folding Cheat Sheet #5 - fifth in a series

Recently uploaded (20)

PPTX
ai tools demonstartion for schools and inter college
PDF
Claude Code: Everyone is a 10x Developer - A Comprehensive AI-Powered CLI Tool
PDF
Raksha Bandhan Grocery Pricing Trends in India 2025.pdf
PDF
Wondershare Filmora 15 Crack With Activation Key [2025
PDF
PTS Company Brochure 2025 (1).pdf.......
PDF
T3DD25 TYPO3 Content Blocks - Deep Dive by André Kraus
PDF
Adobe Illustrator 28.6 Crack My Vision of Vector Design
PPTX
Oracle E-Business Suite: A Comprehensive Guide for Modern Enterprises
PPTX
Transform Your Business with a Software ERP System
PPTX
Computer Software and OS of computer science of grade 11.pptx
PDF
Which alternative to Crystal Reports is best for small or large businesses.pdf
PPTX
Operating system designcfffgfgggggggvggggggggg
PDF
Internet Downloader Manager (IDM) Crack 6.42 Build 42 Updates Latest 2025
PDF
Nekopoi APK 2025 free lastest update
PDF
Digital Systems & Binary Numbers (comprehensive )
PPTX
Reimagine Home Health with the Power of Agentic AI​
PPTX
Embracing Complexity in Serverless! GOTO Serverless Bengaluru
PDF
top salesforce developer skills in 2025.pdf
PDF
System and Network Administration Chapter 2
PPT
Introduction Database Management System for Course Database
ai tools demonstartion for schools and inter college
Claude Code: Everyone is a 10x Developer - A Comprehensive AI-Powered CLI Tool
Raksha Bandhan Grocery Pricing Trends in India 2025.pdf
Wondershare Filmora 15 Crack With Activation Key [2025
PTS Company Brochure 2025 (1).pdf.......
T3DD25 TYPO3 Content Blocks - Deep Dive by André Kraus
Adobe Illustrator 28.6 Crack My Vision of Vector Design
Oracle E-Business Suite: A Comprehensive Guide for Modern Enterprises
Transform Your Business with a Software ERP System
Computer Software and OS of computer science of grade 11.pptx
Which alternative to Crystal Reports is best for small or large businesses.pdf
Operating system designcfffgfgggggggvggggggggg
Internet Downloader Manager (IDM) Crack 6.42 Build 42 Updates Latest 2025
Nekopoi APK 2025 free lastest update
Digital Systems & Binary Numbers (comprehensive )
Reimagine Home Health with the Power of Agentic AI​
Embracing Complexity in Serverless! GOTO Serverless Bengaluru
top salesforce developer skills in 2025.pdf
System and Network Administration Chapter 2
Introduction Database Management System for Course Database

OO Inheritance - Not Always Evil - Refactoring to Open-Closed with Inheritance

  • 1. Refactoring  an  unmaintainable  mess  of  nested   condi3onals  to  the  Open/Closed  principle       -­‐  using  OO  inheritance  -­‐     -­‐  an  example  -­‐   Inheritance  is  not  always  evil!   ©  2014  Philip  Schwarz   hHps://twiHer.com/philip_schwarz   philip.johann.schwarz@gmail.com         This  work  is  licensed  under  a   Crea3ve  Commons  AHribu3on-­‐NonCommercial-­‐NoDerivs  3.0  Unported  License.  
  • 2. This  talk  complements  and  extends  some  aspects  of  my  OCP  talk:   Downloadable  at  hHps://github.com/philipschwarz/presenta3ons  
  • 3. Shortly  aVer  giving  the  OCP  talk  I  watched  the  following:   Sandi’s  talk  complements  and  extends  parts  of  mine  so  well       hHp://www.poodr.com/   that  I  just  HAVE  TO  show  you  the  video!  
  • 4. So  this  is  not  your  regular  talk.     I’ll  wrap  my  slides  around  her  talk   ‱  slides  at  the  beginning:   ‱  to  give  you  addi3onal  background  that   helps  you  follow  the  video   ‱  to  link  back  to  the  topics  of  my  other   presenta3on   ‱  slides  at  the  end:  to  recap  and  elaborate   some  of  Sandi’s  key  points   What  I’ll  actually  be  doing  is   showing  you  the  video  of  Sandi’s   talk  (A  talk  within  a  talk!).  
  • 6. The  Open-­‐Closed  Principle   Modules  should  be  both  open  and  closed   Bertrand  Meyer  Object  Oriented   SoVware  Construc3on   1988   We  want  modules  to  be  both                                  for  extension  and                              for  modiïŹca3on  
  • 7. the  two  goals  of     openness  and  closedness     with  tradiEonal   techniques   are  incompaEble  
  • 8. With  non-­‐OO  methods,     there  seem  to  be  only  2  soluEons,     equally  unsaEsfactory  
  • 9. If  non-­‐OO  methods  are  all  we  have,  then   Meyer  says  we  face  a  change  or  copy   dilemma   CHANGE   COPY  
  • 10. A  B   C   D   E   A  module  and  its  clients   A’  F   G   H   I   New  clients  which  need  A’,  an  adapted  or  extended  version  of  A   Typical  situa3on  where  the  needs  for  Open  and  Closed   modules  are  hard  to  reconcile   =    client  of  
  • 11. Analysability   Stability   Reliability   soluEon   -­‐ -­‐ -­‐ Analysability   Stability   Reliability   soluEon   -­‐   -­‐   -­‐   With  non-­‐OO  methods,  there  are  only  only  2  soluEons  available  to  us,     BOTH  UNSATISFACTORY   mulEple  maintenance  problem   Change  by     ModiïŹca3on   CHANGE   COPY  
  • 12. A  B   C   D   E   A’  F   G   H   I   So  how  can  we  have  modules  that  are  both                                and                                    ?   How  can  we  keep  A  and  everything  in  the  top  part  of  the Â ïŹgure  unchanged,  
   
while  providing  A’  to  the  boHom  clients,  and  avoiding  duplicaEon  of  soTware?    
  • 13. A  B   C   D   E   A’  F   G   H   I   With  the  OO  concept  of  inheritance   Inheritance  allows  us  to  get  out  of  the  CHANGE  OR  COPY  dilemma
   
because  inheritance  allows  us  to  deïŹne  a  new  module  A'  in  terms  of  an  exisEng   module  A,  
by  staEng  only  the  diïŹ€erences  between  the  two     A’  deïŹnes  new  features,  and  redeïŹnes  (i.e.  modiïŹes)   one  or  more  of  A’s  features   inherits  from   Change  by     Addi3on  
  • 14. Hacking = Slipshod approach to building and modifying code Slipshod = Done poorly or too quickly; careless. The  Hacker     may  seem     bad   but  oVen  his     heart  is  pure.  
  • 15. He  sees  a  useful  piece  of  soVware,  which  is  almost  able  to  address  the  needs  of  the     moment,  more  general  than  the  soVware’s  original  purpose.     Hacker     Spurred  by  a  laudable  desire  not  to  redo  what  can  be  reused,  our  hacker  starts     modifying  the  original  to  add  provisions  for  new  cases   soluEon  
  • 16. The  impulse  is  good  but  the  eïŹ€ect   is  oVen  to  pollute  the  soVware   with  many  clauses  of  the  form     if  that_special_case  then
   if  (<special  case  D>)   then 
   if  (<special  case  C>)   then 
   if  (<special  case  B>)   then 
   if  (<special  case  A>)   then 
   switch!
  • 17. Open-Closed Principle =   One  way  to  describe  the  OCP  and  the  consequent  OO  techniques  is  to  think  of  them   as  organised  hacking   Hacking   The  organised  form  of  hacking  will  enable  us  to  cater  to  the  variants     without  aïŹ€ecEng  the  consistency  of  the  original  version.   Inheritance   Change  by     ModiïŹca3on   Change  by     Addi3on  
  • 18. extends  is  evil!!!!!   But,  using  inheritance  is  no  longer  the  main  approach   to  sa3sfying  the  OCP   Allen  Holub   2004   2003  
  • 19. Using  inheritance  is  s3ll  one  of  the  ways  of  saEsfying  the  OCP,     and  was  considered  THE  approach  for  a  long  while   Why  extends  is  evil   1988  -­‐  1st  ed.     1997  –  2nd  ed.     1995     That  started  changing  with  the    emergence  of  the     design  techniques  presented  in  Design  Paerns   2003  
  • 20. mulEple  maintenance  problem   Change  by     ModiïŹca3on   CHANGE   soluEon   COPY     soluEon   Hacker     Change  by     Addi3on   OCP   soluEon   Chooses   Chooses   switch! extends     is  evil!!!!!   But
  
  • 22. Sandi  deals  with  a  perfect   example  of  the   unmaintainable  mess  that   you  end  up  with  when  you   keep  extending  code  by   adding  condi3onals   switch!
  • 23. The  CondiEonal  Sandi     will  be  dealing  with   switch!
  • 24. REFACTOR   Sandi  deals  with  the  43-­‐line  condi3onal  by  refactoring  it     so  it  sa3sïŹes  the  Open  Closed  Principle   switch!
  • 25. Inheritance           Sandi  uses  the  original  approach  to  sa3sfying  the  OCP:     using  OO  inheritance                 So  we  get  a  nice  example  of  the  technique   inheritance  is  not  evil,     and  I  can  tell  you  exactly  when  it   is  safe  to  use  it  
  • 26. switch! Sandi’s  talk  also
     looks  a  liHle  bit  at  why     switch  creep  takes  root   acts  as  an  example  of   refactoring  from  procedural   code  to  OO  code   contains  other  bits  of     her  design  wisdom   Refactoring  
  • 27. Sandi’s  talk  is  centered  around  the  Gilded  Rose  Kata  
  • 28. A  code  kata  is  an  exercise  in  programming   which  helps  a  programmer  hone  their  skills   through  prac3ce  and  repe33on   A  kata  is  an  exercise  in  karate  where  you   repeat  a  form  many,  many  3mes,  making  liHle   improvements  in  each   The  intent  behind  a  code  kata  is  similar  
  • 29. The  Gilded  Rose  Inn   An  Inn  is  where  travellers  can  seek  lodging  and,  usually,  food  and  drink   The  Gilded  Rose  Kata  centers  around  a Â ïŹc3onal  Inn  in  a  game  called  World  of  WarcraT      
  • 30. Hi  and  welcome  to  team  Gilded  Rose.  As  you  know,  we  are  a   small  inn  with  a  prime  loca3on  in  a  prominent  city  ran  by  a   friendly  innkeeper  named  Allison.       hHp://iamnotmyself.com/2011/02/13/refactor-­‐this-­‐the-­‐gilded-­‐rose-­‐kata/   The  Original  Gilded  Rose  Kata   Aged  Brie   Sulfuras,  Hand  of  Ragnaros   Backstage  Pass  to  a     TAFKAL80ETC  concert   +5  Dexterity  Vest   Elixir  of  the     Mongoose     We  also  buy  and  sell  only  the Â ïŹnest  goods.  Unfortunately,  our   goods  are  constantly  degrading  in  quality  as  they  approach   their  sell  by  date.  We  have  a  system  in  place  that  updates  our   inventory  for  us.  It  was  developed  by  a  no-­‐nonsense  type   named  Leeroy,  who  has  moved  on  to  new  adventures.  
  • 31. Your  task  is  to  add  the  new  feature  to  our  system  so     that  we  can  begin  selling  a  new  category  of  items.       First  an  introduc3on  to  our  system
  
  • 32. ‘sellIn’  denotes  the  number  of  days  we  have  to  sell  the  Item   int sellIn = 4;! All  items  have  a     sellIn  value    
  • 33. ‘quality’  denotes  how  valuable  the  item  is   int quality = 7;! All  items  have  a     quality  value    
  • 34. At  the  end  of  each  day  the  system  lowers  both  values  for  every  item   for (Item item : items) ! {! ! ! ! ! ! }! sellIn -= X! quality -= Y!
  • 36. ! ! ! ! ! ! quality -= Y! Once  the  sell  by  date  has  passed
   
quality  degrades  twice  as  fast   x  2  
  • 37. ‱  Once  the  sell  by  date  has  passed,  Quality  degrades  twice  as  fast   ‱  The  Quality  of  an  item  is  never  nega3ve   ‱  “Aged  Brie”  actually  increases  in  Quality  the  older  it  gets   ‱  The  Quality  of  an  item  is  never  more  than  50   ‱  “Sulfuras”,  being  a  legendary  item,  never  has  to  be  sold  or  decreases  in  Quality   ‱  “Backstage  passes”,  like  aged  brie,  increases  in  Quality  as  it’s  SellIn  value     approaches;      Quality  increases  by  2  when  there  are  10  days  or  less  and  by  3  when  there  are      5  days  or  less  but  Quality  drops  to  0  aVer  the  concert   That’s  just  the Â ïŹrst  of  several  addi3onal  ‘rules’  aïŹ€ec3ng  items:  
  • 38. It  is  not  hard  to   imagine  developers   implemen3ng  those   requirements  one   at  a  3me,  each  3me   adding  one  or  more   branches  to  the   condi3onal.   switch!
  • 39. We  have  recently  signed  a  supplier  of  conjured   items.       Feel  free  to  make  any  changes  to  the   UpdateQuality  method  and  add  any  new  code   as  long  as  everything  s3ll  works  correctly.   However,  do  not  alter  the  Item  class  or  Items   property  as  those  belong  to  the  goblin  in  the   corner  who  will  insta-­‐rage  and  one-­‐shot  you  as   he  doesn’t  believe  in  shared  code  ownership   Conjured  Item   Conjured     Mana  Cake   X   This  requires  an  update  to  our  system:     “Conjured”  items  degrade  in  Quality  twice  as   fast  as  normal  items  
  • 40. That  was  the  original  kata  (in  C#)  
  • 41. Emily  Bache   This  is  designed  as  a  refactoring  kata,  where  you  take  this  less  than  clean  code,  and   transform  it  via  small  steps  into  something  that  can  be  maintained  and  extended.   Conjured  Item   When  you  have  the  code  under  control,  it   should  be  easy  to  add  the  new  feature  for   “Conjured”  items.  
  • 42. Two  approaches  to  this  Kata   ‱  In  the  original  version  of  this  Kata,  there  were  no  tests  provided,   only  a  textual  descrip3on  of  the  requirements.     ‱  In  a  later  addiEon,  I  added  Text-­‐Based  (aka  Approval)  tests.       Emily  Bache   So  you  can  do  this  kata  in  two  ways,     ‱  either  wriEng  your  own  tests,  and  prac3ce  wri3ng  really  good  ones     ‱  or  just  jump  straight  to  the  refactoring  part,  leaning  on  the  text-­‐based  tests.  
  • 43. Sandi  takes  neither  of  these  approaches:     https://github.com/jimweirich/gilded_rose_kata The  original  had  no  tests.  Since  this  is  a  refactoring  kata,  I  feel  the   tests  are  important  and  provide  a  fairly  complete  test  suite.  Just   delete  the  tests  if  you  wish  to  "go  it  alone".   she  uses  a  Ruby  version  of  the  kata  that  already  has  tests  
  • 44. Sandi  also  ignores  the  restric3on  we  saw  earlier:     ‘do  not  alter  the  Item  class  or  Items  property’         In  fact  she  goes  further:  she   doesn’t  even  look  at  the   explana3on  of  the  problem.   She  just  takes  the  code  and  tries  to     add  the  required  new  func3onality   X   “But  I  didn’t  do  that  [look  at  the   problem  explana3on].  I  wanted  to   treat  this  problem  as  if  it  was  a  real   produc3on  problem,  and  that  my  only   source  of  informa3on  was  the  tests   and  the  code”  
  • 45. Watch  ‘All  the  LiHle  Things’   (just  under  40  minutes  long)   hHps://www.youtube.com/watch?v=8bZh5LMaSmE     hHp://www.confreaks.com/videos/3358-­‐railsconf-­‐all-­‐the-­‐liHle-­‐things  
  • 46. Let’s Recap and Elaborate Some of Sandi’s Take Home Points
  • 47. RailsConf  2014   Ruby  on  Ales  2014   There  are  two  versions  of  Sandi’s  Talk:   In  recapping,  I’ll  sample  from  both  versions.  
  • 48. Your  task  is  to  add  the  new  feature  to  our  system  so     that  we  can  begin  selling  a  new  category  of  items.      
  • 49. I  went  and  I  tried.     I  tried  really  hard,  but  I  failed   miserably.  I  could  not  do  it.     I  spent  hours  trying
     I  found  it  impossible  
  • 50. if 
 ! then 
 ! else 
! IMPOSSIBLE   ALL   If  it  is  so  hard,  if  it  is  impossible  to   change  that  if  statement,     and  I  am  supposed  to  be  all  OOP,       then  you  have  to  wonder  why  I  even  tried.     What  made  me  choose  as  my  strategy,   changing  that  if  statement?  
  • 51. Well  it  is  because  I  felt     I  was  supposed  to  do  it.   And  here  is  what  happens,  right?   you  write  some  code   someone  asks  for  a  change     What  do  we  do?  You  go  looking  around  the   codebase  for  code  that  is  the  closest  thing  to   the    thing  that  you  are  trying  to  do.  You  put   the  new  code  there  
  • 52. if 
 ! then 
 ! else 
! if 
 ! then 
 ! else 
! Maybe  the Â ïŹrst  person  that  wrote  it  put  an  if   statement  in.     And  if  statements  exert  gravita3onal  pull.     and  if  that  thing  already  has  an  if  statement,   well  they  just  put  in  another  branch  on  it,   right?  that’s  how  it  works.   Novices  especially,  they  are  afraid  to  make   new  objects  so  the  just  go  put  more  code  in     where  they  can Â ïŹnd  the  thing  they  are  trying   to  add    
  • 53. So,  the  natural  tendency  of  code  is  to  grow   bigger  and  bigger  and  bigger,  and  there  comes   a  point  when  it  gets  big  enough  that  it  3ps   DIS   and  it  feels  like  even  if  you  are  the  kind   of  person  who  would  normally  make  a   new  class,                 that  you  would  be  doing  the  past  and  the   future  a  disservice  by  pu|ng  the  code   anywhere  else.  
  • 54. at  that  point  it  is     so  big  that  you  cannot   imagine  pu|ng  code   anywhere  else.   if 
 ! then 
 ! else 
! if 
 ! then 
 ! else 
! when  you  have  a  5000  line  in   an  ac3ve  record,  you  do  not   make  a  20  line  service  object   that  goes  with  it  when  you   have  a  new  requirement,   you  feel  like  you  have  to  put   the  code  where  it  is   Service   X  
  • 55. Let’s  take  a  2  minute  detour  to  see  a  real-­‐world  example  of  a  condi3onal   that  has  grown  well  beyond  the  3pping  point.      
  • 57. switch! Detour  over.   Now  back  to   Sandi’s  talk   Ăšïƒš Â Ăšïƒš Â Ăšïƒš  
  • 58. If  the  paHern  is  a  good  one   then  the  code  gets  beHer,  and   if  the  paHern  is  a  bad  one,  we   exacerbate  the  problem.   We  have  a  bargain  to   follow  the  paHern.      
  • 59. And  so  the     paHern     failed  me.     That  if  statement,  it   felt  like  it  had   evolved,     evolu3onarily,         if 
 ! then 
 ! else 
! if 
 ! then 
 ! else 
! and  that  any   change  I  made  I   was  supposed  to   make  there  
  • 60. But  fortunately  I  couldn’t  do  it.     And  so  I  decided  I  would  make  a  new  paHern:     I  am  not  going  to  try   to  add  Conjured,  I   am  going  to  refactor   the  code  so  that  it  is   simpler  and  so  that  I   can  then  add   Conjured.     Conjured  Item  
  • 61. inheritance   But,  but
extends  is  evil!!!!   Sandi  sa3sïŹed  the  OCP  using  inheritance  
  • 62. Despite  the  fact  that  people   tell  you  ‘never  ever  ever  use   inheritance’
   inheritance     is  not  evil!!!!!   X  
  • 63. 1.  The  hierarchy  is  shallow  and  narrow,  it  is  not  deep  and  wide   If  those  condi3ons  are  all  true  for  the  thing  that  you  are  doing   I  will  give  you  dispensa3on  to   use  it  in  a  very  speciïŹc  case     2.  The  subclasses  use  every  bit  of  code  that  is  in  the  superclass     3.  If  you  draw  a  mental  image  of  your  object  graph,  this  lile  hierarchical  cluster  is  at                  the  edge  of  the  graph  (it  is  on  a  leaf  node  of  your  object  hierarchy)   then  it  is  hard  to Â ïŹnd  another  more  intenEon-­‐revealing  way  to  write  this  code.  
  • 64. 1.  The  hierarchy  is  shallow  and  narrow,  it  is  not  deep  and  wide   2.  The  subclasses  use  every  bit  of  code  that  is  in  the  superclass   Let’s now look at how Sandi elaborates on her first two conditions In her book: POODR
  • 65. 1.  The  hierarchy  is  shallow  and  narrow,  it  is  not  deep  and  wide   A  hierarchy’s  shape  is  deïŹned  by  its  overall  breadth  and  depth   It  is  this  shape  that  determines  ease  of  use,  maintenance,  and  extension.   Here  are  a  few  of  the  possible  variaEons  of  shape:  
  • 66. Easy  to  understand   Slightly  more  complicated.   A  bit  more  challenging   Have  a  tendency  to  get  wider   DiïŹƒcult  to  understand     and  costly  to  maintain   SHOULD  BE  AVOIDED  
  • 67. The  problems  with  deep  hierarchies   They  have  a  very  long  search     path  for  message  resolu3on   They  provide  numerous  opportuni3es  for  objects  in  that  path  to  add  behavior  as  the   message  passes  by.   Objects  depend  on  everything  above  them,  so  a  deep  hierarchy  has     a  large  set  of  built-­‐in  dependencies,  each  of  which  might  someday  change.   Programmers  tend  to  be  familiar  with  just  the  classes  at  their  tops  and  boHoms;   *  They  tend  to  understand  only  the  behavior  implemented  at  the  boundaries          of  the  search  path   *  The  classes  in  the  middle  get  short  shriT.   *  Changes  to  these  vaguely  understood  middle  classes  stand  a  greater  chance  of                  introducing  errors.  
  • 68. 1.  The  hierarchy  is  shallow  and  narrow,  it  is  not  deep  and  wide  
  • 69. 2.  “The  subclasses  use  every  bit  of  code  that  is  in  the  superclass”   What  does  she  mean?  Let’s  look  at  how  she  elaborates  this  in  POODR     Subclasses  are  specializaEons  of  their  superclasses.     A  MountainBike  should  be  everything  a  Bicycle  is,  plus  more.   Any  object  that  expects  a  Bicycle  should  be  able  to  interact  with  a   MountainBike  in  blissful  ignorance  of  its  actual  class.   These  are  the  rules  of  inheritance;  break  them  at  your  peril.    
  • 70. For  inheritance  to  work
the  objects  that  you  are   modeling  must  truly  have  a  generalizaEon–specializaEon   rela3onship.     [When]  subclasses
are  not   truly  specializaEons  of  their     superclasses,  the  hierarchy     becomes  untrustworthy.   IS-­‐A   __   trust  
  • 71. Untrustworthy  hierarchies   force  objects  that  interact   with  them  to  know  their   quirks   trust   Inexperienced  programmers     do  not  understand  and   cannot Â ïŹx  a  faulty  hierarchy  
  • 72. Knowledge  of  the  structure     of  the  hierarchy  leaks  into     the  rest  of  the  applica3on,     creaEng  dependencies  that     raise  the  cost  of  change.     if (bicycle instanceof MountainBike) { // do XYZ } if (bicycle instanceof MountainBike) { // do XYZ } if (bicycle instanceof MountainBike) { // code that knows about } oTen  by  explicitly     checking  the  classes   of  objects.     when  asked  to  use     one  they  will  embed     knowledge  of  its     quirks  into  their  own     code,  
  • 73. All  of  the  code  in  an   abstract  superclass     should  apply  to  every     class  that  inherits  it   Superclasses  should  not   contain  code  that  applies     to  some,  but  not  all,   subclasses.   =======   =======   =======   =======     =======     =======   =======   =======   =======   =======   =======   =======   =======   =======   =======   =======  
  • 74.   When  interac3ng  with   these  awkward  objects,   programmers  are  forced   to  know  their  quirks  and   into  dependencies  that   are  beHer  avoided.   Faulty  abstracEons  cause   inheri3ng  objects  to   contain  incorrect  behavior;   aHempts  to  work  around   this  erroneous  behavior   will  cause  your  code  to   decay.    
  • 75. subclasses  agree  to  a   contract     they  promise  to  be     subsEtutable     for  their  superclasses.  
  • 76. Subclasses  that  fail  to  honor     their  contract  are  diïŹƒcult  to     use.  They’re  “special”and     cannot  be  freely  subsEtuted     for  their  superclasses.        These  subclasses  are  declaring  that     they  are  not  really  a  kind-­‐of  their     superclass  and  cast  doubt  on  the     correctness  of  the  en3re  hierarchy.   They  are  not  permied     to  do  anything  that     forces  others  to  check     their  type  in  order  to     know  how  to  treat  them     or  what  to  expect  of  them.     if (bicycle instanceof MountainBike) { // code that knows } trust   IS-­‐A   __  
  • 77. Let’s  look  in  more  detail  at  the  LSP  to     beHer  understand  what  Sandi  means     by  contract,  and  subsEtutability   When  you  honor  the  contract,  you  are   following  the  Liskov  SubsEtuEon   Principle,  which  is  named  for  its   creator,  Barbara  Liskov,  and  supplies   the  “L”  in  the  SOLID  design  principles   Barbara  Liskov   The  Liskov  SubsEtuEon  Principle  (LSP)  -­‐  1988  
  • 78. Let  q(x)  be  a  property  provable  about   objects  x  of  type  T.       Then  q(y)  should  be  provable  for  objects  y   of  type  S  where  S  is  a  subtype  of  T.   [in  a  Type  hierarchy]  the  supertype’s  behavior  must  be  supported  by  the  subtypes:   subtype  objects  can  be  subsEtuted  for  supertype  objects  without  aïŹ€ecEng  the   behavior  of  the  using  code.     Behaviour  of  -­‐-­‐-­‐-­‐>   supported     by  -­‐-­‐-­‐-­‐>   2000  
  • 79. [the  LSP]  allows  using  code  to  be  wrien  in  terms  of  the  supertype     speciïŹcaEon,  yet  work  correctly  when  using  objects  of  the  subtype.     For  example,  code  can  be  wriHen  in  terms  of  the  Reader  type,  yet  work  correctly   when  using  a  BuïŹ€eredFileReader.   private void foo(BufferedReader bufferedReader) throws IOException { 
 bar(bufferedReader); 
 } private void bar(Reader reader) throws IOException { 
 System.out.println( reader.read() ); 
 }
  • 80. the  subsEtuEon  principle  requires  that  the  subtype   speciïŹca3on  support  reasoning  based  on  the  supertype   speciïŹca3on.       Three  proper3es  must  be   supported:     1. Signature  Rule     2. Methods  Rule     3. ProperEes  Rule    
  • 81. The  subtype  objects  must  have  all  the  methods  of  the  supertype,  and  the  signatures  of   the  subtype  methods  must  be  compaEble  with  the  signatures  of  the  corresponding   supertype  methods.   This  rule  is  enforced  by  the  compiler,  so  we  are  all  familiar  with  it.   #1  The  Signature  Rule    
  • 82. 1. Signature  Rule     2. Methods  Rule     3. ProperEes  Rule     Before  we  can  cover  the  other  two  rules  we     must  brieïŹ‚y  look  at  Design  by  Contract   The  other  two  rules  cannot  be  checked  by  a     compiler  because  they  require  reasoning  about     the  meaning  of  speciïŹca3ons  
  • 83. Viewing  the  rela3onship  between  a  class  and   its  clients  as  a  formal  agreement  ,  expressing   each  party’s  rights  and  obligaEons   DbC  uses  precondiEons,  postcondiEons  and  class  invariants     to  document  (or  beHer,  programma3cally  assert)     the  contract  between  classes,  methods  and  their  callers.   1986   Bertrand  Meyer   Design  by  Contract  (DbC)     DbC  
  • 84. Condi3ons  that  must  always  be  true  of  a  class.   They  are  implicitly  added  to  the  precondiEons  and  postcondiEons  of  every  method.   DbC   Object  Oriented   SoTware  ConstrucEon   Condi3ons  that  must  be  true  before  a  method  can  execute.     if  the  condi3ons  are  not  met,  it  is  a  bug  in  the  client.   Condi3ons  that  must  be  true  when  a  method  is Â ïŹnished  execuEng.     if  the  condi3ons  are  not  met,  it  is  a  bug  in  the  method.  
  • 87. #2  The  Methods  Rule     Calls  of  these  subtype  methods  must  “behave  like”  calls  to  the  corresponding   supertype  methods.   The  subtype  objects  must  have  all  the  methods  of  the  supertype,  and  the  signatures  of   the  subtype  methods  must  be  compaEble  with  the  signatures  of  the  corresponding   supertype  methods.   #1  The  Signature  Rule     What  does  Liskov  mean  by  “behave  like”?   Let’s  look  at  Meillir-­‐Jones’  explana3on,  in  terms  of     precondi3ons  and  postcondi3ons    
  • 88. ‱  Every  opera3on’s  precondiEon  is  no  stronger  than   the  corresponding  opera3on  in  the  superclass       ‱  Every  opera3on’s  postcondiEon  is  at  least  as   strong  as  the  corresponding  opera3on  in  the   superclass         a  subtype  method  can   ‱  expect  the  same  or  less     ‱  promise  the  same  or  more   Explana3on  of  “methods  must  ‘behave   like’  calls  to  the  corresponding  supertype   methods”   Meillir-­‐Jones   A  subtype  method  can   weaken  the  precondiEon   and  can  strengthen  the   postcondiEon   1999  
  • 89. #2  The  Methods  Rule     Calls  of  these  subtype  methods  must  “behave  like”  calls  to  the  corresponding   supertype  methods.   The  subtype  objects  must  have  all  the  methods  of  the  supertype,  and  the  signatures  of   the  subtype  methods  must  be  compaEble  with  the  signatures  of  the  corresponding   supertype  methods.   #1  The  Signature  Rule     The  subtype  must  preserve  all  properEes  that  can  be  proved  about   supertype  objects.   #3  The  ProperEes  Rule     The  class  invariant  of  a  subclass  must  be  equal  to  or   stronger  than  that  of  its  superclass  
  • 90. An  Example  of  a  subclass  viola3ng   the  contract  of  its  superclass   Robert  MarEn  (aka  Uncle  Bob)   Agile  SoTware  Development   Principles,  Paerns  and  PracEces   2002  
  • 91. public class Rectangle { private Point topLeft; private double width; private double height; public void setWidth(double width) { this.width = width; } public double getWidth() { return width; } public void setHeight(double height) { this.height = height; } public double getHeight() { return height; } 
 } Imagine  that  this  applica3on  works  well   and  is  installed  in  many  sites.   One  day,  the  users  demand  the  ability  to   manipulate  squares  in  addi3on  to   rectangles.   It  is  oVen  said  that  inheritance   is  the  IS-­‐A  relaEonship.     In  other  words,  if  a  new  kind   of  object  can  be  said  to  fulïŹll  the   IS-­‐A  relaEonship  with  an  old  kind  of   object,  the  class  of   the  new  object  should  be  derived   from  the  class  of  the  old  object.  
  • 92. public class Rectangle! {! !
! !! !public void setWidth(double width)! !{ ! ! !this.width = width; ! !} !! !
! ! public void setHeight(double height) { this.height = height; } 
! }!For  all  normal  intents  and  purposes,  a  square  is  a  rectangle.   So  it  is  logical  to  view  the  Square  class  as     being  derived  from  the  Rectangle  class.   IS-­‐A   ! public class Square extends Rectangle! { !! }!
  • 93. public class Rectangle! {! !
! @Ensures({“getWidth() = width”})! !public void setWidth(double width)! !{ ! ! !this.width = width; ! !} !! !
! !@Ensures({“getHeight() = height”})! public void setHeight(double height) { this.height = height; } 
! }! @Invariant(“getWidth() = getHeight()”)! public class Square extends Rectangle! { !! }! A  square  has  the  invariant  that  its  width  and  height  are  idenEcal,     but  Square  inherits  Rectangle’s  seHers,  which  do  not  preserve  the  invariant.   public void f(Square square) { square.setWidth(5); assert square.getHeight() == 5; } There  is  a  problem  though   The  asserEon  fails   To  see  why,  let’s  make  the  contract  explicit  
  • 94. public class Rectangle! {! !
! @Ensures({“getWidth() = width”})! !public void setWidth(double width)! !{ ! ! !this.width = width; ! !} !! !
! !@Ensures({“getHeight() = height”})! public void setHeight(double height) { this.height = height; } 
! }! We  can  sidestep  the  problem  by  overriding  the  seHers.   @Invariant(“getWidth() = getHeight()”)! public class Square extends Rectangle! {! @Ensures({“getWidth() = width”})! !public void setWidth(double width)! !{ ! ! !this.width = width; ! ! !this.height = width; ! !} !! ! @Ensures({“getHeight() = height”})! public void setHeight(double height) { this.height = height; ! !this.width = height; } !! }! Now  Square  and  Rectangle  appear  to  work.  No  maHer  what  you  do  to  a  Square  object,  it   will  remain  consistent  with  a  mathema3cal  square,  and  regardless  of  what  you  do  to  a   Rectangle  object,  it  will  remain  a  mathema3cal  rectangle.  
  • 95. public class Rectangle! {! !
! @Ensures({“getWidth() = width”})! !public void setWidth(double width)! !{ ! ! !this.width = width; ! !} !! !
! !@Ensures({“getHeight() = height”})! public void setHeight(double height) { this.height = height; } 
! }! @Invariant(“getWidth() = getHeight()”)! public class Square extends Rectangle! {! @Ensures({“getWidth() = width”})! !public void setWidth(double width)! !{ ! ! !this.width = width; ! ! !this.height = width; ! !} !! ! @Ensures({“getHeight() = height”})! public void setHeight(double height) { this.height = height; ! !this.width = height; } !! }! The  asserEon  now  passes.   The  invariant  of  the  Square  is  now  sa3sïŹed.   public void f(Square square) { square.setWidth(5); assert square.getHeight() == 5; } Moreover,  you  can  pass  a  Square  into  a   func3on  that  accepts  a  Rectangle,  and  the   Square  will  s3ll  act  like  a  square  and  will   remain  consistent.  
  • 96. public class Rectangle! {! !
! @Ensures({“getWidth() = width”})! !public void setWidth(double width)! !{ ! ! !this.width = width; ! !} !! !
! !@Ensures({“getHeight() = height”})! public void setHeight(double height) { this.height = height; } 
! }! So  we  might  conclude  that  the  design  is  now  self-­‐consistent  and  correct.     @Invariant(“getWidth() = getHeight()”)! public class Square extends Rectangle! {! @Ensures({“getWidth() = width”})! !public void setWidth(double width)! !{ ! ! !this.width = width; ! ! !this.height = width; ! !} !! ! @Ensures({“getHeight() = height”})! public void setHeight(double height) { this.height = height; ! !this.width = height; } !! }! However,  this  conclusion  would  be  amiss.  A  design  that  is  self-­‐consistent  is  not   necessarily  consistent  with  all  its  users!    
  • 97. public class Rectangle! {! !
! @Ensures({“getWidth() = width”})! !public void setWidth(double width)! !{ ! ! !this.width = width; ! !} !! !
! !@Ensures({“getHeight() = height”})! public void setHeight(double height) { this.height = height; } 
! }! public void g(Rectangle rectangle) { rectangle.setWidth(5); rectangle.setHeight(4); assert rectangle.getArea() == 20; } Consider  a  client’s  func3on  g:   @Invariant(“getWidth() = getHeight()”)! public class Square extends Rectangle! {! @Ensures({“getWidth() = width”})! !public void setWidth(double width)! !{ ! ! !this.width = width; ! ! !this.height = width; ! !} !! ! @Ensures({“getHeight() = height”})! public void setHeight(double height) { this.height = height; ! !this.width = height; } !! }!
  • 98. public class Rectangle! {! !
! @Ensures({“getWidth() = width”})! !public void setWidth(double width)! !{ ! ! !this.width = width; ! !} !! !
! !@Ensures({“getHeight() = height”})! public void setHeight(double height) { this.height = height; } 
! }! public void g(Rectangle rectangle) { rectangle.setWidth(5); rectangle.setHeight(4); assert rectangle.getArea() == 20; } This  func3on  sets  the  width  and  height  of     what  it  believes  to  be  a  Rectangle.     @Invariant(“getWidth() = getHeight()”)! public class Square extends Rectangle! {! @Ensures({“getWidth() = width”})! !public void setWidth(double width)! !{ ! ! !this.width = width; ! ! !this.height = width; ! !} !! ! @Ensures({“getHeight() = height”})! public void setHeight(double height) { this.height = height; ! !this.width = height; } !! }!   The  func3on  works Â ïŹne  for  a  Rectangle  but   fails  if  passed  a  Square.       Problem:  The  author  of  g  assumed  that   changing  the  width  of  a  Rectangle  leaves  its   height  unchanged.  
  • 99. @Invariant(“getWidth() = getHeight()”)! public class Square extends Rectangle! {! @Ensures({“getWidth() = width”})! !public void setWidth(double width)! !{ ! ! !this.width = width; ! ! !this.height = width; ! !} !! ! @Ensures({“getHeight() = height”})! public void setHeight(double height) { this.height = height; ! !this.width = height; } !! }! public class Rectangle! {! !
! @Ensures({“getWidth() = width”})! !public void setWidth(double width)! !{ ! ! !this.width = width; ! !} !! !
! !@Ensures({“getHeight() = height”})! public void setHeight(double height) { this.height = height; } 
! }! Clearly,  it  is  reasonable  to  assume  that  changing  the  width  of  a  rectangle  does  not   aïŹ€ect  its  height!     In  fact  it  is  so  obviously  right  that  we  didn’t  even  bother  explicitly  adding  it  as  a   postcondi3on  of  Rectangle’s  seHers,  we  leV  it  implicit!     Let’s  make  it  explicit.  
  • 100. public class Rectangle! {! !
! @Ensures({! “getWidth() = width! getHeight() = old(getHeight())”})! !public void setWidth(double width)! !{ ! ! !this.width = width; ! !} !! !
! !@Ensures({! “getHeight() = height! getWidth() = old(getWidth())”})! public void setHeight(double height) { this.height = height; } ! }! Clearly,  it  is  reasonable  to  assume  that  changing  the  width  of  a  rectangle  does  not   aïŹ€ect  its  height!   @Invariant(“getWidth() = getHeight()”)! public class Square extends Rectangle! {! @Ensures({“getWidth() = width”})! !public void setWidth(double width)! !{ ! ! !this.width = width; ! ! !this.height = width; ! !} !! ! @Ensures({“getHeight() = height”})! public void setHeight(double height) { this.height = height; ! !this.width = height; } !! }!   In  fact  it  is  so  obviously  right  that  we  didn’t  even  bother  explicitly  adding  it  as  a   postcondi3on  of  Rectangle’s  seHers,  we  leV  it  implicit!     Let’s  make  it  explicit.  
  • 101. public class Rectangle! {! !
! @Ensures({! “getWidth() = width”! getHeight() = old(getHeight())”})! !public void setWidth(double width)! !{ ! ! !this.width = width; ! !} !! !
! !@Ensures({! “getHeight() = height”! getWidth() = old(getWidth())”})! public void setHeight(double height) { this.height = height; } ! }! @Invariant(“getWidth() = getHeight()”)! public class Square extends Rectangle! {! @Ensures({“getWidth() = width”})! !public void setWidth(double width)! !{ ! ! !this.width = width; ! ! !this.height = width; ! !} !! ! @Ensures({“getHeight() = height”})! public void setHeight(double height) { this.height = height; ! !this.width = height; } !! }! Clearly,  the  postcondi3on  of  Square’s  setWidth  is  weaker  than  the  postcondi3on  of     Rectangle’s  setWidth,  since  it  does  not  enforce  the  constraint   (getHeight() = old(getHeight()).  Similarly  for  Square’s  setHeight.   Square’s  setWidth  and  setHeight  methods  violate  the  contract  of  the  Rectangle  base  class.  
  • 102. ‱  Every  opera3on’s  precondiEon  is  no  stronger  than  the   corresponding  opera3on  in  the  superclass       ‱  Every  opera3on’s  postcondiEon  is  at  least  as  strong  as  the   corresponding  opera3on  in  the  superclass         “methods  must  ‘behave  like’  calls  to  the   corresponding  supertype  methods”   #2  The  Methods  Rule     Square’s  seers  don’t     behave  like  Rectangle’s   Seers!   The  postcondiEons   of  Square’s  seers     are  weaker  than   those  of   Rectangle’s   seers!   1.  Signature  Rule     2.  Methods  Rule     3.  ProperEes  Rule     Square  Violates   Rectangle’s  contract  
  • 103. It  is  oVen  said  that  inheritance  is  the  IS-­‐A  rela3onship.       e.g.  a  square  is  a  rectangle,  therefore   Square  should  be  derived  from  the   Rectangle.   ISA   If  a  new  kind  of  object  can  be  said  to  fulïŹll  the  IS-­‐A  rela3onship  with  an   old  kind  of  object,  the  class  of  the  new  object  should  be  derived  from  the   class  of  the  old  object.   Flawed  reasoning  –  recap  
  • 104. But  IS-­‐A  is  about  behaviour.   In  OOD,  a  square  IS-­‐A  rectangle  only  if  it  behaves  like  a  rectangle,  if  it  honours   Rectangle’s  contract,  if  it  sa3sïŹes  the  LSP.     The  contract  may  be  implicit  (not  so  good).     A  square  is  a  rectangle,  but  only  in  a   geometrical  sense,  not  in  a  behavioural  sense.     In  OOD,  Square  violates  Rectangle’s  contract,  it  violates   the  LSP,  therefore  it  does  not  behave  like  a  Rectangle:  it   is  not  true  that  a  Square  IS-­‐A  Rectangle  and  therefore     Square  should  not  inherit  from  Rectangle.     IS-­‐A   __   X   X   It  may  be  expressed  in  comments  (beHer).     It  may  be  expressed  as  automated  unit  tests  (much  beHer).     Or  it  may  be  expressed  using  a  DbC  framework  (rare?).    
  • 105.               To  adhere  to  LSP  in  Java,  we  must  make  sure  that  developers  deïŹne  precondi3ons  and   postcondi3ons  for  each  of  the  methods  on  an  abstract  class.       X   In  order  to  take  advantage  of  LSP,  we  must   adhere  to  OCP  because  violaEons  of  LSP  also   are  violaEons  of  OCP,  but  not  vice  versa.   X  X   When  deïŹning  our  subclasses,  we  must  adhere  to  these  precondi3ons  and   postcondi3ons.       If  we  do  not  deïŹne  precondiEons  and  postcondiEons  for  our  methods,  it  becomes   virtually  impossible  to Â ïŹnd  violaEons  of  LSP.   Kirk     Knoernschild   The  Liskov  SubsEtuEon  Principle  is  one  of  the   prime  enablers  of  OCP.   We  can  think  of  the  Liskov  Subs3tu3on   Principle  (LSP)  as  an  extension  to  OCP.     2002  
  • 106. When  interac3ng  with   these  awkward  objects,   programmers  are  forced   to  know  their  quirks   and  into  dependencies   that  are  beHer  avoided.   when  asked  to  use  one   they  will  embed   knowledge  of  its  quirks   into  their  own  code   if (bicycle instanceof MountainBike) { // do XYZ } if (bicycle instanceof MountainBike) { // do XYZ } if (bicycle instanceof MountainBike) { // code that knows about } oVen  by  explicitly     checking  the  classes   of  objects.     Recap:  Sandi  on  consequences  of     untrustworthy  Hierarchies  
  • 107. every  viola3on  of  the   LSP  is  a  latent  viola3on   of  the  OCP     X   X   because  in  order  to   repair  the  damage  
   we  are  going  to  have   to  add  if  statements   and  hang   dependencies  upon   subtypes   if (bicycle instanceof MountainBike) { // do XYZ } if (bicycle instanceof MountainBike) { // do XYZ } if (bicycle instanceof MountainBike) { // code that knows about } Uncle  Bob  on  violaEons  of  LSP  
  • 108. Next  Eme  you  are  faced  with  adding  logic  to  a  non-­‐trivial  condiEonal,   don’t  just  follow  the  paern  and  add  another  branch.   See  if  the  condi,onal  is  one  of  those  that  can  be  refactored  to  the  OCP,     using  inheritance  if  necessary.     Next  Eme  you  consider  introducing  an  inheritance  hierarchy,  ask  yourself  if  it   meets  Sandi’s  criteria  for  using  inheritance.     If  not,  consider  the  consequences  of  going  ahead  (if  you  decide  to  do  so).  
  • 109. Next  Eme  you  create  a  base  class,  spend  some  Eme  thinking  about  how  its  contract    needs  to  be  expressed.     Is  it  really  acceptable  to  leave  it  implicit?  Is  it  so  obvious?     Is  it  workable  and  eïŹ€ecEve  to  express  the  contract  using  unit  tests?      If  not,  maybe  explore  the  possibility  of  using  a  DbC  framework.    If  not,  express  the  contract  using  unit  tests.  
  • 110. Next  Eme  you  create  a  derived  class,  verify  that  it  saEsïŹes  the  contract  of  its  superclass.   Next  Eme  you  come  across  instanceof  usages,  see  if  they  are  the  smell  of     an  untrustworthy  hierarchy.     If  it  doesn’t,  take  remedial  ac,on.   If  so, Â ïŹx  the  hierarchy.  
  • 112. References     All  images  sourced  from  hHp://www.google.co.uk/advanced_image_search,  so  see   there  for  details  of  which  are    subject  to  copyright     PracEcal  Object-­‐Oriented  Design  in  Ruby:  An  Agile  Primer  –  by  Sandi  Metz  |   Publica3on  Date:  September  15,  2012  |  ISBN-­‐10:  0321721330    |  ISBN-­‐13:   978-­‐0321721334     Agile  SoTware  Development,  Principles,  Paerns,  and  PracEces  –  by  Robert  C.   MarEn  |  Publica3on  Date:    October  25,  2002  |  ISBN-­‐10:  0135974445  |  ISBN-­‐13:   978-­‐0135974445     Object-­‐Oriented  SoTware  ConstrucEon  –  by  Bertrand  Meyer  |  Publica3on  Date:  3   April  1997  |  ISBN-­‐10:  0136291554  |  ISBN-­‐13:  978-­‐0136291558  |  Edi3on:  2     Program  Development  in  Java  –  AbstracEon,  SpeciïŹcaEon  and  OO  Design  –  by   Barbara  Liskov,  with  John  Guag  |  Publica3on  Date:  6  Jun  2000  |  ISBN-­‐10:   0201657686  |  ISBN-­‐13:  978-­‐0201657685      
  • 113.   Java  Design:  Objects,  UML,  and  Process  –  by  Kirk  Knoernschild  |  Publica3on  Date:   December  18,  2001  |    ISBN-­‐10:  0201750449  |  ISBN-­‐13:  978-­‐0201750447     The  Coding  Dojo  Handbook  -­‐  a  pracEcal  guide  to  creaEng  a  space  where  good   programmers  can  become  great  programmers  –  by  Emily  Bache  |  Publica3on  Date:   29  October  2013  |  hHps://leanpub.com/codingdojohandbook     Fundamentals  of  Object  Oriented  Design  in  UML  –  by  Meilir  Page-­‐Jones  |  Publica3on   Date:  November  13,  1999  |  ISBN-­‐13:  978-­‐0201699463    ISBN-­‐10:  020169946X       The  AnE-­‐IF  Campaign  -­‐  hHp://an3ifcampaign.com/     The  Gilded  Rose  Kata  -­‐  hHp://iamnotmyself.com/2011/02/13/refactor-­‐this-­‐the-­‐gilded-­‐rose-­‐kata/           References  (con3nued)     Â