Testowanie i Jakość Oprogramowania
Laboratorium 6: Code Smells.
Code Smell
Code Smell to termin używany w programowaniu do
opisywania pewnych cech kodu źródłowego, które wskazują na potencjalne
problemy z jego jakością. Niekoniecznie oznaczają one błędy, ale
często prowadzą do trudniejszego utrzymania, rozszerzania i testowania kodu.
Code Smells wewnątrz klasy
- Komentarze (Comments) – Czy komentarze są rzeczywiście potrzebne? Powinny wyjaśniać "dlaczego", a nie "co". Jeśli możesz, przekształć kod tak, aby komentarze nie były konieczne.
- Długa metoda (Long Method) – Krótsze metody są łatwiejsze do czytania, zrozumienia i debugowania. Jeśli możesz, podziel długą metodę na mniejsze.
- Długa lista parametrów (Long Parameter List) – Im więcej parametrów ma metoda, tym bardziej jest skomplikowana. Staraj się ograniczać ich liczbę lub grupować je w obiekty.
- Duplikacja kodu (Duplicated Code) – Powtarzający się kod to problem, który należy eliminować. Zasada DRY (Don't Repeat Yourself).
- Złożoność warunków (Conditional Complexity) – Unikaj rozbudowanych bloków warunkowych. Możesz rozważyć wzorce projektowe, takie jak dekorator, strategia czy stan.
- Eksplozja kombinatoryczna (Combinatorial Explosion) – Jeśli masz wiele podobnych fragmentów kodu, rozważ użycie generyków lub wzorca interpreter.
- Zbyt duża klasa (Large Class) – Duże klasy są trudne do czytania i zrozumienia. Sprawdź, czy klasa nie ma zbyt wielu odpowiedzialności.
- Typ w nazwie (Type Embedded in Name) – Unikaj umieszczania typów w nazwach metod.
- Nieczytelna nazwa (Uncommunicative Name) – Czy nazwa metody jasno mówi, co ona robi? Jeśli nie, zmień ją na bardziej czytelną.
- Niespójne nazwy (Inconsistent Names) – Stosuj jednolitą terminologię w całym kodzie.
- Martwy kod (Dead Code) – Usuwaj nieużywany kod. Od tego są systemy kontroli wersji.
- Spekulatywna ogólność (Speculative Generality) – Pisz kod rozwiązujący obecne problemy, a nie potencjalne przyszłe scenariusze (YAGNI - You Ain’t Gonna Need It).
- Nietypowe rozwiązanie (Oddball Solution) – Dla tego samego problemu powinna istnieć jedna metoda rozwiązania.
- Tymczasowe pola (Temporary Field) – Jeśli obiekt zawiera wiele opcjonalnych pól, sprawdź, czy rzeczywiście są potrzebne.
Code Smells pomiędzy klasami
- Alternatywne klasy z różnymi interfejsami (Alternative Classes with Different Interfaces) – Jeśli dwie klasy są wewnętrznie podobne, ale mają różne interfejsy, rozważ wprowadzenie wspólnego interfejsu.
- Obsesja na punkcie prymitywów (Primitive Obsession) – Nie używaj wielu zmiennych typu podstawowego zamiast dedykowanej klasy.
- Klasa przechowująca tylko dane (Data Class) – Unikaj klas, które jedynie przechowują dane, bez metod operujących na nich.
- Nagromadzenie danych (Data Clumps) – Jeśli pewne dane zawsze pojawiają się razem, rozważ utworzenie klasy grupującej te dane.
- Odrzucone dziedziczenie (Refused Bequest) – Jeśli klasa dziedziczy po innej, ale nie używa jej funkcjonalności, być może nie powinna korzystać z dziedziczenia.
- Nadmierna intymność (Inappropriate Intimacy) – Klasy nie powinny znać swoich wewnętrznych szczegółów nawzajem.
- Nieodpowiednia ekspozycja (Indecent Exposure) – Unikaj niepotrzebnego udostępniania elementów klasy na zewnątrz.
- Zazdrość o funkcje (Feature Envy) – Jeśli metoda nadmiernie korzysta z innej klasy, powinna się w niej znajdować.
- Bezużyteczna klasa (Lazy Class) – Każda klasa powinna mieć istotną funkcję w projekcie.
- Łańcuchy wywołań (Message Chains) – Unikaj długich sekwencji wywołań metod.
- Zbędny pośrednik (Middle Man) – Jeśli klasa jedynie deleguje pracę innym, może być zbędna.
- Rozbieżna zmiana (Divergent Change) – Jeśli jedna klasa wymaga częstych zmian w różnych, niezwiązanych częściach, może mieć zbyt wiele odpowiedzialności.
- Rozproszona modyfikacja (Shotgun Surgery) – Jeśli zmiana w jednej klasie wymusza zmiany w wielu innych, spróbuj ograniczyć wpływ zmian do jednej klasy.
- Równoległe hierarchie dziedziczenia (Parallel Inheritance Hierarchies) – Jeśli każda nowa klasa wymaga utworzenia innej klasy w innym hierarchicznym drzewie, być może warto uprościć strukturę.
- Niekompletna klasa biblioteczna (Incomplete Library Class) – Jeśli biblioteka nie oferuje potrzebnej metody i nie możesz jej zmodyfikować, spróbuj ją wydzielić osobno.
- Rozrastające się rozwiązanie (Solution Sprawl) – Jeśli do wykonania jednej rzeczy potrzebujesz pięciu klas, być może projekt jest zbyt skomplikowany.
Uniknij Code Smells i rozwiąż zadanie rekrutacyjne
Wykorzystaj dotychczas zdobytą wiedzę i postaraj się rozwiązać problem. Napisz testy
oraz zaimplementuj rozwiązanie.
Proszę zaimplementować program, który będzie odpowiedzialny za wyszukiwanie zbiorów
liczb powtarzających się elementów o ściśle określonym rozmiarze. Dla podanego
zbioru liczb (lista elementów o dowolnej długości) użytkownik powinien przekazać
również rozmiar wyszukiwanych zbiorów. Funkcja powinna zwracać listę składającą
się z pojedynczych elementów reprezentujących wyszukiwane zbiory.
Realne zadanie rekrutacyjne do firmy schibsted.
Uniknij Code Smells i zaprojektuj interfejs dla pojazdu księżycowego
Jako inżynier firmy NASA zostałeś poproszony o
zaprojektowanie, przetestowanie oraz implementację ruchu pojazdu księżycowego.
Musisz być świadomy ograniczeń, które zostały uwzględnione w specyfikacji technicznej.
Specyfikacja techniczna pojazdu księżycowego:
Bardzo proszę zaproponować interfejs pojazdu księżycowego dostosowany do specyfikacji
technicznej. Proszę zaimplementować mechanizm poruszania się pojazdu księżycowego.
Zachowanie pojazdu powinno być dobrze przetestowane przy pomocy modułu
unittest.
Wiem, że nic nie wiem
~Sokrates