Object Calisthenics (PyCon SK 2017)

90
Object Calisthenics 9 steps to better OO code

Transcript of Object Calisthenics (PyCon SK 2017)

Page 1: Object Calisthenics (PyCon SK 2017)

ObjectCalisthenics9stepstobetterOOcode

Page 2: Object Calisthenics (PyCon SK 2017)

Agenda

Learnhowtomakeourcodemore:

readablereusabletestablemaintainable

Page 3: Object Calisthenics (PyCon SK 2017)

Raiseyouhandifyouknowoneofthefollowing:

DRYKISSSOLIDYAGNIZenofPython

Page 4: Object Calisthenics (PyCon SK 2017)

Calisthenics

Page 5: Object Calisthenics (PyCon SK 2017)

Cal•is•then•ics-/ˌkaləsˈTHeniks/

Page 6: Object Calisthenics (PyCon SK 2017)

"Calisthenicsareexercisesconsistingofavarietyofgrossmotormovements;often

rhythmicalandgenerallywithoutequipmentorapparatus."

Wikipedia

Page 8: Object Calisthenics (PyCon SK 2017)

WrittenforJava

Page 9: Object Calisthenics (PyCon SK 2017)

Whybother?

Page 10: Object Calisthenics (PyCon SK 2017)

Codeisreadmorethanit'swritten

Authorunknown

Page 11: Object Calisthenics (PyCon SK 2017)

Youneedtowritecodethatminimizesthetimeitwould

takesomeoneelsetounderstandit-evenifthat

someoneelseisyou

ArtofReadableCodebyDustinBoswell,TrevorFoucher

Page 12: Object Calisthenics (PyCon SK 2017)

Rule#1

Onlyonelevelofindentationpermethod

Page 13: Object Calisthenics (PyCon SK 2017)

classBoard(object):def__init__(self,data):#Level0self.buf=""foriinrange(10):#Level1forjinrange(10):#Level2self.buf+=data[i][j]

Page 14: Object Calisthenics (PyCon SK 2017)

classBoard(object):def__init__(self,data):self.buf=""self.collect_rows(data)defcollect_rows(self,data):foriinrange(10):self.collect_row(data[i])defcollect_row(self,row):forjinrange(10):self.buf+=row[j]

Page 15: Object Calisthenics (PyCon SK 2017)

products=self.get_products_by_user(...)ifproductsisNone:products=self.get_products_by_media(...)ifproductsisNone:products=self.get_products_by_domain(...)ifproductsisNone:products=self.get_any_products(...):ifproductsisNone:raiseException('Accessdenied')else:...else:...else:...else:...

Page 16: Object Calisthenics (PyCon SK 2017)

Chainofcommand

Page 17: Object Calisthenics (PyCon SK 2017)

Benefits

SingleresponsibilityBetternamingShortermethodsReusablemethods

Page 18: Object Calisthenics (PyCon SK 2017)

Rule#2

Donotuseelsekeyword

Page 19: Object Calisthenics (PyCon SK 2017)

ifoptions.get_categories()isNone:...eliflen(options.get_categories())==1:...elifSPECIAL_CATEGORYinoptions.get_categories():...elifoptions.get_categories()andoptions.get_query():...elifoptions.get_content_type():...

Page 20: Object Calisthenics (PyCon SK 2017)

deflogin(self,request):ifrequest.user.is_authenticated():returnredirect("homepage")else:messages.add_message(request,messages.INFO,'Badcredentials')returnredirect("login")

Page 21: Object Calisthenics (PyCon SK 2017)

deflogin(self,request):ifrequest.user.is_authenticated():returnredirect("homepage")

messages.add_message(request,messages.INFO,'Badcredentials')returnredirect("login")

Page 22: Object Calisthenics (PyCon SK 2017)

deffunction(param):ifparamisnotNone:value=paramelse:value="default"

returnvalue

Page 23: Object Calisthenics (PyCon SK 2017)

deffunction(param):value="default"ifparamisnotNone:value=param

returnvalue

Page 24: Object Calisthenics (PyCon SK 2017)
Page 25: Object Calisthenics (PyCon SK 2017)

Extractcode

Page 26: Object Calisthenics (PyCon SK 2017)

Defaultvalue

Page 27: Object Calisthenics (PyCon SK 2017)

Polymorphism

Page 28: Object Calisthenics (PyCon SK 2017)

Strategypattern

Page 29: Object Calisthenics (PyCon SK 2017)

Statepattern

Page 30: Object Calisthenics (PyCon SK 2017)

Examples

https://github.com/gennad/Design-Patterns-in-Python

