Namngivning i koden Möjliga konflikter och lösningar Djupstudie inom coachning av programvaruteam, våren 2003 Adrian Ulander Sammanfattning Ett problem som brukar finnas i projekt är namngivningar i koden. Olika gruppmedlemmar ser olika på hur man “bör” namnge sina klasser, metoder och variabler. Jag har givit mig in i denna djungel av tips och “regler” för att försöka hitta en röd tråd som kan vara dels årets projekt till nytta, men framförallt kommande. Förutom att jag har att sökt information och underlag till studien från andra projekt har jag använt den kod som har skrivits under projekten i PVG-kursen Frågorna jag ställde mig var; Hur har årets deltagare valt att göra när de har namngivit delar i koden? Har det uppstått några problem till följd av detta? Vilka åtgärder fick göras? Det finns många intressanta frågor som kan ställas, varav jag hoppas att jag har fått med de flesta. Jag har bland annat tittat på de coding standards som finns inom Java Code Conventions och hur man bör använda dem i namngivningssyften. Ward Cunningham har skrivit ett flertal artiklar1 som berör namngivning inom programmering, bland annat “System of Names” som tar upp några viktiga tips angående namngivning. På Berkeley har Ben Liblit skrivit en intressant artikel om the kognitiva aspekterna av namngivning. 1 inom wiki-wiki-web, en “uppfinning” där alla kan gå in och ändra i webbsidorna, medför att det finns många medförfattare Sida 2 av 10 Innehållsförteckning Innehållsförteckning.....................................................................................................................................3 Inledning.........................................................................................................................................................4 Bakgrund........................................................................................................................................................4 Grundläggande kodkonventioner i Java...................................................................................................5 Vanliga problem vid namngivning.............................................................................................................5 Kort tid vid namngivning...........................................................................................................................5 Långa namn.................................................................................................................................................6 Korta namn..................................................................................................................................................6 Konsekvens.................................................................................................................................................7 Förvillande namn........................................................................................................................................7 Förkortningar..............................................................................................................................................7 Slutsats.............................................................................................................................................................9 Vidare läsning................................................................................................................................................9 Referenslista.................................................................................................................................................10 Sida 3 av 10 Inledning Innan jag påbörjade arbetet trodde jag att det skulle vara ganska lätt att hitta regler för hur man bör namnge sin kod. Det visade sig dock ganska snabbt att det är svårt att göra en helt objektiv bedömning av vad som är bra och dåligt. Det finns väldigt många olika tankar för hur man ska göra, allt ifrån de som tycker att man bör skriva koden så enkel att man kan använda sig av enbart enbokstavsvariabler till de som vill ha en ”kod” i namnen som beskiver vad de gör och varifrån de kommer. Jag har därmed fått göra en egen bedömning av de regler som jag tycker passar bäst in i vår problemdomän. Jag har valt att koncentrera mig på vad man bör tänka på och vilka effekter namngivning i koden har, med tyngdpunkten på Java. I vissa fall har jag även antagit att man använder sig av XP-metodiken. Namngivningskonventionerna skiljer sig något åt mellan olika programspråk, bland annat handlar det om hur man avgränsar ord, men det ingår även annat. Trots detta kommer de tips som jag kommer att ge att vara användbara de flesta programspråk. Jag har även valt att jämföra namnbruket inom de olika projekten i kursen ProgramVaruuveckling i Grupp (PVG)2 våren 2003. Kursen ges vid Lunds Tekniska Högskola till andraårsstudenter som går datateknikprogrammet. Kursen har som mål att lära ut XP-metodiken, som fortsättningskurs finns Coachning av Programvaruteam3, den här rapporten är skriven som en djupstudie inom den senare kursen. Projekten hade samma uppgift att lösa och bör därför ha haft liknande klasser. Bakgrund Programkod har ett eget språk som, naturligtvis, har vissa likheter med vårt språk. Men det finns vissa skillnader; bland annat kan man inte använda sig av lika målande beskrivningar av saker i programkod som man kan i vanlig text eftersom man då får alldeles för långa och otympliga namn. Men det är även viktigt att man inte går för långt åt andra hållet, variabler med namn som: x, anInt är tyvärr inte helt ovanliga, men för läsbarheten av programkoden kan de vara ödesdigra. Samma problem uppkommer dessvärre nästan varje gång, till stor del ligger det i att programmeraren inte är uppmärksam nog samt att den har för bråttom. Bästa tipset i sådana fall är att ta det lugnt och göra gemensamma kodgenomgångar. 2 3 EDA260, www.cs.lth.se/Education/LTH/EDA260/ Coachning av programvaruteam, www.cs.lth.se/Education/LTH/Coach/ Sida 4 av 10 Grundläggande kodkonventioner i Java Inom Java finns det ett gediget dokument som beskriver hur koden bör se ut4, bland annat beskrivs där hur man bör placera sina hakparanteser med mera. Det finns även ett kort avsnitt om konventioner för namngivning. Det som tas upp är hur namnen bör vara utformade. Konventionerna är som följer5: Paketnamn: Prefixet ska vara en av de toppdomäner som finns enligt ISO standard. De resterande delarna i paketnamnet kan till exempel vara avdelningsnamn, projektnamn eller inloggningsnamn för den/de som har gjort paketet. Exempel: se.lth.cs.jlist Klassnamn: Namnet ska vara ett eller flera substantiv där den första bokstaven i varje ord ska vara stor. Man bör undvika förkortningar, förutsatt att förkortningen inte är mer använd än den längre formen (till exempel HTML). Klassnamnet avslutas naturligtvis med .java. Exempel: Turtle.java Interface: Namnges med adjektiv eller substantiv. Adjektiv är användbart till exempel om man vill beskriva beteendet på interfacet. Formatering av bokstäver sker på samma sätt som med klasser. Exempel: Serializable.java, Collection.java Metoder: Metoder bör vara ett eller flera verb där den första bokstaven är liten och den första bokstaven i de efterföljande orden stora. Det finns även exempel på fall då det är passar med substantiv eller adjektiv istället. Substantiv där man beskriver vad man får ut från metoden och adjektiv där man beskriver beteendet. Exempel: moveTurtle(), top(), empty() Variabler: Skrivs på samma sätt som metoder, dock med substantiv istället för verb. Variabler med endast en bokstav bör undvikas, kan dock användas i temporära sammanhang som uppräknare med mera. Exempel: String turtleColor Konstanter: Enbart stora bokstäver med ’_’ som avgränsare. Exempel: int TURTLE_WIDTH Vanliga problem vid namngivning När man skriver ny kod finns det några problem som man ställs inför varje gång. Jag tar här upp några av dem samt ger exempel från projektens kod. Kort tid vid namngivning Ett ofta uppkommande problem verkar vara att man vet vad metoden kommer att göra, man vet vilka data som kommer att behandlas men det är svårt att sätta ett ord på det. En metod som skapar alla objekt (paneler med mera i ett grafiskt användargränssnitt) som kommer att användas heter i ett fall makeObjects()6. Det är namn som visserligen speglar vad som händer i metoden men metodnamnet är samtidigt lätt att misstolka som något man måste använda när man vill skapa objekt. setUp() hade i mina ögon varit ett bättre namn. Problem som ovan uppkommer gärna i samband med tidspress, tiden som läggs på namngivning är försvinnande liten. Från att man kommer på att man kanske bör ha en 4 5 6 Java Code Conventions, www.java.sun.com/docs/codeconv/ Listan är fritt översatt från java.sun.com/docs/codeconv/html/CodeConventions.doc8.html#367 PVG2003, grupp cs0307, GUI.java Sida 5 av 10 metod där alla objekt skapas till att man börjar skriva den är runt fem till tio sekunder7. Namnet rotar sig snabbt och nästa gång man går över koden känns namnet självklart. Särskilt om det är samma personer som skapade koden som går igenom den. Om man har regelbundna så kallade ”stand up-meetings” där man berättar vilka nya metoder och variabler man har skapat samt vad de gör/står för, kan gruppen gemensamt komma överens om eventuella nya namn. Det är positivt om man tidigt gemensamt kan ändra namnet till bättre mer anpassade namn. Det bidrar dessutom till att man sprider kunskap om koden i gruppen. Om man tränar sig i att åstadkomma bra och informativa namn kommer det till slut bli något som sker automatiskt. Det blir därmed inte något problem att man lägger lite tid på namngivningen eftersom man intuitivt väljer bra namn. Långa namn Det finns en avvägning man måste göra mellan långa beskrivande namn och kortare mer lätthanterliga namn. Det gäller dock inte samma principer för klassnamn som det gör för variabelnamn. Det finns flera fördelar med att ha väl beskrivande klassnamn. Till exempel blir det mycket enklare för oinsatta att förstå strukturen och användningen av de olika klasserna. Ett av kursens absolut längsta klassnamn är ContestantByStart NumberAndCompetitionClassComparator8, detta är dock ett exempel på ett väl långt klassnamn. Det hade förmodligen gått lika bra att beskriva vilken typ av lopp eller sortering som komparatorn är avsedd att användas till. Ett annat problem som långa namn medför är att de inte får plats på raden, särskilt om man är långt inne i ”if-while-for”-kombinationer (nästlade satser). Korta namn Det finns tillfällen då man tillåts använda mycket korta namn (läs: enbokstavsnamn) i koden. Det är när man ska göra en loop och behöver ett index (rekommenderade bokstäver är; i, j och k), förutsättningen är att man använder indexet enbart i sin loop, måste man använda den även utanför finns risken att man snabbt glömmer bort vad den egentligen är. Om iterationsindexet har en högre mening, till exempel om det betyder olika typer av motorcyklar bör man däremot välja ett beskrivande namn för det. I ett exemplet skulle mcType eller MCType (beroende på hur man vill förkorta motorcykel). Ett bra tips från wiki-wiki-web är att man kan välja sina temporära enbokstavsvariabler namn som; xx, jj och så vidare9. På sådant sätt är det enkelt att göra en så kallad ”search-and-replace” då man upptäckter att ett bättre namn behövs. Risken finns naturligtvis att man är för lat för att upptäcka det. Det är lätt att välja namn som x, test eller temp när man testar ny kod. Tyvärr är risken ganska stor att man ”glömmer” att ändra dem till bättre namn då man har fått rätt på koden. Slutsatsen är att man bör välja vettiga namn redan från början, då minskar risken att man glömmer kvar dåliga namn till noll. Exempel på korta namn finns det massvis av i projekten, men framförallt används de som index i loopar och är därför motiverade. 7 8 9 enligt muntlig undersökning i projektgruppen samt bland bekanta PVG2003, grupp cs0301, ContestantByStartNumberAndCompetitionClassComparator.java www.c2.com/cgi/wiki?SystemOfNames – jgsack Sida 6 av 10 Konsekvens Om man har en klass som heter till exempel ContestantList bör man kunna anta att den uppför sig som en lista. Om det inte är en lista bör den ha ett annat namn. Är det en lista bör dess metoder för att lägga till och ta ut element vara namngivna och ge samma resultat som för en generell lista. Är det en lista för deltagare är det förmodligen bara deltagare som man kommer att lägga in i listan (kommer man att lägga in annat ska den ha ett annat namn), alltså är det inte nödvändigt att kalla metoden för att lägga in saker i listan för addContestant, add bör kunna fungera lika bra. På samma sätt bör man inte använda olika ord för samma sak. Kallas något som används för att ta saker ur en lista fetch i en klass ska det inte heta retrive i någon annan, förutsatt att interfacet är lika. Förvillande namn Ward Cunningham skriver att ”människor gör ofta antagningar baserat enbart på objektnamnen”, det visar hur viktigt det är att klassnamnen verkligen speglar klassens innehåll och användningsområde. Ett exempel från wiki-wiki-web är metoden runTests() som fanns i tidiga JUnit-paket10. Det är lätt att tro att metoden användes för att köra test, men i själva verket är det en metod som ger antalet körda test. Känslan förstärks av att det i en klass finns en metod för antalet testfall, countTestCases(). Författaren som tar upp exemplet ger flera exempel på bättre namn, ett är testsRunCount()11 (jag hade föredragit countTestsRun() för att vara konsekvent med den tidigare nämnda metoden). I senare versioner har man bytt ut namnet mot det mer passande runCount(), tyvärr har man fortfarande kvar namnet för antalet testfall och man har därmed inte en konsekvent namngivning. Från projekten finns det exempel på när detta misslyckas, jämför klassnamnen Time och RealTime12. Båda klasserna återfinns i samma projekt, den första hanterar tider (beräknar skillnad mellan två tider med mera) och den andra används för att få aktuell tid. Namnet RealTime får åtminstone mig att tänka på realtidstillämpningar, man skulle dessutom kunna tro att RealTime är en superklass till Time men så är ju absolut inte fallet. I en annan grupps projekt (två grupper faktiskt) finns klassen TimeStamp13, den klassen klarar samma saker som Time och RealTime tillsammans, namnet ger dessutom något klarare information av vad den ska användas till. Förkortningar I Javas code conventions nämns att man bör undvika förkortningar förutsatt att förkortningen inte är mer använd än det förkortade namnet. Problemet med förkortningar är att de i vissa fall kan vara högst personliga. Till exempel skulle förkortningen FTR inte uppenbart vara en förkortning för FinishTimeRegistrator. Ett följdproblem som förkortningar kan ge är problem med uttal. Krångliga bokstavskombinationer blir omöjliga att uttala på ett bra sätt, de blir därmed svåra att diskutera. Att ha egenpåhittade förkortningar talar dessutom emot att ha beskrivande lättförståeliga namn. Det här är viktigare att tänka på att undvika förkortningar när man namnger klasser 10 11 12 13 JUnit 2.1, www.sourceforge.net/projects/junit/, TestResult.java www.c2.com/cgi/wiki?SystemOfNames – Dave Whipp PVG2003, grupp cs0301, Time.java respektive Realtime.java PVG2003, grupp cs0302 och cs0304, TimeStamp.java Sida 7 av 10 och metoder än när man namnger variabler. Att använda nbrOfContestants istället för numberOfContestants är nästan att rekommendera. Däremot är nbrOfCont förmodligen att ta det hela lite för långt. Sida 8 av 10 Slutsats Jag skrev tidigare att jag trodde att det skulle vara lätt att hitta en standard för hur man ska namnge. Jag trodde även att det skulle vara lätt att hitta fel och brister i projektens kod. Det har däremot visat sig att kodkvaliteten, åtminstone vad det gäller namnen, är ganska bra. Fortfarande finns det många tips och idéer som man kan ta till sig. Inte minst när det gäller Ward Cunninghams ord om klassnamn. Många av felen är lätta att rätta till, såvida det gäller variabel och metodnamn. Har man misslyckats med ett klassnamn är risken större att det hänger kvar, särskilt om man använder sig av CVS. Detta eftersom det är, förvisso inte svårt, men omständligt att byta namn i ett CVS-system. Efter det här arbetet kommer jag att ta med mig mer uppmärksamhet in i kommande projekt rörande namngivning. Många av de saker jag har tagit upp har mer eller mindre redan varit kända. Men jag har framförallt fått upp ögonen för vikten av att man gemensamt kommer överens om en ”namngivningspolicy” samt vikten av träning. Jag kommer nog dessutom att vara mer uppmärksam och dessutom genomföra förändringar då jag ser dåliga namn. Redan i slutet av projektet har jag upptäckt att jag mer ofta har lagt märke till och påpekat dåliga namn. Som coach av ett XP-team kan det tänkvärt att komma ihåg vikten av att hålla koden i bra skick. Att ha det som en kontinuerlig rutin att diskutera de namn som man har valt och kommer att välja kan man minska antalet kostsamma missförstånd. Vidare läsning Jag rekommenderar starkt den litteratur som finns i referenslistan. Framförallt anser jag att Ottingers artikel ger många klara tips och idéer. På olika wiki-wiki-webs14 hittar man bra diskussioner om namngivning där man kan få mycket inspiration, men det som framförallt kommer fram där är att det finns många olika uppfattningar. Det som Ward Cunningham (med flera) har skrivit ger en bra överblick, man får även många exempel på bra och dåliga namn. Det är även därifrån jag har hittat många av mina exempel. Ben Liblits artikel är mer åt det teoretiska hållet och tar främst upp hur och varför programmerare väljer sina namn så som de gör (eller borde göra). Han hittar bland annat en koppling mellan vår grammatik och grammatiken för program. 14 Ward Cunninghams är tveklöst den jag har haft mest nytta av, www.c2.com Sida 9 av 10 Referenslista Cunningham med flera, System of Names, www.c2.com/cgi/wiki?SystemOfNames Cunningham med flera, System Metaphor, www.c2.com/cgi/wiki?SystemMetaphor Fowler, Refactoring: Improving the Design of Existing Code, Addison-Wesley, 2000 Jeffries, Anderson, Hendrickson, Extreme Programming Installed, Addison-Wesley, 2001 Liblit, Speaking in Code: Cognetive Perspectives on the Role of Naming in Computer Programs, www.cs.berkeley.edu/~liblit/naming/naming.pdf, 2001 Ottinger, Rules for Variable and Class Naming, www.objectmonitor.com/resources/articles/naming.htm Java Code Conventions, www.java.sun.com/docs/codeconv/ Sida 10 av 10