Anda di halaman 1dari 9

12/14/2015

PatternsforbuildingexcellentexamplesIssue3.2

Patternsforbuildingexcellentexamples
PracticingRubyIssue3.2::PublishedbyGregoryBrownonJanuary10,2012

GoodcodeexamplesarethesecretsaucethatmakesPracticingRubyahighqualitylearningresource.
Thatsaid,theartofbuildingexcellentexamplesisonethatIthinkallprogrammersshouldpractice,
notjustthosefolksouttheretryingtoteachforaliving.Theabilitytoexpressideasclearlythrough
wellfocusedsnippetsofcodeiskeytowritinggoodtests,documentation,bugreports,codereviews,
demonstrations,andawholelotofotherstuff,too.
Inthisarticle,I'veidentifiedfivepatternsIuseforexpressingideasthroughcodeexamples.These
techniquesrunthegamutfrombuildingcontrived"HelloWorld"programstocraftingfullscale
sampleapplicationsusingaliterateprogrammingstyle.Eachtechniquehasitsownstrengthsand
weaknesses,andI'vedonewhatIcouldtooutlinethemwherepossible.
Althoughthisisn'tnecessarilyacomprehensivelist,itcanhelpyoustarttoimprovethewayyouwrite
yourexamplesandalsoservesasagoodjumpingoffpointforfurtherdiscussiononthetopic.

Contrivedexamples
Foranygivenprogramminglanguageorsoftwarelibrary,theoddsareprettygoodthatthefirst
exampleyou'llrunisacontrived"HelloWorld"program.Thefollowingexampleistakenfromthe
Sinatrawebframeworkbutissimilarinspirittoprettymucheveryother"HelloWorld"application
outthere:


 


Thiskindofexampleseemsquiteuselessonthesurfaceandisneitherinterestingnoreducational.As
itturnsout,thesecharacteristicsarepreciselywhatmakethis"HelloWorld"programperfect!The
contrivednatureoftheexampleallowsittoserveasasimplesanitycheckforsomeonewhoistrying
outSinatraforthefirsttime.
Ifyoutrytorunthisexampleandfindthatitdoesn'tworkcorrectly,thereareonlyafewpossible
pointsoffailure.Inmostcases,notevengettinga"HelloWorld"programtoruncorrectlycanbe
blamedononeofthreethings:outofdatedocumentation,issueswithyourenvironment,orusererror.
Thefactthatthereareveryfewmovingpartsmakesitmucheasierforyoutodeterminethesourceof
https://practicingruby.com/articles/patternsforbuildingexcellentexamples

1/9

12/14/2015

PatternsforbuildingexcellentexamplesIssue3.2

yourproblemthanitwouldbeiftheexampleweresignificantlymorecomplex.Thiseaseof
debuggingispreciselywhymostintroductorytutorialsstartoffwitha"HelloWorld"programrather
thansomethingmoreexciting.
Althoughthemostcommonusecaseforcontrivedexamplesistoconstruct"HelloWorld"
applications,thereareotherusecasesforthistechniqueaswell.Inparticular,contrivedexamplesare
agoodfitfordiscussionsaboutsyntacticorstructuraldifferencesbetweentwopiecesofcode.Asan
example,considerashorttutorialthatexplainswhyausermightwanttouseRuby's
functionality.Itcouldstartbyshowingaclassthatimplementsaccessorsexplicitly:













Afollowupexamplecouldthenbeprovidedtoshowhowtosimplifythecodevia:








