Czy jest możliwe osiągnięcie bezwzględnego stanu zerowego błędu dla oprogramowania na dużą skalę?

71

Mówię na przykład o ponad 20-30 milionach linii kodu, na przykład oprogramowania w skali i złożoności programu Autodesk Maya.

Jeśli zamrozisz programowanie tak długo, jak to konieczne, czy rzeczywiście możesz naprawić wszystkie błędy, dopóki po prostu nie będzie ani jednego błędu, jeśli coś takiego można zweryfikować komputerowo? Jakie są argumenty za i przeciw istnieniu systemu wolnego od błędów?

Ponieważ istnieje pewne pojęcie, że każda poprawka powoduje więcej błędów, ale nie sądzę, że to prawda.

Przez błędy miałem na myśli od najprostszych literówek w interfejsie użytkownika, do poważniejszych błędów zapobiegawczych, które nie mają obejścia. Na przykład określona funkcja skryptowa niepoprawnie oblicza wartości normalne. Nawet jeśli istnieją obejścia, problem nadal musi zostać rozwiązany. Można więc powiedzieć, że można wykonać tę konkretną czynność ręcznie zamiast korzystać z dostarczonej funkcji, ale ta funkcja wciąż musi zostać naprawiona.

Joan Venge
źródło
11
„zostało powiedziane przez kilku czołowych programistów” - nie brzmią dla mnie jak najlepsi programiści. Brzmią jak najlepsi hakerzy. Jedną z PODSTAWOWYCH OBOWIĄZKÓW programisty jest zrozumienie, co robi ich kod i jak wpływa na system jako całość. Dlatego mamy TDD, wzorce projektowe itp. Jeśli nie można tego zrobić, system jest śmieciowy - proces rozwoju został przeprowadzony w chaotyczny, przypadkowy, niezdyscyplinowany, nienaukowy sposób.
Wektor
51
Jeśli jeszcze nie wiesz, że błąd istnieje, to czy nadal jest to błąd?
Blrfl 21.04.13
5
@Blrf: Co ważniejsze, jeśli użytkownik końcowy nie wie o błędzie, czy istnieje?
mattnz 21.04.2013
40
„Istnieją dwa sposoby konstruowania projektu oprogramowania. Jednym ze sposobów jest uczynienie tego tak prostym, że oczywiście nie ma braków. Innym sposobem jest uczynienie go tak skomplikowanym, aby nie było żadnych oczywistych braków ”. - CAR Hoare
Andrew Lewis
5
Tak jest, ale wiele osób nie chce kwestionować swoich podstawowych przekonań.
Joan Venge

Odpowiedzi:

92

Jak wspomniał Mikey, pisanie bezbłędnego kodu nie jest celem. Jeśli o to właśnie dążysz, mam dla ciebie bardzo złe wieści.

Kluczową kwestią jest to, że nie doceniasz złożoności oprogramowania.

Po pierwsze - ignorujesz większy obraz działania programu. Nie działa w izolacji na idealnym systemie. Nawet najbardziej podstawowe programy „Hello World” działają w systemie operacyjnym, dlatego nawet najprostsze programy są podatne na błędy, które mogą występować w systemie operacyjnym.

Istnienie bibliotek czyni to bardziej złożonym. Podczas gdy systemy operacyjne wydają się być dość stabilne, biblioteki są mieszane, jeśli chodzi o stabilność. Niektóre są cudowne. Inne ... nie tak bardzo ... Jeśli chcesz, aby Twój kod był w 100% wolny od błędów, musisz także upewnić się, że każda biblioteka, z którą korzystasz, jest całkowicie wolna od błędów, a wiele razy po prostu nie jest to możliwe, ponieważ możesz nie mieć kodu źródłowego.

Następnie są wątki do przemyślenia. Większość programów na dużą skalę używa wątków w dowolnym miejscu. Staramy się być ostrożni i piszemy wątki w taki sposób, aby nie występowały warunki wyścigu i impas, ale po prostu nie jest możliwe przetestowanie każdej możliwej kombinacji kodu. Aby przetestować to skutecznie, należy sprawdzić każdą możliwą kolejność poleceń przechodzących przez procesor. Nie zrobiłem matematyki na tym, ale podejrzewam, że wyliczenie wszystkich możliwych gier w szachy byłoby łatwiejsze.

Sprawy stają się trudne do niemożliwych, gdy spojrzymy na samą maszynę. Procesory nie są idealne. Pamięć RAM nie jest idealna. Dyski twarde nie są idealne. Żaden z elementów w maszynie nie został zaprojektowany tak, aby był idealny - są one zaprojektowane jako „wystarczająco dobre”. Nawet idealny program ostatecznie zawiedzie z powodu czkawki ze strony maszyny. Nic nie możesz zrobić, aby to zatrzymać.

Konkluzja: Czy możesz napisać „Bug free software”?

NIE

Każdy, kto mówi ci inaczej, nie ma pojęcia.

Po prostu spróbuj napisać oprogramowanie, które jest łatwe do zrozumienia i utrzymania. Gdy to zrobisz, możesz nazwać to dniem.


EDYCJA: Niektóre osoby komentowały doskonały punkt, który całkowicie przeoczyłem: kompilator.

O ile nie piszesz w asemblerze, jest całkiem możliwe, że kompilator zepsuje twój kod (nawet jeśli udowodnisz, że kod jest „idealny”).

Lista błędów w GCC, jednym z najczęściej używanych kompilatorów: http://gcc.gnu.org/bugzilla/buglist.cgi?product=gcc&component=c%2B%2B&resolution=---

