System design este arta de a concepe arhitecturi software scalabile, fiabile și eficiente, mergind dincolo de scrierea de cod funcțional. În practică, acest lucru înseamnă să anticipezi cum va crește sistemul odată cu numărul utilizatorilor și să iei decizii critice despre stocarea datelor, comunicarea între servicii și gestionarea erorilor. Fără aceste cunoștințe, chiar și cele mai bune algoritme pot eșua sub presiunea traficului real. Înțelegerea conceptelor de bază te ajută să eviți capcanele comune și să comunici eficient cu echipa tehnică.
Concepte cheie
- Scalabilitate: Capacitatea sistemului de a gestiona creșterea volumului de muncă adăugând resurse, fie prin scalare verticală (hardware mai puternic) sau orizontală (mai multe servere).
- Disponibilitate: Măsura timpului în care sistemul este operational și accesibil utilizatorilor, adesea măsurată în "nine-uri" (de exemplu, 99.9% uptime).
- Latency vs. Throughput: Latency-ul este timpul necesar pentru a procesa o singură cerere, în timp ce throughput-ul reprezintă numărul total de cereri procesate într-o anumită perioadă.
- Consistența datelor: Garantează că toți utilizatorii văd aceeași informație la același timp, echilibrând adesea consistența puternică cu cea eventuală pentru performanță.
- Load Balancing: Distribuirea traficului de rețea între mai multe servere pentru a preveni supraîncărcarea oricărui nod individual.
- Caching: Stocarea temporară a datelor frecvent accesate în locații rapide (memorie RAM) pentru a reduce timpul de răspuns și sarcina asupra bazei de date.
- Decuplare (Decoupling): Separarea componentelor sistemului astfel încât modificările într-o parte nu afectează direct celelalte, facilitând mentenanța și escalarea independentă.
Exemplu practic
Imagină-ți un sistem de rezervare de bilete pentru evenimente. Un scenariu real implică gestionarea concurenței când sute de utilizatori încearcă să cumpere ultimul bilet simultan.
# Simplificare conceptuală a unui lock distribuit
def book_ticket(user_id, event_id):
if acquire_lock(event_id): # Verificăm dacă evenimentul este "blocat"
try:
if check_availability(event_id):
process_payment(user_id)
update_inventory(event_id)
return success()
else:
return error("Sold out")
finally:
release_lock(event_id) # Eliberăm lock-ul indiferent de rezultat
else:
return error("Try again later")
Aici, lock-ul previne vânzarea aceluiași bilet către doi clienți diferiți. Fără acest mecanism, apare o condiție de cursă (race condition), ducând la erori financiare și nemulțumirea clienților.
Greșeli frecvente
- Over-engineering: Construirea unei arhitecturi complexe (microservicii, Kubernetes) pentru un proiect mic care ar putea fi rezolvat simplu cu o bază de date monolitică.
- Ignorarea single point of failure: Nu se prevede nicio soluție de redundanță; dacă un singur server se oprește, întregul sistem cade.
- Neglijarea monitorizării: Nu se implementează instrumente de logging și alerting, făcând imposibilă diagnosticarea problemelor în producție.
- Alegerea greșită a bazei de date: Folosirea unei baze de date relaționale pentru date nestructurate sau de tip graf, ceea ce duce la performanțe slabe.
Întrebări de interviu
Întrebare: Cum ai proiecta un URL shortener ca Bitly? Răspuns: Trebuie să gestionezi hash-uri unice, redirecționări rapide și analytics. O abordare comună folosește o bază de date NoSQL pentru stocarea mapării ID->URL și un CDN pentru cache-ul redirecționărilor frecvente.
Întrebare: Care este diferența dintre scalarea verticală și cea orizontală? Răspuns: Scalarea verticală implică adăugarea de putere (CPU/RAM) la un singur server, având un limit fizic. Scalarea orizontală implică adăugarea de noi servere la cluster, oferind o scalabilitate teoretic nelimitată, dar necesitând gestionarea complexității distribuției datelor.
Exercițiu
Sarcină: Desenează o schiță (whiteboard) pentru un sistem de chat în timp real (tip WhatsApp). Timp: 45 minute. Cerințe:
- Identifică componentele principale (Client, Load Balancer, Server, Database).
- Explică cum se menține conexiunea live (WebSockets vs HTTP polling).
- Propune o strategie simplă de stocare a istoricului mesajelor.
- Notează unde ai introduce caching pentru profilurile utilizatorilor.
Această exercițiu te va ajuta să aplici teoria și să te obișnuiești cu fluxul de gândire necesar în interviurile tehnice.