Jak zmniejszyć liczbę błędów podczas kodowania?

30

Nikt nie jest doskonały i bez względu na to, co robimy, od czasu do czasu będziemy produkować kod, który zawiera błędy. Jakie są metody / techniki ograniczania liczby zgłaszanych błędów, zarówno podczas pisania nowego oprogramowania, jak i zmiany / utrzymywania istniejącego kodu?

GSto
źródło
Dobrą metodą jest wykonanie bardziej wstępnego projektu (nie za dużo, ale wystarczająco, aby twój kod był bardziej uporządkowany i łatwiejszy do zrozumienia).
Giorgio

Odpowiedzi:

58

Unikaj wymyślnego kodowania. Im bardziej skomplikowany kod, tym większe prawdopodobieństwo błędów. Zwykle w nowoczesnych systemach wyraźnie napisany kod będzie szybki i wystarczająco mały.

Użyj dostępnych bibliotek. Najłatwiejszym sposobem na uniknięcie błędów związanych z pisaniem programu narzędziowego jest nie pisanie go.

Naucz się kilku formalnych technik dla bardziej skomplikowanych rzeczy. Jeśli występują skomplikowane warunki, przybij je długopisem i papierem. Najlepiej znać niektóre techniki dowodowe. Jeśli mogę udowodnić, że kod jest poprawny, prawie zawsze jest dobry, z wyjątkiem dużych, głupich, oczywistych błędów, które można łatwo naprawić. Oczywiście dzieje się tak tylko do tej pory, ale czasem możesz formalnie rozumować o małych, ale skomplikowanych rzeczach.

W przypadku istniejącego kodu dowiedz się, jak refaktoryzować: jak wprowadzać niewielkie zmiany w kodzie, często za pomocą zautomatyzowanego narzędzia, dzięki którym kod jest bardziej czytelny bez zmiany zachowania.

Nie rób niczego zbyt szybko. Poświęcenie trochę czasu z góry, aby zrobić wszystko dobrze, aby sprawdzić, co zrobiłeś i pomyśleć o tym, co robisz, może się później opłacić.

Po napisaniu kodu użyj tego, co musisz, aby był dobry. Testy jednostkowe są świetne. Często możesz pisać testy z wyprzedzeniem, co może być świetną informacją zwrotną (jeśli są wykonywane konsekwentnie, jest to programowanie oparte na testach). Kompiluj z opcjami ostrzegania i zwracaj uwagę na ostrzeżenia.

Poproś kogoś innego, aby spojrzał na kod. Formalne recenzje kodu są dobre, ale mogą nie być w dogodnym czasie. Wyciągaj żądania lub podobnie, jeśli scm nie obsługuje ich, zezwalaj na asynchroniczne recenzje. Sprawdzanie znajomych może być mniej formalną recenzją. Programowanie par zapewnia, że ​​dwie pary oczu patrzą na wszystko.

David Thornley
źródło
x2 - co powiedział Ryan.
JBRWilkinson
2
także większość języków może być mniej lub bardziej wybredna. Chcesz, żeby był tak wybredny, jak to możliwe.
1
„Naucz się kilku formalnych technik dla bardziej skomplikowanych rzeczy.” ... na przykład?
Dan Rosenstark,
1
@ Yar: Oczekuję czegoś takiego jak systemy wyjaśnione w tej książce: amazon.com/Verification-Sequential-Concurrent-Programs-Computer/... ; chociaż muszę powiedzieć, że konkretna książka jest wyjątkowo sucha i nudna, więc prawdopodobnie są tam o wiele lepsze (ale to jedyna, którą przeczytałem).
Joeri Sebrechts
30

Testy jednostkowe pozwalają zmniejszyć liczbę błędów, które pojawiają się po raz drugi. Jeśli znajdziesz błąd w kodzie, napisanie testu jednostkowego sprawi, że nie pojawi się później. (Poza tym czasem trudno jest pomyśleć o wszystkich przypadkach i napisać tysiące testów jednostkowych)

Ryan Hayes
źródło
3
„Myślenie o wszystkich przypadkach z góry” prowadzi do czystych, w pełni określonych interfejsów, co może być tylko dobrą rzeczą. Testy jednostkowe są trudne do napisania tylko wtedy, gdy instalujesz je w kodzie, który nie został zaprojektowany z myślą o testowaniu.
Mike Seymour,
1
Jeśli możesz, powinieneś. Niestety większość miejsca widziałem testy jednostkowe jako coś, co kosztuje więcej niż tylko „szybkie naprawianie błędów”. Tak więc, jeśli możesz, powinieneś napisać testy z góry, ale jeśli nie jest to postrzegane jako „opłacalne”, pisanie ich wraz z poprawkami błędów pomaga budować go z czasem bez nadmiernego budżetu na pisanie testów jednostkowych .
Ryan Hayes
4
„Testowanie pokazuje obecność, a nie brak błędów”. - E. Dijkstra. To powiedziawszy, zautomatyzowane testy są zdecydowanie bardzo użytecznym sposobem na utrzymanie i podniesienie jakości oprogramowania.
limist
9