riwalk
źródło
8
Odpowiedź nadal brzmi „nie”, ponieważ zawsze będą „błędy”, w których coś działa - po prostu nie tak, jak klient lub właściciel produktu chciałby, aby to działało. Niektórzy z nas mogą nazywać te prośby o funkcje lub prośby o zmianę zachowania lub dodanie funkcjonalności - ale dla osoby, która jest denerwowana przez jakiś „błąd” każdego dnia, rzeczą, która ich denerwuje, jest błąd. (To długa droga do powiedzenia, że ​​niektóre błędy są w oku patrzącego.) BEZ BŁĘDÓW KOD jest niemożliwy. Celuj w kod, który jest wystarczająco dobry, aby osiągnąć zamierzony cel.
szybko_niedz
6
Pójdę o krok dalej: kod może mieć ukryte defekty, na przykład możesz mieć kod, który nie ma właściwego zasięgu, sprawdź dane wejściowe. Jeśli dane wejściowe z jakiegoś szczęśliwego powodu nigdy nie są poza zasięgiem, błąd nigdy się nie ujawnia. Pewnego dnia podczas prac konserwacyjnych lub zmian funkcji ten fragment kodu jest wywoływany z innego miejsca, które NIE WYKORZYSTUJE go z wartością spoza zakresu. Błąd teraz się objawia - ale był tam cały czas. Możesz mieć w tym wszystkim szaleństwo - ale wyeliminowanie każdej możliwości zła jest nadal niemożliwe.
szybko_niedz
11
@ JohnR.Strohm Nie jestem pewien, dlaczego uważasz, że program „modulatora przepływu komunikatów”, program z 556 liniami kodu, ma coś wspólnego z pytaniem dotyczącym teoretycznego systemu 20 milionów linii. Być może z wyjątkiem wykazania, że ​​jakkolwiek trudno było udowodnić poprawność małego programu, astronomicznie trudniej byłoby udowodnić poprawność ogromnego programu.
Eric King
9
Chociaż pierwotne pytanie tego nie uczyniło, chciałbym zauważyć, że istnieje gigantyczna różnica między „teoretycznie możliwym” a „praktycznie możliwym”. Chociaż bezbłędna baza kodów o wartości 20 milionów wierszy jest prawdopodobnie teoretycznie możliwa, prawie na pewno jest to praktycznie niemożliwe na dzisiejszym rynku. Kto wie, co przyniesie przyszłość.
Eric King
4
@ JohnR.Strohm Powinieneś przeczytać artykuł uważniej. Mówią sami: It is important to note, however, that even all of these steps provide no guarantee of absolute security. It is tempting to believe that a formally specified and proved program should be absolutely correct, but there are several reasons why a proved program may not behave exactly as expected.co oznacza, że ​​nie można udowodnić, że jest wolny od błędów, ale raczej nie ma błędów. Raczej jak TDD.
Izkata,
27

Matematycznie MOGĄ być możliwe napisanie „bezbłędnego” oprogramowania o takiej złożoności, w zależności od tego, jak zdefiniujesz „błąd”. Udowodnienie, że MOŻE być również matematycznie możliwe, poprzez zaprojektowanie systemu testowego, który wykonywałby każdą linię kodu w każdy możliwy sposób - każdy możliwy przypadek użycia. Ale nie jestem pewien - jeśli masz do czynienia z systemem wykonującym złożone obliczenia, możesz napotkać „problem nieskończoności” ...

Praktycznie rzecz biorąc, w systemie wielkości i zakresu, o którym mówisz, jest to NIEMOŻLIWE . Napisanie takiego „wolnego od błędów” systemu może zająć 1000 lat i napisać system, który udowodni, że zajmie to wykładniczo więcej czasu: będziesz musiał wymyślić każdy możliwy przypadek użycia i napisać system, który przetestuje każdy jeden - i nie sądzę, aby można było ustalić, czy rzeczywiście uwzględniono każdy przypadek użycia w systemie o takim rozmiarze i zakresie, o jakim mówisz, w czymkolwiek przypominającym rozsądną ilość czasu.

IMO twoje pytanie jest nieco źle skierowane: Naszym celem jako programistów nie jest pisanie „bezbłędnego” oprogramowania. Naszym celem jest pisanie oprogramowania UŻYTECZNEGO, ELASTYCZNEGO, ŁATWEGO W UTRZYMANIU .

Użyteczny: system spełnia zasadnicze wymagania, dla których został zaprojektowany. Mogą występować błędy - ale będą to „przypadki skrajne” - wartości odstające lub irytujące, a nie błędy, które zagrażają podstawom systemu - solidne.

Konserwowalne: Błędy można łatwo izolować i naprawiać, a NIE tworzyć nowych błędów.

Elastyczność: Twój system można łatwo zmieniać i rozszerzać bez znacznego przeprojektowywania i przestojów: większość zmian wymaga po prostu dodania nowej klasy lub modułu, który pasuje do już i tak dobrze zaprojektowanych wzorców i struktury.

Dobre praktyki projektowe, dobre praktyki kontroli, dobra praca zespołowa, sumienni programiści - taka jest recepta na DOBRE OPROGRAMOWANIE . (nie IDEALNY - ale DOBRY )

Wektor
źródło
3
„Udowodnienie, że MOGĄ być również matematycznie możliwe, poprzez zaprojektowanie systemu testowego, który wykonywałby każdą linię kodu w każdy możliwy sposób - każdy możliwy przypadek użycia.”: Taki program ogólnie nie istnieje (i można to udowodnić!). Tak więc ogólny algorytm dowodzenia poprawności nie istnieje.
Giorgio
3
Korekta: Osiągnięto wolne od błędów oprogramowanie, KOMPLETNE Z FORMALNYM MATEMATYCZNYM DOWODEM POPRAWNOŚCI. Dokonano tego w 1982 r. Google „modulator przepływu komunikatów”.
John R. Strohm,
6
@ JohnR.Strohm: Nie prawda. Oto tylko jeden cytat - jest kilka artykułów i kilka miejsc, w których poruszają podobne obawy: „Często pojawia się pytanie:„ Czy zweryfikowałeś weryfikatora? ”. Być może, co zaskakujące, inżynierowie często zadają to metamatematyczne pytanie nie tylko spiczastemu naukowcy. Oczywiście, jeśli maszyna kiedykolwiek odpowie na pytanie „Czy kiedykolwiek kłamiesz?”, odpowiedź nie będzie bardziej pouczająca niż wtedy, gdy człowiek odpowie na pytanie ”.
Wektor
1
Miałem na myśli, że nie ma ogólnego algorytmu, który działałby dla dowolnego programu wejściowego i dowolnej specyfikacji wejściowej. Możesz obsługiwać tylko określone przypadki (np. Twój przykład).
Giorgio
1
@Giorgio - więc IMO, przestrzeganie dobrych praktyk projektowych jest o wiele ważniejsze niż zajmowanie się poprawnością matematyczną: zaprojektuj swój kod, aby zapewnić jego dobrą integrację i zgodność z tym, co już istnieje - i jest wystarczająco solidny, aby łatwo obsługiwać defekty, gdy wyjdą na jaw (co zrobią).
Wektor
27

