Obrona dla płyty kotłowej?

15

Dla mnie kod płyty głównej jest oczywiście zły. Jednak spotkałem programistę, który wykazuje opór przy każdej próbie zmniejszenia płyty kotłowej. Uświadomiłem sobie, że nie miałem łatwo sformułowanego, dobrze przemyślanego argumentu po odrazie, którą rozwinąłem z czasem.

Jakie są niektóre kontrargumenty, abym mógł sformułować przekonujący argument za faworyzowaniem mniejszej liczby płyt grzewczych? Innymi słowy, jakie są argumenty (jeśli w ogóle) na korzyść płyty kotłowej?

(Mam na myśli to, co myślę, że ogólnie rozumie się przez płytę kotłową, ale dobrym przykładem są pobierające i ustawiające w Javie).

roztargniony
źródło
7
Argumenty przeciwko zduplikowanemu kodowi (przy założeniu, że płyta grzewcza jest kopiowana / wklejona): stackoverflow.com/a/2490897/1583
Oded
1
@Oded: Zgadza się. Ale źle odczytałeś pytanie. :) Próbuje sprawdzić, czy jest coś do powiedzenia na temat kodu płyty wzorcowej. Domyślam się, że jest bardzo dobrze poinformowany o wadach.
Steven Jeuris
3
@StevenJeuris - doskonale przeczytałem pytanie. Dlatego nie opublikowałem odpowiedzi. Dodam tylko do drugiej strony argumentu. Właśnie dlatego OP ma „dobrze sformułowany, dobrze przemyślany argument po odrazie, którą rozwinąłem dla niego z czasem” na następny raz;)
Oded
2
Plansza może być przyjemna estetycznie: en.wikipedia.org/wiki/Ten_Is_the_House_That_Jack_Built
SK-logic
Kilka dobrych odpowiedzi i komentarzy, które się uzupełniają ... trudno wybrać, który z nich zaakceptować.
streszczony

Odpowiedzi:

15

Jedną ważną rzeczą do zapamiętania jest to, że kod jest zwykle zmniejszany przez usunięcie niepotrzebnego kontekstu. Jeśli kompilator może coś rozgryźć, argument jest oczywisty , nie ma potrzeby jawnego zapisywania tego.

Byłoby wspaniale, gdyby tylko kompilator miał zamiar go przeczytać. Pamiętaj jednak, że „programy powinny być pisane tak, aby ludzie je czytali, a tylko przypadkowo, aby maszyny mogły je uruchomić”. (Jak na ironię, ten cytat pochodzi z podręcznika poświęconego jednemu z najtrudniejszych ze wszystkich języków dla zwykłych ludzi do czytania, w dużej mierze ze względu na jego nadmierną zwięzłość).

To, co może ci się wydawać nudne, powtarzalne, jest dla ciebie cennym kontekstem dla kogoś, kto przyjdzie rok (lub pięć) później i będzie musiał zachować twój kod.

WRT konkretnie przykład Java, zgodzę się, że jest to dobry przykład złej płyty, ponieważ można ją zastąpić czymś, co jest zarówno krótsze i łatwiejsze do odczytania, jak i bardziej elastyczne: Właściwości. Ale to nie znaczy, że wszystkie elementy syntaktyczne z wszystkich języków są tak marnotrawne, jak programy pobierające i ustawiające z Javy i C ++.

