Κεφάλαιο 1: Εισαγωγή στο Clean Architecture
Θα προσπαθήσω στο παρακάτω άρθρο να περιγράψω τι είναι το Clean Architecture και πότε και γιατί κάποιος θα ήθελε να το χρησιμοποιήσει για να στήσει ένα software solution. Στο κάτω κάτω, γιατί είναι χρήσιμο; Ποιος ο σκοπός του; Θα αναφέρουμε και λίγο την ιστορία του, γιατί κάθε αρχιτεκτονική λύση γεννιέται για να καλύψει συγκεκριμένες ανάγκες που προέκυψαν από προβλήματα στον πραγματικό κόσμο της ανάπτυξης λογισμικού.
Το Clean Architecture δεν είναι απλώς μια μόδα ή ένα «κόλπο» για να κάνουμε τον κώδικά μας πιο περίπλοκο. Είναι μια προσπάθεια να οργανώσουμε το λογισμικό μας σαν ένα καλά δομημένο οικοδόμημα: με θεμέλια, όρους και υποσυστήματα που μπορούν να αλλάξουν χωρίς να καταρρεύσει ολόκληρη η κατασκευή. Σκοπός του είναι να διαχωρίζει τις ευθύνες, να κάνει τον κώδικα πιο κατανοητό, επεκτάσιμο και, κυρίως, ευκολότερο στη συντήρηση και τις δοκιμές.
Ιστορικό υπόβαθρο
Η ιδέα του Clean Architecture προέρχεται κυρίως από τον Robert C. Martin (γνωστός και ως Uncle Bob). Το 2012 περίπου παρουσίασε το μοντέλο του «Clean Architecture» βασισμένο σε παλαιότερα patterns όπως το Onion Architecture και το Hexagonal Architecture. Όλα αυτά είχαν έναν κοινό στόχο: να χωρίσουν την επιχειρησιακή λογική (business rules) από τεχνολογικές εξαρτήσεις όπως βάσεις δεδομένων, web frameworks ή third-party libraries.
Ο λόγος που εμφανίστηκαν αυτά τα patterns ήταν καθαρά πρακτικός: τα συστήματα μεγάλωναν, οι developers προσθέτανε features χωρίς περιορισμούς, και πολύ γρήγορα τα projects γίνονταν δυσκολόχρηστα, δύσκολα στη συντήρηση και επικίνδυνα σε αλλαγές. Οι αλλαγές σε ένα μέρος του κώδικα προκαλούσαν ανεπιθύμητες συνέπειες σε άλλα σημεία. Το Clean Architecture ήρθε να βάλει τάξη σε αυτό το χάος.
Βασική ιδέα
Η βασική ιδέα του Clean Architecture είναι απλή αλλά ισχυρή. Ο κώδικας οργανώνεται σε κύκλους ή δακτυλίους, σαν ένα σύστημα με εσωτερικούς πυρήνες και εξωτερικά στρώματα. Στο κέντρο βρίσκονται τα πιο σταθερά και κρίσιμα στοιχεία του συστήματος, όπως η επιχειρησιακή λογική και τα domain models. Αυτά είναι οι κανόνες και οι οντότητες που καθορίζουν πώς λειτουργεί πραγματικά η εφαρμογή, ανεξάρτητα από το πώς την προβάλλουμε ή πού αποθηκεύουμε τα δεδομένα.
Πιο έξω βρίσκονται τα layers που χειρίζονται τις τεχνολογικές λεπτομέρειες, όπως τα frameworks, η βάση δεδομένων ή το UI. Τα layers αυτά προσαρμόζονται στις απαιτήσεις της τεχνολογίας και μεταφράζουν τα δεδομένα προς και από τον πυρήνα, χωρίς να αλλοιώνουν τη λογική του συστήματος. Ένα από τα πιο σημαντικά χαρακτηριστικά είναι ότι οι εξαρτήσεις δείχνουν πάντα προς το κέντρο: κανένα εσωτερικό στοιχείο δεν γνωρίζει λεπτομέρειες για τα εξωτερικά στρώματα. Με αυτό τον τρόπο, αν χρειαστεί να αλλάξεις τεχνολογίες – για παράδειγμα να μεταφέρεις την εφαρμογή από SQL Server σε PostgreSQL ή να αντικαταστήσεις ένα Web API με gRPC – δεν χρειάζεται να ξαναγράψεις την επιχειρησιακή λογική. Ταυτόχρονα, ο κώδικας γίνεται πολύ πιο εύκολος στο testing, καθώς οι use cases και οι domain entities μπορούν να ελεγχθούν ανεξάρτητα από πραγματική βάση δεδομένων ή web server.
Αν φανταστούμε το σύστημα σαν δακτυλίους, ο πιο εσωτερικός περιλαμβάνει τα domain entities και τους κανόνες της επιχειρησιακής λογικής. Αυτός ο πυρήνας αποτελεί το πιο σταθερό κομμάτι του συστήματος, γιατί καθορίζει τι σημαίνει να λειτουργεί σωστά η εφαρμογή και παραμένει ανεξάρτητος από οποιαδήποτε τεχνολογία ή πλαίσιο. Οι κανόνες και οι οντότητες που βρίσκονται εδώ εκφράζουν τις πραγματικές ανάγκες της επιχείρησης και καθοδηγούν ολόκληρο το υπόλοιπο σύστημα.
Αμέσως πιο έξω βρίσκεται το Application Layer, το οποίο διαχειρίζεται τις διαδικασίες και τα use cases της εφαρμογής. Εδώ οργανώνεται η ροή των δεδομένων και καθορίζεται πώς οι επιχειρησιακοί κανόνες εφαρμόζονται σε κάθε περίπτωση. Το Application Layer εξασφαλίζει ότι κάθε λειτουργία εκτελείται σωστά, χωρίς να χρειάζεται να γνωρίζει λεπτομέρειες για το πώς τα δεδομένα αποθηκεύονται ή πώς παρουσιάζονται.
Πιο έξω βρίσκεται το Infrastructure Layer, το οποίο υλοποιεί όλες τις τεχνολογικές λεπτομέρειες που απαιτούν οι εσωτερικοί δακτύλιοι. Εδώ βρίσκονται οι πραγματικοί μηχανισμοί πρόσβασης σε βάσεις δεδομένων, οι adapters για τρίτες υπηρεσίες, καθώς και οι μηχανισμοί logging, caching ή επικοινωνίας με άλλα συστήματα. Το Infrastructure Layer εξυπηρετεί τους εσωτερικούς δακτυλίους, αλλά αυτοί δεν εξαρτώνται ποτέ από αυτό, διατηρώντας την καθαρότητα και την ανεξαρτησία της επιχειρησιακής λογικής.
Στον πιο εξωτερικό δακτύλιο βρίσκεται το Presentation Layer, όπου εντάσσονται τα frameworks, το frontend, οι controllers και τα API endpoints. Αυτό το layer είναι υπεύθυνο για την παρουσίαση των δεδομένων και την επικοινωνία με τον χρήστη ή άλλα συστήματα, χωρίς να επηρεάζει τους κανόνες της επιχειρησιακής λογικής ή τη ροή των use cases. Όλες οι τεχνολογικές λεπτομέρειες, όπως η λήψη αιτημάτων από το Web API ή η εμφάνιση πληροφοριών στο UI, περιορίζονται εδώ, αφήνοντας τους εσωτερικούς δακτυλίους ανεπηρέαστους. Κάθε δακτύλιος μπορεί να αλλάξει ανεξάρτητα από τους εξωτερικούς, χωρίς να γνωρίζει λεπτομέρειες για αυτούς, διασφαλίζοντας ότι το σύστημα παραμένει ανθεκτικό, επεκτάσιμο και εύκολο στη συντήρηση.
Με αυτή τη δομή, ο κώδικας γίνεται πιο κατανοητός, ευέλικτος και ασφαλής για αλλαγές. Ταυτόχρονα, καθιστά την εφαρμογή εύκολη στο testing, αφού οι use cases και οι domain entities μπορούν να ελεγχθούν ανεξάρτητα από την παρουσίαση ή την υποδομή, ενώ οι τεχνολογικές αλλαγές περιορίζονται στα εξωτερικά layers, χωρίς να επηρεάζουν την επιχειρησιακή λογική.
Κεφάλαιο 2: Γιατί είναι χρήσιμο να χρησιμοποιήσεις Clean Architecture
Όταν ξεκινάς να χτίζεις ένα project, ειδικά ένα web app ή ένα σύστημα που προορίζεται να μεγαλώσει, συχνά ξεκινάς απλά. Μία κλάση για το μοντέλο, ένας controller, ένα DbContext και λίγες λειτουργίες CRUD φαίνονται επαρκείς. Στην αρχή όλα δουλεύουν, αλλά όσο το σύστημα μεγαλώνει, εμφανίζονται προβλήματα. Οι controllers γεμίζουν με λογική που δεν τους ανήκει, η αλλαγή μιας τεχνολογίας όπως η βάση δεδομένων ή το API απαιτεί να τροποποιήσεις πολλά μέρη του κώδικα, και κάθε νέα λειτουργία φέρνει τον κίνδυνο να σπάσει κάτι που μέχρι χθες λειτουργούσε σωστά.
Το Clean Architecture έρχεται να βάλει τάξη σε αυτό το χάος. Η βασική του ιδέα είναι να οργανώσει τον κώδικα σε δακτυλίους με σαφώς καθορισμένες ευθύνες. Στο κέντρο βρίσκονται τα domain entities και οι κανόνες της επιχειρησιακής λογικής. Αυτός ο πυρήνας καθορίζει τι σημαίνει να λειτουργεί σωστά η εφαρμογή και παραμένει ανεξάρτητος από τεχνολογίες ή frameworks. Αμέσως πιο έξω βρίσκεται το Application Layer, όπου διαχειρίζονται οι διαδικασίες και τα use cases. Εδώ καθορίζεται πώς εφαρμόζονται οι κανόνες και πώς συνεργάζονται οι οντότητες, χωρίς να χρειάζεται γνώση για το πώς τα δεδομένα αποθηκεύονται ή προβάλλονται.
Πιο έξω βρίσκεται το Infrastructure Layer, το οποίο υλοποιεί όλες τις τεχνολογικές λεπτομέρειες που απαιτούν οι εσωτερικοί δακτύλιοι. Περιλαμβάνει repositories για τη βάση δεδομένων, adapters για τρίτες υπηρεσίες, logging και caching, αλλά οι εσωτερικοί δακτύλιοι δεν εξαρτώνται από αυτό, ώστε η επιχειρησιακή λογική να παραμένει καθαρή και ανεξάρτητη. Τέλος, ο πιο εξωτερικός δακτύλιος είναι το Presentation Layer, όπου βρίσκονται οι controllers, το frontend και τα API endpoints. Αυτό το layer χειρίζεται την παρουσίαση και την επικοινωνία με τον χρήστη ή άλλα συστήματα, χωρίς να επηρεάζει το Domain ή το Application Layer. Κάθε δακτύλιος μπορεί να αλλάξει ανεξάρτητα από τους άλλους, διατηρώντας έτσι την ανθεκτικότητα και την ευκολία στη συντήρηση.
Η χρησιμότητα του Clean Architecture φαίνεται ξεκάθαρα σε μεγάλες εφαρμογές. Αν αλλάξεις τη βάση δεδομένων ή αντικαταστήσεις ένα API, οι αλλαγές περιορίζονται στα εξωτερικά layers, χωρίς να χρειάζεται να ξαναγράψεις τους κανόνες επιχειρησιακής λογικής. Αν χρειάζεται να δοκιμάσεις τη λειτουργικότητα, οι use cases και τα domain entities μπορούν να ελεγχθούν ανεξάρτητα από το UI ή την υποδομή, επιτρέποντας ασφαλή unit tests και μεγαλύτερη εμπιστοσύνη στην εφαρμογή. Το αποτέλεσμα είναι ένα σύστημα πιο σταθερό, πιο ευέλικτο και πολύ πιο εύκολο στη συντήρηση, ακόμα και όταν μεγαλώνει σε πολυπλοκότητα και μέγεθος.
Κεφάλαιο 3: Η ροή ενός αιτήματος μέσα στο Clean Architecture
Φαντάσου ότι ένας χρήστης ανοίγει την εφαρμογή σου και κάνει ένα αίτημα, για παράδειγμα θέλει να δει τη λίστα των μαθημάτων ενός φοιτητή. Το αίτημα φτάνει πρώτα στο Presentation Layer, όπου οι controllers ή το frontend λαμβάνουν τα δεδομένα από τον χρήστη και ετοιμάζουν το request για το σύστημα. Το Presentation Layer φροντίζει να διαβαστούν σωστά τα δεδομένα και να ξεκινήσει η διαδικασία, αλλά δεν παίρνει αποφάσεις για το τι σημαίνει «μαθήματα φοιτητή» ή πώς να υπολογιστούν.
Από εκεί, το αίτημα προχωράει στο Application Layer, όπου ενεργοποιείται η διαδικασία του use case, δηλαδή η λειτουργία που έχει οριστεί για να χειριστεί την κατάσταση. Το Application Layer γνωρίζει τι πρέπει να γίνει και πώς να συνεργαστούν τα domain entities για να παραχθεί το σωστό αποτέλεσμα. Εδώ εφαρμόζονται οι κανόνες της επιχείρησης: ποια μαθήματα έχει δικαίωμα να δει ο φοιτητής, ποια είναι ενεργά, ποια τμήματα σχετίζονται. Το layer αυτό διαχειρίζεται τη ροή, χωρίς να ξέρει από πού έρχονται τα δεδομένα ή πού θα εμφανιστούν στο τέλος.
Στη συνέχεια, το Application Layer χρησιμοποιεί το Infrastructure Layer για να πάρει τα απαραίτητα δεδομένα. Οι repositories εδώ αναλαμβάνουν να επικοινωνήσουν με τη βάση δεδομένων, να φέρουν τις εγγραφές ή να καλέσουν υπηρεσίες τρίτων. Το Infrastructure Layer μετατρέπει τις εντολές του Application Layer σε πραγματικές λειτουργίες, αλλά οι κανόνες της επιχειρησιακής λογικής παραμένουν ανεπηρέαστοι και καθαροί. Εάν αύριο αλλάξει η βάση ή η υπηρεσία τρίτου, μόνο το Infrastructure Layer θα χρειαστεί να τροποποιηθεί.
Τέλος, τα αποτελέσματα επιστρέφουν στο Presentation Layer, όπου μετατρέπονται σε μορφή κατάλληλη για το χρήστη: μπορεί να είναι ένα web page, ένα JSON για API ή ένα στοιχείο στο frontend. Ο χρήστης βλέπει τη λίστα των μαθημάτων, αλλά δεν χρειάζεται να ξέρει τίποτα για τις εσωτερικές διεργασίες. Το σύστημα έχει δουλέψει ομαλά, χωρίς να μπλεχτούν οι κανόνες της επιχειρησιακής λογικής με τεχνολογικές λεπτομέρειες, και κάθε layer έχει κάνει μόνο τη δουλειά που του αναλογεί.
Με αυτόν τον τρόπο, η εφαρμογή παραμένει καθαρή, επεκτάσιμη και εύκολη στη συντήρηση. Οι developers μπορούν να αλλάζουν τεχνολογίες ή να προσθέτουν νέα features χωρίς να επηρεάζεται ο πυρήνας της λογικής, και οι δοκιμές μπορούν να γίνονται μεμονωμένα σε κάθε layer, εξασφαλίζοντας αξιοπιστία και σταθερότητα. Η ροή ενός αιτήματος μέσα στο Clean Architecture δείχνει πώς η οργάνωση σε δακτυλίους προστατεύει την εφαρμογή από το spaghetti code και διατηρεί το σύστημα ευέλικτο και ανθεκτικό στον χρόνο.
Δομή φακέλων (Clean Architecture) με Student, Lesson, Department
MySchoolProject/
│
├── src/
│ ├── MySchool.Domain/
│ │ ├── Entities/
│ │ │ ├── Student.cs
│ │ │ ├── Lesson.cs
│ │ │ └── Department.cs
│ │ ├── ValueObjects/
│ │ │ └── FullName.cs
| | | └── Email.cs
| | | └── Address.cs
| | | └── DepartmentCode.cs
| | | └── LessonCode.cs
| | | └── Grade.cs
| | | └── DepartmentId.cs
│ │ └── Interfaces/
│ │ └── IStudentRepository.cs
| | └── ILessonRepository.cs
│ │ └── IDepartmentRepository.cs
│ ├── MySchool.Application/
│ │ ├── Interfaces/
│ │ │ ├── IStudentService.cs
│ │ │ ├── ILessonService.cs
│ │ │ └── IDepartmentService.cs
│ │ ├── DTOs/
│ │ │ ├── StudentDto.cs
│ │ │ ├── LessonDto.cs
│ │ │ └── DepartmentDto.cs
│ │ └── Services/
│ │ ├── StudentService.cs
│ │ ├── LessonService.cs
│ │ └── DepartmentService.cs
│ │
│ ├── MySchool.Infrastructure/
│ │ ├── Data/
│ │ │ └── MySchoolDbContext.cs
│ │ ├── Repositories/
│ │ │ ├── StudentRepository.cs
│ │ │ ├── LessonRepository.cs
│ │ │ └── DepartmentRepository.cs
│ │ └── Configurations/
│ │ ├── StudentConfiguration.cs
│ │ ├── LessonConfiguration.cs
│ │ └── DepartmentConfiguration.cs
│ │
│ └── MySchool.Presentation/
│ ├── Controllers/
│ │ ├── StudentsController.cs
│ │ ├── LessonsController.cs
│ │ └── DepartmentsController.cs
│ └── MySchool.API.csproj
│
└── tests/
├── MySchool.Application.Tests/
└── MySchool.Domain.Tests/
1. Domain Layer
Το Domain Layer είναι ο πυρήνας της εφαρμογής. Εδώ βρίσκεται όλη η επιχειρησιακή λογική και οι βασικές οντότητες που περιγράφουν το πρόβλημα που λύνει η εφαρμογή. Είναι ανεξάρτητο από τεχνολογίες, βάσεις δεδομένων ή UI.
Τι περιέχει:
Entities (Οντότητες)
- Student → Πληροφορίες όπως Id, Name, Email, Class/DepartmentId κλπ.
- Lesson → Πληροφορίες όπως Id, Title, Teacher, Credits κλπ.
- Department → Πληροφορίες όπως Id, Name, Description.
Value Objects (Προαιρετικά)
- Αντικείμενα που περιγράφουν σύνθετες τιμές χωρίς ταυτότητα, π.χ. Email, Grade, Address.
- Αυτά βοηθούν να διατηρηθεί η ακρίβεια των δεδομένων και η επιχειρησιακή λογική σε ξεχωριστές μονάδες.
Interfaces
- Γενικά interfaces για repositories (IRepository), ώστε το Domain να μην γνωρίζει τίποτα για το πώς αποθηκεύονται τα δεδομένα.
Στο παράδειγμά μας θα μπορούσε να έχει τα IStudentRepository, ILessonRepository και IDepartmentRepository τα οποία θα περιέχουν μεθόδους όπως GetById, GetAll, Add και Delete.
Κεντρικό σημείο: Το Domain Layer δεν ξέρει τίποτα για EF, SQL, API ή UI. Όλα γίνονται μέσω contracts/interfaces.
2. Application Layer
Το Application Layer είναι το layer που χειρίζεται τη ροή της εφαρμογής. Συνδέει το Domain με το Infrastructure, οργανώνει τα use cases και καθορίζει τι πρέπει να γίνει όταν γίνεται ένα αίτημα από το Presentation Layer.
Τι περιέχει:
Interfaces/Services
- Εδώ βρίσκονται τα interfaces για τις υπηρεσίες (IStudentService, ILessonService, IDepartmentService) που χρησιμοποιούν οι controllers.
- Περιγράφουν τι λειτουργίες είναι διαθέσιμες (π.χ., EnrollStudent, AssignLessonToDepartment).
DTOs (Data Transfer Objects)
- Ελαφριές κλάσεις για μεταφορά δεδομένων μεταξύ layers, π.χ., StudentDto με Id, Name, Email.
- Βοηθάει να μην εκθέτουμε ολόκληρες τις οντότητες στις εξωτερικές διεπαφές.
Services/Use Cases
- Υλοποιούν τη λογική των use cases, χρησιμοποιώντας τις οντότητες του Domain και τα repositories μέσω των interfaces.
- Εδώ εφαρμόζεται η επιχειρησιακή λογική και οργανώνεται η ροή των δεδομένων χωρίς να γνωρίζει το Presentation ή το Infrastructure.
Κεντρικό σημείο: Το Application Layer γνωρίζει το Domain Layer αλλά όχι το Presentation ή το Infrastructure Layer άμεσα. Οι dependencies περνάνε μέσω interfaces.
3. Infrastructure Layer
Το Infrastructure Layer είναι το layer που υλοποιεί τις τεχνολογικές λεπτομέρειες. Στην πράξη, εδώ χρησιμοποιούμε EF Core, SQL Server, APIs, Logging, Caching κ.λπ.
Τι περιέχει:
DbContext
- MySchoolDbContext με DbSet, DbSet, DbSet.
- Περιλαμβάνει την επικοινωνία με τη βάση δεδομένων μέσω EF Core.
Repositories
- Πραγματικές υλοποιήσεις των interfaces του Domain Layer.
Π.χ., StudentRepository που υλοποιεί IStudentRepository και χρησιμοποιεί EF για CRUD λειτουργίες.
Configurations
- Κλάσεις που καθορίζουν το mapping των οντοτήτων για EF Core, π.χ., StudentConfiguration με primary key, σχέσεις, constraints.
- Κρατάνε το DbContext καθαρό και οργανώνουν το mapping ξεχωριστά.
Κεντρικό σημείο: Το Infrastructure Layer γνωρίζει το Application και Domain, αλλά οι εσωτερικοί δακτύλιοι δεν εξαρτώνται από αυτό.
4. Presentation Layer
Το Presentation Layer είναι η διεπαφή με τον χρήστη ή τα API endpoints. Εδώ παίρνουμε τα αιτήματα από τον χρήστη και τα στέλνουμε στο Application Layer για επεξεργασία.
Τι περιέχει:
Controllers
StudentsController, LessonsController, DepartmentsController που δέχονται αιτήματα HTTP και καλούν τα services του Application Layer.
Front-end / API projectΜπορεί να είναι Web API, MVC, ή οποιοδήποτε UI project που επικοινωνεί με τους controllers.
Κεντρικό σημείο: Το Presentation Layer δεν έχει επιχειρησιακή λογική, απλώς στέλνει και λαμβάνει δεδομένα από το Application Layer.
Entity Framework Code-First Σχέσεις οντοτήτων μοντελοποίηση και Queries
nikosst
Top comments (0)