Thisscenarioisverysimplisticwhencomparedtotheclassdefinitionswewriteinrealprojects,but
theabsenceofcomplicatedfunctionalitymakesiteasierforthereadertofocusonthesyntactic
differencesbetweenthetwoexamples.ItalsoallowsthenoviceRubyprogrammertothinkofthe
differencebetweenexplicitlydefiningaccessorsandusingasasimplestructural
transformationratherthansomethingwithcomplexsemanticdifferences.Althoughthismentalmodel
isnot100percentaccurate,itemphasizesthebigpicture,whichiswhatactuallymattersforanovice
programmer.Thesimplicityoftheseexamplesmakesthegeneralpatternmucheasiertoremember,
whichjustifieshidingafewthingsbehindthecurtaintoberevealedlater.
Unfortunately,theabilityofcontrivedexamplestohidethesemanticsofourprogrammingconstructs
isjustasoftenadrawbackasitisanasset.Themorecomplexaconceptis,themoredangerousitisto
presentsimplisticexamplesratherthanworkingthroughmorerealisticscenarios.Forexample,itis
commonforobjectorientedprogrammingtutorialstouserealworldobjectsandhierarchiesto
explainhowclassinheritanceworks,butthedisconnectbetweenthesemodelsandthekindsthatreal
softwareprojectsimplementissogreatthatthisapproachcompletelyobfuscatestherealpowerand
purposeofobjectorientedprogramming.Bychoosingascenariothatmayfeelnaturaltothereader
butdoesnotfitnaturallywiththeunderlyingprogrammingconstructs,thissortoftutorialfailsto
emphasizetherightdetailsandleavesthedooropenforawiderangeofmisconceptions.These
incorrectassumptionsendupgettinginthewayoflearningrealobjectorientedprogramming
techniquesratherthanhelpingdevelopanunderstandingofthem.
Icouldeasilyrantonthistopic,butsomeoneelsediditformebywritingagreatmailinglistpost
https://practicingruby.com/articles/patternsforbuildingexcellentexamples

2/9

12/14/2015

PatternsforbuildingexcellentexamplesIssue3.2

entitledGoodbye,shittyCarextendsVehicleobjectorientationtutorial.Despitethesomewhat
inflammatorytitle,itisaveryinsightfulpost,andIstronglyrecommendreadingitifyouwanttosee
astrongargumentforthelimitationsofcontrivedexamplesasteachingtools.
Figuringoutwheretodrawthelinebetweenwhenitisappropriatetouseacontrivedexampleand
whentouseonethatisbasedonapracticalapplicationistricky.Ingeneral,Itrytokeepinmindthat
thepurposeofacontrivedexampleisspecificallytoremovecontextfromthepicture.Outsideof
"HelloWorld"programsandsimplesyntactictransformations,alackofcontexthurtsmorethanit
helps,andsoItrytoavoidcontrivedexamplesasmuchasIcanforprettymucheveryotherusecase.

Cheapcounterfeits
Oneofmyfavoritetechniquesforteachingprogrammingconceptsistoconstructcheapcounterfeits
thatemulatethesurfacelevelbehaviorofamorecomplicatedstructure.These"poorman's
implementations"aresimilartocontrivedexamplesinthattheycanhideasmuchcomplexityasthey'd
likefromthereaderbut,becausetheyaregroundedbysomerealisticscenario,donotsufferfrom
beingtotallydisconnectedfrompracticalapplications.
IhaveusedthistechniqueextensivelythroughoutPracticingRubyandmyotherwrittenworks,andit
almostalwaysworksoutwell.Infact,theissueonImplementingEnumerableandEnumeratorin
RubywasentirelybasedonthisstrategyandturnedouttobeoneofthemostpopulararticlesI've
writtenforthisjournal.Althoughyouareprobablyalreadyveryfamiliarwiththispatternasa
PracticingRubyreader,Icanstillprovideabitofextrainsightbydecomposingitforyou.
Thepurposeofbuildingacheapcounterfeitisnottogainadeepunderstandingofhowacertain
constructactuallyworks.Instead,thepurposeofacounterfeitistoteachpeoplehowtostealideas
fromotherinterestingbitsofcodefortheirownneeds.Forexample,taketheprevious
example:








