Projekt według umowy - Design by contract

Projekt według schematu kontraktowego

Design by contract ( DbC ), znany również jako programowanie kontraktowe , programowanie kontraktowe i programowanie projektowe na zlecenie , to podejście do projektowania oprogramowania .

Nakazuje ona, aby projektanci oprogramowania zdefiniowali formalne , precyzyjne i weryfikowalne specyfikacje interfejsu dla komponentów oprogramowania , które rozszerzają zwykłą definicję abstrakcyjnych typów danych o warunki wstępne , warunki końcowe i niezmienniki . Specyfikacje te są określane jako „umowy”, zgodnie z metaforą pojęciową z warunkami i zobowiązaniami umów biznesowych.

Podejście DbC zakłada, że wszystkie komponenty klienta wywołujące operację na komponencie serwera spełnią warunki wstępne określone jako wymagane dla tej operacji.

Tam, gdzie to założenie jest uważane za zbyt ryzykowne (jak w przypadku przetwarzania wielokanałowego lub rozproszonego ), przyjmuje się podejście odwrotne , co oznacza, że komponent serwerowy testuje, czy wszystkie odpowiednie warunki wstępne są spełnione (przed lub podczas przetwarzania żądania komponentu klienta ) i odpowiada odpowiednim komunikatem o błędzie, jeśli nie.

Historia

Termin ten został ukuty przez Bertranda Meyera w związku z jego projektem języka programowania Eiffel i po raz pierwszy opisany w różnych artykułach począwszy od 1986 roku oraz w dwóch kolejnych wydaniach (1988, 1997) jego książki Object-Oriented Software Construction . Firma Eiffel Software złożyła wniosek o rejestrację znaku towarowego Design by Contract w grudniu 2003 r. i została ona przyznana w grudniu 2004 r. Obecnym właścicielem tego znaku towarowego jest Eiffel Software.

Programowanie kontraktowe ma swoje korzenie w pracach nad weryfikacji formalnej , formalnej specyfikacji i logika hoare'a . Oryginalne składki obejmują:

Opis

Centralną ideą DbC jest metafora tego, jak elementy systemu oprogramowania współpracują ze sobą na podstawie wzajemnych zobowiązań i korzyści . Metafora pochodzi z życia biznesowego, gdzie „klient” i „dostawca” uzgadniają „umową”, która definiuje na przykład, że:

  • Dostawca musi dostarczyć określony produkt (zobowiązanie) i ma prawo oczekiwać, że klient zapłacił swoją opłatę (korzyść).
  • Klient musi uiścić opłatę (obowiązek) i jest uprawniony do otrzymania produktu (korzyść).
  • Obie strony muszą spełnić określone zobowiązania, takie jak przepisy ustawowe i wykonawcze, mające zastosowanie do wszystkich umów.

Podobnie, jeśli metoda z klasy w programowaniu obiektowym zapewnia pewną funkcjonalność, może:

  • Oczekuj, że określony warunek zostanie zagwarantowany przy wejściu przez dowolny moduł klienta, który go wywołuje: warunek wstępny metody — zobowiązanie dla klienta i korzyść dla dostawcy (sama metoda), ponieważ uwalnia go od konieczności zajmowania się sprawami poza warunek wstępny.
  • Zagwarantować pewną właściwość przy wyjściu: warunek końcowy metody — zobowiązanie dla dostawcy i oczywiście korzyść (główna korzyść z wywołania metody) dla klienta.
  • Zachowaj pewną właściwość, zakładaną przy wejściu i gwarantowaną przy wyjściu: niezmiennik klasy .

Umowa jest semantycznie równoważna trójce Hoare'a, która formalizuje zobowiązania. Można to podsumować „trzema pytaniami”, na które projektant musi wielokrotnie odpowiedzieć w umowie:

  • Czego oczekuje umowa?
  • Co gwarantuje umowa?
  • Co zachowuje umowa?

Wiele języków programowania posiada udogodnienia do tworzenia takich asercji . DbC uważa jednak, że umowy te są tak istotne dla poprawności oprogramowania , że powinny być częścią procesu projektowania. W efekcie DbC opowiada się za pisaniem twierdzeń w pierwszej kolejności . Kontrakty można pisać za pomocą komentarzy do kodu , wymuszanych przez zestaw testów lub obu, nawet jeśli nie ma specjalnej obsługi języków dla kontraktów.

Pojęcie kontraktu rozciąga się na poziom metody/procedury; umowa dla każdej metody będzie zwykle zawierała następujące informacje:

  • Dopuszczalne i niedopuszczalne wartości lub typy wejściowe oraz ich znaczenie
  • Zwracane wartości lub typy oraz ich znaczenie
  • Wartości lub typy warunków błędów i wyjątków , które mogą wystąpić, oraz ich znaczenie
  • Skutki uboczne
  • Warunki wstępne
  • Warunki końcowe
  • Niezmienniki
  • (rzadziej) Gwarancje wydajności, np. za wykorzystany czas lub przestrzeń

Podklasy w hierarchii dziedziczenia mogą osłabiać warunki wstępne (ale nie wzmacniać ich) oraz wzmacniać warunki końcowe i niezmienniki (ale nie ich osłabiać). Zasady te są zbliżone do podtypów behawioralnych .

