Piszę kod Ruby dla prostego ćwiczenia szyfrowania i często napotykałem ten dylemat (ćwiczenie to szyfr pasjansa, jeśli musisz wiedzieć). Pytanie dotyczy tego, czy powinienem uzupełnić moją logikę o zmienne opisowe i instrukcje jednoetapowe, które czynią tę funkcję czytelną zamiast zwięzłych, a nawet gęstych instrukcji, które eliminują powtarzanie i / lub minimalizują błędy.
Mój najnowszy przykład: Mój program pobiera dane wejściowe, a ze względu na sztywne wytyczne formatowania może łatwo określić, czy dane wejściowe powinny być szyfrowane, czy odszyfrowywane. Aby uprościć, po przekonwertowaniu / wygenerowaniu klucza szyfrującego i wiadomości w celu ich zgodności, należy odjąć klucz od zaszyfrowanej wiadomości lub dodać klucz do niezaszyfrowanej wiadomości, aby uzyskać pożądany wynik (myśl o kluczu jako o szyfrowaniu, wiadomość + szyfrowanie = kod; kod - szyfrowanie = wiadomość). Pozycja DRY mówi mi, że powinienem przekonwertować zaszyfrowaną wiadomość inaczej niż wiadomość niezaszyfrowaną, aby funkcja, która pobiera klucz szyfrowania i stosuje go do wiadomości, nigdy nie musiała się rozróżniać. Odkryłem, że oznacza to, że potrzebuję zagnieżdżonych instrukcji if w funkcji, ale logika wydaje się być solidna. Ten kod nie jest jednak łatwy do odczytania.
Z drugiej strony mógłbym napisać dwie różne funkcje, które są wywoływane na podstawie flagi ustawianej, gdy aplikacja określa szyfrowanie lub deszyfrowanie. Byłoby to łatwiejsze do odczytania, ale powielałoby funkcję wysokiego poziomu stosowania klucza szyfrowania do wiadomości (powodując, że jest ona szyfrowana lub odszyfrowywana).
Czy powinienem skłaniać się w kierunku czytelnego kodu lub zwięzłego kodu? A może przegapiłem inny sposób na uzyskanie tej funkcjonalności i spełnienie obu zasad? Czy jest to pozycja w skali, w której należy wziąć pod uwagę cel projektu i podjąć najlepsze decyzje, aby mu służyć?
Do tej pory kładę nacisk na zwięzły, suchy kod zamiast czytelnego kodu.
Odpowiedzi:
DRY jest wytyczną, a nie religią. Ci, którzy nadeszli do SUSZENIA ponad wszystko, posunęli się za daleko.
Przede wszystkim użyteczny kod jest najważniejszy. Jeśli kod nie jest użyteczny i użyteczny, to nie jest ... i nie ma sensu pisać go w pierwszej kolejności.
Po drugie, pewnego dnia ktoś będzie musiał zachować Twój kod. Jeśli kodu nie da się utrzymać, złamią twój „piękny” gęsty, zwięzły, SUCHY projekt, przeklinając twoje imię. Nie rób tego Byłem tą osobą i za każdym razem, gdy widzę pewne imię w adnotacji kodu, wzdrygam się.
Tworzenie gęstego kodu pozbawionego „zmiennych opisowych” i umieszczanie wszystkiego w zagnieżdżonych wyrażeniach trójskładnikowych za pomocą lambd bez dokumentacji jest sprytne. Miło wiedzieć, że możesz to zrobić - ale nie rób tego. Sprytny kod jest bardzo trudny do debugowania. Unikaj pisania sprytnego kodu .
Większość czasu poświęcanego oprogramowaniu spędza się na jego konserwacji - nie na pisaniu jej za pierwszym razem. Napisz kod, abyś (lub ktoś inny) mógł szybko i łatwo naprawić błędy i dodawać do niego funkcje zgodnie z wymaganiami za pomocą zaledwie kilku idealnych zmian w projekcie.
źródło
Nie jestem pewien na podstawie pytania, które rozumiesz DRY. Kod DRY to nie to samo, co zwięzłe. Dość często jest odwrotnie.
Tutaj nie jestem pewien, o co chodzi w tym przykładzie. Stwórz funkcję do szyfrowania, funkcję do odszyfrowania, pomocniki dla wspólnej funkcjonalności (mix bajtów) i prosty interfejs do pobierania danych i określania szyfrowania / deszyfrowania ... Nie powtarzaj się.
Ogólnie rzecz biorąc, zarówno DRY, jak i czytelność istnieją, aby pomóc w utrzymaniu i rozszerzaniu kodu. Nie wszystkie scenariusze są sobie równe, duże trafienie w czytelność w celu usunięcia małej powtórki nie jest dobre, podobnie jak garść duplikacji w celu zwiększenia czytelności.
Po naciśnięciu wolałbym czytelność. Duplikat kodu może być nadal testowany - nieczytelny kod prowadzi do zrobienia (i przetestowania) niewłaściwej rzeczy.
źródło
Nie znam twojego konkretnego przypadku, ale mogę podać kilka ogólnych wskazówek.
Celem zarówno czytelności, jak i DRY jest łatwość konserwacji .
Utrzymanie jest ważne w większości sytuacji, w których spędzasz więcej czasu na utrzymywaniu kodu niż na pisaniu. Jest to szczególnie ważne, jeśli uważasz pisanie kodu za specjalny rodzaj konserwacji.
Niestety DRY jest często źle rozumiany. Wynika to częściowo z tego, że wydaje się takie proste, ale podobnie jak wiele prostych rzeczy, może być… cóż… skomplikowane.
Zamiarem DRY jest to, aby każda jednostka funkcjonalności istniała tylko w jednym miejscu. Jeśli zasada ta jest przestrzegana, opiekun kodu, którego zadaniem jest zmiana lub weryfikacja tej funkcjonalności, może natychmiast poradzić sobie z kodem. Jeśli DRY nie będzie przestrzegane, istnieje bardzo realne niebezpieczeństwo, że niektóre kopie funkcji nie będą właściwie utrzymywane.
Najbardziej rażącym naruszeniem DRY jest kodowanie z kopiowaniem i wklejaniem, w którym całe bloki kodu są powtarzane dosłownie w bazie kodu. Jest to zaskakująco powszechne w moim doświadczeniu i w żaden sposób nie zwiększa czytelności. Dlatego refaktoryzacja kodu w celu wprowadzenia wspólnej metody niezmiennie zwiększa zgodność z DRY i czytelność.
Drugim najbardziej rażącym naruszeniem jest „kopiuj-wklej i zmień to trochę”. Ponownie refaktoryzacja w celu wprowadzenia wspólnej metody z parametrami lub rozbicie funkcji na etapy i wyodrębnienie podobieństw prawie zawsze zwiększa czytelność.
Potem są bardziej subtelne naruszenia, w których funkcjonalność jest powielana, ale kod jest inny. Nie zawsze jest to łatwe do wykrycia, ale kiedy go zobaczysz i refaktoryzujesz, aby pobrać wspólny kod do jednej metody / klasy / funkcji, wówczas kod jest zwykle bardziej czytelny niż był wcześniej.
Wreszcie istnieją przypadki powtórzenia projektu. Na przykład mógłbyś kilkakrotnie użyć wzorca stanu w swojej bazie kodu i rozważasz refaktoryzację w celu wyeliminowania tego powtarzania. W takim przypadku należy zachować ostrożność. Być może zmniejszasz czytelność, wprowadzając więcej poziomów abstrakcji. Jednocześnie tak naprawdę nie masz do czynienia z powielaniem funkcjonalności, ale z powielaniem abstrakcji. Czasem warto ... ale często nie jest. Waszą naczelną zasadą będzie pytanie „który z nich jest łatwiejszy do utrzymania”.
Za każdym razem, gdy wykonuję te oceny, staram się wziąć pod uwagę czas, jaki ludzie spędzą na utrzymywaniu kodu. Jeśli kod jest podstawową funkcjonalnością biznesową, prawdopodobnie będzie wymagał większej konserwacji. W takich przypadkach staram się, aby kod był łatwy w utrzymaniu dla osób, które znają bazę kodu i związane z nim abstrakcje. Z przyjemnością wprowadzę trochę więcej abstrakcji, aby ograniczyć powtarzanie. Natomiast skrypt, który jest rzadko używany i rzadko obsługiwany, może być trudniejszy do zrozumienia dla opiekunów, jeśli wymaga zbyt dużej abstrakcji. W takim razie popełniłbym błąd po stronie powtórzeń.
Rozważam także poziom doświadczenia innych członków mojego zespołu. Unikam „fantazyjnych” abstrakcji z niedoświadczonymi programistami, ale wykorzystuję uznane wzorce projektowe z bardziej dojrzałymi grupami.
Podsumowując, odpowiedzią na twoje pytanie jest zrobienie czegokolwiek, co czyni twój kod najbardziej łatwym w utrzymaniu. To, co oznacza to w twoim scenariuszu, zależy od ciebie.
źródło
Jeśli twoje funkcje stają się bardziej skomplikowane i dłuższe (a przez to mniej czytelne), kiedy próbujesz je osuszyć, oznacza to, że robisz to źle. Próbujesz umieścić zbyt wiele funkcji w jednej funkcji, ponieważ uważasz, że jest to jedyny sposób uniknięcia powtarzania tych samych fragmentów kodu w drugiej funkcji.
Tworzenie kodu DRY prawie zawsze oznacza refaktoryzację wspólnej funkcjonalności do mniejszych funkcji. Każda z tych funkcji powinna być prostsza (a przez to bardziej czytelna) niż pierwotna. Aby utrzymać wszystko w pierwotnej funkcji na tym samym poziomie abstrakcji, może to również oznaczać refaktoryzację dodatkowych części, które nie są używane gdzie indziej. Oryginalna funkcja staje się wtedy „funkcją wysokiego poziomu”, wywołującą mniejsze, a także staje się mniejsza i prostsza.
Konsekwencją tego jest przede wszystkim różne poziomy abstrakcji w kodzie - a niektórzy uważają, że tego rodzaju kod jest mniej czytelny. Z mojego doświadczenia wynika, że jest to błąd. Kluczową kwestią jest nadanie mniejszym funkcjom dobrych nazw, wprowadzenie dobrze nazwanych typów danych i abstrakcji, które druga osoba może łatwo uchwycić. W ten sposób „OSUSZANIE” i „czytelność” powinny bardzo, bardzo rzadko wchodzić w konflikt.
źródło
Chociaż nie jestem pewien, co dokładnie powoduje ten problem, moje doświadczenie jest takie, że gdy zauważysz, że DRY i czytelność są sprzeczne, oznacza to, że nadszedł czas, aby coś zreformować.
źródło
Wybrałbym opcję odczytu (= konserwowalną) zamiast DRY w dowolnym dniu tygodnia. W rzeczywistości oba często się wyrównują, ktoś, kto zna koncepcję DRY, generalnie generuje (głównie) czytelny kod.
źródło
Bardzo, bardzo, bardzo, bardzo, bardzo rzadko w mojej karierze znalazłem uzasadniony przypadek, który dowodzi czytelności przeciwko DRY. Najpierw uczyń to czytelnym. Nazwij wszystko dobrze. Skopiuj i wklej w razie potrzeby.
Teraz cofnij się i spójrz na całość, którą stworzyłeś, jak artysta cofający się, by spojrzeć na swoje malarstwo. Teraz możesz poprawnie zidentyfikować powtórzenie.
Powtarzany kod powinien zostać przekształcony we własną metodę lub wyciągnięty do własnej klasy.
Powtarzanie kodu powinno być ostatecznością. Najpierw do odczytu i wysychania, w przeciwnym razie nie do odczytania, jeśli ograniczysz zakres powtarzanego kodu.
źródło