Clean Code curs 4
Rulează videoul

Transcriere

Legat de variabile: în primul rând nu e indicat ca variabilele de tip string sau șir de caractere să conțină cod din alt limbaj de programare. Gen, într-un string din C# să salvez cod SQL, într-un string din Java să salvez cod CSS sau JavaScript sau HTML. De ce? Păi, în primul rând nu am validare pe acel cod, eu pot să scriu acolo verzi și uscate că nu o să valideze niciun mediu de dezvoltare codul scris în interiorul acestei variabile de tip șir de caractere. Apoi, nu funcționează „Intellisense-ul”. Dacă aș alege de exemplu să folosesc clase pentru a scrie cod SQL sau CSS o să meargă „Intellisense-ul”, pot da imediat „find” pe chestiile respective. Și mai apoi e destul de greu de urmărit, adică trebuie formatat foarte bine acel cod ca să poate fi lizibil și mă trezesc când folosesc soluția de versionare și fac commit sau checkin sau cum se numește (o să vorbim imediat și despre soluții de versionare) că acel cod scris de mine ok se duce în toate părțile și nu mai arată deloc bine. Deci, ca și regulă, nu e indicat să scriu un alt limbaj într-un string dintr-un anumit limbaj.

Apoi, variabilele booleane (logice) trebuie să sune ca o întrebare la care se poate răspunde cu adevărat sau fals. De exemplu, am un fișier, salvez într-o variabilă booleană dacă e deschis sau închis. O să pun numele valabilei isOpen, nu open. Adică eDeschis? La asta sigur pot răspunde cu adevărat sau fals. Din nou, verbalizarea mă ajută să îmi dau seama dacă e ok ceea ce fac. Apoi, când există variabile complementare numele trebuie să fie simetrice. De exemplu, aveam fișierul ăsta, aveam o variabilă isOpen, poate mai vrea să mai am o variabilă isClosed. Exact așa o să îi spun, isClosed. N-o să-i spun isDepricated, is nu știu ce, notOpen e și ăsta ok, dar nu isUsedByAnotherUser sau ceva de genul ăsta. Nu, isOpen/isClosed. Trebuie să am o oarecare simetrie. 

Am vorbit până acum despre entități de program, hai să vorbim despre entități de programare. În structurile condiționale, trebuie să evit comparațiile cu true și false. Vedeți aici chiar eu am făcut o greșeală, am spus raspunsCorect == true. raspunsCorect nu e o întrebare, poate mai ok ar fi fost esteRaspunsulCorect, la asta sigur răspundeam la întrebare cu adevărat sau fals. Și nu am de ce să fac chestia asta if (raspunsCorect == true), și chiar sună ciudat când verbalizez. Spun, dacă răspunsul corect este adevărat? Pot să spun dacă am răspuns corect, e mai simplu. De ce răspunsul corect să fie adevărat, dacă e corect? Ok. Apoi pot instanția variabile booleane direct. Vedeți aici că am scris 5 linii de cod ca să instanțiez variabila asta răspunsCorect, când puteam să scriu boolean raspunsCorect = (punctaj != 0). Și gata! Dacă era diferit de 0 îmi punea true, dacă era 0 îmi punea false. Apoi, încercați să nu fiți negativiști. Adică, puneți condițiile pe true în general, nu pe false. Adică încercați prima dată să gândiți problema afirmativă, nu partea negativă. Nu s-o gândiți invers, negativ.

