Witaj na Zine.net online Zaloguj się | Rejestracja | Pomoc

DbC - czyli wyraź swoje intencje

Dzisiaj nieco koncepcyjnie (no tak - a kiedy nie było :)) na temat idei kontraktów, tego jak podchodzić z tą myślą do projektowania i implementacji. O czym konkretnie myśleć i w ogóle PO CO w ten sposób myśleć.

Sama idea Design by Contract wprowadzona została przez twórców języka Eiffel. Nie wiem co panowie mieli na myśli jeśli chodzi o ideologię, lecz zwykle przedstawiana jest przez wprowadzenie pojęć:
  • wymagania (precondition) - warunki wejściowe kontraktu,
  • zapewnienia (postcondition) - warunki wyjściowe kontraktu,
  • niezmienniki (invariant) - warunki obowiązujące dla kontraktu.
Dodatkowo omawiane są wszelakie techniki obsługi błędów (gdyż każdy warunek tak naprawdę stanowi asercję), zasady pisania warunków, łapania wyjątków, włączania przeróżnych opcji konkretnych narzędzi wpierających kontrakty.

Ja wolałabym się skupić na tym czym tak naprawdę jest kontrakt. Oczywiście nie po to by prowadzić akademicką dyskusję, lecz by tworzyć KOD...
Dla mnie cała idea polega na zdefiniowaniu intencji klasy - za pomocą formalnej notacji (wręcz kodu) jesteśmy w stanie opisać to czego użytkownik może się spodziewać po klasie i jej metodach oraz to czego metody oczekują metody gdy się je wywołuje.

Przypomina to ... kontrakt. Ale taki zwykły - międzyludzki.
Jeśli dostawca oferuje pewną usługę, związana jest ona z konkretnymi zasadami dotyczącymi sposobu korzystania z niej. Klient podpisując odpowiednią umowę (kontrakt) musi spełnić te wymagania (np. za nią zapłacić). W odpowiedzi dostaje 'gwarancję', a przynajmniej zapewnienie opisowe dotyczące zakresu tej usługi. Powiązanie to jest obustronne - jeśli klient nie zapłaci za usługę - jej efekty mogą być nieprzewidywalne. Z kolei jeśli usługa nie jest zgodna z zapewnieniami - nie spełnia założeń kontraktu, dostawca może się spodziewać że za nią nie zapłacimy...

No tak... ale jak to się ma do programowania. Fajna idea, ale do czego się może nam przydać? Tak naprawdę jeśli chodzi o kod kontrakty wprowadzają dwie wartości:
- sposób obsługi błędów,
- formalną dokumentację zachowania klasy lub metody.

Ale jak to? Ano tak to...
Dla przykładu rozważmy dostawcę usług internetowych. Wymagania kontraktu dotyczą płacenia rachunków w terminie. Jeśli klient tego nie robi - dostawca nie musi np. spełniać warunków dotyczących szybkości łącza (albo może je po prostu odciąć, ale nie można być pewnym ani dnia ani godziny kiedy się to stanie :)). Sęk w tym, że klient nie może w takim wypadku spodziewać się jakości usług zapisanej w umowie. Z kolei jeśli wymagania zostaną spełnione, to klient spodziewa się spełnienia zapewnień kontraktu - może np. zaplanować (powołując się na szybkość łącza) ściąganie potrzebnych danych.

Wszystko fajnie, tylko jak to się ma do kodu? Może wyjaśnię na przykładzie.
    public void Add2Account(int amount)
    {
        account += amount;
    }

Oto metoda, której zadaniem jest zwiększenie kwoty na rachunku klienta banku. Nawet przy tak prostej metodzie powstaje dużo pytań: Czy metoda przyjmuje wartości ujemne (wtedy metoda tak naprawdę zmniejszałaby kwotę)? Co jest wynikiem metody?

Odpowiada na nie odpowiedni kontrakt. Dotyczyć on będzie: wymagań (warunków jakie muszą spełniać parametry) i zapewnień - metoda zawsze zachowa się w określony sposób:
    require:
    amount > 0
    public void Add2Account(int amount)
    {
        account += amount;
    }
    ensure:
    account = old(account) + amount


Od razu piszę, że nie jest to żadna formalna notacja - jedynie pseudo-kod - pomysł na w miarę przejrzyste zapisanie warunków kontraktu.
Skoro kontrakt metody mówi, że przyjmuje ona jedynie wartości dodatnie, to nie musimy tego sprawdzać w kodzie samej metody. Zapewnienia natomiast przydają się klientom klasy. Teraz oni nie muszą w swoim kodzie robić tysiąca sprawdzeń. Wiedzą, że kwota na rachunku po wykonaniu operacji będzie zawsze większa niż kwota wcześniejsza.
Trzeci rodzaj asercji (niezmienniki) dotyczy zachowania całej klasy - jest to zbiór warunków spełnianych zawsze po wykonaniu jakiejkolwiek metody.

Tak więc podsumowując, benefity z myślenia 'kontraktowego' są następujące:
1. Jasno widać jak dzięki takiemu podejściu pozbywamy się tysiąca if'ów w kodzie.
2. Dokumentacja metody (i klasy) wyrażona jest w kodzie - dotyczy zarówno tego, czego się można spodziewać po zachowaniu (zapewnienia), ale również jak jej używać by działała w prawidłowy sposób (wymagania). Dla naszego przykładu możemy się np. spodziewać istnienia metody, która zmniejsza kwotę na rachunku klienta banku.
OK - to było koncepcyjne i meta-notacyjne. Konkrety następnym razem.

Opublikowane 17 sierpnia 2009 21:11 przez fusion

Komentarze:

18 sierpnia 2009 07:00 by dotnetomaniak.pl

# Cold Fusion : DbC - czyli wyraź swoje intencje

Dziękujemy za publikację - Trackback z dotnetomaniak.pl

Komentarze anonimowe wyłączone