Dacă eşti un programator cu experiență atunci ai auzit de cartea „Clean code” scrisă de Robert C. Martin. În multe companii, această carte a devenit parte din biblia dezvoltatorului. Combinată cu „Clean Coder” (Programatorul Curat), aş spune că aceste două cărţi sunt obligatorii pentru toţi dezvoltatorii.
Voi realiza o serie dedicate acestui subiect. Dacă deja aţi citit cartea, atunci este o ocazie bună să vă o reactualizați. Pentru ceilalţi, acesta este momentul perfect pentru a descoperi cât de bine ar trebui să arate codul. Toate ideile principale sunt preluate din „Clean Code” (Cod Curat). Puteţi privi această serie de articole drept un rezumat al cărţii în sine.
Am decis să încep să scriu despre această temă deoarece sunt lucruri care trebuie reamintite şi recapitulate din când în când. „Clean Code” este genul de carte pe care nu o citeşti doar o dată şi apoi o arunci într-un colţ întunecat al camerei tale. Este genul de carte pe care o reciteşti iar şi iar. De fiecare dată vei descoperi lucruri noi pe care le-ai omis sau care sunt revelatoare pentru tine în mai multe feluri.
Acesta este primul subiect pe care îl vom dezbate în acest articol. Un nume bun poate înlocui o documentaţie de o pagină şi poate ajuta un alt dezvoltator să înţeleagă aplicaţia şi să găsească o problemă într-o perioadă mai scurtă de timp. Totul într-o aplicaţie are un nume, de la un field (câmp) banal la numele unei metode sau al unei componente. De aceea este important să dai şi să utilizezi denumiri potrivite.
De câte ori v-aţi uitat peste un cod scris cu trei luni în urmă şi nu v-aţi putut aminti ce aţi făcut acolo? De aceea, o denumire bună este de neînlocuit.
Un nume bun poate să îţi economisească 10 minute de debugging (depanare) sau 20 de minute de căutare prin documentaţie. Atunci când ne uităm peste un cod, acesta trebuie să se desfășoare în mod coerent. Chiar şi cel mai complex algoritm ar trebui să fie uşor de citit dacă ai o denumire bună.
Numele unui câmp, metodă, clasă sau componentă ar trebui să ne spună de ce a fost creat(ă), care este scopul său principal. Mai jos puteţi găsi exemplul clasic care este dat atunci când vorbim despre acest subiect.
DateTime d;
DateTime dn;
DateTime dlr;
Dacă ne uităm peste aceste definiţii ale câmpurilor sau dacă le vedem undeva în codul nostru, nu am avea nicio idee despre ceea ce reprezintă aceste câmpuri sau de ce au fost ele utilizate (create).
DateTime creatingDate;
DateTime currentDate;
DateTime timeFromLastRun;
Denumirile de mai sus ne oferă mai multe informaţii despre câmpurile noastre. Ne este clar care este scopul fiecărui câmp şi ce fel de informaţii ne oferă.
Nu ar trebui niciodată să folosim o denumire sofisticată sau care ascunde scopul unei resurse anume. Nu uitaţi că un nume lung nu afectează performanţa aplicaţiei. Da, este adevărat că în anumite limbaje aceasta poate să mărească dimensiunea aplicaţiei, dar în zilele noastre spaţiul nu mai este o problemă – este mai scump să ai o echipă de suport care nu înţelege o parte a aplicaţiei.
Găsirea unui nume bun poate dura ceva timp, dar ne poate economisi timp mai târziu. Deoarece găsirea unor denumiri bune este destul de dificilă, este destul de uşor să recurgi la nume care sunt deja consacrate. De exemplu, utilizarea numelor ca „hp”, „cmd” sau „sco” este dăunătoare. Acestea sunt nume care sunt deja utilizate drept comenzi de către sistemul de operare.
Atunci când alegi un nume care este deja utilizat în alt context ar trebui să ai grijă să îl utilizezi în acelaşi context sau cu acelaşi sens. Nu utilizaţi niciodată denumiri consacrate în alte scopuri.
carList
houseList
Ce observați în exemplele de mai sus? Sufixul „List” ne spune că variabila este o colecţie de maşini sau case. Dacă variabila reprezintă numai o maşină sau o casă, atunci numele induce în eroare. De asemenea, există cazuri în care „List” este utilizat chiar dacă desemnează o mulţime sau alte tipuri de colecţii.
Un alt aspect important este denumirea similară a câmpurilor. În exemplele de mai jos avem două câmpuri care sunt diferite numai printr-o singură literă, sau alte două câmpuri care sunt foarte lungi, iar observarea diferenţei este dificilă.
cars
car
optimizelViewConfigurationUsingAVirtualProcess
optimizeIViewConfigurationUsingBVirtualProcess
În exemplul legat de „car(s)”, găsirea unei denumiri precum currentCar
şi carCollection
ne-ar putea ajuta să înţelegem scopul lor.
Evitaţi utilizarea caracterelor care sunt similare, cum ar fi „L” mic (l) şi „I” („i”) mare sau „0” (Zero) şi „O” („o” mare). Este extrem de dificil să observi diferenţa dintre ele. În exemplul de mai sus, cel legat de denumirile lungi, prima literă după „optimize” nu este aceeaşi.
Într-o aplicaţie, se poate întâmpla să sfârşeşti prin a avea denumiri similare, chiar dacă ai încercat să faci o diferenţă clară între ele. Din această cauză se poate să scriem un cuvânt greşit sau să adăugăm numere la finalul unei denumiri.
În exemplul de mai jos avem o metodă care transformă un şir dintr-un format în altul.
void Convert(string s1, string s2)
Numele parametrilor de input (intrare) nu ne ajută să înţelegem logica. Înlocuirea lui s1
cu input
sau inputInXYZFormat
şi s2
cu output
sau converted
sau outputInABCFormat
ne-ar ajuta mai mult.
Când nu avem idei pentru a denumi o clasă, putem sfârşi prin a avea 3 clase cu următoarele nume:
Car
CarData
CarInfo
Problema cu această denumire este că nu există o diferenţă clară între „Data” şi „Info”. Cititorul nu va şti ce fel de informaţie conţine fiecare clasă.
Utilizarea sufixelor sau a prefixelor care reprezintă tipul câmpului nu ne ajută să facem un cod mai lizibil. Care este diferenţa dintre „Name” şi „StringName” sau „NameString”? Nu este nicio diferenţă în final. Un nume precum „CarName” ar fi mai util. Acelaşi lucru este valabil şi pentru denumirea metodei, a proprietăţilor sau a clasei.
Chiar dacă codul este scris pentru maşini (010101001), este destul de sigur că vei ajunge în timpul depanării sau a reutilizării să vorbeşti cu altă persoană despre acel cod. Ar suna destul de stupid să denumeşti un câmp într-un fel pe care nu îl poţi citi sau să foloseşti o denumire care este codată.
'carN4RegS1' – 'carNumberForRegistrationSection1'
'dtoCRcrd100' – 'car'
Sună ciudat? Nu.
Tu ai nevoie să cauţi în cod pentru a vedea diferitele câmpuri utilizate. Da, este adevărat că noile IDE pot face treaba asta pentru noi, dar totuşi trebuie să folosim denumiri care pot fi căutate uşor.
De exemplu, cât de uşor este să găseşti unde a fost utilizat „i” sau „j”? Acelaşi lucru se întâmplă cu cuvintele magice care sunt folosite în linie, fără a le extrage drept constante.
De exemplu, căutarea şi înlocuirea unei valori numerice într-o aplicaţie poate fi un coşmar dacă aceeaşi valoare a fost utilizată în linie pentru cazuri de utilizare diferite.
Nu încerca să reinventezi roata şi să-ţi defineşti propria codificare pentru lucruri care au fost deja definite şi standardizate. Ultimul lucru pe care doreşti să îl ai este propriul tău limbaj personalizat.
De aceea, încearcă să foloseşti prefixe precum „I” pentru interfeţe sau sufixul „Base” pentru clase abstracte. Nu folosi prefixul „C” pentru implementarea claselor sau „m_” pentru variabile.
Dacă sfârşeşti prin a avea o codare personalizată, fă un pas înapoi şi încearcă să vezi de ce ai ajuns în situaţia asta. În funcţie de acest răspuns, ar trebui să iei o hotărâre.
Să începem cu un exemplu:
r
t
p
Chiar dacă suntem dezvoltatori, nu dorim să învăţăm şi să memorăm că „r” înseamnă întregul url al Dacia server din România, „t” este acelaşi url, dar fără informaţia protocol şi „p” reprezintă parametrii de interogare pe care trebuie să îi trimitem la server pentru a putea să ne logăm.
Chiar dacă hărţile mintale nu sunt benefice, există câteva denumiri care sunt standard în zilele noastre. De exemplu, atunci când vedem un „i” sau „j”, ştim din primul moment că vorbim despre o iterare.
Există două reguli simple care ne pot ajuta mult atunci când trebuie să găsim un nume bun pentru clasa noastră sau pentru metode:
Încercaţi să evitaţi denumirea claselor cu prefixe sau sufixe precum Service, Factory, Processor, Data, Info. Aceste denumiri de clase sunt întrebuinţate prea mult (mai ales când nu găsim denumiri mai bune).
Un concept din sistemul tău ar trebui să aibă aceeaşi denumire. Fii consecvent în această privinţă. Nu vrei să ai două nume pentru o clasă care exprimă acelaşi concept. De exemplu „Processor” şi „Analyzer” sau „Controller” şi „Manager”.
Utilizarea aceluiaşi cuvânt per concept îi va ajuta pe dezvoltatori să înţeleagă codul mai uşor.
Nu folosiţi denumiri care sunt din afara contextului şi nu sunt din acel domeniu specific. Este mai natural pentru cineva care lucrează în industria auto să folosească cuvântul „motor” şi nu „sursă de putere”. Ar trebui să utilizaţi denumirile specifice ale domeniului şi nu alte denumiri date de dezvoltatori, care pot fi greşite.
Aceasta poate fi o cauză de neînţelegere între clienţi şi dezvoltatori.
Este destul de uşor să adaugi context lucrurilor care sunt deja clare. De exemplu, într-o clasă denumită „Car”, nu este nevoie să numeşti câmpul culoare al clasei „carColor” sau „colorCar”. Eşti deja în clasa maşină şi toate informaţiile din această clasă sunt legate de „Car (Maşină)”.
Găsirea denumirilor bune într-o aplicaţie poate fi o treabă dificilă şi care necesită mult timp. Nu este simplu să găseşti denumiri bune. Dar ar trebui să investiţi timp pentru a găsi şi utiliza denumiri potrivite.
Diferenţa dintre un programator deştept şi unul profesionist este că profesionistul înţelege importanţa clarităţii. Profesioniştii îşi folosesc abilităţile pentru a scrie cod care poate fi înţeles de către alţii.