Επιδιόρθωση μαϊμού σε γλώσσες δυναμικού προγραμματισμού: Παράδειγμα JavaScript

Javascript
Δυναμικός Προγραμματισμός
Επιδιόρθωση μαϊμού σε γλώσσες δυναμικού προγραμματισμού cover image

Εισαγωγή

Αυτό το άρθρο θα διερευνήσει τις έννοιες των δυναμικών και στατικών γλωσσών προγραμματισμού, τις κύριες διαφορές μεταξύ των δύο και τι παρέχει κάθε παράδειγμα όσον αφορά τα πλεονεκτήματα και τις παγίδες. Αυτή η εξερεύνηση θα επικεντρωθεί περαιτέρω σε δυναμικές γλώσσες προγραμματισμού, ιδιαίτερα σε ένα από τα βασικά μοτίβα που ενεργοποιεί: Monkey Patch, αυτό το μοτίβο θα παρουσιαστεί με τη βοήθεια ενός παραδείγματος στο JavaScript.

Δυναμικές έναντι στατικών γλωσσών προγραμματισμού

Ορολογία

Για να κατανοήσουμε τι συνιστά μια δυναμική γλώσσα ή μια στατική γλώσσα, πρέπει να κατανοήσουμε ορισμένους βασικούς όρους που χρησιμοποιούνται συνήθως σε αυτό το πλαίσιο: Χρόνος μεταγλώττισης, Χρόνος εκτέλεσης και *Έλεγχος τύπου *.

Το Compile και το Runtime είναι δύο όροι που αντιστοιχούν σε διαφορετικά στάδια του κύκλου ζωής ενός προγράμματος υπολογιστή, ξεκινώντας από το Compile time.

Χρόνος μεταγλώττισης

Ο χρόνος μεταγλώττισης είναι το πρώτο βήμα στον κύκλο ζωής ενός προγράμματος. Ένας προγραμματιστής γράφει κώδικα σε μια δεδομένη γλώσσα προγραμματισμού. Τις περισσότερες φορές, το μηχάνημα δεν μπορεί να κατανοήσει τον κώδικα που είναι γραμμένος σε μια γλώσσα υψηλού επιπέδου, επομένως χρησιμοποιείται ένας αποκλειστικός μεταγλωττιστής για να τον μεταφράσει σε μια ενδιάμεση μορφή χαμηλότερου επιπέδου που είναι έτοιμη για εκτέλεση.

Χρόνος εκτέλεσης

Ο χρόνος εκτέλεσης συνήθως περιλαμβάνει δύο βήματα: φόρτωση του προγράμματος στη μνήμη με την κατανομή των πόρων που απαιτούνται για την εκτέλεσή του μαζί με τις οδηγίες του και, στη συνέχεια, εκτέλεση του προγράμματος ακολουθώντας τη σειρά αυτών των οδηγιών.

Το παρακάτω διάγραμμα απεικονίζει αυτή τη διαδικασία:

Έλεγχος τύπου

Ο έλεγχος τύπου είναι μια ενσωματωμένη δυνατότητα σε όλες σχεδόν τις γλώσσες προγραμματισμού. Είναι η δυνατότητα να ελεγχθεί εάν μια τιμή που έχει εκχωρηθεί σε μια δεδομένη μεταβλητή αντιστοιχεί στον σωστό τύπο αυτής της μεταβλητής. Κάθε γλώσσα προγραμματισμού έχει διαφορετικό τρόπο να αναπαραστήσει μια τιμή ενός δεδομένου τύπου στη μνήμη. Αυτές οι διαφορετικές αναπαραστάσεις καθιστούν δυνατό τον έλεγχο της αντιστοιχίας μεταξύ του τύπου μιας τιμής και του τύπου μιας μεταβλητής στην οποία προσπαθείτε να εκχωρήσετε αυτήν την τιμή.

Τώρα που έχουμε μια υψηλού επιπέδου κατανόηση του κύκλου ζωής του προγράμματος και του ελέγχου τύπων, μπορούμε να προχωρήσουμε στην εξερεύνηση στατικών γλωσσών προγραμματισμού.

Στατικές γλώσσες προγραμματισμού

Οι Στατικές Γλώσσες Προγραμματισμού, που αναφέρονται επίσης ως στατικά Δακτυλογραφημένες Γλώσσες είναι γλώσσες που εφαρμόζουν τον έλεγχο τύπου που αναφέραμε στη φάση της μεταγλώττισης. Αυτό ουσιαστικά σημαίνει ότι μια μεταβλητή κρατά τον τύπο της από δήλωση και δεν μπορεί να της αποδοθεί καμία άλλη τιμή εκτός από τιμές από τον τύπο της δήλωσης. Οι στατικές γλώσσες προγραμματισμού προσφέρουν επιπλέον ασφάλεια όταν ασχολούμαστε με τύπους, αλλά μπορούν να επιβραδύνουν τη διαδικασία ανάπτυξης σε ορισμένες περιπτώσεις χρήσης, όταν αυτό γίνεται αυστηρός περιορισμός.