Mason Wheeler
źródło
7
Oczywiście ten argument działa w obie strony. Znaczna ilość kodu na tablicy jest po to, aby uspokoić kompilator i nie pomaga ludziom zrozumieć - aby pozostać przy getterach / setterach, te dziesiątki wierszy muszą być przeczytane całkowicie, aby mieć pewność, że „to tylko get-getery i settery” , zamiast odczytywania pojedynczej krótkiej linii na właściwość, która po prostu stwierdza, że ​​jest to właściwość i jaki ma typ.
6
Myślę, że płyta kotła jest również szkodliwa dla czytelnika. Zmuszając nas do pisania powtarzalnego, pozbawionego znaczenia tekstu, zasłaniamy odpowiednie części kodu innym osobom. Jeśli coś jest pomocne, to z definicji nie jest to bojler.
Andres F.
1
@Giorgio: Wręcz przeciwnie, to znacznie więcej niż tylko moja opinia; jest to opinia zdecydowanej większości ludzi, którzy kiedykolwiek próbowali to studiować. A kiedy „trudne do odczytania” jest przede wszystkim kwestią opinii, fakt, że opinia ta jest tak szeroko rozpowszechniona, czyni ją faktem.
Mason Wheeler,
1
@Mason Wheeler: Na to, jak ludzie postrzegają języki programowania, często wpływa ich przeszłe doświadczenie. Ludzie, którzy nauczyli się programować w programie, uważają C lub Pascala za niezdarnych i trudnych do odczytania. Z drugiej strony ogromna większość osób nauczyła się programować w języku głównego nurtu.
Giorgio
2
Jestem zdania, gdzie, kiedy bardziej kontekst jest ukryty z programatora poprzez usunięcie boilerplate że jedynym sposobem, że człowiek ma zachować większą mapę psychicznego wszystkich rzeczy dzieje się niewidzialny za kulisami I że jest większy uszczerbek, jeśli chodzi o debugowanie niż oszczędność miejsca podczas tworzenia.
Patrick Hughes
7

Argumentem przemawiającym za kodem typu „kocioł” jest to, że zmiana go w jednym miejscu wpływa tylko na jeden przepływ kodu. Należy to zrównoważyć z faktem, że najczęściej chcesz, aby zmiana wpływała na każdy fragment kodu, który z niej korzysta. Ale widziałem rzadkie przykłady, które potwierdzają ten argument.

Powiedzmy, że masz fragment kodu, który mówi

public ForTheBar(Foo foo)
{
    Bar bar = foo.bar();
    return bar.BeFooed();
}

Jest to używane w około 2 miejscach w kodzie.

Pewnego dnia ktoś przychodzi i mówi: „Ok, tylko na tej ścieżce, chcemy, abyś wspiął się na pasek przed zrobieniem go”.

I myślisz „cóż, to jest proste”.

public ForTheBar(Foo foo, bool shouldIGrommit)
{
    Bar bar = foo.bar();

    if (shouldIGrommit)
    {
        bar.BeGrommitted();
    }

    return bar.BeFooed();
}

Następnie użytkownik dodaje nową funkcjonalność i uważasz, że dobrze pasuje do FooTheBar. I sumiennie pytasz ich, czy powinieneś przelecieć ten pasek przed nim, a oni powiedzą „nie, nie tym razem”.

Więc po prostu wywołujesz powyższą metodę.

Ale wtedy twój użytkownik mówi „ok, czekaj, w trzecim przypadku chcemy, abyś Doodle Bar, zanim zadzwonisz do BeFooed”.

Nie ma problemu, myślisz, że mogę to zrobić.

public ForTheBar(Foo foo, bool shouldIGrommit, bool shouldIDoodle)
{
    Bar bar = foo.bar();

    if (shouldIGrommit)
    {
        bar.BeGrommitted();
    }

    if (shouldIDoodle)
    {
        bar.BeDoodled();
    }

    return bar.BeFooed();
}

Nagle twój kod staje się coraz mniej wymagający. Być może powinieneś był zaakceptować powtórzone dwa wiersze kodu. Do tej pory będziesz miał trzy fragmenty kodu, każdy o długości 2-3 wierszy i nie wyglądający na powtarzający się.

To powiedziawszy, przeciwdziałbym temu stwierdzeniem „nie jest to częsty przypadek, a kiedy to się dzieje, można zrefaktoryzować”.

Innym argumentem, który ostatnio usłyszałem, jest to, że kod płytki wzorcowej może czasem pomóc w nawigacji kodu. Przykład, o którym rozmawialiśmy, polegał na tym, że usunęliśmy mnóstwo kodu mapowania płyty kotła i zastąpiliśmy go AutoMapper. Teraz argumentowano, ponieważ wszystko opiera się na konwencjach, nie można powiedzieć IDE „gdzie jest ta właściwość ustawiona” i oczekiwać, że się dowie.