Zgodnie z tym artykułem, oprogramowanie pokładowe dla promu kosmicznego zbliżyło się bardzo blisko - w trzech ostatnich wersjach programu linii 420 000 każdy miał tylko jeden błąd. Oprogramowanie było utrzymywane przez grupę 260 mężczyzn i kobiet. Duża liczba tych osób była weryfikatorami, których jedynym celem było znalezienie błędów.

Aktualizacja oprogramowania umożliwiająca wahadłowiecowi nawigację za pomocą satelitów globalnego pozycjonowania wpłynęła tylko na 1,5% programu lub 6 366 linii kodu. Dane techniczne tej jednej zmiany wynosiły 2500 stron. Specyfikacje dla całego programu wypełniały 30 woluminów i zawierały 40 000 stron, czyli średnio dziesięć linii kodu na stronę specyfikacji.

Budżet nie stanowił problemu - przy 35 milionach dolarów rocznie mogli sobie pozwolić na robienie rzeczy dobrze.

tcrosley
źródło
25
Jeden wykryty błąd. Kto wie, ile niewykrytych błędów? :)
Andres F.
8
Ten „jeden błąd” był szczególnym przypadkiem. Shuttle został pierwotnie zaprojektowany i określono oprogramowanie dla dwóch ramion robota. „Błąd” polegał na tym, że nadal był tam kod obsługujący drugie ramię.
John R. Strohm,
4
+1 Przebiegł bez błędów dla 135 misji od 1981 do 2011 r.
MarkJ
5
@MarkJ: prawdopodobnie nie wiedzielibyśmy, czy prom kosmiczny faktycznie nie zawierał błędów. Każda misja promu kosmicznego jest stale monitorowana przez setki osób, a wszelkie błędy w kodowaniu zostałyby ręcznie poprawione / zastąpione.
Lie Ryan
2
@LieRyan Który ładnie pokazuje jedną wielką właściwość solidnych systemów - jeśli nie zawiodą katastrofalnie i zawsze pozwalają na ręczne dostosowanie, możesz zamiast tego użyć nadmiarowych systemów (takich jak te w centrum sterowania). Oczywiście ma to sens tylko wtedy, gdy masz takie nadmiarowe systemy i jeśli naprawdę możesz zapewnić poprawność i spójność. W typowej aplikacji biznesowej awaria często jest lepsza niż działanie w niespójnym stanie - jest to różnica między irytacją a, powiedzmy, wysyłaniem pieniędzy niewłaściwemu facetowi. Lub otrzymywanie pieniędzy bez wysyłania ...
Luaan
15

Zasadniczo nie, ale i tak powinieneś dać z siebie wszystko. Wytłumaczę dlaczego (lub po prostu przeskocz do wniosku, jeśli nie masz wystarczającej cierpliwości)

Rozważ problem tak trywialny jak implementacja wyszukiwania binarnego. Jedna bardzo popularna implementacja zawierała błąd, który pozostawał niewykryty przez około dwie dekady. Jeśli dwadzieścia linii zajmie dwadzieścia lat, aby bezbłędnie było szeroko stosowane, a nawet rzekomo udowodniono, że jest poprawne, czy naprawdę możemy oczekiwać, że wielki program będzie wolny od błędów?

Ile błędów możemy się spodziewać mimo to, że będzie to ogromny program? Znalazłem jedną liczbę: „10 defektów na 1000 linii” (Kod Complete wydanie drugie, strona 517 - posłużyłem się jedynie przykładem, nie podając żadnych danych), co daje nam około 200 000 do 300 000 błędów w twoim oprogramowaniu. Na szczęście mamy sposoby na poprawę jakości programu. Testy jednostkowe, przeglądy kodu i zwykłe testy ręczne są znane z tego, że zmniejszają liczbę błędów. Mimo to liczba nadal będzie wysoka.

Gdybyśmy mogli rozwiązać 95% wszystkich błędów, byłoby to niewiarygodne. A jednak nadal mamy od 10 000 do 15 000 błędów w oprogramowaniu.

Na szczęście, ponieważ oprogramowanie jest powszechnie używane (a zatem szeroko testowane), zostaną znalezione błędy. Stopniowo będziemy otrzymywać mniej błędów. Jednak mniej błędów oznacza również, że pozostałe są trudniejsze do znalezienia - więc nie oczekuj liniowej krzywej w usuwaniu błędów. Kilka ostatnich błędów będzie naprawdę trudnych do znalezienia i może uniknąć wykrycia przez kilka lat (zakładając, że kiedykolwiek zostaną odnalezione).

Wydaje się również, że błędnie zakładasz, że jeśli oprogramowanie się nie zmieni, nie pojawią się żadne nowe błędy. Jeśli oprogramowanie zależy od bibliotek stron trzecich, nowe wersje mogą uszkodzić niektóre funkcje - wprowadzając nowe błędy, mimo że kod aplikacji jest nadal taki sam. Nowe systemy operacyjne mogą również uszkodzić aplikację, która wcześniej działała doskonale (popularny przykład znajduje się w systemie Windows Vista). Rozważ także błędy kompilatora itp.