+1 dla obu komentarzy do testu jednostkowego.

Poza tym ustaw najwyższy poziom ostrzeżeń oferowany przez kompilator i upewnij się, że ostrzeżenia są traktowane jako błędy. Błędy często chowają się w tych „błędnych” błędach.

Podobnie zainwestuj w narzędzia analizy statycznej, które działają w czasie kompilacji (uważam je za dodatkowy poziom ostrzeżeń kompilatora).

Alan
źródło
+1 za komentarz do analizy statycznej. Bezcenne jest zdobycie wszystkich tych informacji za darmo :)
Morten Jensen,
9

Oprócz tego, co zostało wspomniane:

  • Nie ignoruj ​​kodów błędów - np. Nie zakładaj, że masz prawidłowy wynik, że plik został pomyślnie utworzony itp. Ponieważ pewnego dnia coś się wydarzy.
  • Nie zakładaj, że Twój kod nigdy nie wejdzie w jakiś warunek i dlatego „można bezpiecznie zignorować ten warunek”.
  • Przetestuj swój kod, a następnie niech przetestuje go ktoś inny. Uważam, że jestem najgorszą osobą do testowania własnego kodu.
  • Zrób sobie przerwę, a następnie ponownie przeczytaj kod i sprawdź, czy „przegapiłeś oczywiste”. Często mi się zdarza.

W tej chwili zapominam o wielu innych rzeczach, ale inni na pewno o tym pomyślą. :)

MetalMikester
źródło
7
A jeśli masz pewność, że warunek X nigdy się nie wydarzy ... użyj twierdzenia, aby upewnić się, że gdy wystąpi warunek X, będziesz o tym wiedział (poprzez wyjątek, logowanie lub cokolwiek innego).
Frank Shearar,
@MetalMikester: Testy jednostkowe są dobre. Jednak w przypadku języków wysokiego poziomu i dobrych bibliotek większość trudnych błędów wymaga testów integracji i regresji.
Wektor
9

Opracowałem dość funkcjonalny styl programowania, mimo że moje podstawowe języki to C ++ i Python. Przekonałem się, że jeśli przekażę cały kontekst do funkcji (lub metody), ta funkcja musi wykonać swoją pracę i zwrócą znaczące dane, których szukam, mój kod stanie się znacznie bardziej niezawodny.

Stan niejawny jest wrogiem i z mojego doświadczenia wynika, że ​​źródłem błędów jest nr 1. Ten stan może być zmiennymi globalnymi lub zmiennymi składowymi, ale jeśli wyniki zależą od czegoś, co nie zostało przekazane do funkcji, pytasz o problemy. Oczywiście nie jest możliwe wyeliminowanie stanu, ale jego minimalizacja ma ogromny pozytywny wpływ na niezawodność programu.

Chciałbym również powiedzieć moim współpracownikom, że każda gałąź (jeśli, na chwilę,? :) jest prawdopodobnym błędem. Nie mogę powiedzieć, jaka będzie manifestacja błędu, ale im mniej warunkowe zachowanie ma twój kod, tym bardziej prawdopodobne jest, że będzie wolny od błędów po prostu ze względu na fakt, że pokrycie kodu podczas wykonywania będzie bardziej spójne.

Idź, wszystkie te rzeczy mają również pozytywny wpływ na wydajność. Zdobyć!

dash-tom-bang
źródło
Z mojego doświadczenia może szybko stać się nudne przekazywanie całego stanu dla każdego połączenia, jeśli metody są tak małe, jak powinny. Problem ten można rozwiązać, stosując wiele małych niezmiennych klas o krótkich czasach życia obiektów. W ten sposób możesz zapisać stan tymczasowy jako pola i odrzucić obiekt, gdy nie będziesz już potrzebować tego stanu. :-)
Jørgen Fogh
Inną kwestią do rozważenia w przypadku tego, że staje się nudny, być może próbujesz ominąć zbyt wiele stanu. :)
dash-tom-bang
W wielu przypadkach to prawda, ale często tak nie jest. W niektórych domenach potrzebujesz dostępu do wielu stanów, nawet jeśli nie masz wielu stanów zmiennych . Obecnie pracuję nad generatorem kodu, w którym potrzebuję dostępu do kilku tabel symboli. Nie chcę ich przekazywać każdej metodzie.
Jørgen Fogh
8
  • Napisz mniej kodu, który robi więcej.
  • Pomyśl o implikacjach niskiego poziomu i konsekwencjach wysokiego poziomu
  • Zastanów się nad abstrakcją, którą tworzysz w swoim kodzie.
  • Napisz tylko niezbędną złożoność, jeśli to możliwe.
