Joel on Software

Joel on Software   Ο Ιωήλ περί Λογισμικού

 

Άλλα "Joel on Software" άρθρα στα Ελληνικά

Άλλα "Joel on Software" άρθρα στα Αγγλικά

Στείλτε μήνυμα ηλεκτρονικού ταχυδρομείου στο συγγραφέα (μόνο στα Αγγλικά)

 

Ο Νόμος των Διαρροών στις Αφαιρέσεις


από τον Ιωήλ Σπολσκι
Μεταφραστής ο Δημήτρης Στάικος
Δευτέρα 11 Νοεμβρίου 2002

Η σχεδίαση του Ίντερνετ περιέχει ένα μαγικό σχεδιαστικό στοιχείο στο οποίο βασιζόμαστε κάθε μέρα. Αυτό κρύβεται μέσα στο πρωτόκολλο TCP, ένα από τα θεμελιώδη δομικά στοιχεία του Ίντερνετ.

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

Χρησιμοποιούμε το TCP για πάρα πολλά πράγματα, όπως η μεταφορά ιστοσελίδων και η αποστολή ηλεκτρονικού ταχυδρομείου. Η αξιοπιστία του TCP είναι ο λόγος που κάθε ενδιαφέρον email από την Ανατολική Αφρική μας παραδίδεται σε άψογη κατάσταση. Τι χαρά.

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

Και εδώ βρίσκεται η μαγεία: το TCP είναι χτισμένο πάνω στο IP. Με άλλα λόγια, το TCP είναι υποχρεωμένο να μεταδίδει δεδομένα αξιόπιστα χρησιμοποιώντας μόνο ένα αναξιόπιστο μέσο.

Για να καταλάβετε γιατί αυτό αποτελεί μαγεία, αναλογιστείτε το παρακάτω ισοδύναμο, αν και λίγο κωμικό, σενάριο από τον πραγματικό κόσμο.

Φανταστείτε ότι διαθέτουμε έναν τρόπο να στέλνουμε ηθοποιούς από το Broadway στο Hollywood, βάζοντάς τους σε αυτοκίνητα και κάνοντας την διαδρομή οδηγώντας. Μερικά από τα αυτοκίνητα θα τρακάρουν, και οι αθώοι επιβάτες τους θα σκοτωθούν. Μερικές φορές οι ηθοποιοί θα τα πιουν και όντας μεθυσμένοι θα ξυρίσουν το κεφάλι τους ή θα κάνουν τατουάζ στη μύτη τους, και κατά συνέπεια θα είναι πλέον πολύ άσχημοι για να εργαστούν στο Hollywood. Συχνά οι ηθοποιοί θα φτάσουν με διαφορετική σειρά από αυτή με την οποία ξεκίνησαν, επειδή ακολούθησαν διαφορετικές διαδρομές. Τώρα φανταστείτε μια νέα υπηρεσία η οποία ονομάζεται Hollywood Express, η οποία εγγυάται ότι οι ηθοποιοί (α) θα αφιχθούν (β) με τη σωστή σειρά (γ) σε άψογη κατάσταση. Η μαγεία είναι ότι το Hollywood Express δεν διαθέτει κάποιον άλλο τρόπο για τη μεταφορά των ηθοποιών πέρα από την οδική μεταφορά. Το Hollywood Express λειτουργεί ελέγχοντας αν κάθε ηθοποιός φτάνει σε άψογη κατάσταση, και αν όχι, τότε τηλεφωνεί στα κεντρικά και ζητά να σταλεί ο δίδυμος αδερφός του ηθοποιού. Αν οι ηθοποιοί φτάσουν με λάθος σειρά, το Hollywood Express τους αναδιατάσσει. Αν ένα μεγάλο ΑΤΙΑ συντριβεί στην υπερλεωφόρο στη Νεβάδα και την κλείσει, όλοι οι ηθοποιοί που πήγαιναν από εκείνο το δρόμο επαναδρομολογούνται μέσω Αριζόνα και το Hollywood Express δεν αναφέρει το παραμικρό στους σκηνοθέτες που περιμένουν στην Καλιφόρνια. Αυτοί απλά θα νομίζουν ότι οι ηθοποιοί καταφθάνουν λίγο πιο αργά απ΄ότι συνήθως, και φυσικά δεν έχουν ιδέα για τη συντριβή του ΑΤΙΑ.

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

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

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