Page 31: Object Calisthenics (PyCon SK 2017)

https://www.quora.com/Is-it-true-that-a-good-programmer-uses-fewer-if-conditions-than-an-amateur

Page 32: Object Calisthenics (PyCon SK 2017)

BenefitsAvoidscodeduplicationLowercomplexityReadability

Page 33: Object Calisthenics (PyCon SK 2017)

Rule#3

Wrapprimitivetypesifithasbehaviour

Page 34: Object Calisthenics (PyCon SK 2017)

ValueObjectinDDD

Page 35: Object Calisthenics (PyCon SK 2017)

classValidator(object):defcheck_date(self,year,month,day):pass

#10thofDecemberor12thofOctober?validator=Validator()validator.check_date(2016,10,12)

Page 36: Object Calisthenics (PyCon SK 2017)

classValidator(object):defcheck_date(self,year:Year,month:Month,day:Day)->bool:pass

#Functioncallleavesnodoubt.validator.check_date(Year(2016),Month(10),Day(12))

Page 37: Object Calisthenics (PyCon SK 2017)

BenefitsEncapsulationTypehintingAttractssimilarbehaviour

Page 38: Object Calisthenics (PyCon SK 2017)

Rule#4

Onlyonedotperline

Page 39: Object Calisthenics (PyCon SK 2017)

OK:Fluentinterface

Page 40: Object Calisthenics (PyCon SK 2017)

classPoem(object):def__init__(self,content):self.content=content

defindent(self,spaces):self.content=""*spaces+self.content

returnself

defsuffix(self,content):self.content=self.content+"-"+content

returnself

Poem("RoadNotTravelled").indent(4)\.suffix("RobertFrost")\.content

Page 41: Object Calisthenics (PyCon SK 2017)

NotOK:getterchain

Page 42: Object Calisthenics (PyCon SK 2017)

classCartService(object):defget_token(self):token=self.get_service('auth')\.auth_user('user','password')\.get_result()\.get_token()

returntoken

#1.WhatifNoneisreturnedinsteadofobject?#2.Howaboutexceptionshandling?

Page 43: Object Calisthenics (PyCon SK 2017)

classField(object):def__init__(self):self.current=Piece()

classPiece(object):def__init__(self):self.representation=""

classBoard(object):defboard_representation(self,board):buf=''forfieldinboard:buf+=field.current.representation

returnbuf

Page 44: Object Calisthenics (PyCon SK 2017)

classField(object):def__init__(self):self.current=Piece()defadd_to(self,buffer):returnself.current.add_to(buffer)

classPiece(object):def__init__(self):self.representation=""defadd_to(self,buffer):returnbuffer+self.representation

classBoard(object):defboard_representation(self,board):buf=''forfieldinboard:buf=field.add_to(buf)

returnbuf

Page 45: Object Calisthenics (PyCon SK 2017)

BenefitsEncapsulationDemeter'slawOpen/ClosedPrinciple

Page 46: Object Calisthenics (PyCon SK 2017)

Rule#5

Donotabbreviate

Page 47: Object Calisthenics (PyCon SK 2017)

Whyabbreviate?

Page 48: Object Calisthenics (PyCon SK 2017)

Toomanyresponsibilities

Page 49: Object Calisthenics (PyCon SK 2017)

Nametoolong?

Page 50: Object Calisthenics (PyCon SK 2017)

Split&extract

Page 51: Object Calisthenics (PyCon SK 2017)

Duplicatedcode?

Page 52: Object Calisthenics (PyCon SK 2017)

Refactor!

Page 53: Object Calisthenics (PyCon SK 2017)

classOrder(object):defship_order(self):pass

order=Order()order.ship_order()

//vs

classOrder(object):defship(self):pass

order=Order()order.ship()

Page 54: Object Calisthenics (PyCon SK 2017)

acc=0//accumulator?accuracy?

pos=100//position?pointofsale?positive?

auth=None//authentication?authorization?both?

Page 55: Object Calisthenics (PyCon SK 2017)

BenefitsClearintentionsIndicateunderlyingproblems

Page 56: Object Calisthenics (PyCon SK 2017)

Rule#6

Keepyourclassessmall

Page 57: Object Calisthenics (PyCon SK 2017)

Whatissmallclass?15-20linespermethod50linesperclass10classespermodule

Page 58: Object Calisthenics (PyCon SK 2017)

BenefitsSingleResponsibilitySmallermodules

Page 59: Object Calisthenics (PyCon SK 2017)

Rule#7

Nomorethan2instancevariableperclass

Page 60: Object Calisthenics (PyCon SK 2017)

