sobota, kwietnia 17, 2010

Eyjafjallajökull w kodowaniu, czyli rozplątujemy kilometry sznurka ;-)

Eyjafjallajökull, czyli nazwa najsłynniejszego i najbardziej kłopotliwego teraz wulkanu w Europie kojarzy mi się nieodparcie z kodowaniem i refactoringiem ;-)
Gdy dostajesz zamotany kod, w którym klasy mają po 3 albo i 5 tysięcy linii, a metody w nich rzadko schodzą poniżej 500 linii to zaczyna się szał refactoringu, który służy głównie zrozumieniu kodu.
Bądźmy szczerzy, nic tak nie pozwala zrozumieć kodu jak jego refactoring. Bo mało kto z nas jest w stanie zrozumieć metodę mającą te 300 linii przy jednym przebiegu, szczególnie gdy złośliwie jest w niej więcej niż 1 ścieżka wykonywania.... a zwykle jest ;-) bo jak chyba wszyscy wiedzą metody mające 300 linii powstają zwykle przez dopisywanie do nich kolejnych ścieżek wykonania.
Zaczynasz od ładnej i krótkiej metody, która ma obliczyć procent składany dla parametrów jakimi są kwota, oprocentowanie roczne, ilość lat. Później przychodzi konieczność uwzględnienia podatki Belki, następnie możliwość naliczania odsetek co miesiąc, co tydzień, co dzień. W końcu okazuje się, że liczyć też trzeba przypadki bez podatku Belki. Jeszcze później konieczność przeliczania między walutami w momencie naliczania odsetek i podatku.... i tak dalej, i nagle z prostej metody BigDecimal calculateGain4Year(BigDecimal cash, BigDecimal yearPercentage, int years), która liczyła powiedzmy 20 linii robi się kobyła mająca tych linii 500. Nazwa w ogóle nie pasuje bo teraz metoda ta wygląda tak:BigDecimal calculateGain4Year(BigDecimal cash, BigDecimal yearPercentage, TimeUnit timeUnit, boolean taxation, Currency cashCurrency, Currency transactionCurrency).
Teraz zaczyna się analiza i używanie Extract Method, po tym refactoringu mamy z jednej multum metod w stylu:
  • BigDecimal calculateGain4DayWithTaxation(BigDecimal cash, BigDecimal yearPercentage, Currency cashCurrency, Currency transactionCurrency),
  • BigDecimal calculateGain4DayWithoutTaxation(BigDecimal cash, BigDecimal yearPercentage, Currency cashCurrency, Currency transactionCurrency),
  • BigDecimal calculateGain4MonthWithTaxation(BigDecimal cash, BigDecimal yearPercentage, Currency cashCurrency, Currency transactionCurrency),
