Najpierw trochę tła. Piszę odnośnik z Wiek -> Stawka. Istnieje 7 przedziałów wiekowych, więc tabela przeglądowa składa się z 3 kolumn (od | do | stawki) z 7 wierszami. Wartości rzadko się zmieniają - są to stawki legislacyjne (pierwsza i trzecia kolumna), które pozostają takie same od 3 lat. Doszedłem do wniosku, że najłatwiejszym sposobem przechowywania tej tabeli bez zakodowania na stałe jest w bazie danych w globalnej tabeli konfiguracji, jako pojedyncza wartość tekstowa zawierająca CSV (więc „65,69,0.05,70,74,0.06” to poziomy 65-69 i 70-74 będą przechowywane). Stosunkowo łatwy do przeanalizowania, a następnie użycia.
Potem zdałem sobie sprawę, że aby to zaimplementować, będę musiał utworzyć nową tabelę, repozytorium do owijania go, testy warstwy danych dla repo, testy jednostkowe wokół kodu, który rozpakowuje CSV do tabeli, i testy wokół samego wyszukiwania. Jedyną zaletą całej tej pracy jest unikanie twardego kodowania tabeli odnośników.
W rozmowie z użytkownikami (którzy obecnie korzystają bezpośrednio z tabeli odnośników - patrząc na papierową wersję) istnieje opinia, że „stawki nigdy się nie zmieniają”. Oczywiście to nie jest poprawne - stawki zostały utworzone dopiero trzy lata temu, a w przeszłości rzeczy, które „nigdy się nie zmieniają” miały nawyk zmiany - więc dla mnie, aby programować defensywnie, zdecydowanie nie powinienem przechowywać tabeli odnośników w Aplikacja.
Z wyjątkiem sytuacji, gdy myślę YAGNI . Wdrożona przeze mnie funkcja nie określa zmian stawek. Jeśli stawki się zmieniają, nadal będą się zmieniać tak rzadko, że konserwacja nawet nie jest brana pod uwagę, a funkcja nie jest tak naprawdę na tyle ważna, że wszystko zmieniłoby się, gdyby nastąpiło opóźnienie między zmianą stawki a zaktualizowaną aplikacją.
Prawie zdecydowałem, że nic wartościowego nie zostanie utracone, jeśli zaprogramuję wyszukiwanie na stałe i nie martwię się zbytnio moim podejściem do tej konkretnej funkcji. Moje pytanie brzmi: czy jako profesjonalista właściwie uzasadniłem tę decyzję? Wartości na sztywno to zły projekt, ale problem z usunięciem wartości z aplikacji wydaje się naruszać zasadę YAGNI.
EDYCJA Aby wyjaśnić pytanie, nie martwię się o faktyczną implementację. Obawiam się, że mogę albo zrobić szybką, złą rzecz, i uzasadnić to, mówiąc YAGNI, albo też przyjąć bardziej defensywne, wymagające dużo wysiłku podejście, które nawet w najlepszym przypadku ostatecznie przynosi niewielkie korzyści. Czy jako profesjonalny programista moja decyzja o wdrożeniu projektu, który według mnie jest wadliwy, sprowadza się po prostu do analizy kosztów i korzyści?
EDYCJA Podczas gdy wszystkie odpowiedzi były bardzo interesujące, ponieważ myślę, że sprowadza się to do indywidualnych wyborów projektowych, myślę, że najlepsze odpowiedzi to @ Corbin i @EZ Hart, ponieważ poruszają rzeczy, których nie rozważałem w pytaniu:
- fałszywa dychotomia „prawidłowego usuwania zakodowanych wartości” poprzez przeniesienie jej do bazy danych w porównaniu z „wydajnym zastosowaniem YAGNI” przy użyciu zakodowania na stałe. Istniała trzecia opcja umieszczenia tabeli odnośników w konfiguracji aplikacji, która nie wiąże się z koniecznością poprawnego działania i bez wydajności YAGNI. Zasadniczo nie ograniczamy się do decyzji / decyzji, a sprowadza się to do decyzji o kosztach / korzyściach.
- generowanie kodu może zmniejszyć obciążenie związane z przenoszeniem zakodowanych wartości do bazy danych, a także w sposób, który usuwa również moją nadmiernie inżynierską decyzję o przetwarzaniu pliku CSV do tabeli. Potencjalnie powoduje to również problem z długoterminową konserwacją wygenerowanego kodu, jeśli podstawowe wymagania zmienią się dla metody wyszukiwania. Wszystko to wpływa tylko na analizę kosztów i korzyści i jest prawdopodobne, że gdybym miał dostęp do tej automatyzacji, nie rozważyłbym nawet takiego kodowania na sztywno.
Zaznaczam odpowiedź @ Corbina jako poprawną, ponieważ zmienia ona moje założenia dotyczące kosztów rozwoju i prawdopodobnie w najbliższej przyszłości dodam do mojego arsenału narzędzia do generowania kodu.
Odpowiedzi:
Znalazłeś wadę w swoim procesie rozwoju. Gdy wykonanie właściwego zadania (tworzenie tabeli, repo, testy repo, spłaszczanie testów ...) jest trudne, programiści znajdą sposób na obejście tego. Zwykle wiąże się to z niewłaściwym postępowaniem. W takim przypadku kuszące jest traktowanie danych aplikacji jako logiki aplikacji. Nie rób tego Zamiast tego dodaj przydatne automatyzacje do swojego procesu programowania. Używamy CodeSmith do generowania nudnego kodu, którego nikt nie chce pisać. Po utworzeniu tabeli uruchamiamy CodeSmith, który generuje DAO, DTO i usuwa testy jednostkowe dla każdego z nich.
W zależności od używanych technologii powinieneś mieć podobne opcje. Wiele narzędzi ORM wygeneruje modele na podstawie istniejącego schematu. Migracje po szynach działają w przeciwnym kierunku - tabele z modeli. Metaprogramowanie w językach dynamicznych jest szczególnie skuteczne w eliminowaniu kodu bojlera. Będziesz musiał pracować trochę ciężej, aby wygenerować wszystko, czego potrzebujesz, jeśli masz złożoną aplikację wielowarstwową, ale warto. Nie pozwól, aby uczucie „wow, to jest ból szyi” powstrzymuje cię przed zrobieniem właściwej rzeczy.
Aha, i nie przechowuj danych w formacie wymagającym dodatkowego przetwarzania (CSV). To tylko dodatkowe kroki, które wymagają Twojej uwagi i testowania.
źródło
Aby odpisać i rozszerzyć odpowiedź @ Thorbjørn Ravn Andersen: Utrzymanie obliczeń / wyszukiwania w jednym miejscu to dobry początek.
Twój proces myślowy defensywny kontra YAGNI jest częstym problemem. W tym przypadku sugerowałbym, aby poinformowały go dwie dodatkowe rzeczy.
Po pierwsze - w jaki sposób przedstawiono wymagania użytkownika? Czy określono możliwość edytowania stawek? Jeśli nie, to czy dodatkowa złożoność jest częścią czegoś, za co możesz zapłacić, czy nie? (lub jeśli masz pracowników, że zamiast tego możesz poświęcić czas na inną pracę?) Jeśli tak, to zdecydowanie idź dalej i dostarcz to, o co rozsądnie poproszono.
Po drugie, a może co ważniejsze, sama edytowalność raczej nie spełni rzeczywistych wymagań w obliczu zmiany przepisów. Jeśli i kiedy stawki się zmienią, najprawdopodobniej nastąpi data obniżki i pewne przetwarzanie przed i po, które musi nastąpić. Co więcej, jeśli ten sam interfejs musi następnie wykonać jakiekolwiek przeterminowane przetwarzanie roszczeń, może być konieczne sprawdzenie poprawnej stawki w oparciu o datę wejścia w życie, a nie faktyczną datę.
Krótko mówiąc, zauważam, że rzeczywiste edytowalne wymaganie może być dość złożone, więc dopóki nie zostanie dopracowane, proste jest prawdopodobnie lepsze.
Powodzenia
źródło
Ustaw faktyczne wyszukiwanie jako funkcję biblioteki. Następnie możesz zobaczyć cały kod korzystający z tego wyszukiwania w repozytorium źródłowym, dzięki czemu wiesz, które programy należy zaktualizować, gdy stawki się zmienią.
źródło
PensionRateLookup
klasy), a następnie zostanie użyte globalnie. Zrobiłbym to bez względu na to, czy jest przechowywany poza aplikacją, czy na stałe, w ten sposóbPensionRateLookup
zachowana musi być tylko implementacja klasy. Mój problem polega na tym, jak wykorzystałem YAGNI, aby dojść do wniosku, że zakodowanie na stałe tabeli odnośników jest dopuszczalne.Pokaż mi, czy dobrze zrozumiałem twoje pytanie. Masz 2 opcje zaimplementowania funkcji: albo kodujesz wartość, a twoja funkcja jest łatwa do implementacji (ale nie podoba ci się część kodu) lub masz bardzo duży wysiłek, aby „przerobić” wiele rzeczy, które zostały zrobione dzięki czemu możesz rozwijać swoją funkcję w czysty sposób. Czy to jest poprawne?
Pierwszą rzeczą, jaka przychodzi mi na myśl, jest: „Najważniejszą rzeczą w znajomości dobrych praktyk jest wiedza, kiedy lepiej sobie bez nich radzić”.
W tym przypadku wysiłek jest bardzo wysoki, więc możesz to zrobić w czysty sposób, szanse na efekt uboczny tej zmiany są duże, a zwrot, który otrzymasz, jest niewielki (jak wyjaśniłeś, wydaje się prawdopodobne, że nie będzie zmiana).
Użyłbym podejścia opartego na twardym kodzie (ale przygotowuję go do elastyczności w przyszłości), a w przypadku zmiany tej stawki w przyszłości skorzystam z okazji, aby przefiltrować całą tę wadliwą część kodu. Tak więc czas i koszt można oszacować poprawnie, a koszt zmiany wartości zapisanej na stałe byłby minimalny.
To byłoby moje podejście :)
źródło
Jest to przedmiot, który „nie zmieni się”, dopóki się nie zmieni. To nieuniknione, że to się zmieni, ale ten czas może być trochę daleki.
Twoje uzasadnienie jest prawidłowe. W tej chwili klient nie prosił o możliwość łatwej zmiany tych stawek. Jako taki, YAGNI.
Jednak to, czego nie chcesz, to kod, który uzyskuje dostęp do twoich stawek i interpretuje wyniki rozproszone w całej bazie kodu. Dobry projekt OO pozwoliłby zawrzeć wewnętrzną reprezentację swoich stawek w klasie i ujawnić tylko jedną lub dwie metody niezbędne do wykorzystania danych.
Będziesz potrzebował tej enkapsulacji, aby zapobiec błędom kopiowania i wklejania, lub będziesz musiał dokonać refaktoryzacji w całym kodzie, który wykorzystuje stawki, gdy musisz zmienić wewnętrzną reprezentację. Po podjęciu tej wstępnej ostrożności, bardziej skomplikowanym podejściem może być prosta zamiana i zamiana na bardziej funkcjonalną wersję.
Dodatkowo przywołaj klientowi ograniczenie obecnego projektu. Powiedz im, że w celu utrzymania harmonogramu zakodowałeś wartości na stałe - co wymaga zmiany kodowania, aby je zaktualizować. W ten sposób, gdy dowiedzą się o oczekujących zmianach stawek wynikających z nowych przepisów, mogą po prostu zaktualizować tabelę wyszukiwania lub dokonać bardziej skomplikowanej zmiany w tym czasie. Ale postaw tę decyzję na ich kolanach.
źródło
Podziel różnicę i ustaw dane szybkości w ustawieniach konfiguracji. Możesz użyć formatu CSV, który już masz, unikniesz zbędnego obciążenia bazy danych, a jeśli zmiana będzie kiedykolwiek konieczna, będzie to zmiana, którą klient powinien wprowadzić bez konieczności ponownej kompilacji / ponownej instalacji i bez bałaganu w bazie danych - mogą po prostu edytować plik konfiguracyjny.
Zwykle, gdy patrzysz na wybór między dwiema skrajnościami (naruszenie YAGNI vs. kodowanie dynamicznych danych), najlepsza odpowiedź jest gdzieś pośrodku. Uważaj na fałszywe dychotomie.
Zakłada się, że cała konfiguracja jest w plikach; jeśli jest to coś trudnego, np. rejestr, prawdopodobnie należy zignorować tę radę :)
źródło
Właśnie utworzyłem tabelę DB. (Czy myślałeś o przechowywaniu całego stołu w jednym pliku, oszalałeś?)
Tabela wymaga 2 pól NIE 3. Wiek i stawka. Ten następny wiersz zawiera górną wartość! Dezormalizujesz się, nawet o tym nie wiedząc!
Oto Sql, aby uzyskać stawkę dla osoby w wieku 67 lat.
Nie zawracaj sobie głowy tworzeniem ekranu konserwacji, ponieważ jest on poza zasięgiem. Jeśli poproszą o to później, wydaj prośbę o zmianę i zrób to.
EDYCJA: Jak powiedzieli inni, zachowaj kod, a centrala stawki zostanie scentralizowana, na wypadek gdyby cała struktura stawek uległa zmianie.
źródło
Zgadzam się z większością udzielonych odpowiedzi. Dodam także, że spójność z resztą aplikacji jest ważna. Jeśli jest to jedyne miejsce w kodzie, które ma zakodowane wartości, prawdopodobnie zaskoczy opiekunów. Jest to szczególnie prawdziwe, jeśli jest to duża, stabilna baza kodu. Jeśli jest to mały program obsługiwany przez ciebie, decyzja jest mniej ważna.
Mam daleką pamięć o czytaniu dobrze znanego zwinnego / OOP faceta (takiego jak Dave Thomas, Kent Beck czy ktoś), mówiącego, że ich podstawową zasadą przy powielaniu kodu było dwa i tylko dwa razy: nie refaktoryzuj za pierwszym razem, gdy coś powielisz możesz napisać to tylko dwa razy w swoim życiu. Ale trzeci raz ...
To nie do końca odnosi się do pytania, ponieważ kwestionujesz YAGNI, ale myślę, że dotyczy ogólnej elastyczności zwinnych zasad. Celem zwinności jest dostosowanie się do sytuacji i pójście naprzód.
źródło
Twardy kod w funkcji.
źródło