Nie jest jasne, czy narzędzia sprawdzające kod naprawdę mogą rozwiązać problem błędnego oprogramowania. Z pewnością nie jest możliwe rozwiązanie problemu zatrzymania dla dowolnego programu, ale może być możliwe udowodnienie, że program zachowuje się tak, jak określono ... Ale co wtedy? Być może program sprawdzający ma błąd. Może sama specyfikacja zawiera błąd.

Tak wyraźnie, możemy znacznie zmniejszyć liczbę błędów, ale to naprawdę mało prawdopodobne, że kiedykolwiek dojdziemy do zera.

Ponieważ istnieje pewne pojęcie, że każda poprawka powoduje więcej błędów, ale nie sądzę, że to prawda.

(podkreślenie dodane)

Masz rację. To stwierdzenie jest błędne. Oto przykład:

int main() {
    int x[10];
    x[10] = 8; //Buffer overflow here
    return 0;
}

Teraz naprawmy ten błąd:

int main() {
    int x[11];
    x[10] = 8; //No buffer overflow here
    return 0;
}

Widzieć? Naprawiliśmy błąd i nie wprowadziliśmy żadnych nowych.

Jednak z pewnością poprawne jest, że za każdym razem, gdy naprawisz błąd, ryzykujesz utworzenie nowego, chociaż ryzyko to można zmniejszyć (np. Dzięki testom jednostkowym).

Powiedzmy, że na każde 100 naprawionych przeze mnie błędów przypadkowo wprowadzam nowy. Więc jeśli naprawię 10 000 błędów, wprowadzę 100 nowych błędów. A jeśli naprawię te nowe błędy, wprowadzę jeden błąd. No i co z tego? Program ma teraz 9 999 mniej błędów, więc prawdopodobnie jest lepszy niż był (zakładając, że nowy błąd nie jest 10 000 razy gorszy od poprzednich).

Naprawienie błędu może również ujawnić nowe. Ale te błędy można również naprawić. Jeśli zrobisz wszystko dobrze, w końcu oprogramowanie będzie w lepszym stanie niż się zaczęło.

Kilku najlepszych programistów byłem już stary, że lepiej nie naprawiać wielu błędów z powodu pojęcia, o którym wspomniałem w OP.

To zachowanie jest niedbałe. Jeśli wystąpi błąd i możesz go naprawić. Zrób to. Oczywiście powinieneś zrobić wszystko, aby zapobiec dodawaniu nowych, ale jeśli wprowadzę jeden mały błąd na każde 10 poważnych błędów, które naprawię, nie jest to prawidłowy powód, aby przestać naprawiać błędy. W rzeczywistości jest to dobry powód, aby nadal naprawiać błędy .

Więc mniej błędów naprawisz, mniej błędów wróci do ciebie w przyszłości

Im mniej błędów naprawisz, tym więcej błędów pozostanie w twoim oprogramowaniu, irytując użytkowników. Rzeczywiście, nie „wrócą do ciebie w przyszłości”. Nie wrócą, bo nigdy nie odeszli. Pojęcie „powrotu” jest związane z regresjami. Ponownie możliwe jest zmniejszenie ryzyka regresji.

Niektórych błędów nie można naprawić, ponieważ stały się tak szeroko stosowane, że ludzie zaczęli na nich polegać, a usunięcie błędu spowodowałoby uszkodzenie programu dla tych użytkowników. Zdarza się. Czy jednak w takim przypadku można je uznać za błędy?

Mentalność „napraw błąd, zrób błąd” może być związana z kodem That Horrible Monster - tak nieczytelnym i niemożliwym do utrzymania, że ​​samo dotknięcie go powoduje błędy. Jeśli masz bazę kodu w potworze, być może będziesz musiał najpierw cofnąć potworowanie, zanim cokolwiek zrobisz.

Wreszcie, jeśli jesteś straszny programista, istnieje ryzyko, że coś Ci dotknąć tworzy nowe błędy. To oczywiście denerwuje starszych programistów. Jednak mówiąc: „Nic nie rób. Nie dotykaj niczego. Nawet nie oddychaj”. prawdopodobnie nie jest właściwym sposobem na stworzenie zdrowego środowiska pracy. Edukacja jest lepsza.

Wniosek:

  • Oprogramowanie, które wciąż dostaje mnóstwo nowych funkcji, ale żadnych poprawek nieuchronnie będzie do niczego.
  • Oprogramowanie, które otrzymuje umiarkowaną liczbę nowych funkcji, ale naprawia błędy, ma większą szansę na zastosowanie.
  • Ci, którzy próbują mieć kilka błędów, mają (średnio) mniej błędów niż ci, którym to nie przeszkadza.
  • Nie można oczekiwać, że program w końcu będzie wolny od błędów.
  • Starsi programiści niekoniecznie są kompetentni.
  • Napraw swoje błędy.
  • Zastosuj metodologie, które poprawią jakość twojego oprogramowania.
