Nie wiem, skąd pochodzi twierdzenie, że „nie wykonuje i często nie może przeprowadzić analizy statycznej”. Pierwsza część tego twierdzenia jest po prostu błędna. Drugi zależy od tego, co rozumiesz przez „często”. Wolałbym powiedzieć, że często wykonuje analizę statyczną, a rzadko zawodzi. W zwykłej aplikacji biznesowej rzadko staje się o wiele bliżej nigdy .
Oto pierwsza korzyść:
Korzyści 1: analiza statyczna
Zwykłe twierdzenia i sprawdzanie argumentów mają wadę: są one odraczane do momentu wykonania kodu. Z drugiej strony, umowy kodowe przejawiają się na znacznie wcześniejszym poziomie, albo na etapie kodowania, albo podczas kompilacji aplikacji. Im wcześniej błąd zostanie wykryty, tym taniej go naprawić.
Korzyści 2: rodzaj zawsze aktualnej dokumentacji
Umowy kodeksowe dostarczają również pewnego rodzaju dokumentacji, która jest zawsze aktualna. Jeśli komentarz XML tej metody SetProductPrice(int newPrice)
mówi, że newPrice
powinna być lepsza lub równa zero, możesz mieć nadzieję, że dokumentacja jest aktualna, ale możesz również odkryć, że ktoś zmienił metodę, aby newPrice = 0
rzucić ArgumentOutOfRangeException
, ale nigdy nie zmieniła odpowiedniej dokumentacji. Biorąc pod uwagę korelację między umowami kodu a samym kodem, nie masz problemu z brakiem synchronizacji dokumentacji.
Dokumentacja dostarczana przez kontrakty kodowe jest również cenna, ponieważ często komentarze XML nie wyjaśniają dobrze dopuszczalnych wartości. Ile razy ja zastanawiałem się, czy null
lub string.Empty
czy \r\n
jest autoryzowanym wartość dla metody i komentarze XML milczeli na ten temat!
Podsumowując, bez umów kodowych wiele fragmentów kodu wygląda tak:
Zaakceptuję niektóre wartości, ale nie inne, ale będziesz musiał zgadnąć lub przeczytać dokumentację, jeśli taka istnieje. W rzeczywistości nie czytaj dokumentacji: jest nieaktualna. Wystarczy przejrzeć wszystkie wartości, a zobaczysz te, które zmuszają mnie do rzucania wyjątków. Musisz także odgadnąć zakres wartości, które mogą zostać zwrócone, ponieważ nawet gdybym powiedział ci coś więcej na ich temat, może to nie być prawda, biorąc pod uwagę setki zmian wprowadzonych w ciągu ostatnich lat.
Dzięki umowom kodowym staje się:
Argument tytułowy może być łańcuchem innym niż null o długości 0..500. Poniższa liczba całkowita jest wartością dodatnią, która może wynosić zero tylko wtedy, gdy łańcuch jest pusty. Wreszcie zwrócę IDefinition
obiekt, nigdy nie będzie zerowy.
Korzyści 3: umowy dotyczące interfejsów
Trzecią korzyścią jest to, że umowy kodowe wzmacniają interfejsy. Powiedzmy, że masz coś takiego:
public interface ICommittable
{
public ICollection<AtomicChange> PendingChanges { get; }
public void CommitChanges();
...
}
W jaki sposób, korzystając wyłącznie z twierdzeń i wyjątków, gwarantujesz, że CommitChanges
można je wywołać tylko wtedy, gdy PendingChanges
nie jest puste? Jak byś zagwarantował, że PendingChanges
nigdy tak nie jest null
?
Korzyści 4: egzekwowanie wyników metody
Wreszcie czwartą korzyścią jest możliwość Contract.Ensure
uzyskania wyników. Co jeśli, pisząc metodę zwracającą liczbę całkowitą, chcę mieć pewność, że wartość nigdy nie jest gorsza ani równa zero? W tym pięć lat później, po wielu zmianach od wielu programistów? Gdy tylko metoda ma wiele punktów powrotu, Assert
staje się koszmarem konserwacyjnym.
Rozważ umowy o kod nie tylko jako sposób na poprawność kodu, ale także na bardziej rygorystyczny sposób pisania kodu. W podobny sposób osoba, która używa wyłącznie języków dynamicznych, może zapytać, dlaczego wymuszać typy na poziomie językowym, podczas gdy możesz zrobić to samo w asercjach, gdy jest to potrzebne. Możesz, ale pisanie statyczne jest łatwiejsze w użyciu, mniej podatne na błędy w porównaniu do szeregu twierdzeń i samo dokumentowania.
Różnica między pisaniem dynamicznym a pisaniem statycznym jest bardzo zbliżona do różnicy między zwykłym programowaniem a programowaniem na podstawie umów.