Napisałem strukturę, która reprezentuje współrzędne szerokości i długości geograficznej. Ich wartości wynoszą od -180 do 180 dla długości i 90 do -90 dla szerokości.
Jeśli użytkownik tej struktury podaje mi wartość spoza tego zakresu, mam 2 opcje:
- Rzuć wyjątek (argument poza zakresem)
- Konwertuj wartość na ograniczenie
Ponieważ współrzędne -185 ma znaczenie (można je bardzo łatwo przekonwertować na +175, ponieważ są to współrzędne biegunowe), mógłbym je zaakceptować i przekonwertować.
Czy lepiej jest rzucić wyjątek, aby poinformować użytkownika, że jego kod dał mi wartość, której nie powinien mieć?
Edycja: Znam też różnicę między lat / lng a współrzędnymi, ale chciałem to uprościć dla łatwiejszej dyskusji - nie był to najjaśniejszy pomysł
c#
exceptions
validation
K. Gkinis
źródło
źródło
Odpowiedzi:
Jeśli sednem twojego pytania jest to ...
... wtedy moja ogólna odpowiedź brzmiałaby „odrzuć”, ponieważ pomoże to zwrócić uwagę na potencjalne błędy w kodzie klienta, które w rzeczywistości powodują wyświetlanie nieprawidłowej wartości w programie i dotarcie do twojego konstruktora. Zwracanie uwagi na błędy jest na ogół pożądaną właściwością w większości systemów, przynajmniej podczas programowania (chyba że pożądana właściwość twojego systemu do pomieszania w przypadku błędów).
Pytanie brzmi, czy rzeczywiście masz do czynienia z tą sprawą .
Jeśli struktura danych ma ogólnie modelować współrzędne biegunowe, zaakceptuj wartość, ponieważ kąty poza zakresem -180 i +180 nie są tak naprawdę nieprawidłowe. Są całkowicie poprawne i po prostu zawsze mają odpowiednik w zakresie od -180 do +180 (a jeśli chcesz przekonwertować je na ten zakres, nie krępuj się - kod klienta zwykle nie musi się tym przejmować) .
Jeśli twoja struktura danych wyraźnie modeluje współrzędne Web Mercator (zgodnie z pytaniem w swojej pierwotnej formie), najlepiej postępować zgodnie z wszelkimi postanowieniami wymienionymi w specyfikacji (których nie wiem, więc nie powiem o tym nic) . Jeśli specyfikacja modelowanego elementu mówi, że niektóre wartości są nieprawidłowe, odrzuć je. Jeśli mówi, że można je interpretować jako coś sensownego (a tym samym faktycznie obowiązującego), zaakceptuj je.
Mechanizm użyć do sygnału, czy wartości zostały przyjęte, czy też nie, zależy od cech swojego języka, jego ogólnej filozofii i Twoich wymagań eksploatacyjnych. Tak więc możesz zgłaszać wyjątek (w konstruktorze) lub zwracać zerową wersję swojej struktury (za pomocą metody statycznej, która wywołuje prywatnego konstruktora) lub zwracać wartość logiczną i przekazywać swoją strukturę do obiektu wywołującego jako
out
parametr (ponownie przez metoda statyczna, która wywołuje konstruktora prywatnego) i tak dalej.źródło
To bardzo zależy. Ale powinieneś zdecydować się coś zrobić i udokumentować .
Jedynym zdecydowanie błędem w kodzie jest zapomnienie o tym, że dane wejściowe użytkownika mogą znajdować się poza oczekiwanym zakresem i napisanie kodu, który przypadkowo zachowuje się trochę. Ponieważ wtedy niektórzy ludzie przyjmą błędne założenia co do zachowania twojego kodu i spowoduje błędy, podczas gdy inni skończą w zależności od zachowania, które przypadkowo ma Twój kod (nawet jeśli to zachowanie jest całkowicie nieprzyjemne), a więc będziesz powodować więcej błędów kiedy później naprawisz problem.
W tym przypadku widzę argumenty tak czy inaczej. Jeśli ktoś podróżuje +10 stopni od 175 stopni, powinien skończyć na -175. Jeśli zawsze normalizujesz dane wprowadzane przez użytkownika i traktujesz 185 jako ekwiwalent -175, kod klienta nie może zrobić źle, gdy dodaje 10 stopni; zawsze ma odpowiedni efekt. Jeśli traktujesz 185 jako błąd, zmuszasz każdy przypadek, w którym kod klienta dodaje względne stopnie, aby wprowadzić logikę normalizacji (lub przynajmniej pamiętasz, aby wywołać procedurę normalizacji), w rzeczywistości spowodujeszbłędy (choć, miejmy nadzieję, łatwe do złapania, które zostaną szybko zgniecione). Ale jeśli liczba długości geograficznej zostanie wprowadzona przez użytkownika, zapisana dosłownie w programie lub obliczona za pomocą jakiejś procedury mającej zawsze być w [-180, 180), wówczas wartość spoza tego zakresu najprawdopodobniej wskaże błąd, więc „pomocne „konwersja może ukryć problemy.
Moim ideałem w tym przypadku byłoby prawdopodobnie zdefiniowanie typu reprezentującego prawidłową domenę. Użyj typu abstrakcyjnego (nie pozwól, aby kod klienta po prostu uzyskiwał dostęp do surowych liczb w nim zawartych) i zapewnij zarówno normalizującą, jak i sprawdzającą fabrykę (aby klient mógł dokonać kompromisu). Ale niezależnie od tego, jaką wartość tego typu stworzysz, 185 powinien być nie do odróżnienia od -175, gdy widzisz go za pomocą publicznego interfejsu API (nie ma znaczenia, czy są one konwertowane podczas budowy, czy zapewniasz równość, akcesoria i inne operacje, które w jakiś sposób ignorują różnicę) .
źródło
Jeśli wybranie jednego rozwiązania nie ma dla ciebie większego znaczenia, możesz po prostu pozwolić użytkownikowi zdecydować.
Biorąc pod uwagę, że Twoja struktura jest obiektem o wartości tylko do odczytu i utworzonym przez metodę / konstruktor, możesz zapewnić dwa przeciążenia w zależności od opcji, które użytkownik ma:
Nigdy też nie pozwól, aby użytkownik miał niepoprawną strukturę do przekazania do innych metod, popraw to przy tworzeniu.
Edycja: w oparciu o komentarze, zakładam, że używasz c #.
źródło
catch
wyjątki. Jak powiedzieli inni, pozwala to klientowi ograniczyć się, jeśli sobie tego życzy. Tak naprawdę niczego nie obchodzisz.To zależy, czy dane wejściowe pochodzą bezpośrednio od użytkownika przez jakiś interfejs użytkownika, czy pochodzą z systemu.
Wejście przez interfejs użytkownika
Pytanie użytkownika dotyczy sposobu postępowania z nieprawidłowymi danymi wejściowymi. Nie wiem o twoim konkretnym przypadku, ale ogólnie istnieje kilka opcji:
Wybór zależy od oczekiwań użytkowników i tego, jak ważne są dane. Na przykład Google automatycznie poprawia pisownię w zapytaniach, ale jest to niskie ryzyko, ponieważ nieprzydatna zmiana nie stanowi problemu i jest łatwa do naprawy (a nawet wtedy na stronie wyników jest wyraźnie zaznaczone, że zapytanie zostało zmienione). Z drugiej strony, jeśli wprowadzasz współrzędne dla pocisku nuklearnego, możesz chcieć bardziej sztywnego sprawdzania poprawności danych wejściowych i żadnych cichych poprawek nieprawidłowych danych. Więc nie ma uniwersalnej odpowiedzi.
Co najważniejsze, należy rozważyć, czy poprawienie danych wejściowych ma nawet korzyść dla użytkownika. Dlaczego użytkownik wprowadziłby nieprawidłowe dane? Łatwo jest zobaczyć, jak ktoś może popełnić błąd ortograficzny, ale dlaczego ktoś miałby wprowadzić długość -185? Jeśli użytkownik naprawdę miał na myśli +175, prawdopodobnie napisałby +175. Myślę, że najprawdopodobniej nieprawidłowa długość geograficzna jest po prostu błędem podczas pisania, a użytkownik miał na myśli -85 lub coś innego. W tym przypadku konwersja po cichu jest zła i nieprzydatna . Najbardziej przyjaznym dla użytkownika podejściem dla Twojej aplikacji byłoby prawdopodobnie powiadomienie użytkownika o nieprawidłowej wartości i samodzielne jej poprawienie.
Dane wejściowe za pośrednictwem interfejsu API
Jeśli dane wejściowe pochodzą z innego systemu lub podsystemu, nie ma pytania. Powinieneś rzucić wyjątek. Nigdy nie należy cicho konwertować niepoprawnych danych wejściowych z innego systemu, ponieważ może to maskować błędy w innym miejscu w systemie. Jeśli dane wejściowe są „poprawione”, powinno to nastąpić w warstwie interfejsu użytkownika, a nie głębiej w systemie.
źródło
Powinieneś rzucić wyjątek.
W podanym przykładzie, wysyłając 185 i konwertując to na -175, w niektórych przypadkach może być przydatne zapewnienie takiej funkcjonalności. Ale co, jeśli dzwoniący wyśle 1 milion? Czy oni naprawdę chcą to przekonwertować? Bardziej prawdopodobne jest, że to błąd. Jeśli więc musisz zgłosić wyjątek dla 1 000 000, ale nie dla 185, musisz podjąć decyzję o arbitralnym progu wyrzucenia wyjątku. Ten próg może cię kiedyś podnieść, ponieważ jakaś aplikacja dzwoniąca wysyła wartości wokół tego progu.
Lepiej wyrzucić wyjątek dla wartości spoza zakresu.
źródło
Najwygodniejszą opcją dla programisty byłaby obsługa błędu czasu kompilacji na platformie dla wartości spoza zakresu. W takim przypadku zakres powinien być również częścią sygnatury metody, podobnie jak typ parametrów. W ten sam sposób, w jaki użytkownik interfejsu API nie może przekazać ciągu znaków, jeśli sygnatura metody jest zdefiniowana jako przyjmująca liczbę całkowitą , użytkownik nie powinien mógł przekazać wartości bez sprawdzenia, czy wartość mieści się w zakresie podanym w sygnaturze metody. Jeśli nie jest zaznaczone, powinien otrzymać błąd czasu kompilacji, dzięki czemu można uniknąć błędu czasu wykonywania.
Ale obecnie bardzo niewiele kompilatorów / platform obsługuje ten rodzaj sprawdzania czasu kompilacji. Więc to jest ból głowy programistów. Ale idealnie, twoja metoda powinna po prostu rzucić znaczący wyjątek dla nieobsługiwanych wartości i jasno to udokumentować.
BTW, naprawdę podoba mi się model błędu zaproponowany przez Joe Duffy tutaj .
źródło
Domyślnie powinno być zgłoszone wyjątek. Możesz również zezwolić na opcję typu
strict=false
przymus i zrobić na podstawie flagi, gdzie oczywiściestrict=true
jest domyślna. Jest to dość powszechne:DateFormat
obsługuje łagodny .źródło
strict=false
?Dla mnie najlepszą praktyką jest nigdy nie zmieniać danych wejściowych użytkownika. Podejście, które zazwyczaj wybieram, polega na oddzieleniu sprawdzania poprawności od wykonania.
źródło