luiscubal
źródło
+1: sam szukałem przykładu wyszukiwania binarnego, zostałem pobity;) Gdyby 20 linii szeroko dyskutowanego i rozpowszechnianego kodu zawierało błąd przez 20 lat, ile czasu potrzebowałbyś na 20-milionową bazę kodów, która w na co spojrzy kilkadziesiąt zapracowanych ludzi?
scrwtp
Dzięki. Zastanawiam się, czy ten błąd wyszukiwania binarnego (o którym nigdy wcześniej nie słyszałem) jest związany z tym, że ludzie kopiują dużo kodu bez zastanowienia? Także jeśli mamy tyle błędów, które można nawet wymienić, może narzędzia i praktyki, których używamy, nie są optymalne?
Joan Venge,
1
@JoanVenge Cytuję ten przykład, aby pokazać, jak trudne mogą być znalezienie błędów. W tym przypadku wklejanie kopii było właściwie właściwe , ponieważ okazało się, że jest poprawne, a implementacja napisana od podstaw najprawdopodobniej zawiera więcej błędów. Narzędzia i praktyki, z których korzystamy - jako ogólnie branża - z pewnością nie są optymalne. Najlepsze praktyki łatwo zignorować, a złe nawyki łatwo utrzymać. Ostatecznie błędy zawsze będą istnieć, ponieważ ludzie nie są doskonali. Ale możemy zmniejszyć liczbę błędów, robiąc co w naszej mocy i kładąc nacisk na edukację wysokiej jakości.
luiscubal
7
Myślę, że błąd w binarnym kodzie wyszukiwania pokazuje, jak złożone jest to pytanie. Podstawowym błędem w wyszukiwaniu było potencjalne przepełnienie liczby całkowitej w dodatku. Takie „błędy” są wszechobecne, ponieważ większość ludzi opiera się na domniemanym (i czasami niepoprawnym) założeniu, że dane wejściowe nie będą wystarczająco duże, aby spowodować przepełnienie. Czy to naprawdę błąd, czy tylko źle udokumentowana umowa dotycząca interfejsu? Kiedy ostatni raz wybierałeś zakres, sprawdzałeś sumy w liczbach całkowitych lub sprawdzałeś, czy nie ma przepełnienia po fakcie?
Charles E. Grant
4
Twoje przykładowe serwery, aby podkreślić dość oczywistą obserwację na temat języka programowania i jakości narzędzi. Kompilator produktywnej jakości dla solidnego języka powinien odmówić skompilowania pierwszego przykładu, zwracając zamiast tego fatalny błąd kompilacji. To, że skompilowanie takiej obrzydliwości jest nawet MOŻLIWE, mówi ci wszystko, co musisz wiedzieć o jakości tych narzędzi i możliwości ich wykorzystania do dostarczania oprogramowania wolnego od błędów.
John R. Strohm
12

Powody, dla których nie pisano programów wolnych od błędów, są w większości ekonomiczne.

Nie metody matematyczne do udowodnienia poprawności programu. Zostaną wspomniane na kursie informatyki wysokiej jakości. Istnieją specjalnie zaprojektowane języki programowania. Teoretycznie programowanie bez błędów jest możliwe.

Tak, istnieje niedoskonały sprzęt, który może czasami zmienić nieco wartość, ponieważ neutrino wystrzelone z odległej supernowej miliony lat temu właśnie trafiło w twój procesor we właściwym miejscu. Okej, każda teoria ma swoje założenia i abstrakcje. Ale zakładając, że procesor działa zgodnie z reklamą, istnieją narzędzia matematyczne, które zapewniają, że program również działa poprawnie.

Niektóre wysoko głosowane odpowiedzi w tym temacie wprowadzają w błąd. Na przykład, twierdzenie Gödela o niekompletności i problem zatrzymania sugerują tylko, że nie możesz mieć np. Zautomatyzowanego narzędzia, które decydowałoby o poprawności lub nieprawidłowości dowolnego programu. Ale nie chcemy decydować o poprawności żadnego programu, chcemy jedynie dowód poprawności jednego konkretnego programu.

(Analogicznie, tylko dlatego, że nie można napisać programu do automatycznego rozstrzygania prawdziwości dowolnego twierdzenia matematycznego, nie oznacza to, że nie można udowodnić jednego konkretnego twierdzenia matematycznego.)

Problem polega na tym, że:

Chociaż teoretycznie możliwe jest napisanie programu wolnego od błędów, zrobienie tego byłoby bardzo kosztowne . Pisanie kodu z dowodem jego poprawności jest bardziej skomplikowane niż rzucanie czymś w ścianę i sprawdzanie, czy się przylega. Nawet jeśli „sprawdzenie, czy się przyklei” odbywa się za pomocą testów jednostkowych; a wielu programistów nawet się tym nie przejmuje. Większość programistów nawet nie wiedziałaby, jak to zrobić, co oznacza, że ​​jako firma musiałabyś zatrudnić droższe.

Biorąc pod uwagę wszystkie koszty, typowy klient jest bardziej zadowolony z taniego oprogramowania, które działa dobrze przez 99% czasu (i 99,9% czasu po zainstalowaniu dodatkowych aktualizacji), niż z posiadania prawdopodobnie tysiąc razy droższego oprogramowania, które działa dobrze 100% czas. Ponadto klient chce mieć to oprogramowanie teraz , a nie za dziesięć lub dwadzieścia lat.

Dlatego ludzie świadomie produkują oprogramowanie, które ma pewną szansę na błędy, próbując znaleźć optymalną kombinację, w której błędy nie są zbyt częste i nie są zbyt poważne, a produkcja jest wystarczająco szybka i wystarczająco tania. Połączenie, które zapewnia największy zysk w prawdziwym życiu. (Czasami oznacza to nawet wydanie oprogramowania pełnego błędów, zanim konkurenci wypuszczą cokolwiek, i wydanie bardziej przyzwoitej wersji 2.0, gdy konkurenci są gotowi do wydania pierwszej przyzwoitej wersji.)

Jeśli zamrozisz programowanie tak długo, jak to konieczne, czy rzeczywiście możesz naprawić wszystkie błędy, dopóki po prostu nie będzie ani jednego błędu, jeśli coś takiego można zweryfikować komputerowo?

Z matematycznego punktu widzenia mógłbyś. Z ekonomicznego punktu widzenia, dlaczego ktoś miałby to zrobić? Oznaczałoby to wydać może dwadzieścia lat i kilka milionów dolarów. Tymczasem klienci chcieliby nowych funkcji, a zamrożone aplikacje nie mogłyby ich udostępnić. W momencie, gdy Twoja idealna wersja jest gotowa, rynek jest już zajęty przez twoich konkurentów.