Classshouldhandlesinglevariablestate

Page 61: Object Calisthenics (PyCon SK 2017)

Insomecasesitmightbetwovariables

Page 62: Object Calisthenics (PyCon SK 2017)
Page 63: Object Calisthenics (PyCon SK 2017)

classCartService(object):def__init__(self):self.logger=Logger()self.cart=CartCollection()self.translationService=TranslationService()self.auth_service=AuthService()self.user_service=UserService()

Page 64: Object Calisthenics (PyCon SK 2017)

BenefitsHighcohesionEncapsulationFewerdependencies

Page 65: Object Calisthenics (PyCon SK 2017)

Rule#8

Firstclasscollections

Page 66: Object Calisthenics (PyCon SK 2017)

collectionsmodule

Page 67: Object Calisthenics (PyCon SK 2017)

BenefitsSingleResponsibility

Page 68: Object Calisthenics (PyCon SK 2017)

Rule#9

Donotusesetters/getters

Page 69: Object Calisthenics (PyCon SK 2017)

Accessorsarefine

Page 70: Object Calisthenics (PyCon SK 2017)

Don'tmakedecisionsoutsideofclass

Page 71: Object Calisthenics (PyCon SK 2017)

Letclassdoit'sjob

Page 72: Object Calisthenics (PyCon SK 2017)

Tell,don'task

Page 73: Object Calisthenics (PyCon SK 2017)

classGame(object):def__init__(self):self.score=0

defset_score(self,score):self.score=score

defget_score(self):returnself.score

#UsageENEMY_DESTROYED_SCORE=10game=Game()game.set_score(game.get_score()+ENEMY_DESTROYED_SCORE)

Page 74: Object Calisthenics (PyCon SK 2017)

classGame(object):def__init__(self):self.score=0defadd_score(self,score):self.score+=score

#UsageENEMY_DESTROYED_SCORE=10game=Game()game.add_score(ENEMY_DESTROYED_SCORE)

Page 75: Object Calisthenics (PyCon SK 2017)

BenefitsOpen/ClosedPrinciple

Page 76: Object Calisthenics (PyCon SK 2017)

Catch'emall!

Page 77: Object Calisthenics (PyCon SK 2017)

Catch'emall!1. Onlyonelevelofindentationpermethod,2. Donotuseelsekeyword,3. Wrapprimitivetypesifithasbehavior,4. Onlyonedotperline,5. Don’tabbreviate,6. Keepyourentitiessmall,7. Nomorethantwoinstancevariableperclass,8. FirstClassCollections,9. Donotuseaccessors

Page 78: Object Calisthenics (PyCon SK 2017)

Catch'emall!1. Onlyonelevelofindentationpermethod,2. Donotuseelsekeyword,3. Wrapprimitivetypesifithasbehavior,4. Onlyonedotperline,5. Don’tabbreviate,6. Keepyourentitiessmall,7. Nomorethantwoinstancevariableperclass,8. FirstClassCollections,9. Donotuseaccessors10. ???11. PROFIT!

Page 79: Object Calisthenics (PyCon SK 2017)

Homework

Page 80: Object Calisthenics (PyCon SK 2017)

Createnewprojectupto1000lineslong

Page 81: Object Calisthenics (PyCon SK 2017)

Applypresentedrulesasstrictlyaspossible

Page 82: Object Calisthenics (PyCon SK 2017)

Drawyourownconculsions

Page 83: Object Calisthenics (PyCon SK 2017)

Customizetheserules

Page 84: Object Calisthenics (PyCon SK 2017)

Finalthoughts

Page 85: Object Calisthenics (PyCon SK 2017)

Thesearenotbestpractices

Page 86: Object Calisthenics (PyCon SK 2017)

Thesearejustguidelines

Page 87: Object Calisthenics (PyCon SK 2017)

Usewithcaution!

Page 88: Object Calisthenics (PyCon SK 2017)

Questions?

Page 89: Object Calisthenics (PyCon SK 2017)

Links

https://en.wikipedia.org/wiki/Calisthenicshttps://www.cs.helsinki.fi/u/luontola/tdd-2009/ext/ObjectCalisthenics.pdfhttps://pragprog.com/book/twa/thoughtworks-anthologyhttps://github.com/gennad/Design-Patterns-in-Pythonhttps://en.wikipedia.org/wiki/Law_of_Demeterhttps://www.quora.com/Is-it-true-that-a-good-programmer-uses-fewer-if-conditions-than-an-amateur

Page 90: Object Calisthenics (PyCon SK 2017)

Thankyou!