Jak narysować uwagi programisty w określonych warunkach?

13

Zacznijmy od przykładu.

Powiedzmy, że mam wywoływaną metodę, exportktóra zależy w dużym stopniu od schematu DB. Przez „mocno zależy” rozumiem, że dodanie nowej kolumny do określonej tabeli często (bardzo często) prowadzi do zmiany odpowiedniej exportmetody (zwykle należy również dodać nowe pole do danych eksportu).

Programiści często zapominają o zmianie exportmetody, ponieważ nie jest tak naprawdę jasne, że powinieneś nawet na to spojrzeć. Moim celem jest zmuszenie programisty do wyraźnego podjęcia decyzji, czy zapomniał spojrzeć na exportmetodę, czy po prostu nie chce dodawać pola do danych eksportu. I szukam rozwiązania tego problemu.

Mam dwa pomysły, ale oba mają wady.

Inteligentne opakowanie „Przeczytaj wszystko”

Mogę utworzyć inteligentne opakowanie, które zapewni, że wszystkie dane zostaną odczytane.

Coś takiego:

def export():
    checker = AllReadChecker.new(table_row)

    name    = checker.get('name')
    surname = checker.get('surname')
              checker.ignore('age') # explicitly ignore the "age" field

    result = [name, surname] # or whatever

    checker.check_now() # check all is read

    return result

checkerSprawdza więc, czy table_rowzawiera inne pola, które nie zostały odczytane. Ale wszystko to wygląda na ciężkie i (może) wpływa na wydajność.

„Sprawdź metodę” najczystsze

Mogę po prostu utworzyć unittest, który zapamiętuje ostatni schemat tabeli i zawiedzie przy każdej zmianie tabeli. W takim przypadku programista zobaczyłby coś w rodzaju „nie zapomnij sprawdzić exportmetody”. Aby ukryć programator ostrzegający (lub nie chciałby - to problem), sprawdź exporti ręcznie (to kolejny problem) napraw test, dodając do niego nowe pola.

Mam kilka innych pomysłów, ale są one zbyt kłopotliwe do wdrożenia lub zbyt trudne do zrozumienia (i nie chcę, aby projekt stał się zagadką).


Powyższy problem jest tylko przykładem szerszej klasy problemów, które od czasu do czasu napotykam. Chcę powiązać niektóre fragmenty kodu i / lub infrastruktury, więc zmiana jednego z nich natychmiast ostrzega programistę, aby sprawdził inny. Zwykle masz kilka prostych narzędzi, takich jak wyodrębnianie wspólnej logiki lub pisanie rzetelnych, choć nieszablonowych, ale szukam tego narzędzia w bardziej skomplikowanych przypadkach: może niektóre wzorce projektowe są mi teraz znane.

Vadim Pushtaev
źródło
Czy możesz generować exportna podstawie schematu?
coredump
Nie można go wygenerować w sposób wyjątkowy, dlatego powinienem poprosić programistę, aby spojrzał na kod i podjął decyzję.
Vadim Pushtaev
Czy rozwiązaniem byłoby dodanie dwóch list nazw pól (eksport i brak eksportu) do klasy eksportu i przeprowadzenie testu jednostkowego, który sprawdza, czy te dwie listy łącznie obejmują pełny zestaw pól z bazy danych?
Sjoerd Job Postmus
Czy potrafisz automatycznie wygenerować test, który sprawdza, czy exportma wszystko, czego naprawdę potrzebujesz?
biziclop
1
komentarz w kodzie źródłowym zbyt uproszczone rozwiązanie? Zwykle rzeczy są pomijane, ponieważ nie ma przypomnienia, komentarz by to naprawił.
gbjbaanb

Odpowiedzi:

11

Jesteś na dobrej drodze ze swoim pomysłem na test jednostkowy, ale Twoja implementacja jest zła.

Jeśli exportjest powiązany ze schematem i schemat się zmienił, istnieją dwa możliwe przypadki:

  • Albo exportnadal działa idealnie dobrze, ponieważ nie wpłynęło to na niewielką zmianę schematu,

  • Lub się psuje.

