ABONAMENTE VIDEO REDACȚIA
RO
EN
NOU
Numărul 150
Numărul 149 Numărul 148 Numărul 147 Numărul 146 Numărul 145 Numărul 144 Numărul 143 Numărul 142 Numărul 141 Numărul 140 Numărul 139 Numărul 138 Numărul 137 Numărul 136 Numărul 135 Numărul 134 Numărul 133 Numărul 132 Numărul 131 Numărul 130 Numărul 129 Numărul 128 Numărul 127 Numărul 126 Numărul 125 Numărul 124 Numărul 123 Numărul 122 Numărul 121 Numărul 120 Numărul 119 Numărul 118 Numărul 117 Numărul 116 Numărul 115 Numărul 114 Numărul 113 Numărul 112 Numărul 111 Numărul 110 Numărul 109 Numărul 108 Numărul 107 Numărul 106 Numărul 105 Numărul 104 Numărul 103 Numărul 102 Numărul 101 Numărul 100 Numărul 99 Numărul 98 Numărul 97 Numărul 96 Numărul 95 Numărul 94 Numărul 93 Numărul 92 Numărul 91 Numărul 90 Numărul 89 Numărul 88 Numărul 87 Numărul 86 Numărul 85 Numărul 84 Numărul 83 Numărul 82 Numărul 81 Numărul 80 Numărul 79 Numărul 78 Numărul 77 Numărul 76 Numărul 75 Numărul 74 Numărul 73 Numărul 72 Numărul 71 Numărul 70 Numărul 69 Numărul 68 Numărul 67 Numărul 66 Numărul 65 Numărul 64 Numărul 63 Numărul 62 Numărul 61 Numărul 60 Numărul 59 Numărul 58 Numărul 57 Numărul 56 Numărul 55 Numărul 54 Numărul 53 Numărul 52 Numărul 51 Numărul 50 Numărul 49 Numărul 48 Numărul 47 Numărul 46 Numărul 45 Numărul 44 Numărul 43 Numărul 42 Numărul 41 Numărul 40 Numărul 39 Numărul 38 Numărul 37 Numărul 36 Numărul 35 Numărul 34 Numărul 33 Numărul 32 Numărul 31 Numărul 30 Numărul 29 Numărul 28 Numărul 27 Numărul 26 Numărul 25 Numărul 24 Numărul 23 Numărul 22 Numărul 21 Numărul 20 Numărul 19 Numărul 18 Numărul 17 Numărul 16 Numărul 15 Numărul 14 Numărul 13 Numărul 12 Numărul 11 Numărul 10 Numărul 9 Numărul 8 Numărul 7 Numărul 6 Numărul 5 Numărul 4 Numărul 3 Numărul 2 Numărul 1
×
▼ LISTĂ EDIȚII ▼
Numărul 29
Abonament PDF

Cod curat – limitări, gestionarea erorilor şi a obiectelor

Radu Vunvulea
Solution Architect
@iQuest



PROGRAMARE

În ultimele trei luni am încercat să scriu despre diferite subiecte prezentate în Clean Code. Chiar dacă acesta este al patrulea articol pe această temă, am sentimentul că mai există încă multe probleme despre care ar trebui să discutăm atunci când vorbim despre un cod curat şi bine scris.

Am putea spune că această carte, „Clean Code” scrisă de Robert C. Martin, a stabilit standardele în industria noastră din această perspectivă. Este biblia dezvoltatorilor şi de multe ori este utilizată drept „legea” codului. Nu vreau să intru mai adânc în acest subiect, dar promit că într-o zi voi vorbi în detaliu despre motivele pentru care ar trebui să utilizăm sau nu această carte ca un reper important al dezvoltatorilor .

Subiectul de azi

În acest articol, analiza va fi orientată asupra obiectelor şi structurii datelor XXXX. Vom trece de la formatul codului la cum ar trebui să arate codul şi la cum ar trebui să implementăm funcţionalităţi diferite.

Obiecte şi structura datelor

