Thursday, November 15, 2007

Κακό στυλ. (code style)!

Λατρεύω τον απλό κώδικα - όσο περνάει ο καιρός θέλω ακόμα πιο απλό κώδικα! Ένα παράδειγμα κακού στυλ κατά την προσωπική μου άποψη είναι αυτό
public String myMethod(){
//code
return this.myOtherMethod();
}
Μην το κάνεις αυτό το πράγμα, βοήθησε τον συνάδελφο σου ο οποίος θα έρθει να συνεχίσει - να debug-αρει τον κώδικα σου να κάνει εύκολα την δουλειά του. Τεχνικά ναι δουλεύει - αλλά δεν σου στοιχίζει τίποτα να κάνεις assign ένα variable στο return. Θα μου πεις καλά πολύ μικρή λεπτομέρεια - ή μα καλά είναι απόλυτα σωστό. Ναι είπαμε τεχνικά παίζει - αλλά είναι κακό στυλ.

Όπως και το method chaining. Ναι το ξέρω ο Martin Fowler λέει ότι όλα τα void method πρέπει να επιστρέφουν this. (Βλέπε Smalltalk habits) όπου με αυτό το convention σου επιτρέπουν να γράφεις τον εξής κώδικα

this.doMyMethod().doAnotherThing().yetAnotherDoMethod()


Υπάρχουν μερικά API όπου το method chaining by design το επιτρέπουν παρόλα αυτά προσωπικά πιστεύω ότι πολλές φορές γίνεται misuse και καταλήγουμε πάλι σε δυσκολοδιάβαστο κώδικα.

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

return this.doMyThing().doMyOtherThing();

Τελος, comments - javadoc. Όσο πιο πολύπλοκο είναι το business logic τοσο πιο αφράτο θα είναι το comment σου! Είμαι εντελώς αντίθετος με τους σκληρό πυρηνικούς που υποστηρίζουν ότι ο καλός κώδικας είναι self explainatory. Μαλακίες! Ίσως σε συγκεκριμένα πράγματα τα οποία αποτελούν μοντελοποίηση λογικής την οποία ξέρουμε όλοι ή την θεωρούμε δεδομένη , να το δεχτώ σε ένα ποσοστό. Όταν όμως γράφεις κώδικα για να περιγράψει μια business διαδικασία με 100 extention λογικής - τότε αποτύπωσε την σκέψη σου - είναι το χρέος που έχεις απένατι στον επόμενο που θα του ζητηθεί να κάνει αλλαγές!

Ακούω απόψεις!