W obu przypadkach celem kompilacji jest wyśledzenie tej możliwej regresji. Kilka testów - czy to testy integracyjne, testy systemowe, testy funkcjonalne lub coś innego - zapewniają, że twoja exportprocedura działa z bieżącym schematem, niezależnie od tego, czy zmieniła się od poprzedniego zatwierdzenia, czy nie. Jeśli te testy przejdą pomyślnie, świetnie. Jeśli zawiodą, jest to znak dla programisty, że mógł coś przeoczyć, i wyraźne wskazanie, gdzie szukać.

Dlaczego Twoja implementacja jest nieprawidłowa? Z kilku powodów.

  1. Nie ma to nic wspólnego z testami jednostkowymi ...

  2. ... a właściwie to nawet nie jest test.

  3. Najgorsze jest to, że naprawienie „testu” wymaga, no cóż, faktycznej zmiany „testu”, czyli wykonania operacji całkowicie niezwiązanej z export.

Zamiast tego, wykonując rzeczywiste testy exportprocedury, upewniasz się, że programista naprawi ten błąd export.


Mówiąc bardziej ogólnie, gdy napotkasz sytuację, w której zmiana w jednej klasie zawsze lub zwykle wymaga zmiany w zupełnie innej klasie, jest to dobry znak, że źle popełniłeś swój projekt i naruszasz zasadę pojedynczej odpowiedzialności.

Chociaż mówię konkretnie o zajęciach, dotyczy to mniej więcej innych podmiotów. Na przykład zmiana schematu bazy danych powinna albo zostać automatycznie odzwierciedlona w kodzie, na przykład za pomocą generatorów kodu używanych przez wiele ORM, albo przynajmniej powinna być łatwo zlokalizowana: jeśli dodam Descriptionkolumnę do Producttabeli i nie używam ORM ani generatorów kodu, Spodziewam się przynajmniej jednej zmiany w obrębie Data.Productklasy DAL, bez konieczności przeszukiwania całej bazy kodu i znajdowania niektórych wystąpień Productklasy w, powiedzmy, warstwie prezentacji.

Jeśli nie możesz rozsądnie ograniczyć zmiany do jednej lokalizacji (albo dlatego, że po prostu nie działa, albo wymaga ogromnego rozwoju), możesz stworzyć ryzyko regresji . Kiedy zmieniam klasę A, a klasa Bgdzieś w bazie kodu przestaje działać, jest to regresja.

Testowanie obniża ryzyko regresji i, co jest o wiele ważniejsze, pokazuje lokalizację regresji. Dlatego, gdy wiesz, że zmiany w jednej lokalizacji powodują problemy w zupełnie innej części bazy kodu, upewnij się, że masz wystarczającą liczbę testów, które wywołują alarmy, gdy tylko regresja pojawi się na tym poziomie.

We wszystkich przypadkach unikaj polegania w takich przypadkach tylko na komentarzach. Coś jak:

// If you change the following line, make sure you also change the corresponding
// `measure` value in `Scaffolding.Builder`.

nigdy nie działa. Nie tylko programiści nie czytają go w większości przypadków, ale często kończy się albo usunięty, albo odsunięty od linii, której dotyczy, i staje się niemożliwy do zrozumienia.

Arseni Mourzenko
źródło
Tak, ten „test” w rzeczywistości nie jest testem, jest jakąś pułapką, coś, If you change the following line...co działa automatycznie i nie można go po prostu zignorować. Nigdy nie widziałem, żeby ktoś faktycznie używał takich pułapek, stąd wątpliwość.
Vadim Pushtaev
1
Problem polega na tym, że klasa Bnie przestaje działać, może zaczyna działać nieprawidłowo. Ale nie mogę przewidzieć przyszłości i nie mogę napisać testów, które przewidują przyszłość, więc próbuję przypomnieć deweloperowi, aby napisał ten nowy test.
Vadim Pushtaev
@VadimPushtaev: jeśli chodzi o testowanie, „być może zaczyna działać niepoprawnie”, a „przestaje działać” to dokładnie to samo. Nie możesz przewidzieć przyszłości, ale powinieneś być w stanie dokładnie poznać wymagania i sprawdzić, czy te wymagania są spełnione przez rzeczywisty produkt.
Arseni Mourzenko
Tak, to jest coś. Tak naprawdę chcę przypomnieć deweloperowi, aby pomyślał o nowych wymaganiach . Chcę tylko pomachać ręką: „Cześć, czy na pewno nie zapomnisz o eksporcie? Zapytaj kierownika czy coś, to powszechny problem ”.
Vadim Pushtaev
W każdym razie dziękuję, twoja odpowiedź pomogła mi uporządkować myśli i mam teraz pewien plan.
Vadim Pushtaev
3