Paul Nathan
źródło
Zamierzałem napisać duży post, który podsumowuje się jako „pisz mniej, co robi więcej” (IOW znam i korzystam z dostępnych narzędzi). Zamiast tego dodam +1.
Kaz Dragon,
1
Uważaj jednak, aby nie uzyskać wymyślnego kodu, próbując uzyskać mniej kodu.
gablin
1
@gablin: pod wieloma względami fantazja jest w oczach patrzącego. Mogę dziś pisać i czytać kod, który byłbym oszołomiony 4 lata temu. Haskell dzisiaj jest dla mnie fantazyjny. :)
Paul Nathan
8

Trochę mniej techniczna odpowiedź: nie programuj, gdy jesteś zmęczony (wystarczy 9 ​​godzin dziennie), pijany lub „upieczony”. Kiedy jestem zmęczony, nie mam wymaganej cierpliwości, aby pisać czysty kod.

Alexandru
źródło
2
Uświadomienie sobie tego zwykle zajmuje większości programistów kilka lat. To ważny punkt.
Jeff Davis,
7

Napisz testy jednostkowe i testy integracyjne .

ysolik
źródło
5

Kilka świetnych odpowiedzi tutaj dotyczących testowania jednostek i narzędzi. Jedyne, co mogę do nich dodać, to:

Zaangażuj testerów jak najwcześniej

Jeśli masz zespół testowy, nie wpadnij w pułapkę traktowania ich jako strażników jakości kodu i wyłapywania błędów. Zamiast tego pracuj z nimi i zaangażuj ich jak najwcześniej (w projektach zwinnych będzie to od samego początku projektu, ale zawsze możemy znaleźć sposoby na zaangażowanie ich wcześniej, jeśli naprawdę spróbujemy).

  • Dowiedz się, jaki jest ich plan testów. Przejrzyj z nimi ich przypadki testowe - czy pokrywasz je wszystkie swoim kodem?
  • Zapytaj ich o zrozumienie wymagań. Czy to to samo co twoje?
  • Daj im wczesne wersje robocze do testowania eksploracyjnego - będziesz zaskoczony ulepszeniami, które zasugerują.

Utrzymywanie dobrych relacji roboczych z testerami oznacza, że ​​można wcześnie wychwycić złe założenia i wady, zanim mogą wyrządzić jakąkolwiek szkodę. Oznacza to również, że testerzy czują się upoważnieni do pomocy w projektowaniu produktu i wychwycenia problemów z użytecznością, gdy jest czas, aby je naprawić.

Paddyslacker
źródło
4

Narzędzia analizy statycznej

Wtyczki i aplikacje, takie jak FindBugs, indeksują kod i znajdują miejsca, w których występują potencjalne błędy. Miejsca, w których zmienne nie są inicjowane i używane lub po prostu szalone rzeczy, które 9 razy na 10, ułatwiają powstawanie błędów. Takie narzędzia pomagają mi zapobiegać przemieszczaniu się mojego kośćca po drodze, nawet jeśli nie jest to jeszcze błąd.

PS: Pamiętaj, aby zawsze badać, dlaczego narzędzie mówi ci, że coś jest nie tak. Nigdy nie boli się uczyć (i nie wszystko jest właściwe we wszystkich sytuacjach).

Ryan Hayes
źródło
3

Kontrola kodu lub inne formy wzajemnej oceny, takie jak programowanie par.

Przeglądy kodu strukturalnego, takie jak inspekcja Fagana, mogą być co najmniej tak samo skuteczne i wydajne jak testy jednostkowe, aw niektórych przypadkach okazały się nawet lepsze niż testy jednostkowe. Inspekcje mogą być również używane wcześniej w cyklu życia oprogramowania i z artefaktami innymi niż kod.

Recenzja autorstwa Karla Wiegera to świetna książka na ten temat.

Michał
źródło
2

Oprócz wszystkich innych sugestii tutaj włącz wszystkie możliwe ostrzeżenia do najwyższego poziomu czułości i traktuj je jako błędy. Użyj także wszelkich narzędzi do szarpania, które posiada język.