Thisisagreatfeature,becauseitreplacestediousboilerplatemethodswithaconcisedeclarative
statement.Butwithoutsomesortofexplanationastohowitworks,feelsprettymagical
andmightbeperceivedasaspecialcasethattheRubyinternalsareresponsibleforhandling.This
misconceptioncaneasilybeclearedupbyshowinghowtoimplementacheapcounterfeitversionof
inapplicationcode:












https://practicingruby.com/articles/patternsforbuildingexcellentexamples

3/9

12/14/2015

PatternsforbuildingexcellentexamplesIssue3.2




Ifteachingprogrammershowtouseisliketreatingthemtoanicefishdinner,teaching
themhowtoimplementitislikegivingthemafishingpoleandshowingthemhowtocatchtheirown
meals.Seeingapracticaluseofopensthedoorsforahugerangeofotherapplications,
allofwhichhingeonthesimpleconceptofdynamicmethoddefinition.Forexample,asimilar
techniquecouldbeusedtoconverthideousmethodnameslike
intotheelegantsyntaxshownhere:




Therearecountlessotherapplicationsofdynamicmethoddefinition,manyofwhichIexpect
PracticingRubyreadersarealreadyfamiliarwith.Thepointhereisthatasingleexamplethat
demystifiesacertaintechniquecanmakeahugedifferenceinwhatpossibilitiessomeoneseesina
givensystem.Thispayoffiswhatmakescheapcounterfeitssuchatremendouslygoodteachingtool.
Animportantthingtokeepinmind,however,isthatthistechniqueisusefulmostlyforteaching
concepts,asopposedtoshowingsomeonehowafeatureisreallyimplemented.Ifyouactuallylook
intotheimplementationof,you'llfindanumberofedgecasesthatthischeapcounterfeit
exampledoesnottakeintoconsideration.Althoughthesesubtletiesarenotespeciallyrelevantif
you'rejusttryingtogiveacontextualizedexampleofhowcanbeused,theywouldbe
importanttopointoutifyouweretryingtowriteaspecificationforhowismeantto
work,whichiswhycheapcounterfeitsarenotasubstituteforcasestudiesofrealcodebutinstead
serveadifferentpurposeentirely.

Simplifiedexamples
Diggingdirectlyintothesourcecodeofaprojectisthemostdirectwaytounderstandhowitsfeatures
areimplemented,butitcanbeasomewhatdisorientingprocess.Productioncodeinallbutthemost
trivialprojectstendstoaccumulateedgecases,errorcheckingcode,andotherbitsofcruftthatmake
ithardertoseewhatthecoreideasare.Whengivingatalkabouthowsomethingisimplementedor
writingdocumentationforpotentialcontributors,itissometimeshelpfultoprovidesimplified
examplesthatdemonstratethekeyfunctionalitywhileminimizingdistractions.
SupposeIwanttodoalightningtalkabouthowMiniTestisimplemented,withthegoalofattracting
newcontributorstotheproject.Inatalklikethat,I'ddefinitelyneedtodiscussabitabouthow
assertionswork.Alogicalplacetostartmightbethemethod:

 








TheimplementationofissimpleenoughthatIcouldprobablyshowitasiswithoutlosingmy
audience.ButifIkeepinmindthatthiscodeisgoingtobeshownonaslideforjustafewseconds,I
mightshowthefollowingsimplifiedexampleinstead:

 
https://practicingruby.com/articles/patternsforbuildingexcellentexamples

4/9

12/14/2015

PatternsforbuildingexcellentexamplesIssue3.2