Ekonomiczne uzasadnienie jest w porządku. Żyjemy w świecie, w którym liczą się pieniądze i czas. Ale tylko dlatego, że nie robimy czegoś z powodów ekonomicznych, nie powinniśmy mówić bzdur o tym, jak tego nie da się zrobić nawet w teorii. Kto wie ... może za kilka lat będziemy mieli kilka nowych języków i narzędzi programistycznych, które mogłyby spowodować poprawność dowodząc łatwe .

Viliam Búr
źródło
Dzięki, chociaż chciałbym, aby większość oprogramowania działała w 99% przypadków, większość dużych, których używam, jak ta w OP, jest bardzo wadliwa. Ale myślę, że monopol i kupujący konkurenci również biorą w tym udział. Ale rozumiem twój punkt widzenia.
Joan Venge
1
„Drogi” jest względny. Porównaj koszty znalezienia i usunięcia błędów z kosztem np. Radioterapii zabijającej kilku pacjentów i okaleczającej kilku innych. (Google „Therac 25”.)
John R. Strohm,
6

Nie.

David Hilbert zaproponował swój drugi problem matematyki w 1900 roku, który zasadniczo poprosił świat o udowodnienie, że arytmetyka działa zgodnie z przeznaczeniem. Później zaproponował „ Entscheidungsproblem ”, który zadał coś podobnego pod względem logicznym. „ Pierwsze twierdzenie Kurta Gödela ” udowodniło w 1931 r., Że żadna teoria elementarnej arytmetyki nie może być zarówno spójna, jak i kompletna. Przedstawienie Entscheidungsproblem Alana Turinga jako „ problemu zatrzymania ” przeniosło kwestię prosto do sedna tego pytania, gdzie udowodnił, że nie można udowodnić, czy program zostanie ukończony, czy nie. Biorąc pod uwagę tę nierozstrzygalność, nie można również udowodnić, czy program ma jakieś błędy, czy nie.

Nic z tego nie uwalnia praktykujących programistów wśród nas od dążenia do braku błędów. Oznacza to po prostu, że ogólnie nie możemy odnieść sukcesu.

Ross Patterson
źródło
9
Nierozstrzygalność dotyczy tylko ogólnie - istnieją programy, dla których nie można udowodnić ani poprawności, ani niepoprawności. Ale dla danego programu często można udowodnić poprawność (lub częściej: nieprawidłowość). Zakłada się, że masz formalną specyfikację języka i sprawdzalny kompilator - ten drugi nie istnieje dla żadnego języka programowania wysokiego poziomu, chociaż CompCert jest blisko.
Daniel
+1 za cytowanie odpowiedniego tła teoretycznego. Nie wiedziałem jeszcze, że „Entscheidungsproblem” nazywa się tak samo po angielsku, jak po niemiecku!
Peopleware
5
Zgadzam się z Danielem. Wyzwanie dotyczy jednej instancji; problemy z zatrzymaniem dotyczą wszystkich możliwych przypadków. Trywialnie int main() { return 0; } zatrzymuje się i jest wolny od błędów.
MSalters
1
Problem zatrzymania nie mówi, że nie można udowodnić, czy program będzie działał do końca; mówi, że istnieją programy, dla których nie można udowodnić. Zwykłe codzienne programy nie są w tej klasie. „Chociaż dowód Turinga pokazuje, że nie może istnieć ogólna metoda lub algorytm pozwalający ustalić, czy algorytmy się zatrzymują, poszczególne przypadki tego problemu mogą być bardzo podatne na atak. Biorąc pod uwagę konkretny algorytm, często można wykazać, że musi on zostać zatrzymany dla dowolnego wkładu, a w rzeczywistości informatycy często robią to tylko jako część dowodu poprawności ”.
endolith,
6

Errare humanum est

Nawet jeśli piszesz kod w języku formalnym, takim jak metoda B , którego możesz użyć do matematycznego udowodnienia, że ​​wymagania są spełnione,

Nawet jeśli używasz formalnego języka specyfikacji,

Zawsze jest ludzki krok polegający na wydobyciu potrzeb użytkownika z jednego lub więcej mózgów na komputer.

Ten ludzki krok jest podatny na błędy, a robak jest w jabłku.

mouviciel
źródło
1
Czy nadal występuje błąd, gdy program wykonuje to, o co pytano, zamiast tego, co było zamierzone?
MSalters
Myślę, że to jest ...
Joan Venge
4
@MSalters - Oczywiście, że tak. Nie z umownego punktu widzenia, ale ostatecznie klient nie rozwiązał swojego problemu. Czy poleciałbyś samolotem, którego komputery robią to, o co pytają, a nie co zamierzają?
mouviciel
3

Spory odsetek „błędów”, które napotkałem, można lepiej opisać jako rozbieżność między projektem systemu a oczekiwaniami klientów.

Teraz, niezależnie od tego, czy nazywamy te błędy, czy nie, jest to akademickie, ale faktem jest, że znaczna część prac konserwacyjnych powstaje bezpośrednio w wyniku niedoskonałej komunikacji i zmieniających się oczekiwań klientów.

Nawet jeśli system jest technicznie, dający się udowodnić „poprawny” w sensie spełnienia specyfikacji (choć jest to nieprawdopodobne, by mogło to być w przypadku komercyjnego oprogramowania), nadal będziesz mieć problem z dopasowaniem funkcji oprogramowania do funkcji klienta - zmienne i źle zdefiniowane oczekiwania.

W skrócie:

Nie.

William Payne
źródło
+1 Deweloper i klient mogą mieć bardzo różne poglądy na to, co definiuje „błąd”.
GrandmasterB
Ale co, jeśli programista jest także użytkownikiem? Uważam generalnie najlepsze oprogramowanie z tych ludzi, jeśli chodzi o użyteczność, ponieważ wiedzą dokładnie, jak coś powinno działać, itd.
Joan Venge
2

