“Καρφωμένο” και “hardcode” είναι αργκό όροι που σημαίνουν την άκαμπτη καθήλωση τιμών απευθείας στον κώδικα του προγράμματος, αντί να τις μεταφέρετε σε ρυθμίσεις ή διαμόρφωση. Το hardcode είναι ένα από τα πιο γνωστά anti-pattern στην ανάπτυξη, καθώς μειώνει την ευελιξία και την επαναχρησιμοποιησιμότητα του κώδικα. Σύμφωνα με το Refactoring Guru, το hardcode δυσχεραίνει τη δοκιμή, τη συντήρηση και την προσαρμογή της εφαρμογής σε διαφορετικά περιβάλλοντα. Η συνειδητή χρήση σταθερών αντί του hardcode είναι σημάδι ώριμης αρχιτεκτονικής.
Κύρια σημεία
Hardcode (καρφωμένο) – ενσωμάτωση μιας συγκεκριμένης τιμής στον κώδικα του προγράμματος έτσι ώστε για την αλλαγή της απαιτείται επεξεργασία του πηγαίου κώδικα και μεταγλώττιση της εφαρμογής. Η μεταφορά “καρφωμένο” αντικατοπτρίζει ακριβώς την ουσία: η τιμή είναι σταθερά καθηλωμένη και μπορεί να αποκολληθεί από τον κώδικα μόνο με προσπάθεια.
Παράδειγμα hardcode – το URL του διακομιστή γραμμένο ως συμβολοσειρά απευθείας στο σώμα της συνάρτησης. Εάν ο διακομιστής μεταφερθεί σε άλλη διεύθυνση, ο προγραμματιστής πρέπει να βρει τη συμβολοσειρά στον κώδικα, να την αλλάξει, να ξαναχτίσει την εφαρμογή και να κυκλοφορήσει μια νέα έκδοση. Σε μια εφαρμογή με σωστή αρχιτεκτονική, ένα τέτοιο URL θα είχε μεταφερθεί σε ένα αρχείο διαμόρφωσης, μια μεταβλητή περιβάλλοντος ή μια υπηρεσία διαμόρφωσης.
Ο όρος “καρφωμένο” έχει πιο συναισθηματική χροιά: τονίζει ότι η τιμή είναι τοποθετημένη σταθερά χωρίς δυνατότητα γρήγορης αντικατάστασης. Στο ελληνόφωνο περιβάλλον, και οι δύο εκφράσεις χρησιμοποιούνται ως πλήρη συνώνυμα με αρνητική χροιά. Μερικές φορές το hardcode αποκαλείται ειρωνικά “σταθερά που μεταφέρθηκε σε ξεχωριστή σταθερά από μια σταθερά”.
Hardcode είναι ένα anti-pattern επειδή παραβιάζει τις αρχές συντηρησιμότητας, δοκιμασιμότητας και επεκτασιμότητας του κώδικα. Σε κώδικα όπου οι τιμές είναι “καρφωμένες”, οποιαδήποτε αλλαγή περιβάλλοντος, σχεδίου ή λογικής απαιτεί χειροκίνητη αναζήτηση και αντικατάσταση στις πηγές. Αυτό αυξάνει τον κίνδυνο σφαλμάτων και επιβραδύνει την ανάπτυξη.
Ας εξετάσουμε τις συγκεκριμένες συνέπειες του hardcode στο παράδειγμα μιας τυπικής εφαρμογής κινητού. Εάν η απόσταση όλων των κουμπιών ορίζεται από έναν αριθμό στον κώδικα και όχι μέσω ενός πόρου – η αλλαγή σχεδίου θα απαιτήσει την εύρεση όλων των εμφανίσεων και την αντικατάστασή τους. Εάν το URL του τελικού σημείου είναι σταθερά γραμμένο – η εναλλαγή μεταξύ περιβαλλόντων (dev, stage, prod) είναι αδύνατη χωρίς επαναμεταγλώττιση.
| Συνέπεια | Περιγραφή | Επίπεδο κρισιμότητας |
|---|---|---|
| Δυσκολία συντήρησης | Η αλλαγή απαιτεί αναζήτηση σε όλο τον κώδικα | Υψηλό |
| Σφάλματα αντιγραφής | Δεν βρίσκονται και αντικαθίστανται όλες οι εμφανίσεις | Υψηλό |
| Αδυναμία δοκιμής | Δεν μπορούν να υποκατασταθούν δεδομένα δοκιμής | Μέτριο |
| Προβλήματα εντοπισμού | Τα κείμενα στον κώδικα δεν μεταφράζονται | Μέτριο |
| Περιπλοκή code-review | Ο αξιολογητής πρέπει να θυμάται όλα τα συμφραζόμενα | Χαμηλό |
Μια συνάρτηση που χρησιμοποιεί μαγικούς αριθμούς και σταθερά γραμμένες συμβολοσειρές είναι κλασικό παράδειγμα hardcode. Μετά από ένα μήνα, ο συγγραφέας δεν θα θυμάται τι σημαίνουν τα 18, 0.07 και 2.5. Μετά από ένα χρόνο – κανείς στην ομάδα δεν θα τολμήσει να αλλάξει αυτούς τους αριθμούς, φοβούμενος ότι θα σπάσει τη λογική. Η μεταφορά τιμών σε ονομασμένες σταθερές κάνει τον κώδικα αυτο-τεκμηριωμένο.
// Κακό: μαγικοί αριθμοί και συμβολοσειρές
fun calculatePrice(base: Double): Double {
val tax = base * 0.07
val tip = base * 0.15
val discount = if (base > 100) 10 else 0
return base + tax + tip - discount
}
Το hardcoded URL της βάσης δεδομένων δεν θα επιτρέψει την εκτέλεση δοκιμών σε μια τοπική in-memory βάση δεδομένων. Ο προγραμματιστής θα πρέπει να σηκώσει έναν πλήρη διακομιστή ή να διορθώσει τον κώδικα πριν από τη δοκιμή. Η μεταφορά της διαμόρφωσης από τον κώδικα λύνει το πρόβλημα: οι δοκιμές χρησιμοποιούν παραμέτρους δοκιμής, η παραγωγή χρησιμοποιεί πραγματικές παραμέτρους και ο κώδικας δεν αλλάζει.
Το hardcode είναι anti-pattern, αλλά υπάρχουν νόμιμες εξαιρέσεις όπου μια σταθερά γραμμένη τιμή όχι μόνο επιτρέπεται, αλλά είναι προτιμότερη. Το όριο διατρέχει τον άξονα μεταβλητότητας: εάν η τιμή δεν αλλάζει ποτέ ή σχεδόν ποτέ κατά τον κύκλο ζωής της εφαρμογής, μπορεί να hardcoded. Εάν τουλάχιστον δυνητικά μπορεί να αλλάξει – μεταφέρετε στη διαμόρφωση.
Μαθηματικές και φυσικές σταθερές – ο αριθμός Pi, η επιτάχυνση της βαρύτητας, ο αριθμός των χιλιοστών του δευτερολέπτου σε ένα δευτερόλεπτο – είναι ασφαλείς για hardcode. Ορίζονται από τη φύση ή τα πρότυπα και δεν θα αλλάξουν. Τα μεγέθη σταθερών πινάκων που ορίζονται από την προδιαγραφή μπορούν επίσης να καθοριστούν σταθερά, αλλά με ένα σχόλιο σχετικά με την προέλευση του αριθμού.
Ο αριθμός των χιλιοστών του δευτερολέπτου σε ένα δευτερόλεπτο είναι μια σταθερή σταθερά που ορίζεται από το πρότυπο χρόνου. Δεν έχει νόημα να τη μεταφέρετε σε config, επειδή δεν θα αλλάξει ποτέ. Ωστόσο, ακόμη και τέτοιες σταθερές είναι καλύτερο να δηλώνονται με ένα κατανοητό όνομα, ώστε ο κώδικας να μην περιέχει “μαγικούς αριθμούς”: αντί για 1000, γράψτε MILLISECONDS_IN_SECOND.
// Δικαιολογημένο hardcode: σταθερές σταθερές
private const val MILLIS_IN_SECOND = 1000
private const val LOGIN_TIMEOUT_SECONDS = 30
fun formatDuration(ms: Long): String {
val seconds = ms / MILLIS_IN_SECOND
return "${seconds} sec."
}
Υπάρχουν αρκετές δοκιμασμένες μέθοδοι για την αποφυγή του hardcode, η καθεμία κατάλληλη για τον δικό της τύπο τιμής. Η επιλογή της εναλλακτικής εξαρτάται από το πόσο συχνά αλλάζει η τιμή και ποιος την αλλάζει: ο προγραμματιστής, ο devops ή ο τελικός χρήστης.
Για URL διακομιστών, κλειδιά API και feature flags, χρησιμοποιήστε αρχεία διαμόρφωσης σε μορφή JSON, YAML ή TOML. Στο Android αυτό είναι build.gradle με buildConfigField ή res/values/config.xml. Στο iOS – Info.plist ή xcconfig. Τα configs χτίζονται μαζί με την εφαρμογή, αλλά μπορεί να είναι διαφορετικά για διαφορετικά σχήματα build.
Για μυστικά (tokens, κωδικούς) και παραμέτρους περιβάλλοντος, χρησιμοποιήστε μεταβλητές περιβάλλοντος. Δεν εισέρχονται στο αποθετήριο και μπορεί να διαφέρουν στους διακομιστές dev, stage και prod. Στην ανάπτυξη κινητού, οι μεταβλητές περιβάλλοντος συχνά προσομοιώνονται μέσω σχημάτων build Xcode ή build flavors στο Gradle.
Συμβολοσειρές, χρώματα, μεγέθη, εικόνες πρέπει να μεταφέρονται σε αρχεία πόρων: strings.xml στο Android, Localizable.strings στο iOS, ARB αρχεία στο Flutter. Αυτό απλοποιεί τον εντοπισμό, την προσαρμογή σε διαφορετικές οθόνες και τη σκοτεινή λειτουργία. Η αλλαγή μιας συμβολοσειράς στους πόρους δεν απαιτεί επανεγγραφή του κώδικα.
<!-- Android: res/values/strings.xml -->
<resources>
<string name="app_name">MyApp</string>
<string name="api_base_url">https://api.example.com</string>
</resources>
Για υπηρεσίες και παρόχους, χρησιμοποιήστε Dependency Injection μέσω Dagger, Hilt ή Koin στο Android, Swinject στο iOS. Τα DI frameworks επιτρέπουν την αντικατάσταση υλοποιήσεων εν κινήσει – για δοκιμές, για διαφορετικά περιβάλλοντα, για διαφορετικούς χρήστες. Αυτό είναι το υψηλότερο επίπεδο αφαίρεσης, όπου το “κάρφωμα” της τιμής αντικαθίσταται από έγχυση από έξω.
Η αναδιάρθρωση του hardcode είναι η διαδικασία μεταφοράς σταθερά γραμμένων τιμών σε διαμόρφωση ή πόρους. Είναι μία από τις ασφαλέστερες λειτουργίες αναδιάρθρωσης, εάν εκτελείται μεθοδικά. Η ακολουθία που περιγράφεται παρακάτω είναι κατάλληλη για οποιαδήποτε γλώσσα και πλατφόρμα.
Η αναζήτηση μπορεί να γίνει μέσω IDE (Search in Project) ή με σενάριο. Αναζητήστε συμβολοσειρές, URL, αριθμητικά literal, μεγέθη, χρονικά όρια. Ιδιαίτερη προσοχή σε επαναλαμβανόμενες τιμές: εάν ο ίδιος αριθμός εμφανίζεται σε πέντε σημεία, είναι υποψήφιος για μεταφορά σε σταθερά. Χρησιμοποιήστε grep ή την ενσωματωμένη αναζήτηση IDEA / Xcode.
Για κάθε τιμή που βρέθηκε, δημιουργήστε μια σταθερά με ουσιαστικό όνομα. Ομαδοποιήστε τις σταθερές ανά ενότητα ή κλάση. Το όνομα πρέπει να εξηγεί τι σημαίνει η τιμή, όχι πώς χρησιμοποιείται: API_TIMEOUT, όχι TIMEOUT_30. Μετά την αντικατάσταση, κανένας αριθμός στον κώδικα δεν πρέπει να μείνει χωρίς εξήγηση.
// Πριν: μαγικός αριθμός 0.4
let cardHeight = screenHeight * 0.4
// Μετά: ονομασμένη σταθερά
private let cardHeightRatio: CGFloat = 0.4
let cardHeight = screenHeight * cardHeightRatio
Εάν η τιμή μπορεί να αλλάξει μεταξύ builds ή περιβαλλόντων – μεταφέρετέ την σε ένα αρχείο διαμόρφωσης ή σε πόρους εφαρμογής. Για συμβολοσειρές, χρησιμοποιήστε αρχεία εντοπισμού. Για URL – build config ή xcconfig. Για μεγέθη – αρχεία πόρων (dimens.xml στο Android). Ελέγξτε ότι η εφαρμογή μεταγλωττίζεται και λειτουργεί σωστά μετά τη μεταφορά.
Μετά την αναδιάρθρωση, γράψτε μια δοκιμή που ελέγχει ότι η διαμόρφωση φορτώνεται σωστά και οι τιμές αντιστοιχούν στις αναμενόμενες. Εάν στο μέλλον κάποιος αλλάξει το config, η δοκιμή θα υποδείξει την απόκλιση. Η δοκιμή διαμόρφωσης είναι ένας γρήγορος και αξιόπιστος τρόπος για την πρόληψη της παλινδρόμησης.
Μετά τη μεταφορά στο config, ελέγξτε ότι όλα τα σημεία όπου χρησιμοποιήθηκε η παλιά τιμή αναφέρονται σε μία ενιαία πηγή. Αφαιρέστε τον σχολιασμένο κώδικα και τις παλιές σταθερές που δεν χρησιμοποιούνται πλέον. Ολοκληρώστε την αναδιάρθρωση με ένα commit που περιγράφει ποιες τιμές και πού μεταφέρθηκαν.
Συχνές ερωτήσεις
Hardcode – σταθερή εγγραφή μιας τιμής στον πηγαίο κώδικα αντί να μεταφερθεί σε διαμόρφωση ή πόρους. Αυτό κάνει τον κώδικα λιγότερο ευέλικτο και πιο δύσκολο στη συντήρηση.
Hardcode δυσχεραίνει την αλλαγή της συμπεριφοράς της εφαρμογής, εμποδίζει τη δοκιμή, δημιουργεί αντιγραφή και αυξάνει τον κίνδυνο σφαλμάτων αντιγραφής. Η αλλαγή μιας hardcoded τιμής απαιτεί ανακατασκευή και επανέκδοση της εφαρμογής.
Επιτρέπεται για μαθηματικές σταθερές, σταθερές τιμές που δεν αλλάζουν στον κύκλο ζωής της εφαρμογής και για προσωρινά πρωτότυπα. Στην παραγωγή, ακόμη και οι σταθερές είναι καλύτερο να μεταφέρονται σε ονομασμένες μεταβλητές.
Βρείτε όλους τους μαγικούς αριθμούς μέσω αναζήτησης, αντικαταστήστε τους με ονομασμένες σταθερές ή μεταφέρετέ τους σε ένα αρχείο διαμόρφωσης. Γράψτε μια δοκιμή που ελέγχει τη φόρτωση της διαμόρφωσης. Αφαιρέστε τα αντίγραφα και κάντε commit με περιγραφή των αλλαγών.
Σταθερά – μια ονομασμένη τιμή στον κώδικα, προσβάσιμη για αλλαγή σε ένα σημείο. Hardcode – ανώνυμες τιμές διάσπαρτες σε όλο τον κώδικα. Καλή πρακτική: χρησιμοποιείτε πάντα ονομασμένες σταθερές με ουσιαστικά ονόματα.
Σύνοψη
Θα αναπτύξουμε μια εφαρμογή για κινητά έτοιμη για χρήση
Η IT Sectr δημιουργεί εφαρμογές iOS και Android για νεοφυείς επιχειρήσεις και επιχειρήσεις από το 2017. Θα σας συμβουλεύσουμε και θα προτείνουμε την καλύτερη λύση.
Διαβάστε επίσης