Όλες οι μη στοιχειώδεις αφαιρέσεις, μέχρι ενός βαθμού, παρουσιάζουν διαρροές.

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

  • Μερικές φορές κάτι τόσο απλό όσο η διάσχιση των στοιχείων ενός δισδιάστατου πίνακα μπορεί να έχει δραματικά διαφορετική επίδοση αν γίνει οριζόντια αντί για κάθετα, ανάλογα με το μέγεθος κάθε γραμμής -- η μία κατεύθυνση μπορεί να προκαλέσει σημαντικά περισσότερα page faults, και αυτά είναι πολύ αργά. Ακόμα και στους προγραμματιστές assembly υποτίθεται ότι επιτρέπεται να θεωρούν ότι διαθέτουν ένα μεγάλο επίπεδο χώρο διευθυνσιοδότησης (flat address space), αλλά η εικονική μνήμη είναι απλά μία αφαίρεση, η οποία έχει διαρροές όταν συμβαίνει ένα page fault και ορισμένες προσβάσεις στη μνήμη διαρκούν πολύ περισσότερα νανοδευτερόλεπτα από άλλες.
  • Η γλώσσα SQL έχει σαν σκοπό να απομονώσει τα διαδικαστικά βήματα που είναι απαραίτητα για να εκτελεστεί ένα ερώτημα στη βάση δεδομένων, επιτρέποντάς μας απλά να ορίσουμε τι θέλουμε και να αφήσουμε τη βάση δεδομένων να αποφασίσει για τα βήματα εκτέλεσης του ερωτήματος. Αλλά σε κάποιες περιπτώσεις, ορισμένα ερωτήματα SQL είναι χιλιάδες φορές πιο αργά σε σχέση με άλλα λογικά ισοδύναμα ερωτήματα. Ένα διάσημο παράδειγμα είναι το ότι ορισμένες βάσεις δεδομένων SQL είναι δραματικά πιο αποδοτικές αν στη συνθήκη προσδιορίσουμε "where a=b and b=c and a=c" αντί μόνο για το "where a=b and b=c", παρά το ότι το αποτέλεσμα είναι το ίδιο. Υποτίθεται ότι δεν θα έπρεπε να νοιαζόμαστε για τη διαδικασία εκτέλεσης, αλλά μόνο για τον ορισμό του ερωτήματος. Αλλά μερικές φορές η αφαίρεση έχει διαρροές που προκαλούν φριχτή πτώση στην απόδοση, και τότε χρειάζεται να καταφύγουμε στον αναλυτή σχεδίων εκτέλεσης ερωτημάτων, να μελετήσουμε τι δεν πήγε καλά, και να βρούμε έναν τρόπο να κάνουμε το ερώτημα να εκτελείται πιο γρήγορα.
  • Παρά το γεγονός ότι δικτυακές βιβλιοθήκες όπως το NFS και το SMB μας επιτρέπουν να χειριζόμαστε αρχεία σε απομακρυσμένους υπολογιστές "σαν" να ήταν τοπικά, μερικές φορές η σύνδεση γίνεται πολύ αργή ή χάνεται εντελώς, και τότε το αρχείο παύει να συμπεριφέρεται σαν τοπικό. Εμείς σαν προγραμματιστές πρέπει να γράψουμε κώδικα για να το αντιμετωπίσουμε αυτό. Η αφαίρεση "ένα απομακρυσμένο αρχείο είναι το ίδιο με ένα τοπικό" έχει διαρροές. Ένα άλλο απτό παράδειγμα για τους διαχειριστές συστημάτων Unix: Αν τοποθετήσετε το βασικό κατάλογο χρηστών σε δίσκους που γίνονται mount μέσω NFS, οι χρήστες σας φτιάξουν αρχεία .forward για να προωθήσουν τα μηνύματά τους σε άλλη διεύθυνση (άλλη μια αφαίρεση), και ο εξυπηρετητής NFS πέσει την ώρα που λαμβάνονται νέα μηνύματα ηλεκτρονικού ταχυδρομείου, τα μηνύματα δεν θα προωθηθούν καθώς το αρχείο .forward δεν θα βρεθεί. Η διαρροή της αφαίρεσης προκάλεσε την απώλεια μερικών μηνυμάτων.
  • Οι κλάσεις συμβολοσειρών της C++ υποτίθεται ότι μας επιτρέπουν να προσποιούμαστε ότι οι συμβολοσειρές αποτελούν δεδομένα πρώτης τάξεως. Προσπαθούν να αποκρύψουν το γεγονός ότι ο χειρισμός συμβολοσειρών είναι δύσκολος και μας επιτρέπουν να τις χρησιμοποιούμε σαν να ήταν ακέραιοι. Πρακτικά όλες οι υλοποιήσεις κλάσεων συμβολοσειρών στη C++ υπερφορτώνουν τον τελεστή + ώστε να μπορούμε να γράφουμε s + "bar" για να συνενώσουμε δύο συμβολοσειρές. Άλλα ξέρετε κάτι; Όσο σκληρά και να προσπαθούν, δεν υπάρχει στον πλανήτη κλάση συμβολοσειράς C++ η οποία να μας επιτρέπει να γράψουμε "foo" + "bar", διότι οι σταθερές συμβολοσειρές στη C++ είναι πάντα τύπου char* και ποτέ τύπου string. Η αφαίρεση γέννησε μία διαρροή που η γλώσσα δεν μας επιτρέπει να κλείσουμε. (Αυτό που είναι χαριτωμένο στην όλη υπόθεση είναι το ότι η ιστορία της εξέλιξης της C++ στο πέρασμα των χρόνων, μπορεί να περιγραφεί σαν μια προσπάθεια να διορθωθούν οι διαρροές της αφαίρεσης των συμβολοσειρών. Μου διαφεύγει γιατί δεν μπορούσαν απλά να προσθέσουν μια ενδογενή κλάση συμβολοσειρών στην ίδια τη γλώσσα).
  • Δεν μπορούμε να οδηγήσουμε πολύ γρήγορα όταν βρέχει, παρά το γεγονός ότι το αυτοκίνητό μας διαθέτει υαλοκαθαριστήρες, προβολείς, οροφή και θέρμανση, ανέσεις που μας επιτρέπουνε να μη νοιαζόμαστε και πολύ για το γεγονός ότι βρέχει (μας απομονώνουν από τις καιρικές συνθήκες). Όμως θα πρέπει να ανησυχούμε για τα νερά στο δρόμο, και μερικές φορές η βροχή είναι τόσο δυνατή που δεν μπορούμε να δούμε και πολύ μακριά ώστε αναγκαζόμαστε να οδηγούμε πιο σιγά. Δεν είναι δυνατόν να απομονωθούμε εντελώς από τις καιρικές συνθήκες, και αυτό εξαιτίας του νόμου των διαρροών στις αφαιρέσεις.