Widziałem ludzi, którzy twierdzą podobne rzeczy na temat kontenerów IoC.

Nie mówię, że się z nimi zgadzam, ale mimo to jest to uczciwy argument.

pdr
źródło
2
Wolałem drugą część twojej odpowiedzi. ; p +1
Steven Jeuris
po prostu uświadom sobie, że mój przykład jest dość podobny do twojego ... zgadnij, nawet jeśli to nie jest zdrowy rozsądek, wydaje się, że dzieje się to trochę :)
kritzikratzi
Idk, czy nie byłoby łatwiej i łatwiej uniknąć duplikacji kodu bez komplikowania rzeczy poprzez przekazywanie funkcji grommit i doodle jako argumentów do pierwotnej funkcji rozszerzonej o drugi lub lepszy wariant funkcji argument? Innymi słowy, dodanie przełączników bool i warunkowych jest po prostu złym wzorcem. Przykład zastępuje zły wzorzec (powielanie kodu) gorzej. Jeśli nie możesz przekazać funkcji, byłby to punkt, w którym refaktoryzacja w dwóch odrębnych funkcjach byłaby opcją bez wcześniejszego powielania kodu.
gschenk
6

Ewolucja wydajności

Zaczynasz od tego:

<p>
    <label for="field">My field</label>
    <input type="text" id="field">
</p>

pozbywacie się wszystkich tych irytujących bojlerów i włączacie funkcję:

  1. createFieldHtml( id, label )

    to dobrze, oszczędzam sobie tyle linii!

  2. createFieldHtml( id, label, defaultValue )

    tak, potrzebuję też wartości domyślnej, którą łatwo było dodać.

  3. createFieldHtml( id, label, defaultValue, type )

    fajnie, mogę teraz używać go również do pól wyboru

  4. createFieldHtml( id, label, defaultValue, type, labelFirst )

    Projektant UX powiedział, że etykieta musi znajdować się po polu wyboru.

  5. createFieldHtml( id, label, defaultValue, type, labelFirst, isDate )

    w razie potrzeby wyświetla teraz selektor dat. Hm ... Params trochę wymyka się spod kontroli

  6. createFieldHtml( id, label, defaultValue, type, labelFirst, isDate, containerCssClasses )

    był jeden przypadek, w którym muszę dodać klasy CSS

  7. createFieldHtml( id, label, defaultValue, type, labelFirst, isDate, containerCssClasses, fieldCssClasses, disabled, clearAfter, helpText, uploadPath )

    aaaaaaaaaaaaaaaaaaaaa

W obronie płyty kotłowej

Trudno mi to wyrazić słowami, ponieważ tak naprawdę zauważyłem to niedawno, więc sporządzę listę:

  1. Wydaje mi się, że istnieje pewien strach przed powieleniem nieco rozciągniętych linii. Jeśli to tylko kilka wierszy, może to nie stanowić żadnego problemu. niektóre rzeczy są z natury „prawie powtarzalne” (jak w powyższym przykładzie). Na dłuższą metę nie widzę szans na optymalizację.
  2. Ludzie lubią gdzieś enkapsulować funkcjonalność; jeśli spojrzysz obiektywnie i wydaje się, że to po prostu „ukrywanie bałaganu” - bądź podejrzliwy! może to być czas na dobrą, starą płytę kotłową
  3. Kiedy masz funkcję, która staje się coraz potężniejsza; który wymaga wielu różnych ścieżek wykonania w zależności od danych wejściowych i ostatecznie robi bardzo mało - może to być czas na płycie!
  4. Kiedy dodasz warstwę abstrakcji na wierzchu innej warstwy abstrakcji, ale tylko po to, aby twój kod był krótszy (warstwa podstawowa nie powinna być zmieniana) - czas na płytkę!
  5. Jeśli masz funkcję, która bierze tak wiele parametrów, że naprawdę musisz nazwać parametry - być może jest to czas płyty kotłowej.