Jeśli masz wystarczająco ciasną i ograniczoną specyfikację, możesz być w stanie udowodnić, że program jest wolny od błędów, ale tylko w oparciu o nie dające się udowodnić założenia dotyczące poprawnego działania wszystkiego innego w systemie. Pozostawia to jako oczywistość, że nie ma sposobu, aby udowodnić, że specyfikacje byłyby uważane za poprawne przez tego, kto stworzył pierwotny problem lub przez osobę korzystającą z usługi.

ddyer
źródło
1

Uważam, że sekcja Jima Shore'a „ No Bugs” to bardzo przydatna lektura na ten temat. Krótka forma: Nie można się rozwijać bez produkowania błędów - ale możemy pracować w taki sposób, aby wykryć je jak najwcześniej.

Podczas produkcji samego kodu. Na przykład, pisząc i często uruchamiając testy jednostkowe podczas programowania, stale zapewniamy, że kod wykonuje to, co powinien. Przydatne jest także ciągłe przepisywanie istniejącego kodu w taki sposób, aby jak najdokładniej wyrażał zamierzone zachowanie systemu.

W twoim przypadku jednak mówisz o istniejącej bazie kodu z milionami linii kodu. Jeśli chcesz uzyskać taki błąd systemu, musisz przede wszystkim wiedzieć, co to jest błąd w tym systemie. Możesz napisać pakiety testów post-hoc zapewniających funkcjonalność systemu (jeśli jeszcze nie istnieje). Sieć tych testów może służyć jako przybliżona definicja prawidłowego działania systemu. Ale im więcej masz kodu, tym więcej wysiłku wymaga ten rodzaj ćwiczeń. Dlatego większość firm idzie na kompromis: żyją z niedoskonałością, pracują z listami błędów i konserwacją, aby uzyskać najbardziej denerwujące błędy z systemu.

rplantiko
źródło
1

O weryfikacji przez część komputerową.

Istnieją dwa sposoby weryfikacji programu za pomocą komputera. Jeden testuje, drugi używa systemu sprawdzającego.

Jak tylko wyczerpujące testy nie są możliwe, testowanie nie jest w stanie wykazać, że program nie zawiera błędów, tylko że ma pewne. (I masz problem z pokazaniem, że twoje testy same nie testują na obecność błędów).

Aby użyć systemu sprawdzania, zaczynasz od wymagań formalnych (a one same mogą mieć błąd, mam nadzieję, że język użyty do wymagań będzie bardziej odpowiedni, aby przekonać się, że nie ma tam błędu niż w języku programowania) i zbudować / udowodnić za pomocą pomoc systemów dowodowych, że program jest wolny od błędów (i jest kwestia błędów w systemach dowodowych, ale okazały się one poprawne). Obecny stan techniki to kompilator dla podzbioru C (i ten podzbiór nie jest akademicki, „CompCert obsługuje wszystkie podzbiory C MISRA-C 2004, a także wiele funkcji wykluczonych przez MISRA”).

AProgrammer
źródło
Cytując Donalda Knutha (z pamięci): Możesz udowodnić, że program jest wolny od błędów, ale to nie znaczy, że nie ma żadnych błędów :-)
gnasher729
1

Nie, ponieważ środowisko komputerów i oprogramowania, na którym działa aplikacja, będzie się zmieniać nawet po zamrożeniu kodu. System operacyjny ewoluuje wraz z łatkami i poprawkami, a także urządzeniami i sterownikami. Właśnie wtedy, gdy uważasz, że osiągnąłeś poziom nieznanych błędów, AMD lub nVidia wydadzą aktualizację sterownika wideo, która ma wpływ na sposób interakcji z podsystemem wideo. Teraz Twoja aplikacja ma wady wizualne (takie jak miganie, migotanie lub redukcja liczby klatek na sekundę) dla klientów posiadających określoną kartę graficzną lub konfigurację (SLI? LOL).

Oprócz sprzętu i systemu operacyjnego, pod najważniejszymi aplikacjami znajduje się także szereg produktów pośrednich, które również ewoluują poza twoją kontrolą, a gdy tylko kod stanie się zerowy, stan warstw pod spodem zostanie zmieniony na EOL.

Technologia ewoluuje, podobnie jak firma, która wykorzystuje tę technologię, a idea „uwolnienia” kodu nie jest możliwa ani wykonalna. Firma, która prosi o nowy zestaw funkcji, nie zareaguje dobrze na „mamy zablokowany kod, gdy ścigamy wszystkie znane błędy i nikt nie zgłasza prawidłowej wady oprogramowania w ciągu X miesięcy”. Nawet jeśli firma kupi tę linię, po X miesiącach spyta, w jaki sposób pojawią się nowe funkcje, a odpowiedź nie może być „postanowiliśmy przedłużyć zawieszenie, ponieważ Oracle właśnie wydało łatkę i potrzebujemy X kolejnych miesięcy poświadczam, że ".

Nie, w pewnym momencie firma będzie szukała bardziej elastycznego zespołu programistów, który wspiera potrzebę rozwoju z prędkością technologii. Jest to podstawowy problem, przed którym stoją nowoczesne zespoły programistyczne.

Thomas Carlisle
źródło
0

Tak, ale nigdy się nie dowiesz. Im trudniej wyglądasz, tym więcej znajdziesz. Im cięższy jest system i im więcej przypadków na krawędziach jest używanych, tym bardziej podobna będzie kolejna niezgodność z pierwotną intencją lub specyfikacją. Oznacza to, że sam błąd nie jest dokładną rzeczą i często będzie zależeć od interpretacji, od tego, jak źle ktoś oceni postrzeganą anomalię.

To jest rozmyta rzecz. Niewiele systemów zostało określonych aż do ostatniego bitu. Jeśli system działa dobrze, a użytkownicy nie mają żadnych skarg (nic ich nie podsłuchuje) i są do niego całkowicie przystosowani, równie dobrze można go nazwać wolnym od błędów.

Martin Maat
źródło
-2