Cred că ne amintim cu toţii cursurile de la Universitate, când profesorii încercau să ne explice că ar trebui să expunem dintr-o clasă numai informaţiile de care au nevoie ceilalţi. Dar, din cauză că limbajul de programare actual ne oferă atât de uşor posibilitatea de a expune datele în afara unei clase, adesea sfârşim prin a avea o mulţime de date private dezvăluite sistemului.

Unul dintre colegii mei s-a referit la getter /setter drept dispozitivul diavolului. Este amuzant, dar uneori este adevărat.

Nu este atât de important dacă utilizăm un getter / setter al unei metode. Cel mai important lucru este să expunem datele într-un mod abstract, care să nu dezvăluie detaliile de implementare. De exemplu, dacă este nevoie să dezvăluim o informaţie legată de greutatea unei persoane, noi putem folosi un getter sau o metodă simplă. Ambele soluţii sunt bune atâta timp cât nu oferim niciun fel de detalii de implementare.

public class Person
{
    public double WeightInKg
    {
        ...
    }
    // OR
    public double GetWeightInKg()
    {
        ...
    }
}

În afara acestei clase, nu ştii cum arată aceste date sau care este formatul lor. Dacă am adăuga getters şi setters peste tot, care ar fi valoarea încapsulării? … ZERO.

Atunci când începeți să scrieți cod, e important să țineți cont de faptul că există o mare diferenţă între structurile de date şi obiecte. Cel mai bun lucru pe care puteţi să îl faceţi este să păstraţi o linie clară între acestea două.

Structura datelor expune numai datele, fără nici un fel de funcţionalitate, în contrast cu obiectele, care expun numai funcţionalitatea. Bineînţeles, noi trebuie să ţinem minte că echilibrul dintre cele două este greu de păstrat. Vei avea nevoie de o structură a datelor care expune funcţionalitatea. Trebuie doar să ai în minte datele pe care doreşti să le expui şi unde ar trebui adăugată implementarea funcţionalităţii.

Atunci când implementezi o funcţionalitate, ar trebui să vorbeşti numai cu prieteni şi niciodată cu străini (Legea lui Demeter). Acest lucru înseamnă că o funcţie ar trebui să acceseze / apeleze numai:

• Metode din clasa în care este implementată, • Metode din obiectele create prin înseşi acele metode, • Metode din obiectele care sunt trimise drept argumente, • Metode din obiectele care ajută drept instanţe în clasele în care metoda este implementată

Hibride

Structurile hibride sunt obiecte care conţin de asemenea şi structuri de date. Problema cu acestea este că e destul de greu să le adaugi funcţionalitate nouă sau date noi. Aceasta creează confuzie deoarece nu ştii ce ar trebui să adaugi acolo. Poate indica faptul că scopul acelei entităţi nu este clar şi nici dacă este necesară protejarea datelor.

Obiect cu structură de date

Sunt utilizate mult când este nevoie să stocăm datele undeva (DB) sau să trimitem date prin fir. Acestea se numesc DTO şi de obicei nu au nici un fel de funcţionalitate. Scopul lor este bun, dar ar trebui să reţinem că trebuie să le utilizăm numai în scopul pentru care eu fost create. Altfel, o schimbare în structura de date va atrage multe schimbări în codul nostru.

Deasupra DTO avem Active Records, care sunt similare cu DTO-urile, dar au metode utilizate pentru navigare, cum ar fi Fiind, Save, Delete, Send şi aşa mai departe. Această funcţionalitate este de obicei oferită de DB. Problema cu ele este că dezvoltatorii le folosesc de obicei drept obiecte şi le adaugă noi funcţionalităţi. De aceea ajungem să avem un Active Record care are logică business în interior.

Ce ar trebui să facem? Să creăm Active Records care stochează numai structura de date şi să utilizăm obiecte separate pentru a stoca regulile de business.

Gestionarea erorilor