Γλώσσες Δυναμικού Προγραμματισμού

Οι δυναμικές γλώσσες προγραμματισμού, από την άλλη πλευρά, εφαρμόζουν έλεγχο τύπου κατά το χρόνο εκτέλεσης. Αυτό σημαίνει ότι οποιαδήποτε μεταβλητή μπορεί να κρατήσει οποιαδήποτε τιμή σε οποιοδήποτε σημείο του προγράμματος. Αυτό μπορεί να είναι επωφελές καθώς προσφέρει ένα επίπεδο ευελιξίας στον προγραμματιστή που δεν υπάρχει στις στατικές γλώσσες. Οι δυναμικές γλώσσες τείνουν να είναι πιο αργές στην εκτέλεση από τις στατικές αντίστοιχές τους, καθώς περιλαμβάνουν ένα επιπλέον βήμα δυναμικού υπολογισμού της πληκτρολόγησης κάθε μεταβλητής.

Patch μαϊμού

Η στατική έναντι της δυναμικής πληκτρολόγησης είναι ένα θεμελιώδες χαρακτηριστικό σε μια γλώσσα προγραμματισμού, καθώς η χρήση ενός παραδείγματος πάνω από το άλλο μπορεί να επιτρέψει μια σειρά από διαφορετικά μοτίβα και πρακτικές που μπορούν να βελτιώσουν σημαντικά την ποιότητα και την ταχύτητα ανάπτυξης. Μπορεί επίσης να ανοίξει την πόρτα για πολλούς περιορισμούς και αντι-μοτίβα, εάν δεν ληφθούν προσεκτικά υπόψη κατά τη λήψη αποφάσεων σχεδιασμού.

Ειδικότερα, οι δυναμικά πληκτρολογημένες γλώσσες προγραμματισμού είναι γνωστό ότι προσφέρουν υψηλότερο επίπεδο ευελιξίας, καθώς δεν περιορίζουν μια μεταβλητή σε έναν μόνο τύπο. Αυτή η ευελιξία συνοδεύεται από το κόστος της πρόσθετης ευθύνης του προγραμματιστή κατά την εφαρμογή και τον εντοπισμό σφαλμάτων προγραμμάτων για να βεβαιωθείτε ότι δεν εμφανίζονται απρόβλεπτες συμπεριφορές. Το μοτίβο μπαλωμάτων μαϊμού προέρχεται από αυτή τη φιλοσοφία.

Το Monkey Patch αναφέρεται στη διαδικασία επέκτασης/αλλαγής της λειτουργίας ενός στοιχείου κατά το χρόνο εκτέλεσης. Το εν λόγω στοιχείο μπορεί να είναι μια βιβλιοθήκη, μια κλάση, μια μέθοδος ή ακόμα και μια ενότητα. Η ιδέα είναι η ίδια: ένα κομμάτι κώδικα είναι φτιαγμένο για να ολοκληρώσει μια συγκεκριμένη εργασία και ο στόχος της επιδιόρθωσης μαϊμού είναι να αλλάξει ή να επεκτείνει τη συμπεριφορά αυτού του κομματιού κώδικα έτσι ώστε να ολοκληρώσει μια νέα εργασία, και όλα αυτά χωρίς αλλαγή του ίδιου του κώδικα .

Αυτό είναι δυνατό στη γλώσσα δυναμικού προγραμματισμού, καθώς ανεξάρτητα από τον τύπο στοιχείου που έχουμε να κάνουμε, εξακολουθεί να έχει την ίδια δομή ενός αντικειμένου με διαφορετικά χαρακτηριστικά, τα χαρακτηριστικά μπορούν να περιέχουν μεθόδους που μπορούν να ανατεθούν για να επιτευχθεί μια νέα συμπεριφορά στο αντικείμενο χωρίς να υπεισέλθω στα εσωτερικά και στις λεπτομέρειες εφαρμογής του. Αυτό γίνεται ιδιαίτερα χρήσιμο στην περίπτωση βιβλιοθηκών και λειτουργικών μονάδων τρίτων, καθώς αυτές τείνουν να είναι πιο δύσκολο να τροποποιηθούν.

Το παρακάτω παράδειγμα θα παρουσιάσει μια περίπτωση κοινής χρήσης που μπορεί να ωφεληθεί από τη χρήση της τεχνικής επιδιόρθωσης μαϊμού. Η Javascript χρησιμοποιήθηκε για λόγους υλοποίησης εδώ, αλλά αυτό θα πρέπει να ισχύει γενικά για οποιαδήποτε άλλη δυναμική γλώσσα προγραμματισμού.