Możliwe jest konsekwentne dostarczanie oprogramowania wolnego od błędów, przy zachowaniu odpowiedniej dyscypliny i wspólnej kultury zespołu. (I dobrze przemyślany modułowy kod, kompleksowy zestaw zautomatyzowanych testów, sprawdzanie defektów i dostosowywanie procesu, oraz wiele innych rzeczy, które wymagają wysiłku i pokory, ale zwracają tysiąc razy)

Ale robiąc to, generalnie nie zamierzasz budować systemu 20 MLOC. Jeśli pisanie kodu wolnego od błędów nie jest twoim celem, nie powinno też być budowania wielu systemów MLOC.

Moje własne rozumowanie jest następujące:

Ktoś musi spełnić. Pewna osoba (być może ta sama, być może inna) ma budżet na zaspokojenie potrzeb poprzez pisanie oprogramowania. Wszyscy ci ludzie oczekują pewnych korzyści za swoje pieniądze.

Osoba z budżetem zapłaci niektórym osobom (być może tym samym, być może innym) programistom , aby ci programiści zamienili część ustalonego czasu na oprogramowanie spełniające potrzeby.

Ci programiści pracują zatem nad przekształceniem czyichś pieniędzy w oprogramowanie spełniające potrzeby. Ich obowiązkiem jest dobre wykorzystanie tych pieniędzy.

Ma to następujące konsekwencje w odniesieniu do twojego pytania:

  • Biorąc pod uwagę, że w oprogramowaniu jest błąd, czy w ogóle go naprawisz? Potrzebujesz programisty, aby naprawić błąd, a programista będzie kosztował. Programista nie może zdecydować, czy wydać na to pieniądze. Jest to rola osoby posiadającej budżet.
  • Czy mogę zbudować oprogramowanie 20MLOC od zera, nie pozostawiając niezmienionych błędów? Cóż, rozpoczęcie budowy 20 MLOC wymagało zamiaru wydania ogromnej kwoty pieniędzy. To jest głupie finansowo. I nie jest zbudowany w jeden dzień. Ale oprogramowanie jest na dzisiejsze potrzeby, a nie jutro. Będzie błędna próba zrównoleglenia rozwoju poprzez zatrudnienie wielu programistów. Ale wtedy są szanse, że nie dostaniesz wspólnej kultury i pojawią się błędy, pojawią się marnotrawstwo i opóźnienie, i zabraknie pieniędzy, aby je naprawić. Nie widziałem jeszcze żadnego systemu bez błędów tego rozmiaru. (Widziałem systemy wolne od błędów i systemy 20MLOC, ale nie były takie same)
  • Jestem odpowiedzialny za utrzymanie systemu 20MLOC, którego nie napisałem. Czy będę w stanie osiągnąć zero znanych błędów? Nie zależy to od programistów. Nie mogą zdecydować się na naprawienie błędów, ponieważ to nie ich pieniądze na linii. Czy jest wystarczający zwrot z inwestycji, aby naprawić pozostałe błędy? Cóż, system istnieje już od jakiegoś czasu, a użytkownicy przyzwyczaili się do niego i wykorzystują dziwactwa systemu na swoją korzyść w codziennej pracy. Jeśli naprawisz błędy z zasady, osoba z pieniędzmi może być zmuszona zapłacić za przebudowę jakiejś nieokreślonej funkcji, która zniknęła z systemu, co kosztuje jeszcze więcej pieniędzy.

Chodzi o pieniądze i słusznie.

Laurent LA RIZZA
źródło
-2

Tak.

Ale jak wiadomo, aby być tego wartym, potrzeba zbyt wiele wysiłku.

Zanim będę w stanie obronić moją odpowiedź, musimy najpierw zdefiniować, czym jest błąd:

  • Błąd to zachowanie niezgodne ze specyfikacją.
  • Jednak usterki w specyfikacji (np. 0 zasada robotyki) nie liczą się jako błędy oprogramowania.
  • Dodatkowe funkcje nie są liczone jako błędy, chyba że jest to zabronione przez specyfikację.
  • Ze względu na argumenty sprzeczności w specyfikacji również nie liczą się jako błędy oprogramowania.

Teraz, jak miejmy nadzieję, już wiesz, dobre architektury oprogramowania są modułowe, dzięki czemu każdy moduł może być testowany jednostkowo (lub ręcznie lub cokolwiek) indywidualnie. Dzięki dyscyplinie i starannym testom możliwe jest pisanie pojedynczych modułów, które nie zawierają błędów.

"Ale poczekaj!" Słyszę twój protest: „Co jeśli nieoczekiwane (ale mimo to poprawne) zachowanie jednego modułu spowoduje błąd w innym?” Zatem błąd znajduje się w drugim module. Moduły wolne od błędów mogą być traktowane jako interfejsy API, a interfejsy API, jak wiadomo, wymagają pewnej uwagi, aby były prawidłowo używane.

Pisanie kodu kuloodpornego wymaga dużej wiedzy na temat przypadków brzegowych i logiki przepływu ze strony programisty, a większość programistów albo nie jest wystarczająco inteligentna, by się uczyć, albo po prostu nie obchodzi. Lub częściej są w terminie.

„Ale daj mi miejsce, aby stać, a ja poruszę światem”. - Archimedes

Jonathan Graef
źródło
Wymaga wysiłku, ale to się zwraca.
Laurent LA RIZZA
1
Jeśli pominiesz błędy specyfikacji w równaniu, całe oprogramowanie stanie się bezużyteczne: specyfikacje są tylko narzędziami do zapisywania potrzeb użytkownika w stosunkowo formalny sposób, ale ostatecznie to użytkownik musi być zadowolony, a nie specyfikacja. A tworzenie specyfikacji jest tak samo częścią tworzenia oprogramowania, jak pisanie kodu. W końcu pełna specyfikacja formalna opisywałaby zachowanie systemu, tak jak robi to końcowy kod, specyfikacja po prostu nie jest wydajnie wykonywalna.
cmaster