Jedną z rzeczy, o których ostatnio zawsze zadaję sobie pytanie, jest to:
czy mogę skopiować i wkleić do innego projektu bez zmiany czegokolwiek? jeśli tak, można enkapsulować lub umieścić w bibliotece, jeśli nie: to czas bojlera.

Jest to bardzo sprzeczne z ogólną percepcją, że szablonem jest kod kopiuj i wklej. Dla mnie płyta główna polega na kopiowaniu i wklejaniu, ale zawsze muszę ją trochę poprawiać.


Aktualizacja : właśnie natknąłem się na artykuł podający mój przykład powyżej rzeczywistej nazwy: „zbyt SUCHY anty-wzór”.

Funkcja otrzymuje więcej parametrów i ma coraz bardziej złożoną wewnętrzną logikę do kontrolowania jej zachowania w różnych przypadkach. Zbyt suche funkcje są łatwe do wykrycia. Mają wiele skomplikowanych logik typu „jeśli-to”, które próbują sprostać szerokiej gamie zastosowań. [...] Powtarzanie kodu nie zawsze jest złą rzeczą, jeśli kod jest mały i wykonuje funkcję dyskretną.

To krótka i interesująca lektura, artykuł można znaleźć tutaj: Too Dry Anti-Pattern

kritzikratzi
źródło
1
„Kiedy dodajesz warstwę abstrakcji na innej warstwie abstrakcji, ale tylko po to, aby kod był krótszy” To prawda, powinieneś dodawać warstwy abstrakcji tylko wtedy, gdy istnieje możliwość ponownego użycia.
Steven Jeuris
4
+1. Nie powtarzaj się, ale nie idź do niezręcznych kroków, aby uniknąć prawie powtórzenia się.
Julia Hayward,
4

I gardzić kod szablonowe, ale jest w stanie usunąć kod szablonowe nie zawsze oznacza, że jest to najlepszy sposób, aby przejść.

Struktura WPF ma właściwości zależności , które wiążą się z niesamowitą ilością kodu typu „kocioł”. W wolnym czasie szukałem rozwiązania, które znacznie zmniejsza ilość kodu, który należy napisać. Ponad rok później wciąż ulepszam to rozwiązanie i nadal muszę rozszerzyć jego funkcjonalność lub naprawić błędy.

Jaki jest problem? Jest to świetne narzędzie do nauki nowych rzeczy i odkrywania alternatywnych rozwiązań, ale prawdopodobnie nie jest to najlepsza decyzja komercyjna .

Struktura WPF jest dobrze udokumentowana. To właściwie dokumentuje, jak napisać kod szablonowe. Próba usunięcia tego kodu jest fajnym ćwiczeniem i jest czymś, co zdecydowanie warto zbadać, ale osiągnięcie tego samego poziomu „polerowania”, jaki oferuje msdn, zajmuje dużo czasu, czego nie zawsze mamy.

Steven Jeuris
źródło
Jednak nadal jestem bardzo zadowolony z rezultatu, który mam w tej chwili i chętnie wykorzystuję go w swoich projektach w wolnym czasie. :)
Steven Jeuris
3
za każdym razem, gdy dotykam WPF i tych właściwości zależności, zawsze chciałbym, aby C # miał coś tak prostego jak makra C ++. Pewne makra są nadużywane w niewłaściwych rękach, ale mogą wyeliminować tak wiele powtórzeń. Będę musiał rzucić okiem na twój framework AOP następnym razem, gdy zacznę marzyć o tych makrach :)
DXM
@DXM Jeśli to zrobisz, a to zawiedzie nieszczęśliwie, nie zapomnij mnie winić i opublikować błędy. ; p
Steven Jeuris
Fragment kodu działał dla mnie całkiem dobrze w przypadku właściwości zależności.
Codism
@Codism: Dobrze, że rozwiązaniem, ale gardzić tych zbyt . :)
Steven Jeuris
1

