Skrivande elegant och läsbar kod

I denna handledning kommer vi att ge dig nio praktiska tekniker för att skriva elegant och läsbar kod. Vi kommer inte att prata om specifika arkitekturer, språk eller plattformar. Fokus ligger på att skriva bättre kod. Låt oss börja.

"Att mäta programmeringsframsteg med koden är som att mäta flygplanets byggnadsförlopp efter vikt." - Bill Gates

Introduktion

Om du är en utvecklare så har det förmodligen varit tider när du har skrivit kod och efter några dagar, veckor eller månader såg du tillbaka på det och sa till dig själv "Vad gör den här koden?" Svaret på den frågan kan ha varit "jag vet verkligen inte!" I så fall kan du bara gå igenom koden från början till slut och försöka förstå vad du tänkte när du skrev det.

Det här händer oftast när vi är lat och vi vill bara genomföra den nya funktionen som kunden bad om. Vi vill bara få jobbet gjort med så lite ansträngning som möjligt. Och när det fungerar bryr vi oss inte om själva koden, eftersom kunden aldrig kommer att se ful sanning, än mindre förstå det. Höger? Fel. Idag har samarbetet med programvara blivit standard och människor kommer att se, läsa och inspektera koden som du skriver. Även om din kod inte granskas av dina kollegor, borde du göra det vanligt att skriva tydlig och läsbar kod. Alltid.

För det mesta jobbar du inte ensam på ett projekt. Vi ser ofta ful kod med variabler som har namn som jag, en, p, proffs, och rqs. Och om det verkligen blir dåligt, är det här mönstret synligt över hela projektet. Om detta låter bekant, så är jag ganska säker på att du har ställt dig frågan "Hur kan den här personen skriva kod så här?" Det här gör du givetvis allt tacksamare när du kommer över tydlig, läsbar och till och med vacker kod. Tydlig och ren kod kan läsas på några sekunder och det kan spara dig och dina kollegor mycket tid. Det borde vara din motivation för att skriva kvalitetskod.

1. Lätt att förstå

Vi är alla överens om att kod ska vara lätt att förstå. Höger? Det första exemplet fokuserar på avstånd. Låt oss titta på två exempel.

 returnera genus == "1"? vikt * (höjd / 10): vikt * (höjd * 10);
 om (kön == "1") returvikt * (höjd / 10);  annars returvikt * (höjd * 10); 

Även om resultatet av dessa exempel är identiska, ser de ganska annorlunda ut. Varför ska du använda fler rader av kod om du kan skriva mindre? Låt oss undersöka två andra exempel, något jag slår vad om att du ser ofta.

 för (Node * nod = lista-> huvud; nod! = NULL; nod = nod-> nästa) utskrift (nod-> data);
 Node * node = list-> head; om (nod == NULL) returnera; medan (nod-> nästa! = NULL) Skriv ut (nod-> data); nod = nod-> nästa;  om (nod! = NULL) Skriv ut (nod-> data);

Återigen är resultatet av dessa exempel identiska. Vilken är bättre? Och varför? Får färre rader kod betyda bättre kod? Vi återkommer denna fråga senare i denna handledning.

2. Är mindre alltid bättre?

I datavetenskap hör du ofta frasen "mindre är mer". Generellt sett, om du kan lösa ett problem i färre rader av kod, desto bättre. Det kommer förmodligen att ta dig mindre tid att förstå en 200-linjeklass än en 500-linjeklass. Men är detta alltid sant? Ta en titt på följande exempel.

 bokning ((! room = FindRoom (room_id))) || ! Rum-> isOccupied ());
 rum = FindRoom (room_id); om (rum! = NULL) bokning (! room-> isOccupied ());

Håller inte med om att det andra exemplet är lättare att läsa och förstå? Du måste kunna optimera för läsbarhet. Naturligtvis kan du lägga till några kommentarer till det första exemplet för att göra det lättare att förstå, men det är inte bättre att lämna ut kommentarer och skriva kod som är lättare att läsa och förstå?

 // Bestäm var man ska gissa monsteret längs Y-axeln CGSize winSize = [CCDirector sharedDirector] .winSize; int minY = monster.contentSize.width / 2; int maxY = winSize.width - monster.contentSize.width / 2; int rangeY = maxY - minY; int actualY = (arc4random ()% rangeY) + minY;

3. Namn

Att välja beskrivande namn för saker som variabler och funktioner är en viktig aspekt för att skriva läsbar kod. Det hjälper både dina kollegor och dig själv att snabbt förstå koden. Namngivna en variabel tmp berättar inte något annat än att variabeln är tillfällig av någon anledning, vilket är inget annat än en utbildad gissning. Det berättar inte om variabeln lagrar namn, datum etc..

Ett annat bra exempel är namngivning av en metod sluta. Det är inte ett dåligt namn i sig, men det beror verkligen på metodens genomförande. Om det utförs en farlig operation som inte kan ångras, kanske du vill byta namn på den döda eller paus om åtgärden kan återupptas. Får du idén?