Thiscodeomitssomeimplementationdetails,butitpreservesthemainidea,whichisthatMiniTest's
assertionsworkbyraisinganexceptionwhenatestfails.Thefactthatiswherethenumberof
assertionsiscountedisfairlyobviousandonlyaddsnoisewhenyouwanttogetaroughideaforhow
thecodeworksataglance.Likewise,thefactthatamessagecanbepassedinasaobjectrather
thanastringisaninterestingbutobscureedgecasethatdoesnotneedtobeemphasized.Byremoving
thesetwostatementsfromthemethoddefinition,thecorebehavioriseasiertonotice.
Theprocessofcreatingasimplifiedexamplestartswithlookingattheoriginalsourcecodeandthen
determiningwhichdetailsareessentialtoexpressingtheideayouwanttoexpressandwhichdetails
canbeconsideredbackgroundnoise.Thenextstepistoconstructanexamplethatservesasa
functionalsubsetoftheoriginalimplementationwhenusedwithinacertaincontext.Youdon'twantto
deviatetoomuchfromtheoriginalidea,butyoucancleanupthesyntaxabitwhereappropriateto
maketheexampleeasiertounderstand.Fromthere,youcantreattheexampleasasubstituteforthe
realimplementationforthepurposesofdemonstrationyoujustneedtomakesuretopointoutthat
youhavesimplifiedthingsabit.
WiththisMiniTestexample,thesimplifiedversionofthecodeisonlyslightlylesscomplicatedthan
theoriginal,sothebenefitsofusingthistechniqueareabitsubdued.Inpractice,you'remuchmore
likelytorunintosituationsinwhichtherearedozensoflinesofimplementationcodebutonlya
handfulofthemarecentraltotheideathatyouaretryingtoexpress.Inthosesituations,thispatternis
especiallyeffectiveatcuttingthroughthecrufttogetattherealmeatoftheproblemyouwantto
focuson.However,it'sworthkeepinginmindthatevenrelativelysmallandeasytounderstand
chunksofcodecanbesimplifiediftheyhappentoincludestatementsthatarenotdirectlyrelevantto
thepointyouaretryingtomake.

Reducedexamples
Areducedexampleisonethatreproducesacertainbehaviorinthemostsimplepossibleway.This
techniqueismostcommonlyusedforputtingtogetherbugreportsandisoneofthemostimportant
skillsyoucanhaveasasoftwaredeveloper.
IntheRubyBestPracticesbook,ItoldastoryaboutabugthatwasspottedinPrawnandhowwe
reducedtheoriginalreporttosomethingmuchmoresimpleinordertodiscovertherootcauseofthe
problem.BecausethisisstillthebestexampleI'vefoundofthisprocessinaction,I'llsummarizethat
storyhereratherthantellinganewone.
Adevelopersentusthefollowingbugreporttodemonstratethatourcodeforgeneratingfixedwidth
columnsoftexthadaproblemthatwascausingpagebreakstobeinsertedunnecessarily:


 

 

 



https://practicingruby.com/articles/patternsforbuildingexcellentexamples

5/9

12/14/2015

PatternsforbuildingexcellentexamplesIssue3.2



 


Inthisexample,heexpectedallofhistexttoberenderedononepageandwastryingtoshowthat
eachtimeheusedtheconstruct,anunnecessarypagebreakwascreated.Heshowedthatthiswas
thecasebothwithinthedefaultpageboundariesandwithinamanuallyspecifiedboundingbox.As
farasuserreportsgo,thisexamplewasprettygood,becauseitwasspecificallydesignedtoshowthe
problemhewashavingandwasclearlynotjustsomebrokenproductioncodethathewantedhelp
with.
Thathavingbeensaid,anunderstandingofhowPrawnworksunderthehoodmadeitpossibleto
simplifythisexamplequiteabit,evenbeforeinvestigatingfurther.Becausethedefaultpage
boundariesinPrawnareimplementedintermsofboundingboxesandthemethodjust
temporarilyswapsthosedimensionswithnewones,thesecondpartofthisreportwassuperfluous.
Removingitgotthereproduciblesampledowntotheexampleshownhere:


 