Byłbyś zaskoczony , jak wiele prostych błędów może zostać złapany przez ostrzeżeń i ile z tych prostych rzeczy przekładają się na rzeczywistych błędów w kodzie.

greyfade
źródło
2

Wiele dobrych odpowiedzi tutaj, ale kilka rzeczy, które chciałem dodać. Upewnij się, że faktycznie rozumiesz wymaganie. Widziałem wiele błędów, gdy użytkownik uważał, że wymaganie oznaczało X, a programista uważał, że oznaczało to Y. Odsuń się, aby uzyskać wyjaśnienie dotyczące złych lub niejednoznacznych wymagań. Wiem, że wszyscy lubimy wskakiwać i kodować, ale im więcej czasu poświęcisz na zrozumienie, tym mniej przeróbek i poprawek.

Zapoznaj się z działalnością, którą wspierasz, często widzisz rzeczy w brakujących wymaganiach lub potrzebujesz dalszych wyjaśnień. Wiedz, że jeśli wykonasz zadanie Y, jak stwierdzono, spowoduje to uszkodzenie istniejącej funkcji Z.

Poznaj strukturę swojej bazy danych. Wiele błędów jest wynikiem zapytania, które jest poprawne pod względem składniowym, ale zwraca nieprawidłowe wyniki. Dowiedz się, jak rozpoznać, kiedy wyniki wyglądają śmiesznie. Jeśli piszę złożone zapytanie dotyczące raportów, zawsze mam specjalistę technicznego, który sprawdzi moje wyniki, zanim oznaczę je jako gotowe do użycia, nieuchronnie zobaczą coś w danych, które przegapiłem. Następnie zanotuj sobie, co złapali, czego nie złapałeś, i pamiętaj, że następnym razem zrobisz coś podobnego.

HLGEM
źródło
1

Myślę, że najważniejszą techniką jest nie spiesz się . Jeśli uważasz, że potrzebujesz dwóch dni na kodowanie nowego modułu, ale szef zmusza Cię do kodowania tylko w jeden dzień ... Twój kod będzie prawdopodobnie bardziej wadliwy.

Jedna z książek, które czytałem jakiś czas temu, mówi, że nie powinieneś żyć z rozbitymi oknami , ponieważ ludzie nie będą się przejmować, jeśli ktoś się zepsuje ... Kodowanie jest takie samo, każdy będzie dbał o to, że jako pierwszy zrobi coś złego ale szybko , ale nikomu nie zależy na jednym piekle , z mnóstwem błędów i bardzo złym wyglądem i stylem.

greuze
źródło
1

Postępuję zgodnie z praktyką Test-Code-Test zamiast Code-test-code-test. Pomaga mi to myśleć o przypadkach użycia i odpowiednio ułożyć logikę

viv
źródło
1

Użyj narzędzi kontroli kodu, takich jak ReSharper lub IDE, takich jak IntelliJ IDEA, które ostrzegają przed wieloma błędami kopiowania i wklejania oraz innymi, np. Wskazując zmienne, które „są zapisywane, ale nigdy nie czytają”. Zaoszczędził mi dużo czasu.

DonJoe
źródło
1

Co zaskakujące, nie wymieniono jeszcze trzech bardzo ważnych punktów:

  • Używaj twierdzeń swobodnie. Pytanie, na które powinieneś zawsze zadawać sobie pytanie, nie brzmi „czy powinienem to twierdzić?” ale „czy jest coś, o czym zapomniałem twierdzić?”

  • Wybierz niezmienność. (Używaj ostatecznego / tylko do odczytu swobodnie). Im mniej zmienny masz stan, tym mniej rzeczy może pójść nie tak.

  • Nie optymalizuj przedwcześnie. Wielu programistów śledzi problemy związane z wydajnością, co powoduje, że niepotrzebnie zwijają swój kod i dręczą swoje projekty, nie wiedząc nawet wcześniej, czy wydajność będzie problemem. Po pierwsze, zbuduj oprogramowanie w sposób akademicki, bez względu na wydajność; następnie sprawdź, czy działa słabo; (Prawdopodobnie nie będzie.) Jeśli występują jakiekolwiek problemy z wydajnością, znajdź jedno lub dwa miejsca, w których możesz zapewnić ładne i formalne optymalizacje algorytmiczne, które sprawią, że Twój produkt spełni wymagania dotyczące wydajności zamiast ulepszania i hakowania całej bazy kodu, aby wycisnąć cykle zegara tu i tam.

Mike Nakis
źródło