Ένας λόγος που οι διαρροές των αφαιρέσεων είναι προβληματικές είναι το γεγονός ότι αποδεικνύουν ότι οι αφαιρέσεις δεν απλοποιούν τη ζωή μας τόσο όσο θα θέλαμε. Όταν εκπαιδεύω κάποιον για να γίνει προγραμματιστής C++, θα ήταν ωραίο αν δεν χρειαζόταν να τους διδάξω για το char* και αριθμητική δεικτών (pointer arithmetic). Θα ήταν όμορφο αν μπορούσα να πάω απευθείας στις συμβολοσειρές της STL. Αλλά μια μέρα θα γράψουν τον κώδικα "foo" + "bar", θα συμβούν πραγματικά περίεργα πράγματα, και τότε θα αναγκαστώ ούτως ή άλλως να τους διδάξω τα πάντα σχετικά με το char*. Ή μια μέρα θα προσπαθήσουν να καλέσουν κάποια ρουτίνα του Windows API η οποία έχει μία παράμετρο OUT LPTSTR και δεν θα μπορούν να καταλάβουν πώς να την καλέσουν μέχρι να μάθουν για το char*, τους δείκτες (pointers), το Unicode, τα wchar_t, τα αρχεία επικεφαλίδων TCHAR, και όλα αυτά τα πράγματα που διαρρέουν.

Όταν διδάσκω κάποιον σχετικά με προγραμματισμό COM, θα ήταν ωραίο αν απλά μπορούσα να τους διδάξω πώς να χρησιμοποιούνε τους οδηγούς (wizards) του Visual Studio και όλες τις δυνατότητες σχετικά με αυτόματη παραγωγή κώδικα, αλλά όταν στραβώσει το οτιδήποτε δεν θα έχουν την παραμικρή ιδέα τι συνέβη, που και πώς να ψάξουν και να διορθώσουν το σφάλμα. Θα χρειαστεί λοιπόν να τους διδάξω τα πάντα σχετικά με το IUknown, τα CLSID, τα ProgID, τα ..., ωχ τον κόσμο όλο!

