Frankenstein στον προγραμματισμό είναι κώδικας που συναρμολογείται από ασύμβατα μέρη διαφορετικών τεχνολογιών, στυλ και αρχιτεκτονικών. Σύμφωνα με έρευνα του ThoughtWorks Technology Radar (2024), το 28% των μεγάλων έργων εμφανίζει σημάδια του συνδρόμου Frankenstein — αρχιτεκτονικού εκλεκτικισμού που προκύπτει όταν απουσιάζει ένα ενιαίο τεχνικό όραμα. Κατ’ αναλογία με το μυθιστόρημα της Mary Shelley, τέτοιος κώδικας λειτουργεί, αλλά η συντήρησή του γίνεται εφιάλτης.
Κύρια σημεία
Frankenstein (Frankenstein code, Frankenstein pattern) είναι ένα αντι-πρότυπο όπου ένα σύστημα λογισμικού συναρμολογείται από μέρη που δεν έχουν σχεδιαστεί να λειτουργούν μαζί. Όπως το τέρας του Frankenstein, τέτοιος κώδικας μπορεί να λειτουργεί, αλλά είναι άσχημος, απρόβλεπτος και επικίνδυνος στις παραμικρές αλλαγές.
Ο όρος προέρχεται από τη λογοτεχνία: στο μυθιστόρημα Mary Shelley “Frankenstein, or the Modern Prometheus” (1818), ένας επιστήμονας δημιούργησε ένα ζωντανό ον από θραύσματα σωμάτων διαφορετικών νεκρών ανθρώπων. Στον προγραμματισμό, η αναλογία είναι ακριβής — οι προγραμματιστές παίρνουν κομμάτια διαφορετικών frameworks, βιβλιοθηκών, γλωσσών και τα κολλούν μαζί, με αποτέλεσμα ένα λειτουργικό αλλά τερατώδες αποτέλεσμα.
Η διαφορά του Frankenstein από τον μακαρονάδικο κώδικα (spaghetti code) βρίσκεται στην κλίμακα και τη φύση του προβλήματος. Ο μακαρονάδικος κώδικας είναι μια μπερδεμένη δομή μέσα σε μία τεχνολογική στοίβα. Ο Frankenstein είναι εκλεκτικισμός σε επίπεδο αρχιτεκτονικής: διαφορετικές τεχνολογίες, ασύμβατα παραδείγματα, αντικρουόμενες προσεγγίσεις μέσα σε ένα σύστημα.
Η αρχιτεκτονική μικρουπηρεσιών επιτρέπει τη χρήση διαφορετικών τεχνολογιών για διαφορετικές υπηρεσίες, αλλά υπό την προϋπόθεση σαφών ορίων και τυποποιημένων πρωτοκόλλων επικοινωνίας. Ο Frankenstein είναι χαοτική ανάμειξη χωρίς όρια: REST και GraphQL στον ίδιο ελεγκτή, δύο ORM στο ίδιο module, SQL και NoSQL για την ίδια οντότητα.
Η απουσία τεχνικού ηγέτη ή αρχιτέκτονα είναι η βασική αιτία. Όταν σε ένα έργο δεν υπάρχει κάποιος υπεύθυνος για την ακεραιότητα της αρχιτεκτονικής, κάθε προγραμματιστής επιλέγει εργαλεία “για τον εαυτό του”. Ο ένας προτιμά το Spring, ο δεύτερος το Guice, ο τρίτος μια δική του υλοποίηση DI. Το αποτέλεσμα είναι ένα αρχιτεκτονικό συνονθύλευμα.
Η συγχώνευση έργων είναι η δεύτερη συνηθισμένη αιτία. Δύο ομάδες ανέπτυξαν ανεξάρτητα τα modules τους χρησιμοποιώντας διαφορετικές στοίβες. Όταν τα modules πρέπει να ενωθούν σε μία εφαρμογή, απλώς “κολλούνται” με προσαρμογείς και ενδιάμεσα επίπεδα. Το αποτέλεσμα είναι Frankenstein.
Οι εταιρικές εξαγορές είναι το τρίτο σενάριο. Η εταιρεία Α αγόρασε την εταιρεία Β και θέλει να ενσωματώσει το προϊόν της στο δικό της. Αντί για επαναγραφή — κόλλημα μέσω API, κοινές βάσεις δεδομένων και λύσεις ανάγκης. Σε ένα χρόνο, το σύστημα γίνεται ένα τέρας που κανείς δεν καταλαβαίνει.
| Αιτία | Περιγραφή | Τυπικό αποτέλεσμα |
|---|---|---|
| Χωρίς αρχιτέκτονα | Κάθε προγραμματιστής επιλέγει τη δική του στοίβα | 3 διαφορετικοί HTTP πελάτες σε ένα module |
| Συγχώνευση έργων | Δύο προϊόντα συγχωνεύονται σε ένα | Δύο ORM, δύο τρόποι καταγραφής |
| Εξαγορές | Εξαγορά εταιρείας με το προϊόν της | Υβρίδιο διαφορετικών αρχιτεκτονικών και στυλ |
| Πειράματα | Εισαγωγή νέων τεχνολογιών χωρίς στρατηγική | Java 8 + Java 21 χαρακτηριστικά στο ίδιο αρχείο |
| Πολιτικές αποφάσεις | Επιβολή τεχνολογίας από πάνω χωρίς συμφραζόμενα | Enterprise framework για απλό script |
Έμπειροι προγραμματιστές που θέλουν να δοκιμάσουν νέες τεχνολογίες σε παραγωγή συχνά γίνονται πηγή του Frankenstein. Αντί να περιορίζουν τα πειράματα σε ένα απομονωμένο module, εισάγουν πειραματικό κώδικα σε κρίσιμο μέρος του συστήματος.
Κλασικό παράδειγμα είναι η χρήση πολλαπλών ORM σε μία εφαρμογή. Μερικά modules χρησιμοποιούν Hibernate, άλλα MyBatis, και άλλα άμεσα ερωτήματα JDBC. Οι συναλλαγές γίνονται μη διαχειρίσιμες, η προσωρινή μνήμη ασυνεπής, και ο νέος προγραμματιστής δεν ξέρει ποια προσέγγιση να επιλέξει για μια νέα λειτουργία.
Δεύτερο παράδειγμα είναι η ανάμειξη αρχιτεκτονικών στυλ. Σε έναν ελεγκτή REST API υπάρχουν κλήσεις υπηρεσιών SOAP, άμεσα ερωτήματα SQL, πρόσβαση στο σύστημα αρχείων και δημιουργία HTML. Μια τέτοια εφαρμογή είναι αδύνατο να ελεγχθεί, να επεκταθεί ή να τεκμηριωθεί.
Τρίτο παράδειγμα είναι μια τεχνολογική στοίβα όπου η Python χρησιμοποιείται για το backend, η Node.js για μια μικρουπηρεσία, η C# για τον desktop πελάτη και η Java για την εφαρμογή Android, ενώ όλη η επιχειρηματική λογική είναι διάσπαρτη μεταξύ τους χωρίς σαφή κατανομή ευθυνών.
// frankenstein — μικτά στυλ και τεχνολογίες
// callbacks, Promises και async/await συνδυασμένα
// callbacks
db.query("SELECT * FROM users", function(err, rows) {
if (err) handleError(err);
// Promise μέσα σε callback
fetch("/api/data").then(function(data) {
// async/await μέσα σε then
(async () => {
const result = await processData(data);
sendResponse(result);
})();
});
});
// καθαρός κώδικας — ενοποιημένο στυλ async/await
async function getUserData(userId) {
const user = await db.query("SELECT * FROM users WHERE id = ?", [userId]);
const data = await fetch("/api/data/" + userId);
return await processData(user, data);
}
Μία βάση δεδομένων χρησιμοποιείται ταυτόχρονα ως SQL σχεσιακή (με κανονικοποίηση) και ως NoSQL προσανατολισμένη σε έγγραφα (με στήλες JSON). Μέρος των ερωτημάτων γίνεται μέσω ORM, μέρος μέσω αποθηκευμένων διαδικασιών, μέρος μέσω άμεσων SQL από τον κώδικα. Το σχήμα της βάσης δεν είναι τεκμηριωμένο, οι μεταναστεύσεις συγκρούονται.
Η πολυπλοκότητα ενσωμάτωσης είναι η πρώτη συνέπεια. Ένας νέος προγραμματιστής πρέπει να γνωρίζει 5 γλώσσες, 3 frameworks, 2 αρχιτεκτονικά στυλ για να καταλάβει πώς λειτουργεί το σύστημα. Η ενσωμάτωση διαρκεί από εβδομάδες έως μήνες. Σύμφωνα με το LinkedIn (2023), τα έργα με τεχνολογικό εκλεκτικισμό χάνουν νέους υπαλλήλους 2 φορές πιο συχνά.
Η απρόβλεπτη συμπεριφορά είναι η δεύτερη συνέπεια. Μια αλλαγή σε μια μικρουπηρεσία Python μπορεί απροσδόκητα να σπάσει ένα module Java επειδή χρησιμοποιούν κοινή βάση δεδομένων χωρίς σαφείς συμβάσεις. Η αποσφαλμάτωση τέτοιων προβλημάτων απαιτεί ταυτόχρονη γνώση όλων των τεχνολογιών στη στοίβα.
Η ασφάλεια είναι η τρίτη συνέπεια. Κάθε τεχνολογία στη στοίβα απαιτεί τη δική της διαμόρφωση ασφάλειας, τα δικά της patches, τη δική της παρακολούθηση. Η διατήρηση της ασφάλειας σε αποδεκτό επίπεδο για 5–6 ετερογενείς τεχνολογίες είναι πρακτικά αδύνατη. Μία από αυτές αναπόφευκτα θα αποδειχθεί ευάλωτη.
Το SonarQube μπορεί να μετρήσει τεχνικό χρέος, αλλά δεν μπορεί να μετρήσει το “αρχιτεκτονικό χρέος” — την ασυμβατότητα των στοιχείων. Αυτό το χρέος δεν εμφανίζεται στις προειδοποιήσεις linter, αλλά στην αδυναμία προσθήκης μιας νέας λειτουργίας χωρίς αλλαγή τριών διαφορετικών modules γραμμένων σε διαφορετικές τεχνολογίες.
Το πρώτο και σημαντικότερο βήμα είναι ο διορισμός ενός αρχιτέκτονα ή tech lead υπεύθυνου για την ακεραιότητα της τεχνολογικής στοίβας. Αυτό το άτομο έχει δικαίωμα βέτο στην εισαγωγή νέων τεχνολογιών χωρίς αρχιτεκτονική αναθεώρηση. Όχι δημοκρατία, αλλά υπεύθυνη ατομική απόφαση για τις βασικές τεχνολογίες.
Το δεύτερο — εισαγωγή της διαδικασίας Architecture Decision Record (ADR). Κάθε σημαντική αρχιτεκτονική απόφαση (επιλογή βάσης δεδομένων, framework, πρωτοκόλλου) τεκμηριώνεται ως σύντομο κείμενο: πλαίσιο, εξετασθείσες εναλλακτικές, ληφθείσα απόφαση, συνέπειες. Τα ADR αποθηκεύονται στο αποθετήριο και είναι διαθέσιμα σε όλη την ομάδα.
Το τρίτο — καθιέρωση της αρχής “μία εργασία — ένα εργαλείο”. Για αιτήματα HTTP — ένας πελάτης. Για ORM — μία βιβλιοθήκη. Για καταγραφή — ένα framework. Εξαιρέσεις επιτρέπονται μόνο μέσω ADR με αιτιολόγηση. Αν υπάρχει ήδη Axios στο έργο — μην προσθέτετε fetch, αν υπάρχει SLF4J — μην γράφετε μέσω System.out.
Τα πειράματα επιτρέπονται, αλλά σε απομονωμένο περιβάλλον. Ορίστε ένα module ή υπηρεσία που μπορεί να ξαναγραφεί με νέα τεχνολογία χωρίς επίδραση στο υπόλοιπο σύστημα. Αν το πείραμα πετύχει — τυποποιήστε το μέσω ADR. Αν όχι — αφαιρέστε το χωρίς συνέπειες.
Η καταγραφή είναι το πρώτο βήμα. Δημιουργήστε έναν πλήρη χάρτη της τεχνολογικής στοίβας: ποια frameworks, βιβλιοθήκες, γλώσσες, πρωτόκολλα χρησιμοποιούνται, σε ποια modules και για ποιες εργασίες. Θα δείτε την έκταση του προβλήματος: διπλότυπα εργαλεία, αντικρουόμενες τεχνολογίες, αχρησιμοποίητες εξαρτήσεις.
Η τυποποίηση είναι το δεύτερο βήμα. Επιλέξτε ένα εργαλείο για κάθε εργασία. Για παράδειγμα: μόνο Hibernate για ORM, μόνο SLF4J + Logback για καταγραφή, μόνο REST για API. Τεκμηριώστε το πρότυπο σε ADR. Ξεκινήστε την αντικατάσταση από τα modules όπου ο εκλεκτικισμός προκαλεί τα περισσότερα προβλήματα.
Η στρατηγική Parallel Run είναι το τρίτο βήμα. Τα παλιά και νέα εργαλεία λειτουργούν παράλληλα έως ότου το νέο αποδείξει την αξιοπιστία του. Για παράδειγμα, ο παλιός HTTP πελάτης και ο νέος λειτουργούν ταυτόχρονα, αλλά ο νέος μόνο για μέρος των αιτημάτων. Μετά από περίοδο σταθεροποίησης, ο παλιός αφαιρείται.
// frankenstein — τρεις HTTP προσεγγίσεις σε ένα έργο
// Module A: OkHttp
OkHttpClient client = new OkHttpClient().newCall(request);
// Module B: RestTemplate (Spring)
restTemplate.getForObject(url, String.class);
// Module C: java.net.HttpURLConnection
HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
// ενοποιημένη προσέγγιση: RestTemplate για sync, WebClient για reactive
@Autowired
private RestTemplate restTemplate;
public String callApi(String url) {
return restTemplate.getForObject(url, String.class);
}
Ο τεχνικός ηγέτης είναι το κύριο εργαλείο στην καταπολέμηση του Frankenstein. Όχι διευθυντής, όχι αρχιτέκτονας σε πύργο από ελεφαντόδοντο, αλλά ένας ενεργός προγραμματιστής που γράφει κώδικα, κάνει ανασκόπηση PR και λαμβάνει αρχιτεκτονικές αποφάσεις. Χωρίς ένα τέτοιο άτομο, το έργο αναπόφευκτα ολισθαίνει στον τεχνολογικό εκλεκτικισμό.
Το RFC (Request for Comments) είναι μια διαδικασία δανεισμένη από τις κοινότητες Ανοιχτού Λογισμικού. Πριν από την εισαγωγή οποιασδήποτε σημαντικής τεχνολογίας, ο συγγραφέας γράφει ένα RFC: πρόβλημα, προτεινόμενη λύση, εναλλακτικές, σχέδιο εφαρμογής. Η ομάδα συζητά, ψηφίζει, αποδέχεται ή απορρίπτει. Το RFC δημιουργεί διαφάνεια και αποτρέπει “σιωπηλές” αρχιτεκτονικές αποφάσεις.
Το τεχνολογικό ραντάρ (Technology Radar από την ThoughtWorks) είναι ένα εργαλείο κατηγοριοποίησης τεχνολογιών: Adopt, Trial, Assess, Hold. Η ομάδα αναθεωρεί τακτικά το ραντάρ και ενημερώνει τις καταστάσεις. Αυτό βοηθά να διακρίνουμε το “μοδάτο” από το “χρήσιμο” και να αποφεύγουμε την εισαγωγή μη δοκιμασμένων τεχνολογιών σε κρίσιμο κώδικα.
Η σημαντικότερη ποιότητα της αρχιτεκτονικής είναι η συνέπεια (consistency). Ακόμα και ένα όχι το καλύτερο εργαλείο που χρησιμοποιείται σε ολόκληρο το έργο είναι καλύτερο από το καλύτερο εργαλείο που χρησιμοποιείται μόνο σε ένα module. Η συνέπεια μειώνει το γνωστικό φορτίο, απλοποιεί την ενσωμάτωση και κάνει τον κώδικα προβλέψιμο.
Συχνές Ερωτήσεις
Το polyglot persistence είναι η συνειδητή χρήση διαφορετικών βάσεων δεδομένων για διαφορετικές εργασίες (PostgreSQL για συναλλαγές, Redis για προσωρινή μνήμη, Elasticsearch για αναζήτηση). Το Frankenstein είναι χαοτική ανάμειξη χωρίς στρατηγική. Η διαφορά βρίσκεται στην ύπαρξη αρχιτεκτονικής απόφασης: το polyglot είναι ένα σχέδιο, το Frankenstein είναι η απουσία του.
Ναι, και είναι συχνό πρόβλημα. Όταν κάθε μικρουπηρεσία χρησιμοποιεί τη δική της γλώσσα, βάση δεδομένων, πρωτόκολλο και προσέγγιση ανάπτυξης χωρίς κεντρικοποιημένα πρότυπα — προκύπτει ένας κατανεμημένος Frankenstein. Για τις μικρουπηρεσίες, σημαντικά είναι τα κοινά πρότυπα: ενιαίο πρωτόκολλο (REST/gRPC), ενιαίο μορφότυπο αρχείων καταγραφής, κεντρικοποιημένη παρατηρησιμότητα.
Μην απαγορεύετε — καθοδηγείτε. Ζητήστε από τον συγγραφέα RFC: να περιγράψει γιατί η υπάρχουσα λύση δεν είναι κατάλληλη, ποιες εναλλακτικές εξετάστηκαν, πώς θα γίνει η μετεγκατάσταση. Συχνά κατά τη διαδικασία σύνταξης του RFC, ο προγραμματιστής καταλαβαίνει ότι η νέα τεχνολογία δεν χρειάζεται. Αν το RFC είναι πειστικό — εφαρμόστε το, αλλά με σχέδιο και περιορισμούς.
Πρώτα καταγραφή, μετά τυποποίηση. Μην προσπαθήσετε να ξαναγράψετε τα πάντα ταυτόχρονα. Ορίστε ένα επίπεδο (π.χ. HTTP πελάτες ή καταγραφή), επιλέξτε ένα ενιαίο εργαλείο, γράψτε ADR και μεταφερθείτε σταδιακά. Η μέθοδος Strangler Fig — αντικαταστήστε τα παλιά στοιχεία ένα προς ένα χωρίς να σταματήσετε την εφαρμογή.
Όσο λιγότερες, τόσο καλύτερα. Ιδανικά — μία γλώσσα, ένα framework, μία βάση δεδομένων, ένας τρόπος καταγραφής. Ρεαλιστικά — 2–3 γλώσσες (με σαφή διαχωρισμό), 1–2 βάσεις δεδομένων, 1–2 frameworks. Κάθε επιπλέον τεχνολογία αυξάνει το γνωστικό φορτίο της ομάδας και το κόστος συντήρησης.
Σύνοψη
Θα αναπτύξουμε μια εφαρμογή για κινητά έτοιμη για χρήση
Η IT Sectr δημιουργεί εφαρμογές iOS και Android για νεοφυείς επιχειρήσεις και επιχειρήσεις από το 2017. Θα σας συμβουλεύσουμε και θα προτείνουμε την καλύτερη λύση.
Διαβάστε επίσης