Inmakingthisreduction,Ialsodidsomeotherminorcleanupchoressuchasreworkingthetexttobe
selfdocumentingandremovingtheoptionfor,becauseitdidn'taffectthe
outcome.Atthispoint,evensomeonewithoutexperienceinhowPrawnworkswouldbeabletomore
easilyspottheproblemintheexample.
Althoughisnotatrivialconstruct,ithadonlytwopossiblepointsoffailure:the
methodandthemethod.Becauseisfundamentaltoprettymucheverything
Prawndoesandwehadplentyofevidencethatitwasworkingasexpected,weturnedourattentionto
.
Thepurposeofistoexecutethecontentsofablockwhileignoringalldocumentmarginsand
boundingboxesinplace,essentiallyconvertingeverythingtoabsolutecoordinatesonthepage.After
theblockisexecuted,itissupposedtokeepthetextpointerwhereveritleftoff,whichmeansthatit
shouldnottriggerapagebreakunlessthetextflowsbeyondthebottomofthepage.Totestthis
behavior,wecodedupthefollowingexample:





Afterrunningthisexample,wenoticedthatitexhibitedthesamedefectthatwesawintheuser'sbug
report.BecausethismethodisalmostasdeepdownthePrawncallchainasyoucango,itbecame
clearthatatthispointwehadourreducedexample.Thebenefitofdrillingdownlikethisbecame
apparentwhenweconvertedoursamplecodeintoaregressiontest:





https://practicingruby.com/articles/patternsforbuildingexcellentexamples

6/9

12/14/2015

PatternsforbuildingexcellentexamplesIssue3.2



 






Afterseeingthistestfailandapplyingaquickpatchthatgotittogogreen,wewentbackandranthe
originalbugreporttheuserprovideduswith.Aspredicted,thebadbehaviorwentawayandthings
wereonceagainworkingasexpected.
Thebenefitsofreducingtheexamplebeforewritingaregressiontestweretremendous.Notonlywas
thetesteasiertowrite,butitalsoendedupcapturingtheproblematamuchlowerlevelthanitwould
haveifweimmediatelysetinwithcodifyingthebugreportasaunittest.Inadditiontothesebenefits,
thereductionprocessitselfgreatlysimplifiedthedebuggingprocess,asitallowedustoproceed
methodicallytofindtherootoftheproblem.
I'vemostlyusedthisreductiontechniquewhiledebugging,butitcanalsobeausefulwaytofindyour
wayaroundacomplexcodebase.Bystartingwithapracticalexamplethatexercisesthesystemfrom
theoutermostlayer,youcandrilldownintothecodeandtraceyourwaythroughthecallchainsto
findhowsomeparticularaspectofthesoftwareworks.Althoughthisisalessdirectapproachthan
justreadingthedocumentation,itwillgiveyouabetterfundamentalunderstandingofhowthesystem
hangstogether,andit'safunwaytopracticecodereading.
Whetheryouareexploringanewcodebaseortrackingdownabug,thereductionprocesslimitsthe
scopeofthethingsyouneedtothinkabout,allowingyoutodedicateyourattentioninamorefocused
way.Thiseffectissomewhatsimilartowhatwefindwhenwemakeuseofsimplifiedexamplesbutis
moreofadrillingdownprocessthanitisapruningprocess.Bothhavetheirmerits,andtheycaneven
beusedincombinationattimes.

Sampleapplications
AlthoughallofthetechniquesI'vediscussedsofarcanbequiteusefulforstudying,investigating,and
teachingaboutspecificissues,noneofthemareparticularlysuitablefordemonstratingbigpicture
topics.Whenyouwanttoemphasizehowthingscometogether,asopposedtohoweachindividual
partworks,nothingbeatsthecombinationofasampleapplicationwithagoodwalkthroughtutorial.
SeveralissuesfromPracticingRubyVolume2madeuseofthisformatandwereverywellreceived
bythereadershere.
InLearningnewthingsstepbystep,Ibuiltasmallgameforthepurposeofdemonstratinghowto
developsoftwareintinybitesizedchunks.Thenicethingaboutthisapproachisthatitallowsthe
readertofollowalongathome(eithermentallyorbyliterallyrunningthecodethemselves),while
proceedingattheirownpace.Ihopeitalsoencouragesfolkstoexperimentanddrawtheirown
conclusionsratherthanjustrigidlyfollowingapredefinedscript.
InBuildingUnixstylecommandlineapplications,ItackledthecreationofaRubycloneoftheUnix
utilitybyfocusingondistinctareasoffunctionality,oneatatime.Thisisaslightlylesslinear
formatthanthestepbystepapproachofthegamedevelopmentarticle,butitallowsreaderstolookat
thecompleteapplicationfromseveraldifferentangles,dependingonthetopicsthatinterestedthem
most.
Finally,inDesigningbusinessreportingapplications,Itotallybreakawayfromlinearitybypresenting
https://practicingruby.com/articles/patternsforbuildingexcellentexamples