Όταν διδάσκω κάποιον σχετικά με προγραμματισμό ASP.NET, θα ήταν όμορφο αν μπορούσα να του μάθω ότι μπορούν να κάνουν διπλό κλικ σε διάφορα πράγματα και μετά να γράφουν κώδικα ο οποίος εκτελείται στον εξυπηρετητή όταν ο χρήστης κάνει κλικ πάνω σε αυτά τα πράγματα. Πραγματικά το ASP.NET δημιουργεί μια αφαίρεση που κρύβει τη διαφορά ανάμεσα στο γράψιμο του κώδικα HTML που χειρίζεται το click σε ένα υπερσύνδεσμο (hyperlink <a>) και τον κώδικα που χειρίζεται το κλικ πάνω σε ένα κουμπί. Το πρόβλημα: οι σχεδιαστές του ASP.NET έπρεπε να κρύψουν το γεγονός ότι στην HTML μια φόρμα δεν μπορεί να υποβληθεί (submit) με κλικ πάνω σε ένα υπερσύνδεσμο. Αυτό το κάνουν δημιουργώντας μερικές γραμμές κώδικα Javascript και συνδέοντας αυτόν τον κώδικα στον χειριστή του γεγονότος onclick του υπερσύνδεσμου. Φυσικά η αφαίρεση έχει διαρροές. Αν ο τελικός χρήστης δεν έχει ενεργοποιημένη την Javascript, τότε η εφαρμογή ASP.NET δεν θα λειτουργεί σωστά, και αν ο προγραμματιστής δεν κατανοεί το αφηρημένο μοντέλο του ASP.NET τότε δεν θα έχει ιδέα για το τι συμβαίνει.

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

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

Κατά τη διάρκεια της πρώτης περιόδου που εργάστηκα στη Microsoft σαν μαθητευόμενος, έγραψα μερικές βιβλιοθήκες για συμβολοσειρές οι οποίες να τρέχουν στον Macintosh. Μια τυπική απαίτηση: γράψε μια έκδοση της strcat η οποία να επιστρέψει ένα δείκτη στο τέλος της νέας συμβολοσειράς. Λίγες γραμμές κώδικα C. Οτιδήποτε έκανα προερχόταν απευθείας από το K&R -- ένα μικρό βιβλίο σχετικά με τη γλώσσα προγραμματισμού C.

Σήμερα για να εργαστώ στο CityDesk, πρέπει να γνωρίζω Visual Basic, COM, ATL, C++, InnoSetup, τα εσώτερα του Internet Explorer, κανονικές εκφράσεις, DOM, HTML, CSS, και XML. Όλα είναι εργαλεία πολύ υψηλού επιπέδου σε σχέση με το K&R, αλλά βέβαια πρέπει να γνωρίζω και το K&R αλλιώς την έχω άσχημα.

Πριν από δέκα χρόνια θα φανταζόμασταν ότι σήμερα τα νέα προγραμματιστικά παραδείγματα θα είχαν απλοποιήσει σημαντικά τη διαδικασία του προγραμματισμού. Πράγματι οι αφαιρέσεις που έχουμε δημιουργήσει όλα αυτά τα χρόνια μας επιτρέπουν να αντιμετωπίσουμε τάξεις μεγαλύτερη πολυπλοκότητα στην ανάπτυξη λογισμικού, την οποία δεν είχαμε να αντιμετωπίσουμε πριν από δέκα ή δεκαπέντε χρόνια, όπως ο δικτυακός προγραμματισμός και τα GUI. Και παρόλο που αυτά τα φοβερά εργαλεία, όπως οι μοντέρνες αντικειμενοστραφείς forms-based γλώσσες, μας επιτρέπουν να κάνουν πολύ δουλειά απίστευτα γρήγορα, ξαφνικά μια μέρα έχουμε να αναλύσουμε ένα πρόβλημα εκεί που η αφαίρεση έχει διαρροή, και μας παίρνει δύο εβδομάδες. Και όταν χρειάζεσαι έναν προγραμματιστή ο οποίος θα κάνει κυρίως προγραμματισμό VB, δεν είναι αρκετό να προσλάβεις έναν προγραμματιστή VB, γιατί αυτός θα βρίσκεται σε πλήρες αδιέξοδο κάθε φορά που η αφαίρεση της VB παρουσιάζει διαρροές.

Ο νόμος των Διαρροών στις Αφαιρέσεις μας παρασύρει στον γκρεμό.



Το άρθρο αυτό πρώτο-εμφανίστηκε στα Αγγλικά με το όνομα

The Law of Leaky Abstractions

 

Ο Ιωήλ Σπολσκι είναι ο ιδρυτής της Fog Creek Software, μιας μικρής εταιρείας λογισμικού στη Νέα Υόρκη. Αποφοίτησε από το Πανεπιστήμιο του Γεηλ και εργάστηκε ως προγραμματιστής και στέλεχος διοίκησης στις εταιρείες Microsoft, Viacom και Juno.


Τα περιεχόμενα αυτών των σελίδων αντιπροσωπεύουν τις γνώμες ενός ατόμου.
Όλα τα περιεχόμενα Copyright ©1999-2005  του Ιωήλ Σπολσκι (Joel Spolsky). All Rights Reserved.

FogBUGZ | CityDesk | Fog Creek Software | Joel Spolsky