i tak dalej i tak dalej ;-)
Jeżeli jeszcze się okaże, że np. dla kwot w Euro podatek liczy się jeszcze inaczej to będziemy mieli np. metodę: BigDecimal calculateEuroGain4DayWithTaxation(BigDecimal cash, BigDecimal yearPercentage, Currency cashCurrency, Currency transactionCurrency), która będzie używała metody BigDecimal calculateGain4DayWithTaxation(BigDecimal cash, BigDecimal yearPercentage, Currency cashCurrency, Currency transactionCurrency, TaxationEngine engine).
Po tym refactoringu, czyli de facto analizie kodu, czyli po rozłożeniu go na czynniki pierwsze jesteśmy często właśnie na etapie Eyjafjallajökullu ;-) Kod jest bardziej czytalny [czytalny, nie czytelny, przyjmijmy, że ten neologizm oznacza tyle co możliwy do przeczytania], dzięki czemu można go zrozumieć.
Często na tym etapie kończymy.
Nasz zamotany kod/sznurek został rozwinięty, co prawda jest go nadal kilka kilometrów, ale leży na ziemi, widzimy początek i koniec i jest nadzieja, że ciągnąc za jeden koniec dojdziemy do dowolnego jego elementu [tu utrudnienie polegające na tym, że ponieważ to jest jednak kod, a nie sznurek to tak naprawdę ten sznurek ma na sobie pętle, kilka początków i kilka końców i jeszcze trochę dziwnych urozmaiceń ;-)]
Tu przychodzi czas na syntezę zdobytej wiedzy.
Nie zawsze to robimy, ale jak jest nam dane dotrwać do takiego etapu analizy, że zaczynamy rozumieć "co autor miał na myśli" należy jak najszybciej znajdować jakieś uogólnienia.
Tu chyba dobrze użyć tabelki:
w której widzimy wszystkie możliwe przypadki [nie wszystkie tak naprawdę, bo co do okresu naliczania odsetek mamy tylko dni i miesiące, a mogą być jeszcze np. lata czy tygodnie]. To pozwala zaś dostrzec pewne prawidłowości.
Np. to, że sposób naliczania podatku może zależeć od waluty, ale nie zależy np. od czasu tego co ile naliczamy odsetki.
Ba może się okazać, że istnieje kilka przypadków których w ogóle nie powinniśmy oprogramowywać bo są nieokreślone. Np. może się okazać, że dla przypadku z Euro jako walutą nie powinniśmy w ogóle liczyć podatku. Wtedy wiemy, że w takim przypadku powinniśmy np. wyrzucać wyjątek w stylu IllegalArgumentException.
Inna sprawa, że prawie nigdy nie robi się tego w taki sposób, tylko dokonuje się tej syntezy w głowie by po jakimś czasie wracając do kodu zastanawiać się co właściwie mieliśmy na myśli wyrzucając np. obliczanie podatku jako metodę utliową do waluty ;-)
A cały ten przydługi tekst ze względu na śliczną nazwę wulkanu - Eyjafjallajökull :-)


Podobne postybeta
Bonusy, koszty autorskie i limit 30 krotności...
Ile w tym i przyszłym miesiącu z odsetek za obligacje?
Jest coraz gorzej i będzie jeszcze gorzej  Wasza nadzieja - ona znikąd pochodzi 
Social media to nie jest świat dla introwertyków/ambiwertyków ;-)
Potok świadomości - Machine Learning może tagować posty ;-), iPhone ssie, fajne książki, spać.....