Wszystkie relacje klas występują między klasami klientów i klasami dostawców. Klasa klienta jest zobowiązana do wykonywania połączeń do dostawcy cech, w których wynikowy stan dostawcy nie jest naruszony przez połączenie od klienta. Następnie dostawca jest zobowiązany do podania stanu zwrotu oraz danych, które nie naruszają wymagań państwowych klienta.

Na przykład bufor danych dostawcy może wymagać obecności danych w buforze, gdy wywoływana jest funkcja usuwania. Następnie dostawca gwarantuje klientowi, że gdy funkcja usuwania zakończy swoją pracę, element danych zostanie rzeczywiście usunięty z bufora. Inne kontrakty projektowe to koncepcje niezmiennika klasy . Niezmienny klasy gwarantuje (dla klasy lokalnej), że stan klasy będzie utrzymywany w określonych tolerancjach na końcu każdego wykonania funkcji.

Korzystając z umów, dostawca nie powinien próbować sprawdzać, czy warunki umowy są spełnione – praktyka znana jako programowanie obraźliwe – ogólną ideą jest to, że kod powinien „nie zawieść”, a weryfikacja umowy stanowi siatkę bezpieczeństwa.

Właściwość „fail hard” DbC upraszcza debugowanie zachowania kontraktu, ponieważ zamierzone zachowanie każdej metody jest wyraźnie określone.

To podejście różni się znacznie od programowania defensywnego , w którym dostawca jest odpowiedzialny za ustalenie, co zrobić, gdy warunek wstępny zostanie złamany. Najczęściej dostawca zgłasza wyjątek, aby poinformować klienta, że ​​warunek wstępny został złamany, aw obu przypadkach — zarówno DbC, jak i programowanie defensywne — klient musi wymyślić, jak na to zareagować. W takich przypadkach DbC ułatwia pracę dostawcy.

Design by contract określa również kryteria poprawności modułu oprogramowania:

  • Jeśli warunek wstępny I niezmienny klasy jest spełniony przed wywołaniem dostawcy przez klienta, to niezmienny ORAZ warunek końcowy będzie spełniony po zakończeniu usługi.
  • Dzwoniąc do dostawcy, moduł oprogramowania nie powinien naruszać warunków dostawcy.

Projektowanie według umowy może również ułatwić ponowne wykorzystanie kodu, ponieważ umowa na każdy fragment kodu jest w pełni udokumentowana. Kontrakty na moduł można traktować jako formę dokumentacji oprogramowania dla zachowania tego modułu.

Wpływ na wydajność

Warunki umowy nigdy nie powinny być naruszane podczas wykonywania programu wolnego od błędów. Kontrakty są zatem zazwyczaj sprawdzane tylko w trybie debugowania podczas tworzenia oprogramowania. Później w momencie wydania kontrole umowy są wyłączone, aby zmaksymalizować wydajność.

W wielu językach programowania kontrakty są implementowane za pomocą attach . Asserts są domyślnie kompilowane w trybie wydania w C/C++ i podobnie dezaktywowane w C# i Javie.

Uruchomienie interpretera Pythona z „-O” (od „optymalizuj”) jako argumentem spowoduje również, że generator kodu Pythona nie wyemituje żadnego kodu bajtowego dla asercji.

Skutecznie eliminuje to koszty wykonywania asercji w kodzie produkcyjnym — niezależnie od liczby i kosztów obliczeniowych asercji używanych w rozwoju — ponieważ żadne takie instrukcje nie zostaną uwzględnione w produkcji przez kompilator.

Związek z testowaniem oprogramowania

Programowanie kontraktowe nie zastąpi regularnych strategii badań, takie jak testowanie jednostkowe , testów integracji i testowania systemu . Zamiast tego uzupełnia zewnętrzne testy wewnętrznymi autotestami, które można aktywować zarówno w przypadku testów izolowanych, jak i w kodzie produkcyjnym podczas fazy testowej.

Zaletą wewnętrznych autotestów jest to, że potrafią wykryć błędy, zanim zamanifestują się jako nieważne wyniki zaobserwowane przez klienta. Prowadzi to do wcześniejszego i bardziej szczegółowego wykrywania błędów.

Użycie asercji można uznać za formę wyroczni testowej , sposób testowania projektu przez implementację kontraktu.

Wsparcie językowe

Języki ze wsparciem natywnym

Języki, które natywnie implementują większość funkcji DbC, obejmują:

Języki z obsługą innych firm

Różne biblioteki, preprocesory i inne narzędzia zostały opracowane dla istniejących języków programowania bez natywnego projektowania dzięki wsparciu kontraktowemu:

Zobacz też

Uwagi

Bibliografia

  • Mitchell, Richard i McKim, Jim: Design by Contract: na przykład , Addison-Wesley, 2002
  • Wikibook opisując DBC ściśle do oryginalnego modelu.
  • McNeile, Ashley: Ramy semantyki umów behawioralnych . Materiały z Drugiego Międzynarodowego Warsztatu Modelowania Zachowania: Podstawy i Zastosowania (BM-FA '10). ACM, New York, NY, USA, 2010. W artykule omówiono uogólnione pojęcia kontraktu i zastępowalności .

Zewnętrzne linki