Clean Code curs 3
Rulează videoul

Transcriere

Ce părere aveți despre codul de mai jos? Cum vi se pare la o simplă citire? În primul rând e scris în Java, deci dacă problema aparentă e cu acoladele acest lucru se datorează limbajului Java, acolo așa se preferă. Programatorii de Java preferă să pună acoladele după denumirea funcțiilor, respectiv după structurile de programare, gen după for. Doar din punct de vedere al curățeniei, observăm mai multe probleme și o să vi le enumăr aici pentru că nu puteți răspunde, poate doar în zona de comentarii. 

Prima problemă e cu numele acestei funcții. Ea se numește Calculează, dar nu știm ce calculează. Ar putea să calculeze orice. Dacă stăm bine  și analizăm codul, dar asta presupune să ne petrecem foarte mult timp analizându-l, realizăm că această funcție face de fapt suma elementelor unui ArrayList. Dar, acest lucru ar fi trebuit să fie știut încă de la început, adică aprioric din denumirea metodei. Vedem că nu am ales nicio convenție de nume pentru variabile avem un x, un y. Nu știm cine sunt acest x și acest y, nu știm cine e l-ul. Adică văd că l-am declarat ArrayList, dar apoi, 3 rânduri mai jos, dacă fac l.add(), nici nu știu cine este acest l. Nu știu cine e m. Poate trebuia să se numească sumă, nu?

Ok. Hai să vedem ce reguli aplicăm ca să facem din acest cod, un cod curat. În primul rând spuneam că trebuie să folosim convenții de nume. Acestea sunt convențiile de nume principale, toate celelalte sunt derivate din acestea. Prima convenție e UpperCamelCase, asta presupune scrierea numelor de variabile, respectiv atribute și clase exact cum e scris UpperCamelCase. Adică, primul substantiv din denumire cu literă mare, urmat de al doilea cuvânt tot cu literă mare, urmat de al treilea cuvânt, legat, tot cu literă mare și așa mai departe. De exemplu dacă am clasa „card bancar” pot să scriu CardBancar, legat, cu „C” mare și „B” mare. Asta înseamnă UpperCamelCase. Lower camel case, presupune aceeași scriere doar că încep cu litera mică. Deci dacă am un atribut într-o clasă numit „card bancar”, acel atribut va fi scris card cu „c” mic, „bancar” legat, dar cu „B” mare. Ăsta e lowerCamelCase. În practică, și vă dau un exemplu despre cum folosesc eu, voi puteți să folosiți oricum, asta e doar o convenție stabilită. Pentru UpperCamelCase se folosește în general pentru clase și pentru o anumită categorie de metode, dacă vreți. Eu o folosesc pentru metodele publice. Metodele publice le pun cu UpperCamelCase. Lower camel case, îl folosesc pentru atributele din clasă și pentru metodele private.

Mai există totodată System Hungarian Notation și Apps Hungarian Notation. La ce se referă aceste notații ungare? Notația ungară presupune ca, și acum ne referim la system hungarian notation, presupune ca înaintea unui denumiri de variabilă să punem și tipul ei. De exemplu avem un întreg numarCarduri, scriem iNumarCarduri, unde „n” cu „N” mare, „c” cu „C” mare, folosind totodată notația camelCase. Ca să spunem că acest i e întreg. Am un șir de caractere „titular card” pot să scriu strTitularCard, totul scris legat. Ăsta va fi un system hungarian notation pentru un string. Acum, în practică, system hungarian notation se folosește doar în limbajele „loose type” sau „loosely typed”, limbajele care nu au tipuri de date concrete. Adică declară variabile generale și acele în acele variabile pot pune orice fel de dată. E cazul JavaScript, PHP, în care declar o variabilă și în ce apare acolo pot pune și întreg, pot pune șir de caractere și ea ia tipul valorii puse în ea. Ei, ca să pot să forțez să fac din acest tip, din acest limbaj loose type, să fac un strong type, atunci pun în fața variabilei respective tipul și atunci voi ști clar că de exemplu într-un iNumarCard am voie să salvez doar un întreg, n-am voie să pun un șir de caractere, într-un strTitularCard am voie să pun doar un șir de caractere, nu am voie să pun un întreg.

Pentru limbajele folosite în mod curent și anume C#, Java, C++, care sunt strong type, se preferă mai degrabă Apps Hungarian Notation. Ce presupune acesta? Presupune să pun o literă care îmi spune ori vizibilitatea, ori tipul datei respective. Și eu de exemplu, prefer să pun un m în fața membrilor (atributelor) clasei. De ce? Atributelor private, atenție. De ce? Ca să știu că sunt membri, m de la member. Sunt membri în acea clasă, nu pot fi văzuți din exterior, așa că pun un m. În fața variabilelor statice prefer să pun un s, de la static, în fața constantelor prefer să pun un c și așa mai departe. De exemplu dacă am o constantă în clasa mea, care spune, nu știu, codulBancii, o să am c mic codul băncii cu „C” mare, „B” mare și scris legat. Ăsta e apps hungarian notation pentru constante. 

