Sobes.tech
Senior

Τι γνωρίζετε για την αρχιτεκτονική των ports και των adapters;

sobes.tech AI

Απάντηση από AI

Η αρχιτεκτονική των ports και των adapters, γνωστή και ως Hexagonal Architecture, διαχωρίζει τη λογική του πεδίου εφαρμογής (Core) από τις εξωτερικές εξαρτήσεις (διασυνδέσεις χρήστη, βάσεις δεδομένων, εξωτερικές υπηρεσίες).

Βασικές έννοιες:

  • Ports: Ορίζουν τα interfaces μέσω των οποίων το Core αλληλεπιδρά με τον εξωτερικό κόσμο. Υπάρχουν δύο τύποι:
    • Εισερχόμενα (Driving Ports): Χρησιμοποιούνται από εξωτερικές οντότητες για να καλέσουν τη λειτουργικότητα του Core (π.χ., API interface).
    • Εξερχόμενα (Driven Ports): Χρησιμοποιούνται από το Core για να καλέσουν λειτουργικότητα εξωτερικών οντοτήτων (π.χ., interface repository για πρόσβαση σε δεδομένα).
  • Adapters: Υλοποιούν τα ports, συνδέοντας το Core με συγκεκριμένες εξωτερικές τεχνολογίες ή frameworks.
    • Εισερχόμενοι (Driving Adapters): Υλοποιούν τα εισερχόμενα ports και μετατρέπουν τα εισερχόμενα αιτήματα από το περιβάλλον σε κλήσεις στο Core (π.χ., REST controller).
    • Εξερχόμενοι (Driven Adapters): Υλοποιούν τα εξερχόμενα ports και μετατρέπουν τις κλήσεις από το Core για αλληλεπίδραση με το εξωτερικό περιβάλλον (π.χ., υλοποίηση repository για εργασία με συγκεκριμένη βάση δεδομένων).
  • Core (Πεδίο εφαρμογής): Περιέχει τη λογική επιχειρηματικών κανόνων της εφαρμογής. Είναι πλήρως απομονωμένο από τις εξωτερικές λεπτομέρειες και αλληλεπιδρά μαζί τους μόνο μέσω των ports.

Πλεονεκτήματα:

  • Δοκιμασία: Ο απομονωμένος Core διευκολύνει τη μονάδα δοκιμών της επιχειρηματικής λογικής χωρίς την ανάγκη για mocking σύνθετων εξωτερικών εξαρτήσεων.
  • Ευελιξία: Επιτρέπει την εύκολη αντικατάσταση ή προσθήκη νέων εξωτερικών τεχνολογιών (βάσεις δεδομένων, frameworks) χωρίς να αλλάξει το Core. Αρκεί να γραφεί ένας νέος adapter για το υπάρχον port.
  • Καθαρός κώδικας: Συμβάλλει στη δημιουργία καθαρότερου και πιο εύκολα συντηρήσιμου κώδικα, εστιάζοντας το Core μόνο στους επιχειρηματικούς κανόνες.
  • Διαχωρισμός ευθυνών: Διαχωρίζει σαφώς τις περιοχές ευθύνης.

Σύνδεση με το Frontend:

Στο frontend, η αρχιτεκτονική των ports και adapters εφαρμόζεται για:

  • Διαχωρισμός επιχειρηματικής λογικής του component από τις πηγές δεδομένων: Το component αλληλεπιδρά με το "port" (διασύνδεση), το οποίο μπορεί να υλοποιηθεί από διαφορετικά "adapters" (λαμβάνοντας δεδομένα από API, Local Storage, mock δοκιμές κ.λπ.).
  • Επεξεργασία εξωτερικών γεγονότων: Τα εισερχόμενα ports μπορούν να αντιπροσωπεύουν χειριστές γεγονότων UI, και τα adapters μετατρέπουν αυτά τα γεγονότα σε κλήσεις στη λογική εσωτερικά.
  • Εγκλεισμός της αλληλεπίδρασης με εξωτερικές βιβλιοθήκες: Τα adapters μπορούν να καλύπτουν τις κλήσεις σε τρίτες βιβλιοθήκες (π.χ., βιβλιοθήκη για εργασίες με χάρτες), παρέχοντας στο Core μια απλή και σταθερή διεπαφή.

Παράδειγμα σε JavaScript (σχήμα):

// Παράδειγμα port εξαγωγής (διασύνδεση για λήψη δεδομένων)
class DataGateway {
  getData() {
    throw new Error("Η μέθοδος getData πρέπει να υλοποιηθεί");
  }
}

// Παράδειγμα adapter εξαγωγής (υλοποίηση port για API)
class ApiDataGateway extends DataGateway {
  async getData() {
    const response = await fetch('/api/data');
    return response.json();
  }
}

// Παράδειγμα port εισόδου (διασύνδεση για επιχειρηματική λογική)
class BusinessLogicPort {
  constructor(dataGateway) {
    this.dataGateway = dataGateway;
  }

  async processData() {
    throw new Error("Η μέθοδος processData πρέπει να υλοποιηθεί");
  }
}

// Παράδειγμα Core (επιχειρηματική λογική)
class MyBusinessLogic extends BusinessLogicPort {
  async processData() {
    const data = await this.dataGateway.getData();
    // Λογική επεξεργασίας δεδομένων
    console.log("Δεδομένα επεξεργάστηκαν:", data);
    return data;
  }
}

// Παράδειγμα εισερχόμενου adapter (χρήση λογικής στο UI)
async function initApp() {
  const apiGateway = new ApiDataGateway(); // Συγκεκριμένος adapter
  const businessLogic = new MyBusinessLogic(apiGateway); // Core χρησιμοποιεί port
  await businessLogic.processData(); // Εισερχόμενος adapter καλεί Core
}

initApp();