Legat tot de reguli de clean code, de cod curat în structuri condiționale. Ori de câte ori e posibil, folosiți operatorul ternar. Ăsta ce face? Spre deosebire de if, care e structură de programare, semnul întrebării acesta combinat cu două puncte e operator. E mult mai rapid. Într-adevăr acum în sistemele curente, chiar nu mai contează dacă scriu un if sau un operator ternar, n-o să se simtă o mare diferență. Poate o diferență o să se simtă dacă apelez un if de un milion de ori într-un for, să zicem. Atunci da, poate o să se simtă diferența între if și operatorul ternar. O să termine for-ul ăla mult mai repede. Dar în cazul unui apel simplu e cam același lucru, doar că e mult mai ușor de citit și de verbalizat. Spun că maximul este: a dacă a e mai mare ca b sau b în caz contrar. Într-o singură linie de cod. Apoi există situații, și una dintre ele este LINQ din C#. Dacă nu ați auzit de LINQ, vă rog să căutați despre el într-un motor de căutare. Este un limbaj ce îmi permite să prelucrez niște dicționare și alte obiecte de tip Generics ca și cum ar fi DataTable de tip SQL. Adică tabelă de tip SQL. Pot să fac WHERE pot să fac ANY, pot să fac JOIN-uri dacă vreau. Mă rog, ideea e că în acest LINQ nu am voie să folosesc if, dar operator ternar pot folosi. Deci în acest caz, if oricum e exclus.

Altă regulă pentru structuri condiționale e să nu comparăm direct cu string-uri. Folosim enum dacă am mai multe cazuri. Să spun că am un statutFisier care îmi spune deschis, inchis, inFolosinta, să spunem. Ei, nu e foarte ok să scriu statutFisier == ”deschis”, să pun în alt loc statutFisier=”deschis”. De ce? Păi, unu, pot să scriu la un moment dat, adică nu merge intellisense-ul pe acest (intellisens vorbesc la mod general, nu știu cum s-o numi în alte IDE-uri, adică autocompletarea). Mă pot trezi că scriu în loc de deschis scriu „dechis” că mănânc s-ul și n-o să-mi funcționeze codul și nu mă prind în veci de ce naiba nu funcționează codul. Așa, folosind de exemplu un enum, care e cea mai elegantă variantă, scriu greșit denumirea din enum, n-o să-mi compileze codul. Am eroare de compilare, văd exact unde am scris greșit. Asta în primul rând. În al doilea rând, dacă vine un alt programator și se uită pe codul meu și o să vadă la un moment dat o comparație cu stareFisier==”deschis” sau .equals dacă vorbim de Java, == sau string.equals în C# și o să vadă deschis, o să se întrebe, ok, deschis și care mai sunt cealaltă stări, care or mai fi? Și nu are de unde să știe, trebuie să caute prin cod și să își dea seama care mai sunt celelalte stări. Pe când în cazul unui enum, dă „go to definition” pe enum, se duce la definirea lui, vede că celelalte stări sunt, cum am spus și noi, inchis și inFolosinta și e lămurit cu totul cu privire la tipul stărilor unui fișier.

Apoi, o altă regulă e ca întotdeauna când folosim constante să le identificăm și să le punem la începutul clasei. De ce? În primul rând de ce să le identificăm, hai să vorbim așa. Păi hai să zicem că avem o aplicație care verifică dacă utilizatorul este major. Și aplicația asta o facem, scoatem o versiune pentru Europa și o versiune pentru Statele Unite. În varianta pentru Europa vârsta de majorat este 18 ani, în varianta pentru Statele Unite vârsta de majorat este de 16 ani. Și să spunem că punem o echipă din Europa să facă mentenanță pentru aplicația din Statele Unite. Și atunci o să văd la un moment dat în cod if (varsta > 16). Și o să mă gândesc, păi și ce naiba e cu 16 ăsta. Cine e 16? De ce 16, de ce nu altceva? Nu ar fi mai ok să am o constantă denumită varstaMajorat căreia să îi atribui valoarea 16 sau 18 funcție de țara sau regiunea pentru care fac versiunea, și în cod să compar cu varstaMajorat. Ar fi mai ok și mai lizibilă pentru oricare programator chestia asta. Dacă folosesc și o convenție de nume pentru constantă, deja știe toată lumea că e constantă, ori de câte ori o folosesc în cod, o folosesc pe cea definită mai sus, nu am nevoie să definesc alta.