O să găsiți în practică, în funcție de firma pentru care lucrați, în funcție de proiectul pe care lucrați sau de ce vă impune, de exemplu, o soluție sau un instrument de curățare a codului, despre care o să vorbim puțin mai târziu. În funcție de ce vă e impus de unul dintre acești factori, o să găsiți ori exact aceste convenții, așa cum le-am explicat, ori combinații între acestea. 

Ok, acum că am stabilit exact cum denumim variabile, atributele, funcțiile și clasele, hai să vedem cum aplicăm aceste convenții de nume pe fiecare în parte. La clase, mare atenție la ce denumire alegem pentru clase. Denumirea trebuie să fie sugestivă, dacă cineva citește denumirea acelei clase, trebuie să își dea seama exact că acea clasă face un anumit lucru. Apoi, trebuie să alegem cu atenție o denumire pentru clasă pentru că numele prost alese sunt un magnet pentru programatorii leneși. Adică, e vineri seara, nu am chef să scriu, adică scriu cu silă oricum ultima funcție care să facă nu știu ce, nu știu unde să o pun, o trântesc într-o clasă care se cheamă UtilityManager sau Utils, parcă merge acolo. O trântesc acolo și nu mai știe nimeni de ea. Când va fi vorba de modificat clasa Utils, o să mă minunez de ce găsesc pe acolo.

Apoi, un nume de clasă trebuie să fie compus dintr-un substantiv specific, fără prefixe sau sufixe inutile. Deci, nu UtilityManager, nu UserInfo. User și atât, Utility și atât. Dar Utility am zis deja ca nu e recomandat. Dar nu am de ce să am UserInfo și alte chestii. User e suficient. Apoi, nu trebuie să uităm de principiul Single Responsability. Adică o clasă trebuie să facă un singur lucru și numai unul. Adică nu faceți clase care fac ghiveci. Prelucrează și anumite chestii și alte chestii și tot ce vrei. 

Ok. Legat de convențiile de nume în metode. Un nume corect ales de metodă trebuie să descrie clar ce face acea metodă. Uitați-vă la exemplul de mai devreme cu acel calculează, în primul rând ar fi trebuit să primească ca și parametru o listă sau un ArrayList de obiecte da, de întregi, pe care să îl prelucreze. Și numele corect era sumaElementeArrayList, de exemplu, scris legat, folosind camelCase, chiar UpperCamelCase. Deci scriam SumaElementeLista și gata. Asta făcea. Dacă era o listă specifică, noi am folosit un ArrayList care poate să primească orice obiect. Object are ca și element. Dar, dacă ar fi fost să folosesc o listă, din Generics, care are un tip specific, atunci puteam să scriu direct. Dacă primea ca și parametru o listă de studenți, puteam să fac sumaNoteStudenti.

Există situații într-adevăr când numele prost alese nu pot fi evitate. Ele sunt generate automat de mediu. În acest caz e indicat ca în interiorul acestora să fie doar apeluri de alte metode. Și aici mă refer în general, de exemplu să luam C#-ul, cu Windows Forms. Putem discuta la fel de bine de Android. Deci, la C#, la Windows Forms știți că aveți, de exemplu, evenimentul de load pe formulare – onLoad. Nu am cum să schimb, să nu am numele formular underscore onLoad ca și nume de metodă. Dacă scriu, n-o să mai funcționeze programul pentru că e înglobată în limbajul de programare. La fel cum la Android pe buton de exemplu am onClick și așa mai departe. Unde nu pot evita această denumire generată de sistem, voi alege ca în funcția respectivă să fac doar apel de metodă. Și de exemplu, să zicem că, nu știu, la încărcarea unui formular, la Form1_OnLoad, vreau să încarc datele și să validezi formularul. Voi apela o funcție incarcaDate, o funcție valideazaFormular și atât voi face în metoda onLoad. Și codul e considerat clean. Apoi, atenție, am spus o funcție care încarcă date și o funcție care validează. Niciodată o funcție care și încarcă și validează. De ce? Ori de câte ori numele unei metode conține o conjuncție (și, sau, ori), e ok să fac din ea două metode sau chiar e indicat să fac din ea două metode. Deci am, unde am VerificaSiTrimiteMail, ValideazaUtilizatorSiInsereaza. Nu, am ValideazaUtilizator și InsereazaUtilizator. VerificaUtilizator, TrimiteMail. Nu am metode compuse. 

Apoi, nu abreviați denumirile metodelor. De la asta venea chestia asta, „nu abr den met”. Limbajele curente, calculatoarele, de fapt, curente au stiva sistem destul de mare, au suficient de multe, de mult spațiu de memorie. Nu am de ce să abreviez denumirile metodelor. Am nevoie de o propoziție întreagă ca să descriu ce face acea metodă, e mai indicat să folosesc o propoziție întreagă decât să abreviez chestii. De exemplu, hai să luam o metodă, să spunem că TrimiteMail. Nu trtMail, nu ValideazaUtilizator – ValidUsr. ValideazaUtilizator, e suficient. Sau ValidUser, nu VldUsr. Că nu știu, poate, echipa în care lucrez și pentru care scriu cod e multiregională, fiecare are cultura proprie, poate în nu știu ce limbă usr înseamnă cu totul altceva și acel coleg înțelege că funcția face cu totul altceva.

Comments

comments


0 comentarii

Lasă un răspuns

Substituent avatar