Wydaje mi się, że twoje zmiany są nieokreślone. Załóżmy, że mieszkasz w miejscu, w którym nie ma kodów pocztowych, więc nie masz kolumny kodów pocztowych w tabeli adresów. Następnie wprowadzane są kody pocztowe lub zaczynasz kontaktować się z klientami mieszkającymi tam, gdzie są kody pocztowe i musisz dodać tę kolumnę do tabeli.

Jeśli element pracy mówi po prostu „dodaj kolumnę kodu pocztowego do tabeli adresów”, wówczas tak, eksport zostanie zerwany lub przynajmniej nie wyeksportuje kodów pocztowych. Ale co z ekranem wprowadzania, który służy do wprowadzania kodów pocztowych? Raport z listą wszystkich klientów i ich adresów? Istnieje wiele rzeczy, które należy zmienić po dodaniu tej kolumny. Zapamiętywanie tych rzeczy jest ważne - nie powinieneś liczyć na przypadkowe artefakty kodu, aby „uwięzić” programistów w zapamiętywaniu.

Gdy zostanie podjęta decyzja o dodaniu znaczącej kolumny (to znaczy nie tylko jakiegoś buforowanego całkowitego lub zdormalizowanego wyszukiwania lub innej wartości, która nie należy do eksportu, raportu lub ekranu wprowadzania), utworzone elementy pracy powinny zawierać WSZYSTKIE zmiany potrzebne - dodanie kolumny, aktualizacja skryptu wypełniania, aktualizacja testów, aktualizacja eksportu, raportów, ekranów wprowadzania danych i tak dalej. Nie wszystkie mogą być przypisane (lub odebrane) przez tę samą osobę, ale wszystkie muszą zostać wykonane.

Czasami programiści decydują się na samodzielne dodawanie kolumn w ramach wprowadzania większych zmian. Na przykład ktoś mógł napisać element roboczy, aby dodać coś do ekranu wprowadzania i raportu, bez zastanowienia się nad tym, jak jest to realizowane. Jeśli tak się często zdarza, musisz zdecydować, czy twój dodawca elementu pracy musi znać szczegóły implementacji (aby móc dodać wszystkie odpowiednie elementy pracy), czy też programiści muszą wiedzieć, że element roboczy- adder czasami pomija rzeczy. Jeśli jest to ta ostatnia, potrzebujesz kultury „nie zmieniaj schematu; przestań i pomyśl o tym, co jeszcze wpłynie”.

Gdyby było wielu programistów i zdarzyło się to więcej niż jeden raz, ustawiłbym alert meldowania dla kierownika zespołu lub innej wyższej osoby, aby otrzymywać powiadomienia o zmianach schematu. Osoba ta mogłaby następnie poszukać powiązanych elementów pracy, aby poradzić sobie z konsekwencjami zmiany schematu, a jeśli brakujących elementów pracy, mogła nie tylko je dodać, ale także edukować każdego, kto je pominął w planie.

Kate Gregory
źródło
2

Niemal zawsze podczas tworzenia eksportu tworzę również odpowiedni import. Ponieważ mam inne testy, które w pełni wypełniają eksportowaną strukturę danych, mogę następnie zbudować test jednostkowy w obie strony, który porównuje w pełni wypełniony oryginał z wyeksportowaną, a następnie zaimportowaną kopią. Jeśli są takie same, eksport / import jest zakończony; jeśli nie są takie same, test jednostkowy kończy się niepowodzeniem i wiem, że mechanizm eksportu wymaga aktualizacji.

Pete Kirkham
źródło
może to sprawdzić, czy każdy obiekt jest zapisywany i ponownie ładowany z db. Nie obejmuje przypadku, w którym istniejące pole db nie ma odpowiadającego pola obiektu.
k3b
@ k3b true. Przynajmniej w moich systemach to zwykle występuje, gdy coś nie jest już używane, ale nie zostało usunięte ze schematu, który jest poza zakresem mechanizmu eksportu - testy jednostkowe sprawdzają trwałość obiektu, czy każde pole obiektu jest trwało, ale nie testuję nieużywanych kolumn, ponieważ nie miałoby to zauważalnego wpływu na funkcję systemu.
Pete Kirkham