9 comments:

  1. return ((this->elementalProperty(&clause)==PROPERTY_VALID)?(this->getNotifier)->demystifyFunction(arg1,&arg2):RESULT_UNSPECIFIED_ERROR);

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

    Ας είναι καλά η μαλακία των άλλων που έκαναν τα ίδια (και πρόσφατα η ObjC) που με έβαλαν στο σωστό το δρόμο:)

    Για σχολίασε τον κώδικα σε παρακαλώ!:D

    ReplyDelete
  2. Τι; Self-explanatory code; Δεν υπάρχει, είναι ψέμα, όπως ο Αγιος Βασίλης! :)

    Τα σχόλια πρέπει να αποτελούν το 50% του κώδικα, και λίγα λέω. Οχι σχόλια του στυλ "here we declare a string" αλλα σχόλια που εξηγούν το business logic. Σε συνδυασμό ίσως με κάποιο issue tracking software που ενσωματώνεται στο source control σας (είπε ο φιλόσοφος και μετά πήγε πίσω στην τρύπα του).

    Gemini (για παράδειγμα). Και αναφορά του issue number στα comments. Τουλάχιστον. Θέλει και να ΞΕΡΕΙ κανεις πως να περνάει σωστά issues.

    (Ψιτ, είμαι .NET developer, οι βασικές αρχές όμως είναι οι ίδιες).

    ReplyDelete
  3. Δεν κατάλαβα για πιο λόγο πρέπει κάνουμε assignment για ένα τόσο μικρό scope.

    Προσωπικά τον ακόλουθο κώδικα:

    public String foo() {
      String bar = bar();
      return bar;
    }

    τον αλλάζω σε:

    public String foo() {
      return bar();
    }

    ReplyDelete
  4. Είμαι της άποψης πως όντως ο καλός κώδικάς είναι self-explanatory. Με τη σοφή επιλογή ονομάτων στα variables και methods, χρήση generics και enhanced for-each loop (αντί του παλιού for) κτλ. Επίσης χρησιμοποιώ όσο το δυνατόν τις μεθόδους που μου δίνουν τα jars των Apache Commons (Collections, Lang, Math).

    Ακολουθώ σίγουρα το στυλ του Cherouvim στο κώδικα. Κάνω local variables μόνο όταν θα τα χρησιμοποιήσω παραπάνω από μια φορά. Δεν βρίσκω λόγο να έχω μια παραπάνω γραμμή και να έχω να σκεφτώ για το όνομα ενός παραπάνω variable

    Διαφωνώ με το γυρομυριστή (50% σχόλια;). Θα πρέπει μετά να κάνεις maintain και τα σχόλια...

    ReplyDelete
  5. πάντα επιστρέφω ένα variable και δεν κάνω call μέσα στο Return - συνεχίζω να το θεωρώ κακό - μήπως θέλεις να αναφέρω πως κάνεις σωστό exception handling πάνω στο return...ΔΕΝ ΜΠΟΡΕΙΣ!

    Οσο πιο πολλα σχολια τόσο καλύτερο, το να κάνεις maintain κώδικα και σχόλια είναι part of the job. Είναι επαγγελματικό χρέος να βοηθήσεις τους συνάδελφους και να του σώσεις 10 λεπτά μετά από 1 χρόνο που δεν θα καταλαβαίνει τι γίνεται μέσα στον self (και καλά) explaιnatory code. Για μένα είναι θέμα επαγγελματισμού!

    ReplyDelete
  6. Είμαι φοιτητής ακόμα κι ελάχιστα μπορώ να έχω γνώμη γι' αυτά που λέτε περί Java2, όμως συμφωνώ με αρκετά που ειπώθηκαν.

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

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

    ReplyDelete
  7. My 2c...

    return: Κατ' αρχάς το "return bla();" δεν έχει πρόβλημα. Αν θες να τσεκάρεις για exception, απλώς δεν το γράφεις έτσι.

    this: Τι νόημα έχει το this; Δεν έχω δει δείγματα "σωστού" κώδικα να λένε this για να καλέσουν μια μέθοδο. Υπάρχει κάποιος λόγος που δεν ξέρω;

    Method chaining: Συνήθως χρησιμοποιείται πάνω σε mutable objects (that.doX().doY()) ή σε immutable όταν θες μόνο το τελικό object (οπότε δεν έχεις ), αλλά δεν έχω δει ποτέ στο this.

    Commenting: Ααα ναι... το αιώνιο "documentation conundrum"... Θες όσο περισσότερο documentation αντέxεις να γράφεις (μόνο που πάντα χρειάζεσαι λίγο παραπάνω), σε όσο λιγότερα σημεία γίνεται (για να μην κάνεις αλλαγές σε 10 μεριές) αλλά και χωρισμένο ανάλογα με το σκοπό που εξυπηρετεί. Βάλε λοιπόν σχόλια μέσα στον κώδικα για να βγάλεις άκρη όταν θες να το συντηρήσεις, στο javadoc για να βγάλεις άκρη όταν το χρησιμοποιείς, σε wiki για να είναι πιο φιλικό και προσβάσιμο σε όλο το team, κράτα και κάποιο πιο formal documentation που έχει προκύψει από την ανάλυση μαζί με διαγράμματα...
    Για να μη κάνω τον έξυπνο, ούτε εγώ έχω βρει κάποια χρυσή τομή.

    Self-explanatory code: Ναι, μπορεί σε αρκετά καλό βαθμό να γίνει. Με ονομασίες παρμένες από τη business logic ορολογία, μπορείς να κάνεις αρκετά. Αρκεί να μη φοβάσαι τις λίγες παραπάνω γραμμές κώδικα. Και αν χρησιμοποιείς μεταβλητές με αυτό το σκεπτικό μπορεί να δίνεις καλύτερα "hints" τι στο καλό είναι όλα αυτά τα νούμερα που παίζεις σαν ζογκλέρ (μια περίπτωση που έχω προσωπικά συναντήσει). Αρκετές φορές είναι καλύτερα να είσαι πιο περιγραφικός ("verbose" in the vernacular) για λόγους συντηρησιμότητας.

    ReplyDelete
  8. @Doc
    1.έγραψα τεχνικά σωστό - ΩΣ συνήθειο είναι λάθος -γιατί να σου μείνει τότε και σε περιπτώσεις που θες να κάνεις Exception handling (πχ εχεις ξεχασει κάποιο Runtim- θα πας να την γράψεις την μαλακια στο return - και θα στείλεις τον άλλο για χόρτα. Το στυλ πολλές φορές ειναι καλό και κακό συνήθειο!

    2.το this είναι μια καθαρά προσωπική μου επιλογή για να κάνω reference στο current instance, και τις μεθοδους τους - ειναι ιδιαίτερα ωραίο μαζί με την χρήση του super σε περιπτώσεις που εχεις πολλά layer κληρονομικότητας!

    3. δεν βρίσκω κάτι παράξενο
    this.doX.doY όλα επιστρέφουν this.

    4. Commenting - οσο πιο πολυ τόσο καλύτερο - δεν με πειράζει - μετά απο διαφορετικα project προτιμώ να έχω αρκετά comments που θα με βοηθήσουν να καταλάβω τι κάνω - παρά να είμαι στο έλεος του συναδέλφου που ΜΟΛΙΣ εφυγε απο την εταιρία!

    5.Self-explanatory code = δεν υπάρχει τέτοιο πράγμα..ειναι σαν τον Αι Βασίλη, ψεμα - προσωπική άποψη! Δεν έχω συναντήσει ακόμα τέτοιο κώδικα σε real project

    Μετά απο 2 εβδομάδες με τον ρυθμό δουλειάς ξεχνάς ποιο ηταν το προηγούμενο σου project

    ReplyDelete
  9. Αντίλογος 4 papo:

    1. Ακόμα δεν καταλαβαίνω τι θες να πεις. Έχεις κανένα παράδειγμα;

    2. Δηλαδή πάμε να επαναφέρουμε ένα από τα στοιχειώδη πράγματα που θελήσαμε να αφαιρέσουμε με τον OO προγραμματισμό; Το current instance είναι implicitly referenced (όλες οι μέθοδοι που είναι χωρίς object αναφέρονται στο this). Το κόλπο με το super που λες, ποιό είναι;

    3. Ομολογουμένως το βασικό μου πρόβλημα ήταν πάλι το this.

    4. Σύμφωνοι... αλλά... how much is too much? Εκεί είναι το κόλλημα καμμιά φορά.

    5. Ε... υπάρχει και το

    if (notvalid()) reportFailure();
    else reportSuccess();

    τελοσπάντων δεν βάζεις σχόλια και σε αυτό, έτσι;
    Τώρα, όσο αυξάνεται κάπου η πολυπλοκότητα και μειώνεται η δυνατότητα για "hints", φυσικά και αρχίζεις τη "διάνθηση" με σχόλια... κάργα! :)

    ReplyDelete