7/9

12/14/2015

PatternsforbuildingexcellentexamplesIssue3.2

thesourcecodeofafullapplicationinliterateprogrammingstyle.Thisapproachallowsreadersto
studytherealimplementationcodeandmycommentarysidebysideandtobouncearoundastheysee
fit.Thislackofexplicitstructureencouragesreaderstoexploreinafreeformfashionratherthan
focusingonsomepredefinedareasofinterests.
AlthoughthesearticlesweresomeofthemostsuccessfulonesthatI'vepublishedhereatPracticing
Ruby,theywerealsoamongthemostchallengingtowrite.Ihadtoapplyamuchhigherstandardof
writingclearandconcisecodethanIwouldifIweresimplytryingtomakeaprojecteasyenoughfor
metomaintainonmyown.Theprosewastrickytoorganize,becauseit'shardtodecidewhichareas
toemphasizeandwhichtoglossoverinacompleteapplication.Forthesereasons,sample
applicationscanbeacumbersomeandtimeconsuminglearningresourcetoproduce.However,the
investmentseemstobewellworthitintheend.

Reflections
Writinggoodexamplescanbeseriouslyhardwork.Thisiswhyalltoooftenweseepeopleoverusing
contrivedexamplesorsimplyattemptingtopassoffunrefinedsnippetsofproductioncodeaslearning
materials.However,codeexamplesinalloftheirmyriadformslaythefoundationforhowwe
communicateourideasassoftwaredevelopers.
Animportantthingtorememberwhenwritingcodeexamplesisthattheprocessisinmanyways
similartowritingprose.Ifwesimplyspitoutabraindumpwithoutthinkingabouthowitwillbe
interpretedandunderstoodbyothers,wewillendupwithcrappyresults.Butifwerememberthatthe
maingoalofwritingourexamplesistocommunicateanideatoourfellowprogrammers,wenaturally
begintoaskthequestionsthatleadustoimproveourwork.
Ihopethatbysharingthesefewpatternswithyou,I'vegivenyousomeusefulideasforhowto
improveyourcodecommunicationskills.FollowingthepatternsI'veoutlinedherewillleadyouto
writingbetterexamplesforyourdocumentation,bugreports,unittests,tutorials,andquiteafewother
thingsaswell.
ThoughthetechniquesI'veshownhereareonesthatworkwellinawiderangeofcontexts,Iamsure
thereareotherapproachesworthlearningabout.Ifyou'veseenanoveluseofcodeexamplesinthe
wild,pleaseletmeknow!I'dalsobehappytohearanyotherthoughtsyouhaveonthistopic,andI
wouldn'tmindhelpingafewfolkscomeupwithgoodexamplesfortheprojectsthey'reworkingon.If
you'vegotsomethingyouwantmetotakealookat,justleaveacommentandI'llbesuretogetback
toyou.
Follow@practicingdev

https://practicingruby.com/articles/patternsforbuildingexcellentexamples

Tweet

8/9

12/14/2015

PatternsforbuildingexcellentexamplesIssue3.2

https://practicingruby.com/articles/patternsforbuildingexcellentexamples

9/9

Anda mungkin juga menyukai