Οσμές στη Σχεδίαση του Λογισμικού (Code Smells) Πρόγραμμα Μεταπτυχιακών Σπουδών στην Εφαρμοσμένη Πληροφορική
Design Problems non-compliance with design principles excessive metric values violations of design heuristics lack of design patterns Fowler’s bad smells
Software Ageing well-designed code Design quality decays
Οσμές Οι ενδείξεις κακής σχεδίασης λογισμικού είναι γνωστές ως «οσμές» λογισμικού (code smells - Fowler) Τα code smells δεν προκαλούν προβλήματα στη λειτουργικότητα του συστήματος (για αυτό και συχνά συσσωρεύονται) Ωστόσο, η ύπαρξή τους ενδέχεται να δυσχεράνει τη μελλοντική συντήρηση του λογισμικού (προσθήκη λειτουργικότητας, διόρθωση σφαλμάτων, κατανόηση, επαναχρησιμοποίηση κλπ) Οι κακές οσμές ανιχνεύονται σχετικά εύκολα από τους έμπειρους σχεδιαστές και ο εντοπισμός μπορεί να υποβοηθάται από εργαλεία Οι οσμές μπορούν να εξαλειφθούν με την εφαρμογή κατάλληλη αναδόμησης
Long Method Pieces of code with large size, high complexity and low cohesion int i; int product = 1; for(i = 0; i < N; ++i) { product = product *i; } System.out.println(product); int i; int sum = 0; for(i = 0; i < N; ++i) { sum = sum + i; } System.out.println(sum); Ενδεδειγμένη Αναδόμηση: Εξαγωγή μεθόδου (Extract Method)
Feature Envy A method is “more interested in a class other than the one it actually is in” Target m1() m2() m3() Source m(Target t) { t.m1(); t.m2(); t.m3(); } m() { m1(); m2(); m3(); } Ενδεδειγμένη Αναδόμηση: Μετακίνηση μεθόδου (Move Method)
Large (& Complex) Class You have one class doing work that should be done by two Καθηγητής + υπολΦόρου(); + υπολΑπόδοσης(); - type : int ΑΦΜ Εφορία Εισόδημα Αξιολόγηση Βαθμολογία Σεμινάρια Καθηγητής + υπολΑπόδοσης(); - type : int Αξιολόγηση Βαθμολογία Σεμινάρια Υπάλληλος + υπολΦόρου(); - type : int ΑΦΜ Εφορία Εισόδημα Ενδεδειγμένη Αναδόμηση: Εξαγωγή Κλάσης (Extract Class)
Duplicated Code Ενδεδειγμένη Αναδόμηση: Pull Up Method Number one on the stink parade is duplicated code. If you see the same code structure in more than one place, you can be sure that your program will be better if you find a way to unify them Ενδεδειγμένη Αναδόμηση: Pull Up Method
State Checking State Checking manifests itself as conditional statements that select an execution path based on the state of an object Context + method() { type.method(); } - type : int - STATE_A : int = 1 - STATE_B : int = 2 Context + method() { } - type : int - STATE_A : int = 1 - STATE_B : int = 2 Type +method() type switch(type) { case STATE_A: break; case STATE_B: } doStateA(); StateA +method() { } StateB +method() { } doStateB(); Ενδεδειγμένη Αναδόμηση: Αντικατάσταση Συνθήκης με Πολυμορφισμός (Replace Conditional with Polymorphism)
And even more complex smells Refused Bequest
Context Mammal + breatheAir() + regulateBodyTemp() + giveBirthToLiveYoung() + produceMilkIfFemale() + swim() In the world of OO systems, inheritance is not a panacea + breatheAir() + regulateBodyTemp() + giveBirthToLiveYoung() + produceMilkIfFemale() + swim() + breatheAir() + regulateBodyTemp() + giveBirthToLiveYoung() + produceMilkIfFemale() + swim()
Problem Goal: Identification of Refused Bequest Code Smells “a subclass does not want to support the interface inherited from its parent class” [Fowler] non-trivial problem to resolve Appropriate Refactoring: Replace Inheritance with Delegation Famous quote: “Favor Composition over Inheritance” [GoF]