8 komentarzy:

  1. No i dzięki takim postom trzymam Twój blog ciągle w RSSach;)

    OdpowiedzUsuń
  2. Ja tam wolę takie sznurkowe nazwy. Lepsze to niż nazwy, które mówią nic, bo składają się ze spółgłosek jakiegoś słowa w języku portugalskim lub flamandzkim. Ponad to kod napisany sznurkowo pozwala na przełożenie realizacji dokumentacji na bliżej nieokreśloną przyszłość, co jak wiadomo spowoduje samoistne przekładanie się realizacji doku w nieskończoność.

    OdpowiedzUsuń
  3. Ale w pewnym momencie zaczynają się problemy bo nazwy są do siebie zbyt podobne.
    Np. calculateGain4MonthWithTaxation() i calculateGain4YearWithTaxation(). Trudno je odróżnić, a także trudno je wykorzystać w bardziej generycznym przypadku, gdy np. mamy listę "kont" i chcemy sprawdzić czy powinniśmy im naliczyć w danym dniu odsetki, i naliczyć tym które się łapią.
    Wtedy najpewniej chcielibyśmy by była sobie lista obiektów Account, które miałyby metodę do sprawdzenia czy akurat dziś należy naliczyć odsetki i taką która je będzie obliczała, a te metody korzystałyby z jakichś obiektów wewnętrznych do obliczeń.

    OdpowiedzUsuń
  4. Slabo sie czlowiekowi robi jak czyta takie rzeczy. Co ze wzorcami projektowymi????

    OdpowiedzUsuń
  5. Widze zes z Krakowa. Robilem kiedys w innej krakowskiej firmie i robili taki sam syf. A podobno w Krakowie takie dobre uczelnie?

    OdpowiedzUsuń
  6. Są bardzo miłe, bardzo przydatne, ale po pierwsze wymagają przeszkolenia całego developmentu jak ich używać jak do nich refactorować kod, a to kosztuje, kosztuje też utrzymanie porządku i pilnowanie tego by każdy developer pracował z kodem w taki sposób, po drugie do głębokiego refactoringu potrzebne są unit testy, których praktycznie żaden projekt istniejący już parę lat nie ma, a biznes niechętnie płaci za unit testy [mówiąc inaczej, zwykle nie chce płacić za pisanie testów], po trzecie wzorce projektowe nie są panaceum na całe zło świata, po czwarte jeżeli nie daj boże trzeba taki zrefaktorowany do wzorców kod mergować to zaczynają się prawdziwe kłopoty, po piąte nic nie stoi na przeszkodzie [poza tym co niżej ;-)] by synteza o której tu mówię prowadziła do użycia wzorców.

    Tak, znam całą litanię o tym, że trzeba spłacić dług technologiczny, który się zaciąga, ale z punktu widzenia każdego biznesu jaki widziałem lepiej zrobić teraz coś szybko i może nie do końca perfekt, ale dostarczyć produkt klientowi, niż pójść w zabawy z kodem, które klientowi nic nie dadzą poza opóźnieniem dostarczenia produktu. W najgorszym przypadku się po prostu dany fragment napisze od podstaw w momencie gdy będzie to potrzebne.

    OdpowiedzUsuń
  7. Slyszalem, ze sabre to taka dobra firma a w dzisiejszych czasach nawet do slabych firm nie przyjmuje sie ludzi ktorzy na slowa 'wzorzec strategii' robia tak zwana rybke. w ogole macie bajke stara jak swiat. na poczatku projektuje sie dupiato bo trzeba szybko, bo nikt nie wymaga, zeby bylo lepiej itp. a po jakims czasie okazuje ze zrobil sie taki smrod ze nikt go nie chce ruszyc. ten smrod sie ciagnie i poteguje z roku na rok. wzorce projektowe to nie jest panaceum na wszystko. napewno nie jest to metoda na slabych programistow, ale jest to tez napewno metoda na wlasni taki syf.

    OdpowiedzUsuń
  8. Widzisz, i tu się mylisz bo smrodu nie ma.
    Bo nawet najdzikszy kod po krótkim czasie zaczyna się oswajać, byli tylko nie stosować podejścia religijnego w stylu "tylko wzorce" albo znów innego chorego podejścia "extends is evil" czy podobnych.

    Wzorców używa się tam gdzie to ma sens, a nie wszędzie gdzie popadnie. Gdy zaczynasz refactoring dużego kodu, który powstał jak się czasem wydaje w czasach gdy ktoś jeszcze nie do końca rozumiał co to znaczy programować w danym języku to najpierw trzeba go zmusić by był napisany w danym języku [miałem kiedyś okazję pracować z kodem, który miał wtedy z 10-15 lat, który wyglądał jak żywcem wzięty z C++ i wrzucony do Java'y i tam trzeba było najpierw zrozumieć kod i go przepisać tak by przypominał Java'ę. i to była duża, międzynarodowa firma, związana z telekomunikacją, a ten soft był używany do bardzo ważnych rzeczy [bez niego nie można by było używać dość istotnych urządzeń]].

    Wzorca są świetne gdy chce się uniknąć wielokrotnego wynajdywania koła.

    A co do rozmów kwalifikacyjnych, to mogę Cię zapewnić, że jedna z najbardziej pożądanych przez programistów firm na świecie [taka z nazwą na G ;-)] na rozmowie nie pyta o wzorce.

    OdpowiedzUsuń