Problem z płytą grzewczą polega na tym, że narusza ona OSUSZANIE. Zasadniczo, pisząc szablon, powtarzasz ten sam kod (lub bardzo podobny kod) dla wielu klas. Kiedy ten kod wymaga zmiany, wcale nie jest pewne, że programista zapamięta wszystkie miejsca, w których kod został powtórzony. Prowadzi to do błędów, w których używane są stare interfejsy API lub stare metody.

Jeśli przebudujesz płytę główną na wspólną bibliotekę lub klasę nadrzędną, musisz zmienić kod tylko w jednym miejscu, gdy zmieni się interfejs API. Co ważniejsze, gdy nastąpią nieoczekiwane zmiany, kod pęka w jednym miejscu i pozwala dokładnie wiedzieć, co trzeba naprawić, aby wszystko znów działało. Jest to zdecydowanie lepsze niż scenariusz, w którym jedna zmiana powoduje awarie w dziesiątkach, a nawet setkach klas.

kwantowy
źródło
2
Jak to jest argument na korzyść płyty kotłowej ?
Chris Wesseling,
0

Zamierzam zastosować inny takt. Spójność w rozwoju jest jedną z najważniejszych cech projektowania oprogramowania, jest kluczowym narzędziem umożliwiającym rozszerzanie aplikacji i utrzymanie ich, ale może być trudna do osiągnięcia przy zarządzaniu zespołem w wielu witrynach, językach i strefach czasowych.

Jeśli zostanie osiągnięta, spójność sprawi, że kod będzie znacznie bardziej dostępny „kiedy już go zobaczysz, zobaczysz je wszystkie”, znacznie tańszy w utrzymaniu i refaktoryzacji, ale przede wszystkim znacznie łatwiejszy do rozszerzenia. Kiedy piszesz bibliotekę, która wymaga trochę podstaw, wraz z mocą swojej biblioteki dałeś także programistom:

  • Punktem początkowym jest zrozumienie preambuły (płyty kotłowej) Twojej funkcjonalności, większość kluczowych klas i punktów dostępu zwykle będzie stanowić część płyty kotłowej. Daje to programistom punkt wyjścia do dokumentacji
  • Oczekiwania na umieszczenie na programistach staną się oczywiste, na przykład jeśli skonfigurujesz obiekt śledzenia w ramach preambuły, programiści będą wiedzieć, gdzie rejestrować wyjątki i informacje
  • Implikowane zrozumienie, gdy zmuszasz programistę do przejścia przez proces tworzenia instancji klas, może wywnioskować techniki, których będą potrzebować, aby uzyskać dostęp do reszty biblioteki i mieć możliwość wprowadzenia ich do wszelkich konwencji używanych w całej bibliotece
  • Łatwa weryfikacja, gdy potrzebny jest Twój kod, może zazwyczaj bardzo łatwo zweryfikować się z wyjątkami i klauzulami ochronnymi, zapobiegając utknięciu konsumentów w dalszej linii, gdy już popełnisz wadliwy proces
  • Konfiguracja biblioteki, która wymaga kodu typu „płyta podstawowa”, jest łatwa, ponieważ istnieje już oczywisty punkt implementacji umożliwiający dostosowanie funkcji do pojedynczej ścieżki wykonania. Jest to szczególnie przydatne, jeśli wymagany kod płyty rozszerzeń jest wzbogacony o wzorzec fabryczny lub poleceń

Gdy konsumenci Twojej biblioteki opanują tworzenie instancji, mogą łatwo tworzyć metody prywatne / rozszerzenia, klasy nadrzędne, a nawet szablony w celu zaimplementowania kodu szablonu.

Dead.Rabit
źródło
-3

Jedynym prawdziwym problemem z kodem typu „kociołek” jest to, że gdy znajdziesz w nim błąd, musisz naprawić wszędzie, gdzie go używałeś, a nie w jednym miejscu, którego używałeś ponownie .

Edward Strange
źródło