Mam projekt, który jest wystarczająco duży, że nie mogę już dłużej zachować każdego aspektu w głowie. Mam do czynienia z wieloma klasami i funkcjami, a także przekazuję dane.
Z czasem zauważyłem, że ciągle pojawiają się błędy, ponieważ zapomniałem, jaką dokładną formę muszą mieć dane, gdy przekazuję je różnym funkcjom ( np. Jedna funkcja akceptuje i wyświetla tablicę ciągów, inna funkcja, którą napisałem znacznie później, akceptuje ciągi przechowywane w słowniku itp., więc muszę przekształcić ciągi, z którymi pracuję, od umieszczenia ich w tablicy do umieszczenia ich w słowniku ).
Aby uniknąć konieczności ciągłego ustalania, co się zepsuło, zacząłem traktować każdą funkcję i klasę jako „izolowany byt” w tym sensie, że nie może polegać na kodzie zewnętrznym, podając poprawne dane wejściowe i musi sam sprawdzać dane wejściowe (lub, w niektórych przypadkach przekształć dane, jeśli dane są podane w niewłaściwej formie).
To znacznie skróciło czas, jaki spędzam, upewniając się, że przekazywane przeze mnie dane „pasują” do każdej funkcji, ponieważ same klasy i funkcje ostrzegają mnie teraz, gdy niektóre dane wejściowe są złe (a czasem nawet poprawiają to), a ja nie muszę już przejść z debuggerem przez cały kod, aby dowiedzieć się, gdzie coś poszło nie tak.
Z drugiej strony zwiększyło to również ogólny kod.
Moje pytanie brzmi, czy ten styl kodu jest odpowiedni do rozwiązania tego problemu?
Oczywiście najlepszym rozwiązaniem byłoby całkowite przefakturowanie projektu i upewnienie się, że dane mają jednolitą strukturę dla wszystkich funkcji - ale ponieważ ten projekt stale się rozwija, musiałbym więcej wydawać i martwić się czystym kodem niż dodawać nowe rzeczy .
(FYI: Nadal jestem początkującym, więc przepraszam, jeśli to pytanie było naiwne; mój projekt jest w Pythonie).
źródło
Odpowiedzi:
Lepszym rozwiązaniem jest lepsze wykorzystanie funkcji i narzędzi języka Python.
Ten problem został złagodzony za pomocą
namedtuple
. Jest lekki i nadaje członkom tablicy łatwe semantyczne znaczenie.Aby skorzystać z funkcji automatycznego sprawdzania typów bez przełączania języków, możesz skorzystać z podpowiedzi do typów . Dobry IDE może to wykorzystać, aby poinformować cię, gdy zrobisz coś głupiego.
Wygląda na to, że martwisz się, że funkcje przestaną działać, gdy zmienią się wymagania. Można to wykryć za pomocą automatycznych testów .
Chociaż nie twierdzę, że ręczne sprawdzanie nigdy nie jest właściwe, lepsze wykorzystanie dostępnych funkcji językowych może pomóc w rozwiązaniu tego problemu w łatwiejszy do utrzymania sposób.
źródło
namedtuple
i wszystkich innych fajnych rzeczy. Nie o tym nienamedtuple
wiedziałem - i chociaż wiedziałem o automatycznych testach, nigdy tak naprawdę nie korzystałem z niego zbyt często i nie zdawałem sobie sprawy, jak bardzo by mi to pomogło w tym przypadku. Wszystko to wydaje się być tak dobre jak analiza statyczna. (Automatyczne testowanie może być nawet lepsze, ponieważ mogę uchwycić wszystkie subtelne rzeczy, które nie zostałyby złapane w analizie statycznej!) Jeśli znasz jakieś inne, daj mi znać. Pozostawię pytanie otwarte dłużej, ale jeśli nie otrzymam innych odpowiedzi, zaakceptuję twoje.OK, rzeczywisty problem jest opisany w komentarzu pod tą odpowiedzią:
Problemem jest tutaj użycie listy ciągów, w których kolejność oznacza semantykę. To bardzo podatne na błędy podejście. Zamiast tego należy utworzyć niestandardową klasę z dwoma polami o nazwach
title
ibibliographical_reference
. W ten sposób nie będziesz ich mieszać i unikniesz tego problemu w przyszłości. Oczywiście wymaga to refaktoryzacji, jeśli już używasz list ciągów znaków w wielu miejscach, ale wierz mi, na dłuższą metę będzie to tańsze.Powszechnym podejściem w językach dynamicznych jest „pisanie kaczką”, co oznacza, że tak naprawdę nie zależy ci na „typie” przekazywanego obiektu, zależy ci tylko na tym, czy obsługuje metody, które na nim wywołujesz. W twoim przypadku po prostu przeczytasz pole wywoływane,
bibliographical_reference
gdy jest ono potrzebne. Jeśli to pole nie istnieje na przekazanym obiekcie, pojawi się błąd, co oznacza, że do funkcji został przekazany niewłaściwy typ. Jest to tak samo dobra kontrola typu, jak każda inna.źródło
Po pierwsze, teraz odczuwasz zapach kodu - spróbuj zapamiętać, co doprowadziło cię do świadomości tego zapachu i spróbuj wyostrzyć swój „mentalny” nos, ponieważ im szybciej zauważysz zapach kodu, tym szybciej - i łatwiej - jesteś w stanie rozwiązać podstawowy problem.
Programowanie obronne - jak nazywa się tę technikę - jest ważnym i często używanym narzędziem. Jednak, podobnie jak w przypadku wszystkich rzeczy, ważne jest, aby używać właściwej kwoty, zbyt małej liczby czeków i nie złapiecie problemów, zbyt wielu, a kod będzie przepełniony.
To może być mniej dobry pomysł. Jeśli zauważysz, że część twojego programu wywołuje funkcję z niepoprawnie sformatowanymi danymi, NAPRAW TĄ CZĘŚĆ , nie zmieniaj wywoływanej funkcji, aby móc i tak trawić złe dane.
Poprawa jakości i łatwości konserwacji twojego kodu to na dłuższą metę oszczędność czasu (w tym sensie muszę ponownie ostrzec przed funkcją autokorekty wbudowaną w niektóre z twoich funkcji - mogą być podstępnym źródłem błędów. Tylko dlatego, że twój program nie ulega awarii i nagrywanie nie oznacza, że działa poprawnie ...)
Aby w końcu odpowiedzieć na twoje pytanie: Tak, programowanie defensywne (tj. Weryfikacja poprawności podanych parametrów) jest - w zdrowym stopniu - dobrą strategią. To powiedziawszy , jak sam powiedziałeś, twój kod jest niespójny, i zdecydowanie polecam, abyś poświęcił trochę czasu na refaktoryzację zapachowych części - powiedziałeś, że nie chcesz martwić się o czysty kod cały czas, poświęcając więcej czasu na „czyszczenie” niż w przypadku nowych funkcji ... Jeśli nie utrzymasz kodu w czystości, możesz poświęcić dwa razy więcej czasu na „oszczędzanie” na nie utrzymywaniu czystego kodu na błędach związanych ze zgnieceniem ORAZ trudności z implementacją nowych funkcji - dług techniczny może zmiażdżyć cię.
źródło
W porządku Kiedyś kodowałem w FoxPro, gdzie miałem bloki TRY..CATCH prawie w każdej dużej funkcji. Teraz koduję w JavaScript / LiveScript i rzadko sprawdzam parametry w funkcjach „wewnętrznych” lub „prywatnych”.
„Ile sprawdzić” zależy bardziej od wybranego projektu / języka niż umiejętności kodowania.
źródło