Παράδειγμα

Εφαρμόστε ένα Ελάχιστο Πλαίσιο Δοκιμών με το Native HTTP Module του Node

Οι δοκιμές μονάδων και ολοκλήρωσης μπορεί να εμπίπτουν στις περιπτώσεις χρήσης του επιδιορθώματος Monkey. Συνήθως περιλαμβάνουν περιπτώσεις δοκιμών που εκτείνονται σε περισσότερες από μία υπηρεσίες για δοκιμές ενοποίησης ή εξαρτήσεις API ή/και βάσης δεδομένων για δοκιμές μονάδων. Σε αυτά τα δύο σενάρια, και για να επιτευχθούν οι στόχοι των δοκιμών, θα θέλαμε οι δοκιμές μας να είναι ανεξάρτητες από αυτούς τους εξωτερικούς πόρους. Ο τρόπος για να το πετύχετε αυτό είναι μέσω της κοροϊδίας. Η κοροϊδία είναι η προσομοίωση της συμπεριφοράς των εξωτερικών υπηρεσιών, ώστε η δοκιμή να μπορεί να επικεντρωθεί στην πραγματική λογική του κώδικα. Η επιδιόρθωση μαϊμού μπορεί να είναι χρήσιμη εδώ, καθώς μπορεί να τροποποιήσει τις μεθόδους των εξωτερικών υπηρεσιών αντικαθιστώντας τις με μεθόδους κράτησης θέσης που ονομάζουμε "stub". Αυτές οι μέθοδοι επιστρέφουν το αναμενόμενο αποτέλεσμα στις περιπτώσεις δοκιμών, ώστε να μπορούμε να αποφύγουμε την έναρξη αιτημάτων στις υπηρεσίες παραγωγής μόνο για χάρη των δοκιμών.

Το παρακάτω παράδειγμα είναι μια απλή υλοποίηση της ενημέρωσης κώδικα Monkey στην εγγενή λειτουργική μονάδα http του NodeJs. Η ενότητα http είναι η διεπαφή που υλοποιεί τις μεθόδους πρωτοκόλλου http για NodeJs. Χρησιμοποιείται κυρίως για τη δημιουργία barebone διακομιστών http και την επικοινωνία με εξωτερικές υπηρεσίες χρησιμοποιώντας το πρωτόκολλο http.

Στο παρακάτω παράδειγμα έχουμε μια απλή δοκιμαστική περίπτωση όπου καλούμε μια εξωτερική υπηρεσία για να λάβουμε τη λίστα των αναγνωριστικών χρηστών. Αντί να καλέσουμε την πραγματική υπηρεσία, επιδιορθώνουμε τη μέθοδο λήψης http, έτσι απλά επιστρέφει το αναμενόμενο αποτέλεσμα που είναι μια σειρά από τυχαία αναγνωριστικά χρήστη. Αυτό μπορεί να μην φαίνεται να έχει μεγάλη σημασία, δεδομένου ότι απλώς ανακτούμε δεδομένα, αλλά εάν εφαρμόσουμε μια άλλη δοκιμαστική περίπτωση που περιλαμβάνει την αλλαγή δεδομένων κάποιου είδους, ενδέχεται να αλλάξουμε κατά λάθος δεδομένα σχετικά με την παραγωγή κατά την εκτέλεση δοκιμών.

Με αυτόν τον τρόπο μπορούμε να υλοποιήσουμε τις λειτουργίες μας και να γράφουμε δοκιμές για κάθε λειτουργικότητα, διασφαλίζοντας παράλληλα την ασφάλεια των υπηρεσιών παραγωγής μας.

// import the http module
let http = require("http");

// patch the get method of the http module
http.get = async function(url) {
  return {
    data: ["1234", "1235", "1236", "1236"]
  };
}

// example test suite, call new patched get method for testing
test('get array of user ids from users api', async () => {
  const res = await http.get("https://users.api.com/ids");
  const userIds = res.data;
  expect(userIds).toBeDefined();
  expect(userIds.length).toBe(4);
  expect(userIds[0]).toBe("1234");
});

Ο παραπάνω κώδικας είναι απλός, εισάγουμε τη λειτουργική μονάδα http, εκχωρούμε εκ νέου τη μέθοδο http.get με μια νέα μέθοδο που απλώς επιστρέφει μια σειρά από αναγνωριστικά. Τώρα καλούμε τη νέα διορθωμένη μέθοδο μέσα στη δοκιμαστική περίπτωση και παίρνουμε το νέο αναμενόμενο αποτέλεσμα.

