Czytałem Refaktoryzację Martina Fowlera . Ogólnie jest znakomity, ale jedna z rekomendacji Fowlera wydaje się sprawiać trochę kłopotów.
Fowler zaleca zastąpienie zmiennych tymczasowych zapytaniem, więc zamiast tego:
double getPrice() {
final int basePrice = _quantity * _itemPrice;
final double discountFactor;
if (basePrice > 1000) discountFactor = 0.95;
else discountFactor = 0.98;
return basePrice * discountFactor;
}
wybierasz metodę pomocnika:
double basePrice() {
return _quantity * _itemPrice;
}
double getPrice() {
final double discountFactor;
if (basePrice() > 1000) discountFactor = 0.95;
else discountFactor = 0.98;
return basePrice() * discountFactor;
}
Ogólnie zgadzam się, z tym wyjątkiem, że jednym z powodów, dla których używam zmiennych tymczasowych jest to, że linia jest zbyt długa. Na przykład:
$host = 'https://api.twilio.com';
$uri = "$host/2010-04-01/Accounts/$accountSid/Usage/Records/AllTime";
$response = Api::makeRequest($uri);
Gdybym spróbował to wpisać, linia byłaby dłuższa niż 80 znaków.
Alternatywnie otrzymuję łańcuchy kodów, które same nie są o wiele łatwiejsze do odczytania:
$params = MustacheOptions::build(self::flattenParams($bagcheck->getParams()));
Jakie są strategie pogodzenia tych dwóch kwestii?
coding-style
refactoring
variables
Kevin Burke
źródło
źródło
$host
i$uri
przykład jest w pewnym sensie wymyślony - chyba że host był odczytywany z ustawienia lub innych danych wejściowych, wolałbym, aby znajdowały się w tej samej linii, nawet jeśli zawija się lub nie wychodzi.Odpowiedzi:
Jak
1. Istnieją ograniczenia długości linii, dzięki czemu można zobaczyć + zrozumieć więcej kodów. Nadal są ważne.
2. Podkreśl osąd w sprawie ślepej konwencji .
3. Unikaj zmiennych temp, chyba że optymalizujesz pod kątem wydajności .
4. Unikaj używania głębokich wcięć do wyrównywania w instrukcjach wieloliniowych.
5. Podziel długie instrukcje na wiele linii wzdłuż granic pomysłów :
Rozumowanie
Głównym źródłem moich (debugujących) problemów ze zmiennymi tymczasowymi jest ich zmienność. Mianowicie, założę, że są jedną wartością podczas pisania kodu, ale jeśli funkcja jest złożona, jakiś inny fragment kodu zmienia swój stan w połowie. (Lub odwrotnie, gdzie stan zmiennej pozostaje taki sam, ale wynik zapytania zmienił się).
Rozważ trzymanie się zapytań, chyba że optymalizujesz wydajność . Pozwala to zachować logikę użytą do obliczenia tej wartości w jednym miejscu.
Podane przykłady (Java i ... PHP?) Pozwalają na stosowanie instrukcji wieloliniowych. Jeśli linie stają się długie, rozbij je. Źródło jquery doprowadza to do skrajności. (Pierwsza instrukcja biegnie do wiersza 69!) Nie, że niekoniecznie się zgadzam, ale istnieją inne sposoby na uczynienie twojego kodu czytelnym niż używanie zmiennych tymczasowych.
Kilka przykładów
1. Przewodnik po stylu PEP 8 dla Pythona (nie najładniejszy przykład)
2. Paul M Jones w Przewodniku po stylu gruszkowym (środek argumentu drogowego)
3. Długość linii Oracle + konwencje owijania (przydatne strategie do przechowywania 80 znaków)
4. MDN Java Practices (podkreśla osąd programisty nad konwencją)
źródło
Myślę, że najlepszym argumentem za użyciem metod pomocniczych zamiast zmiennych tymczasowych jest czytelność dla ludzi. Jeśli jako człowiek masz więcej problemów z odczytaniem łańcucha metod pomocniczych niż tymczasowe varialbe, nie widzę powodu, dla którego powinieneś je wyciągać.
(Proszę popraw mnie jeżeli się mylę)
źródło
Nie sądzę, że musisz ściśle przestrzegać 80 znaków lub że zawsze należy wyodrębnić lokalną zmienną temp. Ale należy badać długie kolejki i lokalnych pracowników tymczasowych, aby uzyskać lepsze sposoby wyrażania tego samego pomysłu. Zasadniczo wskazują, że dana funkcja lub linia jest zbyt skomplikowana i musimy ją rozbić. Musimy jednak zachować ostrożność, ponieważ złe dzielenie zadania na części tylko komplikuje sytuację. Więc mam rozbić rzeczy na łatwe do zregenerowania i proste elementy.
Pozwól mi spojrzeć na zamieszczone przez ciebie przykłady.
Moje spostrzeżenie jest takie, że wszystkie wywołania interfejsu API twilio zaczynają się od „https://api.twilio.com/2010-04-1/”, a zatem istnieje bardzo oczywista funkcja wielokrotnego użytku:
W rzeczywistości uważam, że jedynym powodem do wygenerowania adresu URL jest wysłanie żądania, więc zrobiłbym:
W rzeczywistości wiele adresów URL zaczyna się od „Accounts / $ accountSid”, więc prawdopodobnie wyodrębnię to również:
A jeśli zmienimy twilio api w obiekt, który posiada numer konta, możemy zrobić coś takiego:
Korzystanie z obiektu $ twilio ma tę zaletę, że ułatwia testowanie jednostkowe. Mogę nadać temu obiektowi inny obiekt $ twilio, który tak naprawdę nie odwołuje się do twilio, który będzie szybszy i nie zrobi dziwnych rzeczy dla twilio.
Spójrzmy na drugi
Tutaj pomyślałbym o:
lub
lub
W zależności od tego, który z nich jest bardziej przydatny.
źródło
Właściwie nie zgadzam się z wybitnym panem Fowlerem w tej sprawie w sprawie ogólnej.
Zaletą wyodrębnienia metody z wcześniej wprowadzonego kodu jest ponowne użycie kodu; kod w metodzie jest teraz oddzielony od początkowego użycia i można go teraz używać w innych miejscach kodu bez kopiowania i wklejania (co wymagałoby wprowadzania zmian w wielu miejscach, gdyby ogólna logika skopiowanego kodu kiedykolwiek musiała się zmienić) .
Jednak równą, często większą wartością konceptualną jest „ponowne wykorzystanie wartości”. Pan Fowler nazywa te wyodrębnione metody w celu zastąpienia zmiennych tymczasowych „zapytaniami”. Co jest bardziej wydajne; sprawdzanie bazy danych za każdym razem, gdy potrzebujesz konkretnej wartości, lub zapytanie i zapisywanie wyniku (zakładając, że wartość jest na tyle statyczna, że nie spodziewałbyś się jej zmiany)?
W przypadku prawie wszystkich obliczeń wykraczających poza względnie trywialne w twoim przykładzie, w większości języków tańsze jest przechowywanie wyniku jednego obliczenia niż jego dalsze obliczanie. Dlatego ogólne zalecenie ponownego obliczania na żądanie jest nieuczciwe; kosztuje więcej czasu programisty i więcej czasu procesora, a także oszczędza trywialną ilość pamięci, która w większości nowoczesnych systemów jest najtańszym zasobem tych trzech.
Teraz metoda pomocnicza w połączeniu z innym kodem może być „leniwa”. Po pierwszym uruchomieniu zainicjuje zmienną. Wszystkie dalsze wywołania zwracałyby tę zmienną, dopóki metoda nie otrzyma wyraźnego polecenia ponownego obliczenia. Może to być parametr metody lub flaga ustawiona przez inny kod, który zmienia dowolną wartość obliczania tej metody:
Teraz, dla tego trywialnego obliczenia, które wykonuje jeszcze więcej pracy niż jest zapisane, dlatego ogólnie zalecałbym trzymanie się zmiennej temp; jednak w przypadku bardziej skomplikowanych obliczeń, których generalnie nie chcesz uruchamiać wiele razy i których potrzebujesz w wielu miejscach w kodzie, jest to sposób, w jaki to zrobiłbyś.
źródło
Metody pomocnicze mają swoje miejsce, ale musisz uważać na zapewnienie spójności danych i niepotrzebnego zwiększania zakresu zmiennych.
Na przykład twój własny przykład cytuje:
Najwyraźniej obie
_quantity
i_itemPrice
są zmienne globalne (lub na poziomie klasy najmniejszej), a więc nie ma możliwości, żeby być modyfikowany pozagetPrice()
Dlatego istnieje możliwość, że pierwsze połączenie
basePrice()
zwróci inną wartość niż drugie połączenie!Dlatego sugerowałbym, że funkcje pomocnicze mogą być przydatne do izolowania złożonej matematyki, ale w miejsce zmiennych lokalnych należy zachować ostrożność.
Trzeba także unikać reductio ad absurdum - czy należy obliczyć
discountFactor
metodę obliczeniową ? Twój przykład staje się:Partycjonowanie powyżej pewnego poziomu powoduje, że kod jest mniej czytelny.
źródło
Jeśli akurat pracujesz w języku o nazwanych parametrach (ObjectiveC, Python, Ruby itp.), Zmienne temp są mniej przydatne.
Jednak w przykładzie basePrice wykonanie zapytania może zająć trochę czasu i możesz zapisać wynik w zmiennej tymczasowej do wykorzystania w przyszłości.
Jednak podobnie jak ty używam zmiennych temp do rozważenia przejrzystości i długości linii.
Widziałem także, że programiści wykonują następujące czynności w PHP. Jest interesujący i świetny do debugowania, ale jest trochę dziwny.
źródło
Uzasadnieniem tego zalecenia jest to, że chcesz mieć możliwość korzystania z tego samego wstępnego obliczenia w innym miejscu swojej aplikacji. Zobacz temat Zastąp temperaturę zapytaniem w katalogu wzorców refaktoryzacji:
Dlatego w przykładzie hosta i identyfikatora URI zastosowałbym to zalecenie tylko wtedy, gdy planuję ponownie użyć tego samego identyfikatora URI lub definicji hosta.
W takim przypadku ze względu na przestrzeń nazw nie zdefiniuję globalnej metody uri () lub host (), ale nazwę z większą ilością informacji, taką jak twilio_host () lub archive_request_uri ().
Następnie w przypadku problemu z długością linii widzę kilka opcji:
uri = archive_request_uri()
.Uzasadnienie: W bieżącej metodzie chcesz, aby identyfikator URI był wymieniony. Definicja URI jest nadal podzielona na czynniki.
uri() { return archive_request_uri() }
Jeśli często korzystasz z rekomendacji Fowlera, będziesz wiedział, że metoda uri () ma ten sam wzorzec.
Jeśli z powodu wyboru języka musisz uzyskać dostęp do metody lokalnej za pomocą „ja”. Poleciłbym pierwsze rozwiązanie, dla zwiększenia ekspresji (w Pythonie zdefiniowałbym funkcję uri w bieżącej metodzie).
źródło