Sobes.tech
Senior

Ce știți despre arhitectura porturilor și a adaptoarelor?

sobes.tech AI

Răspuns de la AI

Arhitectura porturilor și adaptatoarelor, cunoscută și sub numele de arhitectură hexagonală (Hexagonal Architecture), separă logica domeniului aplicației (Core) de dependențele externe (interfețe de utilizator, baze de date, servicii externe).

Concepte principale:

  • Porturi: Definește interfețele prin care Core-ul interacționează cu lumea exterioară. Porturile sunt de două tipuri:
    • Porturi de intrare (Driving Ports): Sunt utilizate de entitățile externe pentru a apela funcționalitatea Core-ului (de exemplu, API-ul).
    • Porturi de ieșire (Driven Ports): Sunt utilizate de Core pentru a apela funcționalitatea entităților externe (de exemplu, interfața de repository pentru accesul la date).
  • Adaptatoare: Implementează porturile, conectând Core-ul la tehnologii sau framework-uri externe specifice.
    • Adaptatoare de intrare (Driving Adapters): Implementează porturile de intrare și transformă cererile din mediul extern în apeluri către Core (de exemplu, un controller REST).
    • Adaptatoare de ieșire (Driven Adapters): Implementează porturile de ieșire și transformă apelurile din Core pentru a interacționa cu mediul extern (de exemplu, o implementare a repository-ului pentru a lucra cu o bază de date specifică).
  • Core (Domeniul de business): Conține logica de business a aplicației. Este complet izolat de detaliile externe și interacționează cu acestea doar prin intermediul porturilor.

Beneficii:

  • Testabilitate: Izolarea Core-ului facilitează testarea unitară a logicii de business fără a fi nevoie să se mock-eze dependențele externe complexe.
  • Flexibilitate: Permite înlocuirea sau adăugarea ușoară a tehnologiilor externe (baze de date, framework-uri) fără a modifica Core-ul. Este suficient să se scrie un nou adaptor pentru portul existent.
  • Cod curat: Contribuie la crearea unui cod mai curat și mai ușor de întreținut, concentrând Core-ul doar pe regulile de business.
  • Separarea responsabilităților: Separă clar zonele de responsabilitate.

Legătura cu Frontend:

Pe frontend, arhitectura porturilor și adaptatoarelor se aplică pentru:

  • Separarea logicii de business a componentelor de sursele de date: Componentele interacționează cu "portul" (interfața), care poate fi implementat de diferiți "adaptatori" (care primesc date din API, Local Storage, mock-uri de test etc.).
  • Prelucrarea evenimentelor externe: Porturile de intrare pot reprezenta handler-e pentru evenimentele UI, iar adaptatorii transformă aceste evenimente în apeluri către logica internă.
  • Incapsularea interacțiunii cu biblioteci externe: Adaptatorii pot înveli apelurile către biblioteci terțe (de exemplu, o bibliotecă pentru lucrul cu hărți), oferind Core-ului o interfață simplă și stabilă.

Exemplu în JavaScript (schema):

// Exemplu de port de ieșire (interfață pentru obținerea datelor)
class DataGateway {
  getData() {
    throw new Error("Metoda getData trebuie să fie implementată");
  }
}

// Exemplu de adaptor de ieșire (implementarea portului pentru API)
class ApiDataGateway extends DataGateway {
  async getData() {
    const response = await fetch('/api/data');
    return response.json();
  }
}

// Exemplu de port de intrare (interfață pentru logica de business)
class BusinessLogicPort {
  constructor(dataGateway) {
    this.dataGateway = dataGateway;
  }

  async processData() {
    throw new Error("Metoda processData trebuie să fie implementată");
  }
}

// Exemplu de Core (logica de business)
class MyBusinessLogic extends BusinessLogicPort {
  async processData() {
    const data = await this.dataGateway.getData();
    // Logica de procesare a datelor
    console.log("Date procesate:", data);
    return data;
  }
}

// Exemplu de adaptor de intrare (utilizarea logicii în UI)
async function initApp() {
  const apiGateway = new ApiDataGateway(); // Adaptor concret
  const businessLogic = new MyBusinessLogic(apiGateway); // Core folosește portul
  await businessLogic.processData(); // Adaptorul de intrare apelează Core-ul
}

initApp();