Design By Contract
Dzisiejszy wpis będzie o znanej i generalnie dość znanej i mającej wiele zalet metodyce Design By Contract. Temat „wypłynął” ponownie dla wielu javovców tym razem dzięki wydaniu biblioteki CoFoJa (o którym właśnie będzie ten post) przez dwóch pracowników Google przy ścisłej współpracy z autorem pierwowzoru tego projektu. Dlaczego jednak nietypowy tytuł posta – „trzeźwe spojrzenie”? Ponieważ w odróżnieniu od niektórych nie oceniam technologii na podstawie „wow factor” a realnej używalności. Gotowi mini review tego toola? No to lecimy… :-)
Contracts For Java
Na początek warto rzucić okiem na googlowy blog gdzie ogłoszono premierę tego narzędzia oraz oczywiście samą stronę domową projektu CoFoJa. Oczywiście na samym przekierowaniu nie poprzestanę więc zaczniemy od mini definicji od strony użytkownika metodyki design by contract. Jak możemy przeczytać chociażby w pragmatycznym programiście metodyka ta ma dość spory potencjał i ciekawe możliwości – generalnie chodzi o określanie „kontraktów” na naszych metodach. Zakładanie kontraktów ma pewną wyższość nad pisanie testów jednostkowych ponieważ możemy kontrakt założyć na interfejsie a wszystkie implementujące go klasy będą z nim związane
Kontrakt może na przykład zapewnić:
- wykonanie danej metody tylko i wyłącznie wtedy gdy przekazane jej argumenty spełniają pewne kryteria (w kontekście CoFoJa byłoby to @Requires)
- zagwarantowanie spełnienia pewnych warunków po opuszczeniu metody (w kontekście CoFoJa byłoby to @Ensures ewentualnie @ThrowEnsures jeśli chcemy mieć kontrakt na rzucenie wyjątku)
- zagwarantowanie ogólnych warunków na konkretnej np. klasie (@Invariant)
Ok, skoro znamy podstawowe building blocks (zaczerpnięte skądżeby inąd niż z Eiffla oczywiście) zobaczmy jakieś przykładowe poadnotowane nimi API:
A teraz praktycznie
Najlepiej jest chwilkę się w niego wgryźć, powinien być stosunkowo zrozumiały. Nie chcemy nigdy mieć ujemnej ilości bananów – spowodowałoby to złamanie kontraktu. Podobne przykładowe kontrakty wejściowe/wyjściowe widzimy na metodach oraz jeden mały tip: metoda old() jest dostarczana automagicznie i oznacza „starą wartość tego wywołania” czyli przed wykonaniem metody na którą zakładamy ten kontrakt. Poza tym mamy tutaj do czynienia w sumie z zwyczajnym kodem Java który niestety jest wewnątrz stringa… Świadomy programista zapewne już ma zapaloną lampkę alarmową, że to będzie nie refaktorowalne i bez sensu… Na pocieszenie dodam iż kod Java zawarty w tych stringach faktycznie jest „kompilowany”i jak coś popsujemy składniowo, kontrakty się nie skompilują i dostaniemy normalne informacje jakby to się nam nie kompilował normalny „nasz kod”. Co do wygody refaktoringu… Na szczęscie korzystam z porządnego IDE (IntelliJ IDEA) i takie „problemy” mnie nie dotyczą ;-). Wybrałem inject języka Groovy do tych stringów aby parser składniowy nie dziwił się pojawienia się metody old() „z nikąd”:
Problem z „nie podpowiadaniem metod” jak i „nie da się refaktorować” jak widać został od razu wyeliminowany :-) Hooray for JetBrains. Poszukajmy jednak kolejnego problemu z tym API… Tak jest, @ThrowEnsures jest trochę brzydki a nie koniecznie musi być cały w stringu. Jak działa obecnie? Przekazujemy mu listę stringów gdzie parami występują „wyjątek” + „warunek kiedy ma zostać rzucony”. Chętniej zobaczył bym to w formie podobnej do poniższej (tylko szybki szkic taki), a wy?
Ok czas na uruchomienie kodu z „włączonymi kontraktami”… I… niestety nie okazało się to takie trywialne na obecnym etapie projektu. Niestety trzeba sobie ręcznie poustawiać processowanie adnotacji (norma, tutaj się niewiele zmieni) jednak trochę problemów nastarcza mi obecnie widoczność klas/pól dla CoFoJa w intellij. Classpath (dla procesora) zdaje się być ustawiony poprawny oraz jego klasa jak i inne opcje też jednak nie dochodzi do poprawnego przeparsowania wszystkich reguł. No cóż, może jutro się uda – tymczasem odsyłam do poradnika dla użytkowników Eclipse gdzie to członek społeczności sprawnie poradził sobie z tym problemem :-)
Trzeźwe spojrzenie: „Czy obecnie warto?”
Pozostaje pytanie… Czy warto się zainteresować CoFoJa jak i samym DBC? Pytanie jest chyba równie ogólne jak „czy warto meta-programować?” także wprost odpowiedzi nie udzielę. Miejmy jednak na uwadze że jak na razie używanie CoFoJa nie jest zbyt wygodne a adnotacje można by jeszcze trochę poszlifować. Trzeba by jeszcze rzucić okiem jak stoimy z integracją tego z Maven – aby normalnie testując bądź klikając sobie po projekcie te kontrakty mogły się przydawać. Sama idea jest ciekawa i jakby integracja z narzędziami była wygodniejsza – a może od razu pluginy do IDE – można by się nad tym porządniej zastanawiać. Jak na razie projekcik odkładamy ten projekt spokojnie na półkę „worth watching” i liczymy na rychłe wydanie 2.0. :-)
PS: Jeżeli interesują Cię takie jak i inne ciekawe metodyki i sposoby tworzenia pięknego, czystego kodu, zapraszam serdecznie na co 2 tygodniowe spotkania SCKRK gdzie obecnie dyskutujemy w formie „reading club” nad Domain Driven Design :-)
1
komentarz