Tuesday, November 24, 2009

Μοcking...και ο πόνος του broken test

Σήμερα σκεφτόμουν την απίστευτη παρουσίαση του Robert C Martin.Περί της ευθύνης του κάθε προγραμματιστή. Do no Harm έλεγε ο uncle bob, με τον κώδικα σου με το πως υλοποιείς με το να τεστάρεις. Μην λες αμέσως ναι σε κάθε request του management - σκέψου, ανέλυσε τα υπέρ και τα κατά, μερικές φορές πες όχι όταν κάτι ήταν παράλογο. Σήμερα ήταν μια τέτοια μέρα.

Μέσα σε έναν σχετικά πολύπλοκο κόσμο, τον κόσμο του συστήματος που αναπτύσσουμε μου ζητήθηκε να κάνω μια μικρή αλλαγή - η οποία καταστρατηγεί την λογική συγκεκριμένου module, σπάει την όποια ωραία υλοποίηση του αγαπητού συναδέλφου μου (ο οποίος με διαβάζει κιόλας χαχαη hello vlad!). 5 με 6 γραμμές κώδικα οι οποίες φυτρώνουν κάτι εκεί που δεν θα έπρεπε.

Πριν το κάνω, απο την προηγουμενη εβδομάδα είχα νιώσει το do no harm και είχα γράψει ένα email το οποίο εξηγούσε οτι η συγκεκριμένη αλλαγή αν γινόταν με τον γρήγορο και πρόχειρο τρόπο θα είχε α) μικρό κόστος υλοποίησης β) potentially μεγάλο κόστος regression testing γ) μεγάλο κόστος σε maintenability - δηλαδή αν το διαβάσει ένας άσχετος μετα απο μερικούς μήνες δεν θα το καταλάβει. Η άλλη αντιπρόταση ήταν να γίνει πιο σωστά - με μεγαλύτερες αλλαγές και χρόνο - αλλά θα ήταν ολοκάθαρη λύση.

Η απάντηση που έλαβα και μάλλον λαμβάνετε και εσείς αγαπητοί συνάδελφοι ήταν - do it γρήγορα. Do no harm λοιπόν και αφού είχα κάνει το χρέος μου σαν επαγγελματίας και είχα εξαντλήσει τα όρια της ευθύνης και δύναμης που έχω προχώρησα. Μισή ώρα δουλειά το hack - επίτηδες το πλασάρω πάντα έτσι για να μπορώ να τονίζω σε έναν non techie αναλυτή ότι αυτό δεν είναι σωστό.

6 γραμμές κώδικα σε ένα μεγάλο module που γενικά δεν το έχουν πειράξει αρκετοί  - φέρνει σπασμένα test-s τα οποία με αρκετό μεράκι ο αγαπητός συνάδελφος - έχτισε expectation με expectation. Οπαδός και χρήστης του JMock δεν ήμουν ποτέ - το ομολογώ, βρίσκω το Mockito αρκετά πιο όμορφο και απλό -αν και γενικότερα αρχίζω να πιστεύω μετά από λίγα χρόνια εμπειρία ότι το Mocking σαν τεχνική σε αρκετά πολύπλοκο κώδικα από ένα σημείο και μετά γίνεται εφιάλτης maintenance και χάνεις πολλές ώρες.

Ξεκινάω να διαβάζω και κάπου έχασα την μπάλα - expectation εδώ και εκεί - μία γραμμή μία κλήση σε κώδικα που γίνεται expected να αλλάξεις και τα γ@μησες όλα - απλά η σειρά σε 2 statement και τέλος. Μετά από βοήθεια αρχίζω να φυτρώνω και εγώ τα extra expectations μου, αφού προσπάθησα να βρώ τον κατάλληλο τρόπο έτσι ώστε όταν τα διαβάσει κάποιος άλλος να καταλάβει. Συνέχισα μέχρι που έπεσα σε σενάρια οπου μερικά chain invocation στον κανονικό κώδικα που έμπλεκα Mocked και non  mocked objects δεν μπορούσαν να σπάσου σε απλά  expectations (κλήσεις μεθόδων δηλαδή).

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

Εκει θυμήθηκα τον κακόμοιρο στο συνέδριο που τόλμησε να πει στον uncle bob ότι ειναι πόνος να κάνεις maintain tests και να προσθέσω..ιδιαίτερα όταν δεν τα έχεις γράψει εσύ και έφαγε την κατσάδα του αιώνα.