Om du arbetar med en variabel för vikten av potatis, varför skulle du namnge den tmp? När du återvänder den del av koden några dagar senare kommer du inte att återkalla vad tmp används till.

Vi säger inte det tmp är ett dåligt namn för en variabel, eftersom det finns tider när tmp är helt rimligt som ett variabelt namn. Ta en titt på följande exempel där tmp är inte ett dåligt val alls.

 tmp = first_potato; first_potato = second_potato; second_potato = tmp;

I ovanstående exempel, tmp beskriver vad det gör, det lagrar tillfälligt ett värde. Det överförs inte till en funktion eller metod, och den ökas inte eller ändras. Den har en väldefinierad livstid och ingen erfaren utvecklare kommer att kastas av variabelns namn. Ibland är det dock bara vanlig latskap. Ta en titt på nästa exempel.

 NSString * tmp = användarnamn; tmp + = "" + user.phone_number; tmp + = "" + user.email; ... [mall setObject: tmp forKey: @ "user_info"];

Om tmp lagrar användarens information, varför heter den inte användarinformation? Korrekt namngivning av variabler, funktioner, metoder, klasser etc. är viktigt när du skriver läsbar kod. Det gör inte bara din kod mer läsbar, det sparar tid i framtiden.

Objektiv-C är ganska ordentlig, men det är väldigt lätt att läsa. Apple använder en väldefinierad namngivningskonvention som du kan anta i de flesta programmeringsspråk. Du kan läsa mer om denna namngivningskonvention i Programmering med Objective-C.

4. Lägg till meningar till namn

Som vi såg i föregående tips är det viktigt att välja namn klokt. Det är dock lika viktigt att du lägger till mening på de namn du använder för variabler, funktioner, metoder etc. Det hjälper inte bara att undvika förvirring, det gör den kod du skriver lättare att förstå. Att välja ett namn som är vettigt är nästan som att lägga metadata till en variabel eller metod. Välj beskrivande namn och undvik generiska. Ordet Lägg till, till exempel, är inte alltid idealisk som du kan se i nästa exempel.

 bool addUser (Användare u) ...

Det är inte klart vad Lägg till användare är tänkt att göra. Lägger den till en användare i en lista med användare, till en databas eller till en lista över personer som inbjudits till en fest? Jämför detta med registerUser eller signupUser. Det här är mer meningsfullt. Höger? Ta en titt på följande lista för att få en bättre uppfattning om vad vi kör på.

Ord synonymer
do göra, utföra, exekvera, komponera, lägga till Start lansera, skapa, börja, öppna explodera detonera, spränga, starta, brista

5. Namnstorlek

Många programmerare gillar inte långa namn, eftersom de är svåra att komma ihåg och omständliga att skriva. Naturligtvis bör ett namn inte vara löjligt länge newClassForNavigationControllerNamedFirstViewController. Detta är svårt att komma ihåg och det gör helt enkelt din kod ful och oläslig.

Som vi såg tidigare är motsatsen, korta namn, inte heller bra. Vad är rätt storlek för en variabel eller metodnamn? Hur bestämmer du mellan att namnge en variabel len, längd, eller user_name_length? Svaret beror på sammanhanget och den enhet som namnet är knutet till.

Långa namn är inte längre ett problem när man använder en modern IDE (Integrated Development Environment). Kodfärdiggörande hjälper dig att undvika skrivfel och det gör också förslag till att komma ihåg namn mindre smärta.

Du kan använda korta (er) namn om variabeln är lokal. Det är dessutom rekommenderat att använda kortare namn för lokala variabler för att hålla koden läsbar. Ta en titt på följande exempel.

 NSString * länk = [[NSString allokera] initWithFormat: @ "http: // localhost: 8080 / WrittingGoodCode / resurser / GoodCode / getGoodCode /% @", idCode]; NSURL * infoCode = [NSURL URLWithString: länk];

6. Namn på Booleans

Booleaner kan vara knepiga att namnge, eftersom de kan ha en annan betydelse beroende på hur du läser eller tolkar namnet. I nästa kodbit, read_password kan innebära att lösenordet har lästs av programmet, men det kan också innebära att programmet ska läsa lösenordet.

 BOOL readPassword = YES;

För att undvika detta problem kan du byta namn på ovanstående booleska till didReadPassword för att ange att lösenordet har lästs eller shouldReadPassword för att visa att programmet behöver läsa lösenordet. Det här är något du ser mycket i mål-C, till exempel.

7. Att kommentera eller inte kommentera

Att lägga till kommentarer till kod är viktigt, men det är lika viktigt att använda dem sparsamt. De bör användas för att hjälpa någon att förstå din kod. Läsning av kommentarer tar dock också tid och om en kommentar inte lägger till mycket värde, är den tiden bortkastad. Nästa kodsedel visar hur inte att använda kommentarer.

 // Detta händer när minnesvarning tas emot - (void) didReceiveMemoryWarning [super didReceiveMemoryWarning]; // Kassera alla resurser som kan återskapas.  // Detta validerar fälten - (BOOL) valideraFields 