~/SphericalTartWorker$ npm test

> nodejs@1.0.0 test
> jest

PASS  ./index.test.js
  ✓ get array of user ids from users api (25 ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        0.977 s, estimated 2 s
Ran all test suites.

Συνήθεις παγίδες και περιορισμοί

Δεν πρέπει να προκαλεί έκπληξη το γεγονός ότι η επιδιόρθωση μαϊμού έχει τα δικά της ελαττώματα και περιορισμούς. Στο πλαίσιο των λειτουργικών μονάδων στο σύστημα λειτουργικών μονάδων κόμβου, η επιδιόρθωση μιας καθολικής λειτουργικής μονάδας όπως το http θεωρείται μια λειτουργία με παρενέργειες, επειδή το http είναι προσβάσιμο από οποιοδήποτε σημείο εντός της βάσης κώδικα και οποιαδήποτε άλλη οντότητα μπορεί να έχει εξάρτηση από αυτήν. Αυτές οι οντότητες αναμένουν από τη λειτουργική μονάδα http να λειτουργεί με τη συνήθη συμπεριφορά της, αλλάζοντας μία από τις μεθόδους http διακόπτουμε αποτελεσματικά όλες τις άλλες εξαρτήσεις http μέσα στη βάση κώδικα.

Δεδομένου ότι λειτουργούμε σε μια δυναμικά πληκτρολογημένη γλώσσα, τα πράγματα ενδέχεται να μην αποτύχουν αμέσως και θα προτιμούσαμε την προεπιλογή σε μια απρόβλεπτη συμπεριφορά που καθιστά τον εντοπισμό σφαλμάτων μια εξαιρετικά περίπλοκη εργασία. Σε άλλες περιπτώσεις χρήσης, μπορεί να υπάρχουν δύο διαφορετικές ενημερώσεις κώδικα του ίδιου στοιχείου στο ίδιο χαρακτηριστικό, οπότε δεν μπορούμε πραγματικά να προβλέψουμε ποια ενημερωμένη έκδοση κώδικα θα υπερισχύει της άλλης, με αποτέλεσμα έναν ακόμη πιο απρόβλεπτο κώδικα.

Είναι επίσης σημαντικό να αναφέρουμε ότι η επιδιόρθωση μαϊμού μπορεί να έχει μικρές διαφοροποιήσεις στη συμπεριφορά μεταξύ διαφορετικών γλωσσών προγραμματισμού. Όλα εξαρτώνται από τον γλωσσικό σχεδιασμό και τις επιλογές υλοποίησης. Για παράδειγμα, στην python, δεν θα επηρεαστούν όλες οι περιπτώσεις που χρησιμοποιούν μια επιδιορθωμένη μέθοδο από την ενημερωμένη έκδοση κώδικα. Εάν ένα στιγμιότυπο καλέσει ρητά την επιδιορθωμένη μέθοδο, τότε θα λάβει τη νέα ενημερωμένη έκδοση, αντίθετα, άλλες περιπτώσεις που μπορεί να έχουν μόνο χαρακτηριστικά που δείχνουν προς την ενημερωμένη μέθοδο και δεν την καλούν ρητά θα λάβουν την αρχική έκδοση, αυτό οφείλεται στο πώς η python δεσμευτικό στις τάξεις λειτουργεί.

Συμπέρασμα

Σε αυτό το άρθρο εξερευνήσαμε τις υψηλού επιπέδου διακρίσεις μεταξύ στατικών και δυναμικών γλωσσών προγραμματισμού, είδαμε πώς οι δυναμικές γλώσσες προγραμματισμού μπορούν να επωφεληθούν από νέα παραδείγματα και μοτίβα που αξιοποιούν την εγγενή ευελιξία που προσφέρουν αυτές οι γλώσσες. Το παράδειγμα που παρουσιάσαμε σχετίζεται με την επιδιόρθωση μαϊμού, μια τεχνική που χρησιμοποιείται για να επεκτείνει τη συμπεριφορά του κώδικα χωρίς να τον αλλάξει από την πηγή. Είδαμε μια περίπτωση όπου η χρήση αυτής της τεχνικής θα ήταν ευεργετική μαζί με τα πιθανά μειονεκτήματά της. Η ανάπτυξη λογισμικού έχει να κάνει με συμβιβασμούς και η χρησιμοποίηση της σωστής λύσης για το πρόβλημα απαιτεί λεπτομερείς σκέψεις από τον προγραμματιστή και καλή κατανόηση των αρχών και των βασικών αρχών της αρχιτεκτονικής.


Career Services background pattern

Υπηρεσίες καριέρας

Contact Section background image

Ας μείνουμε σε επαφή

Code Labs Academy © 2024 Όλα τα δικαιώματα διατηρούνται.