Wydaje się, że większość ludzi traktuje debugowanie raczej jako sztukę niż naukę. Dla tych, którzy traktują to jako naukę, a nie sztukę - jakich procesów zwykle używasz w obliczu nowego problemu / błędu / problemu?
Wydaje się, że większość ludzi traktuje debugowanie raczej jako sztukę niż naukę. Dla tych, którzy traktują to jako naukę, a nie sztukę - jakich procesów zwykle używasz w obliczu nowego problemu / błędu / problemu?
Odpowiedzi:
Mówiąc bardzo ogólnie, robię to:
Spróbuj wyizolować problem. Pomyśl, co się zmieniło, gdy błąd pojawił się po raz pierwszy. Nad czym pracujesz? Którą część kodu zmieniłeś? 99% moich błędów jest rozwiązanych w ten sposób. Zwykle jest to coś głupiego.
Jeśli zgaduję, gdzie jest problem, przyjrzyj się kodowi, który wydaje się być przyczyną. Przeczytaj to. Przeczytaj to nawet na głos. Zadaj sobie pytanie: „Co próbuję osiągnąć?”. W przypadku niektórych rodzajów problemów: czy może to mieć jakieś skutki uboczne lub może mieć wpływ na kod w innym miejscu w sposób, o którym nie myślałem?
Spróbuj na różne sposoby przeanalizować, co pójdzie nie tak, gdzie i kiedy (patrz poniżej).
Jeśli nadal nie mam pojęcia, sprawdzam, czy starsza wersja mojego źródła ma ten sam problem, spróbuj znaleźć, kiedy na osi czasu programowania pojawił się problem. Aby to zrobić, musisz pracować z dobrym systemem kontroli wersji, takim jak git (git ma funkcję bisect właśnie do tego rodzaju debugowania).
Jeśli nadal nie masz pojęcia, zrób sobie przerwę ... to naprawdę często pomaga.
Wróć do tablicy kreślarskiej - sprawdź, jak powinien działać Twój program i czy ma to sens.
To naprawdę zależy od rodzaju problemu, ale zakładając, że mam ogólne pojęcie o tym, gdzie może być problem, to:
Jeśli podejrzewam, że problem dotyczy jakiejś części kodu / ostatniej zmiany, próbuję najpierw usunąć / skomentować / zmienić lub cokolwiek innego, aby błąd zniknął, upraszczając kod, a następnie przywróć problematyczny kod i weź dobrze na to spojrzeć.
Uruchom debugger z punktami przerwania (jeśli to w ogóle możliwe) i spójrz na to, jak wyglądają moje dane, które próbują znaleźć, kiedy zaczyna działać źle, aby uzyskać lepszy obraz tego, co się dzieje.
bzr qdiff
polecenia.
Staram się używać programowania opartego na testach ( TDD ). Piszę test, który replikuje błąd, a następnie próbuję go zaliczyć. Czasami pisanie testu pomaga znaleźć błąd.
To przez większość czasu utrzymuje mnie z dala od debuggera i zapewnia testy regresji, aby zapobiec ponownemu wprowadzeniu błędu.
Niektóre linki:
Istnieje wiele definicji słowa nauka, ale brzmi to tak, jakbyś miał na myśli to, co może być dokładniej nazwane „ metodą naukową ”. Metodę naukową można podsumować jako obserwowanie niektórych zjawisk (prawdopodobnie błąd lub nieoczekiwane zachowanie programu), formułowanie hipotezy lub hipotez wyjaśniających zachowanie oraz najbardziej prawdopodobne eksperymentowanie w celu udowodnienia tego (napisanie testu, który rzetelnie odtwarza problem).
Rodzaje błędów (zjawisk), które mogą wystąpić, są praktycznie nieograniczone, a niektóre niekoniecznie wymagają dobrze zdefiniowanego procesu. Na przykład czasami widzisz błąd i od razu wiesz, co go spowodowało, ponieważ dobrze znasz kod. Innym razem wiesz, że przy pewnych danych wejściowych (akcja, seria kroków itp.) Następuje niepoprawny wynik (awaria, złe wyjście itp.). W takich przypadkach często nie wymaga dużo „naukowego” myślenia. Pewna myśl może pomóc w ograniczeniu przestrzeni wyszukiwania, ale powszechną metodą jest po prostu przejście przez kod w debuggerze i zobaczenie, co poszło nie tak.
Jednak sytuacje, które uważam za najciekawsze i być może godne procesu naukowego, są związane z ostatecznym rezultatem i poproszeniem o wyjaśnienie, jak to się stało. Oczywistym przykładem jest zrzut awaryjny. Możesz załadować zrzut awaryjny i obserwować stan systemu, a Twoim zadaniem jest wyjaśnienie, jak dostał się w tym stanie. Zrzut awarii (lub rdzenia) może pokazywać wyjątek, zakleszczenie, błąd wewnętrzny lub jakiś „niepożądany” stan zdefiniowany przez użytkownika (np. Powolność). W takich sytuacjach na ogół wykonuję następujące kroki:
Wąska obserwacja : w razie potrzeby zapoznaj się z informacjami bezpośrednio dotyczącymi konkretnego problemu. Oczywiste są tutaj stos wywołań, lokalne zmienne, jeśli je widać, linie kodu otaczające problem. Ten rodzaj badania konkretnego miejsca nie zawsze ma zastosowanie. Na przykład badanie „powolnego” systemu może nie mieć takiej oczywistej lokalizacji początkowej, ale awaria lub błąd wewnętrzny prawdopodobnie będzie miał natychmiastowy i oczywisty cel. Jednym konkretnym krokiem może być użycie narzędzi takich jak windbg (uruchom! Analizuj -v na załadowanym zrzutu awaryjnym i spójrz na to, co ci mówi).
Szeroka obserwacja : przestudiuj inne części systemu. Sprawdź stan wszystkich wątków w systemie, spójrz na dowolne informacje globalne (liczba użytkowników / operacji / pozycji, aktywnych transakcji / procesów / widżetów itp.), Informacje o systemie (OS) itp. Jeśli użytkownik podał jakieś dane zewnętrzne , pomyśl o tych w połączeniu z tym, co zaobserwowałeś. Na przykład, jeśli powiedzieli ci, że problem występuje w każdy wtorek po południu, zadaj sobie pytanie, co to może znaczyć.
Hipoteza: To jest naprawdę zabawna część (i nie żartuję z tego, że jest zabawna). Często wymaga to dużo logicznego myślenia w odwrotnej kolejności. Myśl o tym, jak system wszedł w obecny stan, może być bardzo przyjemna. Podejrzewam, że jest to część, którą wielu ludzi uważa za sztukę. I przypuszczam, że może być tak, że programista po prostu zacznie losowo rzucać w nią rzeczami, aby zobaczyć, co się trzyma. Ale z doświadczeniem może to być dość dobrze zdefiniowany proces. Jeśli w tym momencie myślisz bardzo logicznie, często można zdefiniować możliwe zestawy ścieżek, które doprowadziły do danego stanu. Wiem, że jesteśmy w stanie S5. Aby tak się stało, S4a lub S4b musiały wystąpić, a może S3 przed S4a itp. Częściej nie, może istnieć wiele elementów, które mogą prowadzić do danego stanu. Czasami pomocne może być zapisanie na notatniku prostego schematu przepływu lub stanu lub szeregu kroków związanych z czasem. Rzeczywiste procesy tutaj będą się znacznie różnić w zależności od sytuacji, ale poważne przemyślenia (i ponowne zbadanie w poprzednich krokach) w tym czasie często dostarczą jednej lub więcej wiarygodnych odpowiedzi. Zauważ też, że niezwykle ważną częścią tego kroku jest wyeliminowanie rzeczy niemożliwych. Usunięcie niemożliwego może pomóc przyciąć przestrzeń rozwiązania (pamiętaj, co Sherlock Holmes powiedział o tym, co pozostało po wyeliminowaniu niemożliwego). Zauważ też, że niezwykle ważną częścią tego kroku jest wyeliminowanie rzeczy niemożliwych. Usunięcie niemożliwego może pomóc przyciąć przestrzeń rozwiązania (pamiętaj, co Sherlock Holmes powiedział o tym, co pozostało po wyeliminowaniu niemożliwego). Zauważ też, że niezwykle ważną częścią tego kroku jest wyeliminowanie rzeczy niemożliwych. Usunięcie niemożliwego może pomóc przyciąć przestrzeń rozwiązania (pamiętaj, co Sherlock Holmes powiedział o tym, co pozostało po wyeliminowaniu niemożliwego).
Eksperyment : na tym etapie spróbuj odtworzyć problem na podstawie hipotez wyprowadzonych w poprzednim kroku. Jeśli poważnie pomyślałeś w poprzednim kroku, powinno to być bardzo proste. Czasami „oszukuję” i modyfikuję bazę kodu, aby pomóc w danym teście. Na przykład ostatnio badałem wypadek, który doszedłem do wniosku, że był spowodowany wyścigiem. Aby to zweryfikować, po prostu umieszczam Sleep (500) między kilkoma liniami kodu, aby pozwolić innym wątkom na wykonanie swoich złych rzeczy we „właściwym” czasie. Nie wiem, czy jest to dozwolone w „prawdziwej” nauce, ale jest to całkowicie uzasadnione w kodzie, który posiadasz.
Jeśli uda ci się go odtworzyć, masz duże szanse, że już prawie skończyłeś (pozostaje ci tylko prosty krok, aby to naprawić ... ale to na kolejny dzień). Pamiętaj, aby sprawdzić nowy test w systemie testów regresji. I powinienem zaznaczyć, że moim zdaniem poprzednie oświadczenie o naprawieniu było proste, by mówić z przymrużeniem oka. Znalezienie rozwiązania i jego wdrożenie może wymagać intensywnej pracy. Moim zdaniem naprawienie błędu nie jest częścią procesu debugowania, ale raczej rozwojem. A jeśli poprawka jest w ogóle zaangażowana, powinna ona wymagać pewnego projektu i przeglądu.
Spróbuj zmniejszyć przypadek testowy. Gdy jest wystarczająco mały, zwykle łatwiej jest znaleźć odpowiedni kod, który powoduje problem.
Prawdopodobnie przyczyną problemu jest nowe zameldowanie, a poprzednia codzienna kompilacja była w porządku. W takim przypadku Twój dziennik zmian z kontroli źródła powinien pomóc ci zdecydować, kogo złapać.
Ponadto, jeśli jesteś w C / C ++, rozważ uruchomienie valgrind lub oczyść, aby wyodrębnić problemy związane z pamięcią.
Najtrudniejszą częścią debugowania jest izolacja problemu, szczególnie gdy problem jest ukryty pod kilkoma warstwami. Na studiach studiowałem nagrywanie muzyki i, o dziwo, istniała klasa Studio Electronics, która bezpośrednio dotyczy tutaj. Wykorzystam debugowanie środowiska studyjnego jako ilustrację systematycznego procesu debugowania.
Kod debugujący naprawdę nie jest taki inny. Debugowanie jest znacznie łatwiejsze, gdy kod zgłasza wyjątek. Możesz prześledzić wstecz od śledzenia stosu tego wyjątku i ustawić punkty przerwania w kluczowych pozycjach. Zwykle zaraz po ustawieniu zmiennej lub w linii wywołującej metodę zgłaszającą wyjątek. Może się okazać, że co najmniej jedna wartość jest nieprawidłowa. Jeśli to nie jest poprawne (zero, gdy nie powinno być lub wartość jest poza zakresem), to jest to proces odkrywania, dlaczego to nie jest poprawne. Punkty przerwania w IDE są równoważne elektronicznym punktom testowym (zaprojektowanym dla sondy miernika do sprawdzenia obwodu).
Teraz, kiedy przejdę tę trudną część odkrywania, gdzie jest mój prawdziwy problem, napiszę kilka testów jednostkowych, aby sprawdzić to w przyszłości.
Bardziej praktyczne podejście:
Jeśli błąd jest związany z nieobsługiwanym wyjątkiem - spójrz na ślad stosu. Najczęstsze jest odwołanie zerowe, indeks poza zakresem itp. Oraz własne zdefiniowane wyjątki. Możesz przypisać ten błąd do młodszego programisty, jest to prawdopodobnie łatwe i dobre doświadczenie w nauce.
Jeśli nie zdarza się to na każdej maszynie, jest to prawdopodobnie problem z wyścigiem / problem z wątkami. To super zabawa, aby wyśledzić, umieść na nim swojego znudzonego starszego programistę. Udało się to dzięki wielu logom, dobrej wiedzy i dobrym narzędziom.
Inną dużą klasą błędów jest to, że zespół testowy lub klienci nie lubią określonego zachowania. Na przykład nie podoba im się to, że decydujesz się na wyświetlanie identyfikatorów użytkowników lub że podczas wyszukiwania nie otrzymujesz autouzupełniania. Są to prawdziwe błędy, rozważ lepsze zarządzanie produktem i deweloperów z szerszym spojrzeniem. Naprawienie tego powinno zająć deweloperowi stosunkowo krótki czas, jeśli zbuduje system z myślą o rozbudowie.
80% wszystkich innych błędów można rozwiązać, mając dobre systemy logowania i gromadząc wystarczającą ilość informacji, aby je rozwiązać. Użyj wbudowanego śledzenia z wieloma poziomami złożonych systemów rejestrowania, takich jak Log4Net / Log4J
błędy wydajności są kategorią samą w sobie, zasada Goldera brzmi: „zmień najpierw, napraw później!”, a zdziwisz się, ilu programistów zgadnie, gdzie jest problem, i od razu zajmie się naprawą, aby zobaczyć później jedynie o 3-4% skrócenie czasu odpowiedzi.
Mam dwa podejścia:
Divide and Conquer
Paradygmatem.Takie podejście pomogło mi przez większość czasu.