object calisthenics (pyconpl 2016)
Post on 15-Jan-2017
70 Views
Preview:
TRANSCRIPT
ObjectCalisthenics9stepstobetterOOcode
Agenda
Learnhowtomakeourcodemore:
readablereusabletestablemaintainable
Raiseyouhandifyouknowoneofthefollowing:
DRYKISSSOLIDYAGNIZenofPython
Calisthenics
Cal•is•then•ics-/ˌkaləsˈTHeniks/
"Calisthenicsareexercisesconsistingofavarietyofgrossmotormovements;often
rhythmicalandgenerallywithoutequipmentorapparatus."
Wikipedia
ObjectCalisthenics
JeffBay
WrittenforJava
Whybother?
Codeisreadmorethanit'swritten
Rule#1
Onlyonelevelofindentationpermethod
classBoard(object):def__init__(self,data):#Level0self.buf=""foriinrange(10):#Level1forjinrange(10):#Level2self.buf+=data[i][j]
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]
Benefits
SingleresponsibilityBetternamingShortermethodsReusablemethods
Rule#2
Donotuseelsekeyword
ifoptions.getCategories()isNone:...eliflen(options.getCategories())==1:...elifSPECIAL_CATEGORYinoptions.getCategories():...elifoptions.getCategories()andoptions.getQuery():...elifoptions.getContentType():...
deflogin(self,request):ifrequest.user.is_authenticated():returnredirect("homepage")else:messages.add_message(request,messages.INFO,'Badcredentials')returnredirect("login")
deflogin(self,request):ifrequest.user.is_authenticated():returnredirect("homepage")
messages.add_message(request,messages.INFO,'Badcredentials')returnredirect("login")
Extractcode
Defaultvalue
Polymorphism
Strategypattern
Statepattern
BenefitsAvoidscodeduplicationLowercomplexityReadability
Rule#3
Wrapprimitivetypesifithasbehaviour
ValueObjectinDDD
classValidator(object):defcheck_date(self,year,month,day):pass
#10thofDecemberor12thofOctober?validator=Validator()validator.check_date(2016,10,12)
classValidator(object):defcheck_date(year:Year,month:Month,day:Day)->bool:pass
#Functioncallleavesnodoubt.validator.check_date(Year(2016),Month(10),Day(12))
BenefitsEncapsulationTypehintingAttractssimilarbehaviour
Rule#4
Onlyonedotperline
OK:Fluentinterface
classPoem(object):def__init__(self,content):self.content=content
defindent(self,spaces):self.content=""*spaces+self.contentreturnself
defsuffix(self,content):self.content=self.content+"-"+contentreturnself
Poem("RoadNotTravelled").indent(4)\.suffix("RobertFrost").content
NotOK:getterchain
classCartService(object):defget_token(self):token=self.get_service('auth')\.auth_user('user','password')\.get_result()\.get_token()
returntoken
#1.WhatifNoneisreturnedinsteadofobject?#2.Howaboutexceptionshandling?
classLocation(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
classLocation(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
BenefitsEncapsulationDemeter'slawOpen/ClosedPrinciple
Rule#5
Donotabbreviate
Whyabbreviate?
Toomanyresponsibilities
Nametoolong?
Split&extract
Duplicatedcode?
Refactor!
BenefitsClearintentionsIndicateunderlyingproblems
Rule#6
Keepyourclassessmall
Whatissmallclass?15-20linespermethod50linesperclass10classespermodule
BenefitsSingleResponsibilitySmallermodules
Rule#7
Nomorethan2instancevariableperclass
Classshouldhandlesinglevariablestate
Insomecasesitmightbetwovariables
classCartService(object):def__init__(self):self.logger=Logger()self.cart=CartCollection()self.translationService=TranslationService()self.authService=AuthService()self.userService=UserService()
BenefitsHighcohesionEncapsulationFewerdependencies
Rule#8
Firstclasscollections
collectionsmodule
BenefitsSingleResponsibility
Rule#9
Donotusesetters/getters
Accessorsarefine
Don'tmakedecisionsoutsideofclass
Letclassdoit'sjob
Tell,don'task
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)
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)
BenefitsOpen/ClosedPrinciple
Catch'emall!
Catch'emall!1. Onlyonelevelofindentationpermethod,2. Donotuseelsekeyword,3. Wrapprimitivetypesifithasbehavior,4. Onlyonedotperline,5. Don’tabbreviate,6. Keepyourentitiessmall,7. Nomorethantwoinstancevariableperclass,8. FirstClassCollections,9. Donotuseaccessors
Catch'emall!1. Onlyonelevelofindentationpermethod,2. Donotuseelsekeyword,3. Wrapprimitivetypesifithasbehavior,4. Onlyonedotperline,5. Don’tabbreviate,6. Keepyourentitiessmall,7. Nomorethantwoinstancevariableperclass,8. FirstClassCollections,9. Donotuseaccessors10. ???11. PROFIT!
Homework
Createnewprojectupto1000lineslong
Applypresentedrulesasstrictlyaspossible
Drawyourownconculsions
Customizetheserules
Finalthoughts
Thesearenotbestpractices
Thesearejustguidelines
Usewithcaution!
Questions?
Thankyou!
top related