De ce trebuie să discutăm despre gestionarea erorilor? Deoarece, chiar dacă scopul principal al codului nu este gestionarea erorilor, ci funcţionalitatea care este implementată, ajungem să avem cod în care poate fi văzută numai gestionarea erorilor şi ne este aproape imposibil să găsim detaliile despre funcţionalitatea reală care este expusă acolo.

Pentru a evita aceste situaţii, există câteva lucruri mărunte care pot fi făcute la nivelul codului. Mai întâi de toate, evitaţi să folosiţi coduri de eroare. Acest lucru adaugă mult cod metodelor voastre şi ascunde informaţia după excepţia în sine. De asemenea, cel care apelează trebuie să verifice de fiecare dată codul raportat şi să implementeze un manipulator special pentru diferitele coduri de eroare.

Excepţia poate fi utilizată cu succes în blocuri try/catch care pot fi văzute drept blocuri de „tranzacţie”, unde te aştepţi la excepţii şi eşti pregătit să le gestionezi. De asemenea, există o separare clară între funcţionalitate şi gestionarea excepţiei.

try
{
    // Functionality
} catch (FantaException nullEx)
{
    ...
} catch (CokeException nullEx)
{
    ...
}

Este important să reţinem că funcţia n care naşte o aşteptare ar trebui să furnizeze suficient conţinut despre sursa erorii. Ar trebui să încercăm să definim excepţiile specifice pe baza nevoilor apelantului. De ce? Pentru că scopul lor principal este să îl ajute pe apelant să găsească sursa problemelor.

Nul

Nu ar trebui niciodată să faci două lucruri:

-Să returnezi un NULL. Apelantul va fi nevoit să verifice rezultatul, dacă este nul sau nu şi să adauge un manipulator specific. Mai bine ar fi să returnezi o excepţie care poate fi arhivată şi gestionată de către apelant.

Limitări

Noi suntem înconjuraţi de frontiere. Atunci când utilizăm biblioteci ale unor părţi terţe, cod implementat de alte echipe, nucleu API şi aşa mai departe. În toate aceste situaţii avem trasată o limită, dar şi un set de funcţii pe care le putem utiliza pentru a trece peste ea.

Este important de ştiut cum să păstrăm aceste hotare curate şi utile. Primul lucru pe care ar trebui să îl facem când este nevoie să utilizăm o resursă externă este să ne rezervăm timp pentru a învăţa despre ea şi a o explora. Noi trebuie să descoperim hotarul şi cum putem să gestionăm şi să utilizăm funcţionalitatea expusă de acesta.

Cea mai simplă metodă de a învăţa este să scriem teste care validează scenarii diferite. Astfel, putem fi siguri 100% că diferitele fluxuri vor funcţiona şi că ştim cum să le gestionăm. De asemenea, vom putea valida şi faptul că partea terţă ne oferă ceea ce ne trebuie cu adevărat.

Atunci când avem părţi terţe externe care expun limitări este obligatoriu să definim un adaptor care să ne izoleze de biblioteca terţei părţi. Vom avea cazuri în care va trebui să mimăm comportamentul sau când API-ul terţei părţi se va modifica. În acest caz, nu dorim să creăm efectul de domino în întregul nostru cod.

Adaptorul nu ar trebui să expună 1:1 funcţionalitatea expusă de partea terţă, ci să expună numai funcţionalitatea de care avem nevoie, nu cea care este oferită. Toate detaliile implementate ar trebui să fie puse chiar în adaptor.

Concluzie

Ar mai fi atât de multe lucruri de spus despre subiectele atinse în acest articol. Iată trei lucruri pe care aş dori să le ţineţi minte din acest articol:

De asemenea: Da! Fiecare dintre noi ar trebui să citească „Clean Code”.

NUMĂRUL 149 - Development with AI

Sponsori

  • Accenture
  • BT Code Crafters
  • Accesa
  • Bosch
  • Betfair
  • MHP
  • BoatyardX
  • .msg systems
  • P3 group
  • Ing Hubs
  • Cognizant Softvision
  • Colors in projects