Legat tot de structurile condiționale. Ce se întâmplă când condițiile din structurile condiționare devin prea mari. Păi o variantă e să formatez condițiile în așa fel încât să dau enter după operatorii logici și sau sau. Adică && și II, să trec așa pe mai multe linii. Asta e o variantă. O varianta mai elegantă e să declar variabile intermediare. Să spunem că pentru un fișier verific dacă: e deschis e, nu e în curs de utilizare, utilizatorul curent are drepturi asupra lui și există pe server. Am patru condiții de pus într-un singur if. N-ar fi mai ok să declar două variabile separate, una care îmi spune dacă e deschis și nu-i în curs de utilizare și alta dacă utilizatorul are drepturi și e pe server și la sfârșit în if să compar aceste două variabile? Cred că ar fi mai ok așa. Spuneam mai devreme să folosiți enum. Ei bine, acest enum e indicat doar dacă clasele există deja și vin cu o chestie în plus cu o utilitate în plus, cu o stare în plus. Pe de altă parte dacă gândesc clasa de la început, ceea ce să fim sinceri, că nu prea se întâmplă practic. Adică atunci când o să vă angajați pe un proiect sau dacă deja lucrați, știți chestia asta. Nu o să luați proiectul de la zero. Foarte rar se întâmplă să lucrați pe un proiect de la zero. De obicei vreți lucra pe un proiect cu cod existent. Și de asta e și acel procent uriaș, 90% citit cod, 10% scris cod. Ei, și ideea e că dacă aleg, dacă lucrez, am norocul ăsta ca și programator să încep un proiect de la zero, și știu de la început că am un statut al documentului, poate e mai ok ca acest statut să îl salvez ca și o clasă separată. De ce? Păi poate, peste nu știu cât timp, se schimbă specificațiile și spun că vor să știe și istoricul staturilor sau data la care s-a schimbat ultimul statut. Adică ultima actualizare. Ei bine, dacă am enum, într-un enum nu pot pune așa ceva. Dacă am o clasă StatutulFisierului sau StatusulFisierului, atunci da, acolo pot pune un atribut în plus.

Dacă am multe constante în cod, acest lucru indică o nevoie de înglobare a lor într-o tabelă din baza de date. Și aici vă dau un exemplu clasic din România, de acum 4-5 ani, nu știu câți sunt, când s-a schimbat cota TVA. Ei, mulți programatori care au scris cod „murdar”, ca să facem o analogie la clean cod, și-au hardcodat valoarea de 19% în aplicații. Maxim au definit mai multe constante, că erau mai multe valori de TVA. Era una pentru turism de vreo 9%, asta pentru toată lumea de 19% și, nu mai știu, era scutit cu drept de deducere care era 0. Spun și eu așa din amintiri. Ei și s-a dat ceva de genul, legea să zicem vineri, că de luni toată lumea trece la TVA 24%. Ei și weekendul ăla a fost un weekend alb pentru mulți programatori leneși. Cum spuneam la început, că dacă nu îți faci timp să scrii cod corect, vei pierde foarte mult timp apoi ca să-l modifici. Cei care au hardcodat valoarea asta s-au trezit că trebuie să lucreze, să facă un weekend alb, ca să modifice peste tot. Și dacă au fost și băieți deștepți și-au dat seama că locul constantelor nu e în cod, ci într-o tabelă din baza de date și au pus cotele astea în baza de date. Dacă nu știu care premier se gândea că modifică TVA-ul și dădea o lege de pe o zi pe alta, cum se întâmplă de obicei la noi, foarte simplu, programatorul se ducea în baza de date a clientului, schimba 24 în 25 sau 20 sau 21, cât îl mai fac (pe TVA). Și gata, programul funcționa mai departe fără să fie nevoie de o nouă versiune, fără să fie nevoie de modificare de cod.

Comments

comments


0 comentarii

Lasă un răspuns

Substituent avatar