RSS

Blog

Projektowanie oprogramowania w świecie .NET. Agile, OOP, wzorce projektowe, DDD, ORM, TDD, AOP i inne...

EuroManager. Zastosowanie Code Contracts

20 października 2010 Odsłon: 2490

Design by Contract (TM) to technika programowania defensywnego, postulująca jawne specyfikowanie interfejsów komponentów, np. poprzez deklarowanie warunków, które muszą spełniać argumenty metod (to w zasadzie najczęstszy przypadek). Zwykle w projektach realizujemy to wymaganie albo poprzez zwykłe if-y rzucające ArgumentException, albo tworząc statyczne klasy pomocnicze, takie jak Check czy Require. Od pewnego czasu dostępne jest narzędzie Code Contracts opracowane przez Microsoft Research i to z niego zdecydowałem się skorzystać w projekcie EuroManager.

Code Contracts składa się z kilku powiązanych ze sobą elementów, m.in.:

  • Biblioteki klas, umożliwiających definiowanie kontraktów - obecnie jest ona integralną częścią .NET Framework 4, zatem możemy pisać kod wykorzystujący Code Contracts bez obecności pozostałych elementów, bez pobierania czy kupowania czegokolwiek.
  • Narzędzia do weryfikacji w czasie wykonywania, które wstrzykuje kontrolę kontraktów do assemblies przy kompilacji w trybie Debug i pozwala wyłapać przypadki ich naruszenia. Skorzystanie z narzędzia wymaga pobrania Code Contracts Standard Edition ze strony DevLabs.
  • Narzędzia do weryfikacji statycznej, które potrafi wskazać niektóre naruszenia kontraktów nawet bez uruchamiania aplikacji (efektowne, trzeba to przyznać), ale wymaga CC w wersji Premium (i VS też w wersji Premium).

Po instalacji Code Contracts Standard Edition na karcie projektu pojawi się dodatkowa pozycja, która umożliwia m.in. konfigurację weryfikacji kontraktów (bez czego tak naprawdę deklarowanie kontraktów nie ma większego sensu).

Najprostszym, i zarazem najczęstszym sposobem wykorzystania Code Contracts w projekcie EuroManager jest wspomniana na początku kontrola argumentów metod. Poniżej parę przykładów:

         public ChaseBallState(IPlayer player)
         {
             Contract.Requires(player != null);
 
             this.player = player;
         }
 
 
         public static float Time(float speed, float distance)
         {
             Contract.Requires(speed.IsRational() && speed > 0);
             Contract.Requires(distance.IsRational() && distance >= 0);
 
             return distance / speed;
         }
 

Możliwości mamy tak naprawdę dużo więcej, możemy np. deklarować predykaty dotyczące wartości zwracanych, ale nie chcę tutaj wchodzić w szczegóły - w sieci można znaleźć wiele dobrych tutoriali. Wystarczy rzucić okiem na klasę Contract:

Klasa System.Diagnostics.Contracts.Contract

Klasa System.Diagnostics.Contracts.Contract

Prosta rzecz, a dzięki niej niskim kosztem zyskujemy dużo lepiej wyspecyfikowane metody. Ale to nie wszystko - Code Contracts oferuje też bardziej zaawansowane możliwości, jako przykład podam coś, co uważam za szczególnie przydatne: możliwość definiowania kontraktów dla interfejsów. Zobaczmy to na przykładzie prościutkiego interfejsu ITimeAware:

     [ContractClass(typeof(TimeAwareContract))]
     public interface ITimeAware 
     {
         void Update(float elapsedTime);
     }
 

Interfejs udekorowany został atrybutem ContractClass, który wskazuje klasę stanowiącą jego kontrakt. Ta klasa z kolei jest abstrakcyjną implementacją interfejsu, udekorowaną komplementarnym atrybutem ContractClassFor. W implementacjach swoich metod zawiera wywołania metod klasy Contract.

 
     [ContractClassFor(typeof(ITimeAware))]
     public abstract class TimeAwareContract : ITimeAware 
     {
         public void Update(float elapsedTime)
         {
             Contract.Requires(elapsedTime.IsRational() && elapsedTime > 0);
         }
     }
 

Muszę też wspomnieć tutaj o pewnej wadzie przyjętego podejścia. Klasa stanowiąca kontrakt nie może dziedziczyć z innej klasy, co powoduje, że w przypadku interfejsów rozszerzających inne interfejsy musimy powielać wszystkie definicje metod. Niby nic szczególnego, ale jest to nieco irytujące, choć też nie szukałem zbyt głęboko sposobów na obejście tego zachowania.

Pełną wersję kodu źródłowego można znaleźć na stronie projektu: http://euromanager.codeplex.com.

Komentarze

Aktualizacja danych...
ptsbjsbgbmc, http://www.fdqfdvwghn.com jyjxtfzobi
2012-02-06 04:25

ptsbjsbgbmc, http://www.fdqfdvwghn.com jyjxtfzobi

myipfsbgbmc, http://www.zzlbaiypxk.com gprlwvqcib
2012-02-05 20:08

myipfsbgbmc, http://www.zzlbaiypxk.com gprlwvqcib

cwsrcsbgbmc, <a href="http://www.bgbpafeblw.com">lfuotegrkt</a>
2012-02-05 11:06

cwsrcsbgbmc, <a href="http://www.bgbpafeblw.com">lfuotegrkt</a>

egjipsbgbmc, <a href="http://www.hsmjqhxrkq.com">yzrkyqugwb</a>
2012-02-05 02:36

egjipsbgbmc, <a href="http://www.hsmjqhxrkq.com">yzrkyqugwb</a>

Aktualizacja danych...

Kontakt CV

Ja

Rafał Barszczewski
rb07 at interia.pl
gg: 1242248

Sonda

Jakiego O/R mappera używasz najczęściej w .NET?







Aktualizacja danych...

RSS

20 września 2008

Jak widać, spore zmiany. Zaimplementowałem najważniejsze funkcjonalności, które powinien mieć każdy silnik blogów, a których do tej pory u mnie brakowało. Chodzi mi tu przede wszystkim o tagi i RSS. Poza tym strona startowa bloga będzie teraz wyświetlać najnowszego posta, a na panelu bocznym pojawiła się lista ostatnich wpisów.

Ponadto, postanowiłem wznowić pisanie postów (a właściwie je rozpocząć - bo na dobrą sprawę nigdy poważnie nie zacząłem). W końcu w jakimś celu to wszystko zaprogramowałem ;) Tematyka, którą będę chciał w najbliższym czasie poruszyć, obejmuje zagadnienia związane z projektowaniem i testowaniem aplikacji oraz metodykami i narzędziami, które te procesy wspomagają. Zapewne najwięcej będzie o Domain-Driven Design i Test-Driven Development, choć spróbuję podejść do tych tematów bardzo pragmatycznie (technicznie). Mam też plan, żeby w miarę pisania kolejnych części powstawała konkretna, przykładowa aplikacja, która mogłaby posłużyć jako case-study. Co z tego wszystkiego wyjdzie - zobaczymy niebawem.

13 kwietnia 2007

Nie doszedł (na razie) żaden nowy wpis, ale za to przeorganizowałem trochę ten dział. Na głównej podstronie znajdują się teraz same nagłówki wpisów, a całość możemy przeczytać (i skomentować) po przejściu do szczegółów.

21 października 2006

Pierwszy, historyczny wpis w moim blogu. Od tej pory postaram się regularnie dodawać nowe posty. A już niedługo - moje wrażenia z Microsoft Technology Summit (24-25.10).