Är de här kodavsnitten användbara för dig? Svaret är förmodligen "Nej". Kommentarerna i ovanstående exempel lägger inte till ytterligare information, särskilt eftersom metodnamnen redan är mycket beskrivande, vilket är vanligt i mål-C. Lägg inte till kommentarer som förklarar det självklara. Ta en titt på nästa exempel. Är det inte så mycket bättre att använda kommentarer?

 // Bestäm monsterets hastighet int minDuration = 2.0; int maxDuration = 8,0; int rangeDuration = maxDuration - minDuration; int actualDuration = (arc4random ()% rangeDuration) + minDuration;

Kommentarer som detta gör det mycket enkelt att navigera en kodbas snabbt och effektivt. Det sparar dig från att behöva läsa koden och hjälper dig att förstå logiken eller algoritmen.

8. Stil och konsistens

Varje språk eller plattform har en (eller fler) stilguide och även de flesta företag har en. Lägger du de krökta hängslen av en Objective-C-metod på en separat linje eller inte?

 - (void) calculateOffset 
 - (void) calculateOffset 

Svaret är att det spelar ingen roll. Det finns inget rätt svar. Det finns naturligtvis stilguider du kan anta. Vad som är viktigt är att din kod är konsekvent när det gäller stil. Även om det här inte påverkar kvaliteten på din kod, påverkar det säkerligen läsbarheten och det kommer sannolikt att irritera helvetet av dina kollegor eller den som läser din kod. För de flesta utvecklare är grym kod den värsta typen av kod.

9. Fokuserade metoder och funktioner

Ett vanligt misstag bland utvecklare försöker få så mycket funktionalitet i funktioner och metoder. Detta fungerar, men det är inelegant och gör felsökning i nacken. Ditt liv - och dina kollegas - blir mycket enklare om du bryter större problem i små bitar och hanterar dessa bitar i separata funktioner eller metoder. Ta en titt på nästa exempel där vi skriver en bild till disken. Det här verkar som en trivial uppgift, men det finns mycket mer om det om du vill göra det rätt.

 - (BOOL) saveToImage: (UIImage *) bild medFileName: (NSString *) fileName BOOL result = NO; NSString * documents = nil; NSArray * sökvägar = NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES); om (paths.count) documents = [paths objectAtIndex: 0]; NSString * basePath = [documents stringByAppendingPathComponent: @ "Archive"]; om (! [[NSFileManager defaultManager] fileExistsAtPath: basePath]) NSError * error = nil; [[NSFileManager defaultManager] createDirectoryAtPath: basePath withIntermediateDirectories: JA attribut: nil error: & error]; om (! fel) NSString * filePath = [basePath stringByAppendingPathComponent: fileName]; result = [UIImageJPEGRepresentation (image, 8.0) writeToFile: filePath atomically: YES];  else NSLog (@ "Kan inte skapa katalog på grund av fel% @ med användarinformation% @.", fel, error.userInfo);  returresultat; 

Om en kodenhet försöker göra för mycket, slutar du ofta med djupt nestade villkorliga uttalanden, mycket felkontroll och alltför komplicerade villkorliga uttalanden. Den här metoden gör tre saker, hämtar sökvägen till programmets katalogkatalog, hämtar och skapar sökvägen för arkivkatalogen och skriver bilden till disken. Varje uppgift kan sättas i sin egen metod som visas nedan.

 - (BOOL) saveToImage: (UIImage *) bild medFileName: (NSString *) fileName NSString * archivesDirectory = [self applicationArchivesDirectory]; om (! archivesDirectory) returnerar NO; // Skapa sökväg NSString * filePath = [arkivDirectory stringByAppendingPathComponent: fileName]; // Skriv bild till diskåtergång [UIImageJPEGRepresentation (image, 8.0) writeToFile: filePath atomically: YES]; 
 - (NSString *) applicationDocumentsDirectory NSArray * paths = NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES); returnera paths.count? [sökväg objektAtIndex: 0]: nil; 
 - (NSString *) applicationArchivesDirectory NSString * documentsDirectory = [self applicationDocumentsDirectory]; NSString * archivesDirectory = [documentsDirectory stringByAppendingPathComponent: @ "Arkiv"]; NSFileManager * fm = [NSFileManager defaultManager]; om (! [fm fileExistsAtPath: archivesDirectory]) NSError * error = nil; [fm createDirectoryAtPath: archivesDirectory withIntermediateDirectories: JA attribut: null fel: & error]; om (fel) NSLog (@ "Kan inte skapa katalog på grund av fel% @ med användarinformation% @.", fel, error.userInfo); returnera nil;  returnera arkivkatalog; 

Det här är mycket lättare att felsöka och underhålla. Du kan även återanvända applicationDocumentsDirectory metod på andra ställen i projektet, vilket är en annan fördel att bryta större problem i hanterbara bitar. Testkoden blir också mycket lättare.

Slutsats

I den här artikeln har vi tittat närmare på att skriva läsbar kod genom att klokt välja namn för variabler, funktioner och metoder, vara konsekvent när du skriver kod och bryta komplexa problem i hanterbara bitar. Om du har några frågor eller feedback, var god att lämna en kommentar nedan.