4gl coding worst practices
TRANSCRIPT
1
4GLCodingWorstPracticesaka:TheKeywordForgetListAccordingtoTomTomBascom,WhiteStarSoftwareAbstract:JustbecauseyouCAN-DO()itdoesn'tmeanthatyoushoulddoit.Programmersaredrawntobadexampleslikesmothstoflame.Nomatterhowmanycarefullycraftedcommentsyouputaroundthatoneusageofaspecialcasesomeprogrammerwillfinditandsuddenlypropagateitthroughoutyourapplication.CometothissessiontolearnwhyCAN-DO(),FINDFIRST,RELEASEandmany,manyothercodingworstpracticesshouldbebanned!Oratleastlearnwhyyoushouldnotcontinuetousetheseworstpracticesjustbecause"everyoneelsealwaysdoesitthatway".
4GLCodingWorstPracticesaka:TheKeywordForgetListAccordingtoTom
TomBascom,[email protected]
AFewWordsabouttheSpeaker
• TomBascom:Progressuser&roamingDBAsince1987• Partner:WhiteStarSoftware&DBAppraise,LLC– ExpertconsultingservicesrelatedtoallaspectsofProgressandOpenEdge.– RemotedatabasemanagementserviceforOpenEdge.– Authorof:– Simplifyingthejobofmanagingandmonitoringtheworld’sbestbusinessapplications.
3
4
{disclaimer.i}
• IdonotworkforProgress…• …andafterthiswecanbeprettysurethatIneverwill;)
• Thecontentofthissessionisheavilylacedwithopinion!
5
“Deprecated”=notquite“banned”L
knowledgebase.progress.com/articles/Article/P67734
• Codewillstill“work”butitisstronglyrecommendedtostartmodifyingyourcode.
• TechnicalSupportwilldotheirbesttohelp.• Noescalationswillbeissuedondeprecatedstatementsandclauses.
• Notguaranteedthatoldcodewithdeprecatedstatementswillstillworkinfuturereleases.
6
Progress’OfficiallyDeprecatedFeatures
• UPDATEEDITING• GO-PENDING• CHOOSE• SCROLL• PUTSCREEN• IS-ATTR-SPACE• GATEWAYS• SQL(withinthe4gl)
7
Tom’sList!
8
DOS
• EvenworsethanWindows!
9
DOS
• EvenworsethanWindows!• AndUNIXandVMSandBTOSforthatmatter• ThesestatementsbindyourcodetoaparticularOS.• Yourcodeislessflexibleandmorebrittle…• InsteaduseOS-COMMANDVALUE(cmd)– CMDcanbeastoredinaconfigtable.– PerhapsasatemplatethatyouusewithSUBSTITUTE
10
OS-COMMAND&SUBSTITUTE
11
ifopsys="unix"thendbaCmd="$DLC/bin/proutil&1-Cdbanalys-Bp10>”+“$PROTOP/dbanalys/&2.dba2>&&1&&”.elsedbaCmd="%DLC%~\bin~\proutil&1-Cdbanalys-Bp10>”“%PROTOP%~\dbanalys~\&2.dba2>&&1&&”.os-commandsilentvalue(substitute(dbaCmd,pdbname(1),ldbname(1))).
UnquotedFileNames
• Unfortunately,thiscodeworks:
12
outputtotest.put"hellokitty".
• IMHOthatshouldbeacompilererror.• Allowingunquotedfilenamesisabugwaitingtohappen:
definevariabletestascharacterno-undo.test="xyzzy".outputtotest.put"hellokitty".
CALL
• Thisistheold“HLC”interface.• Youhavetorelinkyour_progresexecutabletouseit.• Thecapabilitiesthatitsupportshavebeenreplacedbytheabilitytocallsharedlibraries,evenonUNIX:
http://dbappraise.com/ppt/shlib.pptx
13
DEFINEWORK-TABLE(WORKFILE)
• Pre-datestemp-tablesandprodatasets.• Noindexes-sosearchesareslow• Nofancy,modernfeatureslikeREAD-JSONetc.• LimitedbyavailableRAM• UngracefulfailureswhenyourunoutofRAM– Sessionscrashes– MaybeeventhewholemachineL
14
ACCUMULATEetc.
• Aggregatephrases,ingeneral,aretoocomplexandfinicky.• AVERAGE,TOTAL,etc.• IMHOitiseasier,andalotclearer,toexplicitlycreatetheintermediatevariablesanddothecalculations.
• Muchlesslikelytobemessedupbyamaintenanceprogrammer.
15
ACCUMULATE
Therearetwowaysofconstructingasoftwaredesign:Onewayistomakeitsosimplethatthereareobviouslynodeficienciesandtheotherwayistomakeitsocomplicatedthattherearenoobviousdeficiencies.
—C.A.R.Hoare,The1980ACMTuringAwardLecture
Debuggingistwiceashardaswritingthecodeinthefirstplace.Therefore,ifyouwritethecodeascleverlyaspossible,youare,bydefinition,notsmartenoughtodebugit.
BrianW.KernighanandP.J.PlaugerinTheElementsofProgrammingStyle.
16
VALIDATE
• Validationexpressionshavenousefulnessinmoderncode.Theyapplytoolateinthedataentrycycletobeuseful(validationsareperformedjustbeforedataiswrittentothedb).Don'tusethem.You'reonthewrongpath.
• Ifyouchangeavalidationexpressionthatchangeisn'tnoticedbycodeuntilyourecompile.
• Validationexpressionsmadegooddemosbackinthedaybuthaveneverreallybeenusefulforrealcode.
• Theroleofvalidationexpressionsisbetterfilledbya“rulesengine”(suchasCorticon).
17
RELEASE
• Almostalwaysasignthattheprogrammerisconfusedaboutrecordlockingortransactionscopeanddoesnotreaddocumentationverycarefully.
18
RELEASEStatement
Fromthedocumentation:
Verifies that a record complies with mandatory field and unique index definitions. It clears the record from the buffer and unites it to the database if it has been changed.
19
RELEASEandRecordLocksmessage"beforefind".pause.findcustomerexclusive-lockwherecust-num=2.displaycust-numnamediscount.message"beforeupdate".pause.updatediscount.message"beforereleasecustomer".pause.releasecustomer.message"afterreleasecustomer".pause.
RECIDTableFlagsUsr----------------------------------3862X63862X63862SL6
RELEASE…
UseproperrecordandtransactionscopingandyouwillneverneedtouseRELEASE:
21
definebufferupd_custforcustomer.foreachcustomerno-lock:ifcustomer.discount>10thendoFORupd_custtransaction:/*strongscopethe“upd_cust"buffer*/findupd_custexclusive-lockwhereupd_cust.custNum=customer.custNum.upd_cust.discount=10.end.end.
CAN-DO()
• Along,longtimeago…• Therewerenolistmanipulationfunctions.• LOOKUP,ENTRYetc.wasnotinthe4gl…• SomeonenoticedthatCAN-DOcouldbesubvertedtoperformthiscommontask:
22
displaycan-do("a,b,c","z").
CAN-DO…morehistory
• A*lot*ofcodewascreatedbyaveryearly,verysuccessfulVARusingthistechnique.
• UnfortunatelyagreatmanyProgressprogrammershavebeenexposedtothatcode.
• Thatdoesnot,however,makeita“bestpractice”orevena“goodidea”.
• Atbestitisa“badhabit”.
23
JustBecauseyouCAN-DO…
…doesn’tmeanthatyouSHOULD-DOUsingasecurityfunctiontoperformstringoperationsismisleading.RatherthanhavingplainEnglishself-documentingcodeyouareabusingafunctiontoachieveapurposethatitwasneverintendedfor.
24
FromtheKbase…
25
http://knowledgebase.progress.com/articles/Article/P100218
UsingtheCAN-DOfunctionasasubstitutefortheLOOKUPfunctionconstitutesamisuseoftheCAN-DOfunctionandisstronglydiscouraged.
http://knowledgebase.progress.com/articles/Article/000041404
TheCAN-DOfunctionisexplicitlydesignedtomatchuser-idpatterns.Usingitforarbitrarystringcomparisonsisnotintendedandwillprovideundefinedresults.
CAN-DO()alternative
• Bad:
• Good:
26
ifcan-do(‘ME,NH,VT,MA,CT,RI’,‘NH’)=truethen…
iflookup(‘NH’,‘ME,NH,VT,MA,CT,RI’)>0then…
ButCAN-DO()supportswild-cards!
• 99%ofthoseusesarecoveredwithBEGINS,MATCHESorCOMPARE
• Butifyoureallyneedit:
27
/*credittoKurtGunderson,PEGJuly232015*/functionmyCANDOreturnslogical(inputtaschar,inputsaschar):return((lookup("*",s)<>0orlookup(t,s)<>0)and(notlookup("!"+t,s)<>0)).endfunction.
…aboutthose“wild-cards”
• CAN-DO("a,b,#","#”)returnsfalse!• CAN-DOusessomemagiccharacters:
.:Matchasinglecharacter*:Matchmultiplecharacters!:Negateamatch#:DistinguishGRANTablevs.non-GRANTablepermissionsinSQL89@:Usedtorepresenttheblankuserid(asofoe11)““:Spacesarenotallowed
• Otherquirkscouldbeaddedatanytime!
28
Andifthatallthatwasn’tBadEnough
• CAN-DO()inaWHEREclause*forces*client-sideselectionandsorting.
29
CAN-DO()Summary
• CAN-DOisasecurityfunction!• Specialcharactersinthedatawillcauseittoproduceunexpectedresults!(akabugs)
• Becauseitisallaboutuseridsitmustbeevaluatedbytheclient.– SoifitisinaWHEREclauseyouwillhaveatablescan!– CAN-DOcannotandwillnotbeevaluatedserver-side.
30
OF
• ImpliedWHEREclause• Usesa”commonnamesthatareindexedimplyJOIN”convention.• Obscurestablerelationships.• LikeVALIDATE,OF“makesagooddemo”.• Butshouldneverbeusedinreallife.
31
USE-INDEX
• OverridesProgress’optimizer:– Youareprobablynotsmarterthanthecompiler*– Icertainlyamnot.
• Forcesasingleindextobeused.• WHEREclausemismatcheswillresultinverypoorperformance.• OnthebrightsideUSE-INDEXprovidesanordering:– Maynotbeclearorobvious–indexnamingconventionscanbemissing,misleadingorwrong.
– MayconflictwithBYphraseandcauseclientsidesorting.
32*Tryingtooutsmartacompilerdefeatsmuchofthepurposeofusingone.—KernighanandPlauger,TheElementsofProgrammingStyle.
USE-INDEX…
• Stillthinkyoushoulduseit?– Proveit!– Usingrealisticandmeaningfultestdata.– Providedetailedandreproducibletestcasesinyourcommentssothatfutureprogrammerswillrecognizeandcelebrateyourbrilliance.
33
FINDFIRST(andLAST)
• ReflexiveandautomaticuseoneachandeveryFINDdoesNOTimproveyourcode.
• ItisNOTa“standard”.• Norisita“bestpractice”.• Nordoesit“alwayswork”.
• Yes,Iknowitisallovertheplaceincertaincodebases.
34
UniqueFINDs
• FINDisdesignedtoreturnexactlyoneorzerorecords.• 99.44%ofFINDstatementsshouldbeforUNIQUErecords.• ThisisoneofProgress’bigadvantagesoverSQL.• IftheWHEREclausespecifiesauniquerecordthenFIRSTaddsnovalue.
• Worse–itconfusesthemaintenanceprogrammerbyimplyingthatthere/should/beanorderedresult-set.
35
UniqueFINDFIRSTperformance• ItisNOTfaster.• ItdoesNOT“eliminateacheckforambiguousrecords”.
• Allofthestatementsabovetakethesametimetorunandhavethesame“logical”impactonthedbengine.
• Allstatementsexecutethesamenumberof“logicalIOops”(ProTop,PROMONorVST“blockaccess”).
• Feelfreetotestityourself!
36
FINDFIRSTcustomerNO-LOCK.FINDcustomerNO-LOCKWHEREcustNum=1.FINDFIRSTcustomerNO-LOCKWHEREcustNum=1.
FasterFINDwithFIRST?
• ButwhatifFIRSTdoesactuallymakeaqueryfaster?– YouhavenotspecifiedUNIQUEcriteria!– YouaremissinganappropriateindextomatchyourWHEREclause.
– MaybeyourWHEREclauseisn’tdoingwhatyouthinkitshouldbedoing?
37
FINDFIRSTSlogan
ReturningtheWrongRecordFaster!
Aprogramthatproducesincorrectresultstwiceasfastisinfinitelyslower.
—JohnOsterhout
38
FINDSECOND?
• YouusedFINDFIRSTanyway…whatareyoudoingaboutthesecondrecord?
• Ifthereactuallyisasecondrecordandyouareactuallydoingsomethingwithit:– Howdidyouspecifytheordering?– Ifyoudon’tcareaboutorder–whatdoesFIRSTmean?– AreyoutreatingitexactlythesameastheFIRSTrecordfroma3NFperspective?– Areyouprocessingtheentireresultset?Whydidn’tyouuseFOREACH?
39
“ItAlwaysWorks”
• Thisusuallymeansthattheprogrammerdoesnotwanttodealwith:
MorethanoneCustomerrecordsfoundbyauniqueFIND.(3166)
• AddingFIRSTwill“makeitgoaway”.• Italsomakesyourresultispotentiallywrong:– Whatifyouforgotacomponentoftheindex?– Ordidn’tknowthatapreviouslyunusedfeaturehasbeenenabledbytheusers?– Ortheuserssuddenlycreateasecondmagicalrecord?
40
MagicFIRSTRecords
• Recordsthatarespecialbyconvention.• Nospecificattributeidentifiestheusage.• AclearviolationofThirdNormalForm.
41
findfirstcustomerno-lockwherecustNum>0.displaycustNumnamediscount.defaultDiscount=discount.findfirstcustomerno-lockwherename>"".displaycustNumnamediscount.defaultDiscount=discount.
FINDFIRSTSummary
• FINDFIRSTisalmostalwaysasignoflazyprogramming• Itdoesnotimproveperformance• Itcancreatebugsandmaskexistingbugs• Somecodebasesareinfestedwithit–butthereisnoreasontomaketheproblemworsebycontinuingthehabit
FORFIRST(andLAST)
43
forfirstcustomerno-lockwherediscount>10:leave.end.displaycustNumnamediscount.foreachcustomerno-lockwherediscount>10bydiscount:leave.end.displaycustNumnamediscount.forfirstcustomerno-lockbydiscount:leave.end.displaycustNumnamediscount./*continue…*/
FORFIRST(continued)
44
definevariableminDiscountasdecimalno-undoinitial99999.definevariableminDiscountCustNumasintegerno-undo.foreachcustomerno-lock:ifdiscount<minDiscountthenassignminDiscount=discountminDiscountCustNum=custNum.end.findcustomerno-lockwherecustNum=minDiscountCustNum.displaycustNumnamediscount./*continue…*/
FORFIRST(results)
• Sowhatdoes“FIRST”mean?
45
CustNumNameDiscount──────────────────────────────────────────────1LiftTours35%1067ArmadaleFitness15%1LiftTours35%6FanaticalAthletes0%
FORFIRST(andLAST)
• GiventhesameWHEREclause:– FINDonlyeverusesoneindex– FORcouldusemultipleindexes
• Sortingoccursafterselection.– FIRSTandLASTproduceasinglerecord(thusthereisnothingtosort).– Basedonwhateverindexwaschosen.– BYisanindexselectiontie-breaker–itisnottheprimaryoptimization.– Selectionmightnotmatchyourhopedfororder.
46
Summary
• DOSetal• UnquotedFileNames• CALL• DEFINEWORKFILE• ACCUMULATE&AggregatePhrases• VALIDATE
• RELEASE• CAN-DO• OF• USE-INDEX• FINDFIRST• FORFIRST
47
Questions?
48
SuggestedAdditions?
49
ThankYou!
50