Chciałbym opowiedzieć Wam o sposobie na radzenie sobie z modelowaniem złożonej logiki. W sytuacji kiedy mnożą się scenariusze i mamy wiele różnych trudnych przypadków do obsłużenia, przydają się diagramy Warniera. Diagramy te łączą ze sobą świat implementacji i wymagań, stojąc twardo po obu stronach. Ciekawą właściwością diagramów Warniera jest to, że pozwalają na wyłapanie wszelkich możliwych przypadków, a co za tym idzie na stworzenie niezawodnego modelu i implementacji. Mi osobiście pomogły poradzić sobie z częścią skomplikowanego projektu, która zaczynała mnie przerastać.
Z początku walczyłem ze swoim problemem przy pomocy tabel decyzyjnych. Minusem jest to, że analizując kolejne przypadki w tabeli należy je później zsyntetyzować do postaci listy konkretnych wytycznych dla programistów. Zadanie okazało się tak trudne, że po tygodniu odłożyłem je na rzecz lektury książki z dziedziny użyteczności. Po jakimś czasie powróciwszy do problemu musiałem się nieźle wysilić, by zrozumieć konkretne przypadki w tabeli decyzyjnej oraz zależności między wnioskami jakie wcześniej opracowałem.
Koniec końców z problemem udało się poradzić przy pomocy nowo poznanej metody diagramów Warniera. Diagram ma co prawda rozmiar A3 ale jest na nim rozrysowana cała funkcjonalność i łatwo go zrozumieć, za co gorąco dziękuję panu Warnier.
Diagramy Warniera wymyślił Jean Dominique Warnier w latach 70-tych, znacznie wyprzedzając tym swoją epokę. Metoda Warniera oparta jest na strukturze danych i relacjach między danymi. Sam diagram składa się z kilku elementów: funkcji, sekwencji, powtórzenia oraz alternatywy. Zobaczmy to na przykładzie.
Przykład 1.
Generator spisów treści dla książki kucharskiej. Są trzy spisy treści jakie mamy wygenerować:
Model danych:
Z początku walczyłem ze swoim problemem przy pomocy tabel decyzyjnych. Minusem jest to, że analizując kolejne przypadki w tabeli należy je później zsyntetyzować do postaci listy konkretnych wytycznych dla programistów. Zadanie okazało się tak trudne, że po tygodniu odłożyłem je na rzecz lektury książki z dziedziny użyteczności. Po jakimś czasie powróciwszy do problemu musiałem się nieźle wysilić, by zrozumieć konkretne przypadki w tabeli decyzyjnej oraz zależności między wnioskami jakie wcześniej opracowałem.
Koniec końców z problemem udało się poradzić przy pomocy nowo poznanej metody diagramów Warniera. Diagram ma co prawda rozmiar A3 ale jest na nim rozrysowana cała funkcjonalność i łatwo go zrozumieć, za co gorąco dziękuję panu Warnier.
Diagramy Warniera wymyślił Jean Dominique Warnier w latach 70-tych, znacznie wyprzedzając tym swoją epokę. Metoda Warniera oparta jest na strukturze danych i relacjach między danymi. Sam diagram składa się z kilku elementów: funkcji, sekwencji, powtórzenia oraz alternatywy. Zobaczmy to na przykładzie.
Przykład 1.
Generator spisów treści dla książki kucharskiej. Są trzy spisy treści jakie mamy wygenerować:
- spis alfabetyczny wg nazwy potraw
- spis wg czasu przygotowania potrawy i jej typu
- spis wg składników
Model danych:
Słownik danych:
lista składników = {składnik + ilość składnika} *powtórzyć dla każdego ze składników*
potrawa = nazwa potrawy +
typ potrawy +
czas przygotowania +
{lista składników} +
opis przygotowania
składnik = nazwa składnika +
jednostka miary [dkg | ml | szklanka | łyżeczka | łyżka stołowa ]
typ potrawy = [zupa | drugie danie | przekąska | ciastka | ciasto | tort ]
Diagram Warniera:
lista składników = {składnik + ilość składnika} *powtórzyć dla każdego ze składników*
potrawa = nazwa potrawy +
typ potrawy +
czas przygotowania +
{lista składników} +
opis przygotowania
składnik = nazwa składnika +
jednostka miary [dkg | ml | szklanka | łyżeczka | łyżka stołowa ]
typ potrawy = [zupa | drugie danie | przekąska | ciastka | ciasto | tort ]
Diagram Warniera:
modelowanie_logiki_-_diagram_warniera.vsd |
modelowanie_logiki_-_diagram_warniera.png |
Kilka słów wyjaśnienia. Diagram czytamy z góry na dół i od lewej do prawej. Czyli najpierw najbardziej ogólny poziom 'Generuj spisy treści' jako nazwa całego naszego programu. Potem poziom generowania spisów treści: 'Begin generuj spisy treści', 'Potrawa', 'End generuj spisy treści' itd.
Klamerka grupuje funkcje niższego poziomu wykonywane w ramach funkcji wyższego poziomu. Przykładowo dla każdej z Potraw (liczba różnych potraw wynosi 'P') wykonywane są funkcje 'Begin potrawa' (1 raz), 'Składnik' (S razy) oraz 'End potrawa' (1 raz).
Liczba '(1)' oznacza, że dana funkcja ma być wykonana jeden raz. Litery '(P)' czy '(S)' oznaczają wielokrotne powtórzenie danej funkcji. Przykładowo mając P potraw należy wziąć po kolei każdą z nich i wykonać dla każdej z nich działania zaznaczone klamerką.
Elementy w klamerce wykonywane są kolejno od góry do dołu (sekwencja).
Symbol plus wpisany w koło oznacza wybór między jedną z dwóch lub więcej wzajemnie się wykluczających alternatyw. Przykładowo w ramach funkcji 'Begin potrawa' mamy sprawdzenie czy dane potrawy są poprawne, a zatem dwie alternatywy: dane poprawne oraz dane niepoprawne. Zawsze tylko jedna z takich alternatyw jest wykonywana. Pozioma kreska nad nazwą warunku oznacza negację danego warunku.
W ramach klamerki możemy zastosować funkcje Begin oraz End. Odpowiednio rozpoczynają one oraz kończą wykonywanie funkcji wyższego poziomu np. 'Begin Potrawa'. Są to funkcje wykonywane zawsze raz. Begin przydaje się do umieszczenia tam wszelkich operacji sprawdzających poprawność danych, walidacji, sprawdzenia stanu początkowego czy podobnych np. 'Begin generuj spisy treści', 'Begin potrawa'.
End jest dobrym miejscem na wykonanie głównych funkcji jakich dotyczy dany program np. 'End składnik', 'End potrawa'. End służy do tego celu, ponieważ nie zawsze jest on wykonywany w danej sekwencji. Wiąże się to z funkcją 'Pomiń', za pomocą której opuszczamy dalsze wykonywanie sekwencji. Przykładowo, jeśli w funkcji 'Begin potrawa' okaże się, że są niepoprawne dane to pomijamy dalsze wykonywanie działań dla tej potrawy (nie wykonujemy funkcji 'Składnik' oraz 'End potrawa') i przechodzimy od razu do funkcji Begin dla następnej potrawy. Innym razem, jeśli w funkcji 'Begin składnik' okaże się, że składnik wymieniony dla potrawy nie istnieje, to w tabeli składniki to pomijamy potrawę. Wówczas, nie jest wykonywana już funkcja 'End składnik' dla tego składnika ani funkcje 'Składnik' oraz 'End potrawa' dla aktualnej potrawy. Jest to zatem wyjście dwa poziomy wyżej.
Widać, że za pomocą diagramu Warniera przechodzimy przez cały zestaw danych. Dla każdej z danych sprawdzamy wszelkie możliwe przypadki oraz wykonujemy niezbędne operacje. Możemy mieć pewność, że nic nam nie umknie. Jednocześnie, nie musimy się martwić o sprawdzanie poprawności wszystkich danych za każdym razem. Wystarczy, że to co chcemy obsłużyć jest później w sekwencji niż sprawdzenie poprawności innego typu danych. Przykładowo, w funkcji 'Składnik' możemy spokojnie założyć, że wszelkie dane powiązanej z tym składnikiem Potrawy są prawidłowe. Inaczej w ogóle nie znaleźlibyśmy się w funkcji 'Składnik'. Właśnie to następstwo stosowania sekwencji sprawia, że skomplikowane scenariusze po prostu znikają.
Diagram Warniera jest świetnym sposobem na dokumentowanie implementacji. Przekazując programistom wymagania w postaci diagramu Warniera możemy być pewni, że kod będzie łatwy w utrzymaniu. Myślę, że diagramy Warniera mają jeszcze wiele innych zalet. Najlepiej będzie jeśli przekonacie się o tym sami. Spróbujcie stworzyć diagram Warniera dla najtrudniejszego problemu jaki macie w swoim projekcie. Ja do rysowania używam Visio (klamerki są w Shapes / Callouts).
Polecam książkę: „Structured Systems Development” autor Kennetha T. Orra. Książka opisuje szczegółowo diagramy Warniera. Jest krótka i szybko się ją czyta. Jest napisana w prosty i ciekawy sposób z dużą liczbą przykładów. Niemal na co drugiej stronie jest jakiś diagram.
Osobom zainteresowanym polecam również „Logical Construction of Programs”, autor Jean Dominique Warnier. Jest napisana trudnym językiem ale za to jest tu również dużo przykładów. Zawiera ona też przykłady bardziej skomplikowane co może wam się przydać w praktyce. Mi np. pomogła zrozumieć zastosowanie funkcji 'Intermediate'.
Klamerka grupuje funkcje niższego poziomu wykonywane w ramach funkcji wyższego poziomu. Przykładowo dla każdej z Potraw (liczba różnych potraw wynosi 'P') wykonywane są funkcje 'Begin potrawa' (1 raz), 'Składnik' (S razy) oraz 'End potrawa' (1 raz).
Liczba '(1)' oznacza, że dana funkcja ma być wykonana jeden raz. Litery '(P)' czy '(S)' oznaczają wielokrotne powtórzenie danej funkcji. Przykładowo mając P potraw należy wziąć po kolei każdą z nich i wykonać dla każdej z nich działania zaznaczone klamerką.
Elementy w klamerce wykonywane są kolejno od góry do dołu (sekwencja).
Symbol plus wpisany w koło oznacza wybór między jedną z dwóch lub więcej wzajemnie się wykluczających alternatyw. Przykładowo w ramach funkcji 'Begin potrawa' mamy sprawdzenie czy dane potrawy są poprawne, a zatem dwie alternatywy: dane poprawne oraz dane niepoprawne. Zawsze tylko jedna z takich alternatyw jest wykonywana. Pozioma kreska nad nazwą warunku oznacza negację danego warunku.
W ramach klamerki możemy zastosować funkcje Begin oraz End. Odpowiednio rozpoczynają one oraz kończą wykonywanie funkcji wyższego poziomu np. 'Begin Potrawa'. Są to funkcje wykonywane zawsze raz. Begin przydaje się do umieszczenia tam wszelkich operacji sprawdzających poprawność danych, walidacji, sprawdzenia stanu początkowego czy podobnych np. 'Begin generuj spisy treści', 'Begin potrawa'.
End jest dobrym miejscem na wykonanie głównych funkcji jakich dotyczy dany program np. 'End składnik', 'End potrawa'. End służy do tego celu, ponieważ nie zawsze jest on wykonywany w danej sekwencji. Wiąże się to z funkcją 'Pomiń', za pomocą której opuszczamy dalsze wykonywanie sekwencji. Przykładowo, jeśli w funkcji 'Begin potrawa' okaże się, że są niepoprawne dane to pomijamy dalsze wykonywanie działań dla tej potrawy (nie wykonujemy funkcji 'Składnik' oraz 'End potrawa') i przechodzimy od razu do funkcji Begin dla następnej potrawy. Innym razem, jeśli w funkcji 'Begin składnik' okaże się, że składnik wymieniony dla potrawy nie istnieje, to w tabeli składniki to pomijamy potrawę. Wówczas, nie jest wykonywana już funkcja 'End składnik' dla tego składnika ani funkcje 'Składnik' oraz 'End potrawa' dla aktualnej potrawy. Jest to zatem wyjście dwa poziomy wyżej.
Widać, że za pomocą diagramu Warniera przechodzimy przez cały zestaw danych. Dla każdej z danych sprawdzamy wszelkie możliwe przypadki oraz wykonujemy niezbędne operacje. Możemy mieć pewność, że nic nam nie umknie. Jednocześnie, nie musimy się martwić o sprawdzanie poprawności wszystkich danych za każdym razem. Wystarczy, że to co chcemy obsłużyć jest później w sekwencji niż sprawdzenie poprawności innego typu danych. Przykładowo, w funkcji 'Składnik' możemy spokojnie założyć, że wszelkie dane powiązanej z tym składnikiem Potrawy są prawidłowe. Inaczej w ogóle nie znaleźlibyśmy się w funkcji 'Składnik'. Właśnie to następstwo stosowania sekwencji sprawia, że skomplikowane scenariusze po prostu znikają.
Diagram Warniera jest świetnym sposobem na dokumentowanie implementacji. Przekazując programistom wymagania w postaci diagramu Warniera możemy być pewni, że kod będzie łatwy w utrzymaniu. Myślę, że diagramy Warniera mają jeszcze wiele innych zalet. Najlepiej będzie jeśli przekonacie się o tym sami. Spróbujcie stworzyć diagram Warniera dla najtrudniejszego problemu jaki macie w swoim projekcie. Ja do rysowania używam Visio (klamerki są w Shapes / Callouts).
Polecam książkę: „Structured Systems Development” autor Kennetha T. Orra. Książka opisuje szczegółowo diagramy Warniera. Jest krótka i szybko się ją czyta. Jest napisana w prosty i ciekawy sposób z dużą liczbą przykładów. Niemal na co drugiej stronie jest jakiś diagram.
Osobom zainteresowanym polecam również „Logical Construction of Programs”, autor Jean Dominique Warnier. Jest napisana trudnym językiem ale za to jest tu również dużo przykładów. Zawiera ona też przykłady bardziej skomplikowane co może wam się przydać w praktyce. Mi np. pomogła zrozumieć zastosowanie funkcji 'Intermediate'.