Απο την μικρή μου εμπειρία στην Ελλάδα σχεδόν πάντα με πάντα θα σου πουν do it the quick and dirty way -(ίσως και παντού τελικά)- που ακόμα και αν εχεις κάτσει και γράψει ένα καλό test πιο πριν θα πρέπει να το βιάζεις δεξιά και αριστερά για να το κάνεις να συμπεριφέρεται σωστά με την αλλαγμένη σου υλοποίηση.

Ελπιζω να μην αργήσουν αρκετά τα πράγματα και με την έλευση του j2ee6 spec και του standalone container ..αρκετό mocking να πάρει πόδι. Ωραία τεχνική δεν λέω αλλά όταν το πράγμα μεγαλώνει - σου κοστίζει 3 φορές τον χρόνο να κάνεις αλλαγή στο test παρά στο σύστημα. Όλα είναι θέμα επιλογών υποθέτω. Απο την άλλη μάλλον ακόμα δεν έχουμε βρει και τους πιο ωραίους τρόπους να τεστάρουμε- έτσι ώστε να μην το θεωρούμε μαρτύριο αλλά αντίστοιχα enjoyable όπως ο κώδικας.

many many expectations ...allowing :P



6 comments:

  1. Ο Robert C. Martin είναι από τους αγαπημένους μου συγγραφείς τεχνικών βιβλίων. Σου προτείνω ανεπιφύλακτα να διαβάσεις τα Agile Software Development και Clean Code.

    Μία φράση του που μου έχει μείνει από το Clean Code είναι ότι οι προγραμματιστές κάθε φορά που σταματάνε να δουλεύουν σε ένα τμήμα του κώδικα έχουν χρέος να το αφήσουν σε καλύτερη κατάσταση από ότι το βρήκανε (σίγουρα easier said than done).

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

    Σπύρος Τζαβέλλας

    ReplyDelete
  2. Κάνοντας και λίγο το δικηγόρο του διαβόλου να πω ότι συχνά η χακιά είναι η σωστή λύση.

    Δεν υπάρχει πάντα ο χρόνος + το χρήμα να γίνει το "σωστό". Και τα περισσότερα project παραδίδονται και τελειώνουν - δεν έχουν δλδ μεγάλη διάρκεια ζωής.

    ReplyDelete
  3. Αν όλα έχουν πάει καλά tests και αλλαγές βγαίνουν νεράκι. Φυσικά δεν πάνε πάντα όλα καλά, οπότε στην περίπτωση του hack χρειάζεται οποσδήποτε inline documentation και παραπομπές στα ανάλογα issues.

    ReplyDelete
  4. Πάρι το jmock είναι λίγο παλούκι μέχρι να το συνηθήσεις, και συμφωνώ ότι στην αρχή για να αλλάξεις το test σου παίρνει περισσότερο χρόνο από το να αλλάξεις τον κώδικα. Αν καταλάβεις όμως πως δουλεύει το jmock τότε είναι piece of cake που λένε και οι Βρετανοί.

    ReplyDelete
  5. Πάντως η χρήση των mock objects για unit testing είναι γενικότερα ένα θέμα αρκετά διφορούμενο.

    Μια ενδιαφέρουσα άποψη που έχω διαβάσει πρόσφατα εδώ είναι ότι τα mock objects πρέπει να χρησιμοποιούνται κυρίως σε περιπτώσεις που ελέγχεται η αλλιλεπίδραση του συστήματος με δεδομένα από εξωτερικές πηγές (βάσεις δεδομένων, web services, κλπ.) και όχι τόσο για τον έλεγχο της εσωτερικής λογικής του συστήματος. Ο λόγος είναι ότι είναι πολύ πιθανό σε περίπτωση αλλαγής του κώδικα, η εφαρμογή στην πραγματικότητα να σπάει, ενώ το unit test που χρησιμοποιεί mock objects να συνεχίζει να περνάει.

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

    ReplyDelete
  6. Το jmock ειναι οντως λιγο παλουκι! Υπαρχουν όμως και εναλλακτικες οπως το easy mock: http://bit.ly/2bZZC5 το οποιο κατα τη γνωμη μου εχει πολυ πιο... ευαναγνωστο API.

    allowing αρρωστια!

    ReplyDelete