R-01-07.doc

(313 KB) Pobierz
PLP_Rozdział1

 

Rozdział 1. Projekt aplikacji

Informacje ogólne

Tworzenie profesjonalnych aplikacji udaje się najlepiej przy odpowiednim wyważeniu proporcji między planem, zrozumieniem potrzeb i znajomością stosowanych narzędzi programistycznych. Nikt z nas nie lubi, gdy coś się nie udaje i z tego powodu całą pracę trzeba rozpoczynać od nowa. Dokładne zaplanowanie aplikacji przed rozpoczęciem tworzenia kodu może zapobiec wielu niepowodzeniom.

Linux jest doskonałą platformą do tworzenia aplikacji. Jego otwarta architektura i dostępność kodu źródłowego powodują, że programowanie staje się naprawdę atrakcyjne.

Niniejszej książki nie należy traktować jako akademickiego podręcznika programowania. Nie mamy zamiaru poświęcać wiele czasu na naukę zarządzania projektem lub naukę metod programowania, ponieważ na te tematy napisano już wiele dobrych książek. W podrozdziale zatytułowanym Materiały źródłowe wskazujemy niektóre zagadnienia wymagające dalszych studiów.

Autorzy książki jako programiści doceniają to, że dzięki prostym technikom i narzędziom można zaoszczędzić wiele czasu i wysiłku. W tym rozdziale omówimy sposoby unikania niektórych pułapek, które mogą pojawić się niespodziewanie podczas tworzenia rzeczywistych aplikacji (a nawet aplikacji tworzonych dla zabawy). Opiszemy tu opracowywanie wymagań, zagadnienia inżynierii oprogramowania, architekturę aplikacji oraz specyfikacje interfejsu. W dalszych częściach książki pokażemy metody kontroli kodu, oczyszczanie go z błędów, testowanie, tworzenie dokumentacji oraz zagadnienia wiążące się z wdrożeniem, czyli bazy danych i graficzne interfejsy programu.

Pokazując narzędzia i technikę programowania oraz biblioteki, będziemy w całej książce posługiwali się jedną aplikacją. Taki temat przewodni ułatwia łączenie wielu rozdziałów w jednolitą całość. Rozpoczniemy od ogólnego zdefiniowania wymagań, następnie przejdziemy do bardziej szczegółowych zagadnień budowy programu i na zakończenie otrzymamy profesjonalny, elegancki i gotowy do rozpowszechniania system produkcyjny do tworzenia programów.

Nie zamierzamy traktować budowanej w książce przykładowej aplikacji jako gotowego produktu przeznaczonego do sprzedaży. Niektóre sytuacje w naszym przykładzie są zmyślone i wielu programistów prawdopodobnie nie zgodzi się na jego praktyczne wdrożenie, w czym z pewnością będą mieli wiele racji.

Jako kanwę książki wybraliśmy aplikację wspomagającą obsługę wypożyczalni płyt DVD. Rozpoczniemy od prostego programu do przechowywania danych o dostępnych płytach DVD, a następnie będziemy dodawać do niego pewne funkcje, np. interfejs graficzny z możliwością wyszukiwania. Pokażemy także zastosowanie niektórych zasad handlowych, np. uzależnianie opłat od wielu zróżnicowanych czynników (takich jak upusty w okresie od poniedziałku do czwartku). Na zakończenie dodamy interfejs WWW pozwalający klientom na zdalną rezerwację płyt.

Rozpoczniemy od kilku wcześniej wybranych założeń dotyczących tworzenia programu.

Zdecydowaliśmy się na użycie języka C. Niezależnie od pojawienia się i wzrostu popularności nowszych i bardziej egzotycznych języków takich jak C++, Java i Perl — język C jest w stanie sprostać większości zadań, których podejmuje się programista, szczególnie w środowisku systemu Linux. Język C jest przede wszystkim językiem systemu UNIX i w nim zostało napisane jądro Linuksa, a więc istnieją dla niego interfejsy do prawie każdej funkcji systemowej. Interfejs aplikacji w Linuksie został zaprojektowany do efektywnej współpracy z programami w języku C. Z poziomu tego języka można łatwo uzyskać dostęp do baz danych i równie łatwo zbudować interfejs graficzny, posługując się pakietami GNOME i GTK+.

Decydujemy się również na użycie „pełnokrwistej” bazy danych, mimo że zakres przykładowej aplikacji nie jest na tyle obszerny, aby w pełni taką bazę wykorzystać. Jest to działanie nieco na wyrost, które umożliwi nam prezentację bazy i interfejsu graficznego w następnych rozdziałach książki.

Stopień szczegółowości aplikacji także został ustalony kompromisowo. Opisując wymagania stawiane aplikacji i jej projekt, pomijamy niektóre zagadnienia występujące w świecie rzeczywistym. Jako przykład można tu podać użycie pól o stałych rozmiarach tam, gdzie zmienny rozmiar mógłby być bardziej przydatny. Niektóre szczegółowe rozwiązania nie są więc w pełni elastyczne.

Ten rozdział składa się z trzech części. W pierwszej krótko omówimy metody tworzenia programu i ich zależność od zmieniających się wymagań. W następnej części przedstawimy wpływ rzeczywistości na formułowanie założeń i ich analizę, pokazując sposób zamiany wymagań użytkownika na bardziej sformalizowane deklaracje, które można wykorzystać podczas tworzenia projektu. Na zakończenie rozdziału przedstawimy podstawową strukturę aplikacji i zaprojektowany interfejs programowy (API) spełniający nasze założenia. Będziemy go używać w dalszych rozdziałach tematycznych naszej książki przy omawianiu zagadnień wprowadzonych w tym rozdziale.

Formułowanie założeń

Wspomnieliśmy wcześniej, że rozpoczynamy pracę od wymagań określonych dosyć ogólnikowo. Nie jest to działanie celowe, lecz po prostu akceptacja rzeczywistości. W wielu projektach proces precyzyjnego określania potrzeb klienta jest zwykłym oszustwem i jedną z przyczyn późniejszych problemów. Nie ma chyba nic gorszego, niż przekonanie się o nieprawidłowości założeń po zbudowaniu całego systemu. W najgorszym przypadku cała praca programistów może wówczas pójść na marne, klient nie zapłaci i może nawet skieruje sprawę do sądu!

Jeżeli nie będziemy zwracać uwagi na to, co nasza aplikacja ma robić, to napotkamy wiele problemów. Mogą to być:

q       poszerzanie i zmiana wymagań (tzw. rozrost właściwości programu),

q       dowolność wymagań,

q       niepełne wymagania lub przyjmowanie z góry jakichś założeń,

q       błędne wymagania,

q       brak elastyczności w fazie projektowania i tworzenia kodu.

Rozrost właściwości programu (ang. feature creep) możemy zaobserwować wówczas, gdy rozpoczniemy pospieszne tworzenie kodu aplikacji. Odbywa się to tak, że mamy ogólne wyobrażenie o tym, co chcemy zrobić, i od razu rozpoczynamy tworzenie kodu. Następnie odkrywamy, że trzeba uwzględnić nową właściwość, zmienić jakąś funkcję lub obsłużyć nowy interfejs. Jeżeli nie uzgodniliśmy z klientem precyzyjnie zakresu wykonywanych dla niego prac, to zaczną się pojawiać coraz to nowe żądania. W takich przypadkach może się zdarzyć, że nigdy nie zakończymy tego, co rozpoczęliśmy! Na szczęście są sposoby uniknięcia tego typu sytuacji.

Dowolność wymagań może się pojawić wówczas, gdy nie dbamy o precyzję używanych sformułowań lub gdy użyte sformułowania mają kilka znaczeń. W języku angielskim, podobnie jak w polskim, istnieje wiele takich słów. Np. słowo „skład” w dawnym znaczeniu to „sklep” lub „magazyn”. Znajdziemy się w wielce kłopotliwym położeniu, jeśli zbudujemy aplikację dla niewłaściwego rodzaju „składu”. Widać więc, jak ważne są dokładne definicje używanych terminów i unikanie technicznego żargonu, jeśli tylko jest to możliwe.

Przyjmowanie z góry jakichś założeń może być bardzo mylące. Prowadzi to do kłopotów zwłaszcza wtedy, gdy działamy w nieznanym obszarze zagadnień. Możemy np. nie zdawać sobie sprawy, że numery ISBN nadawane książkom zawierają cyfrę kontrolną i utworzymy aplikację nie uwzględniającą tego faktu. Wydawnictwo będące naszym klientem nie poinformuje nas o konstrukcji numeru, ponieważ jest to rzecz doskonale znana w tym środowisku zawodowym. Wszyscy oprócz nas wiedzą, że systemy wydawnicze muszą to obsługiwać — mamy więc przykład milczącego przyjęcia założenia.

Jako inny przykład niedopowiedzianych założeń możemy podać zaokrąglanie sum do najbliższych pięciu centów przy płatnościach gotówkowych w Australii i Nowej Zelandii. Wynika to z tego, że monetą o najmniejszym nominale jest tam właśnie pięć centów. Spróbujmy postawić się w sytuacji programisty, który nie uwzględni tego faktu! Podobnie będzie w krajach stosujących podatek od wartości dodanej (VAT) — tu wszyscy oczekują, że systemy obsługi sprzedaży będą go wyliczać zgodnie z miejscowymi zasadami.

Możemy zaoszczędzić wiele czasu niepotrzebnie traconego na borykanie się z tego typu problemami, jeżeli zachowamy ostrożność, będziemy rejestrowali wymagania w sformalizowany sposób i nadamy im odpowiedni priorytet, aby zawsze orientować się w ich ważności.

Jeżeli uzgodnimy zakres funkcjonalny naszej aplikacji przed rozpoczęciem zaawansowanych prac przy tworzeniu kodu, to unikniemy w przyszłości rozrostu wymaganych właściwości, a jeżeli takie zmiany nastąpią — będziemy mogli żądać dodatkowej zapłaty. Aby zachować kontrolę nad zmianami wymagań, możemy użyć „listy życzeń” z zapisem rozrastających się funkcji, na której klient będzie zatwierdzał koszty i skutki żądanych przez niego modyfikacji.

Jeżeli upewnimy się, że na etapie formułowania założeń zgromadzono wystarczająco dużo szczegółów, to prawdopodobieństwo wystąpienia niespodziewanego braku lub przemilczenia wymagań będzie znacznie zmniejszone.

Dowolność w formułowaniu żądań można zmniejszyć, stosując wspólne słownictwo i definiując wszystkie specjalistyczne określenia użyte w założeniach. Należy dokładnie wyrazić wymagania poprzez użycie krótkich zdań, w których słowa takie jak „wymaga” czy „musi” odnoszą się do wymagań obowiązkowych, zaś słowa „powinno” lub „może” dotyczą właściwości opcjonalnych, które aplikacja może mieć przy zapewnieniu odpowiednich środków i czasu na jej realizację. Wszystkie wymagania muszą być sprawdzalne, tzn. powinna istnieć możliwość zbudowania takich testów, które odpowiedzą na pytanie, czy system spełnia dane wymagania. Np. nie można zbadać, czy aplikacja działa „szybko”, ale można sprawdzić, czy aplikacja „reaguje w ciągu kilku sekund”.

Konieczność dobrego zrozumienia wymagań użytkownika może być bardzo frustrująca podczas tworzenia kodu. Trzeba jednak pamiętać, że ten użytkownik (lub sponsor) jest naszym klientem i ma wolność wyboru środków opisujących swoje wymagania. Może się więc zdarzyć, że zapis na serwetce będzie wszystkim, co od niego otrzymamy. Programiści muszą być przygotowani na takie sytuacje. Ponieważ klienci nie mają zwykle ochoty na przygotowanie założeń w odpowiedniej postaci, obowiązek ten spada na nas.

Ogólnie mówiąc, wymagania można podzielić na kilka kategorii, które obejmują:

q       funkcjonalność (czyli to, co trzeba będzie wykonać),

q       wydajność (czyli jak szybko i jak wiele),

q       cechy użytkowe (czyli wygląd ekranów i wymagania czasowe),

q       zgodność (czyli określenie, czego wymaga system przy podłączaniu się do niego),

q       cena,

q       jakość.

Po zebraniu wymagań obydwie strony muszą potwierdzić swoje uzgodnienia, najlepiej w postaci podpisanego dokumentu.

Modele tworzenia kodu

Model zstępujący

Jednym z klasycznych modeli tworzenia aplikacji jest tzw. model zstępujący (ang. waterfall model). Polega on na tym, że każdy etap projektu musi zostać zakończony przed rozpoczęciem następnego. Na rysunku poniżej pokazano schemat działania takiego modelu:

 

Wśród wad tego modelu można wskazać brak innej możliwości reagowania na zmiany w założeniach poza przerwaniem całego projektu. Dodatkowym zagrożeniem jest tu umieszczenie testów pod koniec całego procesu. Jeżeli np. wykryje się błąd w interfejsie lub gdziekolwiek indziej, to skutki mogą być wówczas fatalne.

Niektóre odmiany modelu zstępującego umożliwiają powrót do wcześniejszych etapów, ale nie są to zwykle czynności planowe i konieczność ich stosowania oznacza, że model niezbyt dobrze pasuje do rzeczywistości.

Model iteracyjny

Model iteracyjny (ang. iterative development) reprezentuje współczesne podejście do zagadnienia tworzenia aplikacji i pokonuje wady modelu zstępującego, które polegają na ścisłym wyznaczeniu granic poszczególnych etapów.

Podejście iteracyjne bywa stosowane wtedy, gdy planuje się zmianę założeń podczas realizacji projektu. Na początku zakłada się niewielką liczbę iteracji w celu doskonalenia produktu końcowego. Odzwierciedlają one wyobrażenie o tym, jak odbiorca będzie zmieniał swoje pomysły, nawet jeśli na początku miał na dany temat zupełnie inne zdanie. Elastyczne programy, takie jak np. interfejsy graficzne lub wymyślne systemy wspomagania decyzji, same z siebie są przedmiotem zmiany założeń lub rozrostu wymagań. Trzeba wówczas znaleźć sposób zapobiegania zbyt częstym narzekaniom „Będę to wiedział, jak zobaczę” lub, co gorsza, „Miałem na myśli coś innego, czy możemy to zrobić?”. Model iteracyjny pozwala na cofnięcie się do założeń, dzięki czemu użytkownik widzi wczesne wersje programu a programista może utrzymywać uporządkowaną strukturę logiczną swojego środowiska pracy.

W modelu iteracyjnym obowiązuje ogólna zasada umieszczania w początkowych iteracjach obowiązkowych wymagań o najwyższym priorytecie (jest to tzw. wersja 1.0). Jest on zalecany dla programów o modułowej budowie, z powierzchownym interfejsem graficznym i zmieniającymi się metodami dostępu do danych.

 

Z powyższego schematu wynika, że w każdej iteracji wykonywane są zadania jak dla modelu zstępującego. Zazwyczaj planuje się niewielką liczbę iteracji, w których są rozwiązywane ściśle określone zestawy wymagań. Może się okazać, że większe projekty tworzone w zmiennym środowisku będą wymagały przebudowy kodu, ale zawsze jest to planowane przed rozpoczęciem kolejnej iteracji.

Warto podkreślić, że proces projektowania (i uściślania wymagań) przechodzący do procesu tworzenia kodu i potem do procesu testowania trwa przez cały czas realizacji projektu.

Metoda szybkiego śledzenia

Problem określany jako „Będę to wiedział, jak zobaczę” można czasami pokonać, projektując i programując prostą aplikację od razu po ustaleniu podstawowych wymagań (ang. fast track development — metoda szybkiego śledzenia). Podstawowa aplikacja może więc na początku nie działać dobrze i będzie na pewno pozbawiona wielu funkcji, ale stanowi dobre odniesienie dla procesu gromadzenia założeń.

Zauważmy, że nie jest to dokładnie to samo, co prototyp do jednorazowego użytku. Nie budujemy tutaj aplikacji makietowej przeznaczonej do wyrzucenia (może jednak tak się zdarzyć, jeśli założenia były nierealne). Kod aplikacji ma być kodem rzeczywistym, na którym będzie można sprawdzić słuszność wybranych algorytmów. Plan naszego projektu powinien zawierać dwie lub trzy takie aplikacje cząstkowe, które będą ulepszane, a nie wyrzucane lub tworzone od nowa. Wyjątkami mogą być tu testowe zawartości ekranu, projektowane tylko dla uzgodnienia wyglądu interfejsu.

Wczesne i częste testy

Tuż po utworzeniu wstępnego projektu należy rozpocząć jego testowanie. Zazwyczaj plan testów sporządzany w pisemnej postaci zawiera opis wszystkich niezbędnych testów. Można wówczas weryfikować projekt, sprawdzając czy jego właściwości na danym etapie spełniają przyjęte założenia.

Oprócz tego należy określić strategie testowania całej aplikacji. Możemy podjąć decyzję, co należy testować, jakich narzędzi użyć do tego celu oraz co włączyć w samej aplikacji, aby testowanie było bardziej efektywne.

Testowaniem powinny być objęte następujące obszary:

q       Elementy kodu (testowanie bloków).

q       Interfejsy między elementami (testy integralności).

q       Cały system (testy systemu).

Po dokonaniu zmian należy ponownie przeprowadzić testowanie w celu upewnienia się, że nie powstały nowe problemy. Takie testy nazywane są testami regresyjnymi (ang. regression testing).

Na zakończenie należy pokazać klientowi, że ukończony system rzeczywiście spełnia uzgodnione wymagania. Jest to tzw. test odbiorczy (ang. acceptance testing).

Przed rozpoczęciem tworzenia początkowego kodu należy przetestować środowisko programowania, sprawdzając obecność i poprawność działania kompilatorów i bibliotek.

Po utworzeniu wstępnego kodu przeprowadzamy jego test, sprawdzając poprawność wybranej strategii testowania oraz obecność i poprawność działania niezbędnych narzędzi.

Ogólnie mówiąc, chcąc zmniejszyć ryzyko popełnienia błędu należy testować wszystko i jak najczęściej. Model zstępujący programowania nie sprawdza się więc najlepiej, ponieważ testy są w nim przeprowadzane na zakończenie projektu. Wówczas może być za późno na stwierdzenie, że np. użycie jakiegoś egzotycznego języka programowania było błędem, ponieważ dostępny dla niego debugger nie będzie działał na danym sprzęcie, albo że użyty interpreter nie działa wystarczająco szybko i powoduje spadek wydajności całej aplikacji.

Więcej na temat testów można się dowiedzieć z rozdziału 11.

Wypożyczalnia DVD

Wybierając naszą przykładową aplikację, wyobraźmy sobie wypożyczalnię płyt DVD, w której cała dokumentacja prowadzona jest w postaci zapisów na papierze. Właściciel zadecydował, że jest mu potrzebny system wspomagający codzienne operacje, ponieważ pozwoli mu to przezwyciężyć szereg niedogodności związanych z dokumentacją papierową.

Właściciel wypożyczalni nie jest rzeczywistą postacią. Będziemy posługiwali się jego słowami głównie w sprawach dotyczących ograniczenia kosztów (co nie wymaga naszej pracy) oraz użycia otwartego oprogramowania. Zakładamy także, że właściciel rozumie, iż określenie „System operacyjny” nie oznacza automatycznie Windows.

Ponieważ nasza książka jest poświęcona programowaniu w systemie Linux, byłoby wielce niezręczne utworzenie aplikacji, która miałaby charakter programu zamkniętego, bez udostępnienia wersji źródłowej, używającego zastrzeżonej bazy danych z systemu Windows NT. Takie wewnętrzne ograniczenia nie występują w systemie Linux. Oczywiście, programista może zawsze zdecydować się na tworzenie rozwiązań zastrzeżonych, stosując komercyjne produkty.

Musimy porozmawiać z kierownikiem wypożyczalni, aby zapoznać się z jej działaniem i zrozumieć występujące tam problemy. Warto również zaobserwować funkcjonowanie wypożyczalni i porozmawiać z jej klientami. Wszystko to ma na celu dobre poznanie otoczenia, w którym ma działać system.

Na tym etapie gromadzenia założeń prawie zawsze odkrywamy fakt, że klient zazwyczaj mówi, jak są wykonywane jakieś operacje, a nie czego one dotyczą. Bardzo ważne jest zdobycie informacji o tym, do czego poszczególne operacje służą — w przeciwnym wypadku powstanie skomputeryzowany system obsługi istniejących problemów, a nie system rozwiązujący te problemy.

Założenia wstępne

Rozmawiając z właścicielem wypożyczalni zdobędziemy pewne wymagania początkowe. Każdemu z tych wymagań należy nadać unikatowy identyfikator. Wymagania użytkownika (klienta) będziemy wyróżniać początkowymi literami „UR”:

UR1 — klienci zwracają płyty DVD do skrytki jeszcze przed otwarciem wypożyczalni. Jeśli zwrócono kilka kopii tego samego filmu, to nie mogę ich rozróżnić.

UR2 — nie mam innego sposobu na sprawdzenie, które płyty są w danym momencie wypożyczone przez klientów, jak pójście na zaplecze i rzut oka na regał. Zniechęca to klientów, którzy muszą odstawić pudełko na półkę, ponieważ okazało się, że film został wypożyczony.

UR3 — system musi być przyjazny.

UR4 — chciałbym utrzymać kasę sklepową, ponieważ niedawno ją kupiłem.

UR5 — słyszałem o tym, że programiści udostępniają klientom kody źródłowe systemów komputerowych i chciałbym taki kod uzyskać. W przyszłości, jeśli coś będzie źle działać lub zechcę coś zmienić, wykonanie poprawek będę mógł zlecić komu zechcę.

UR6 — na system nie mogę wydać więcej niż 1000 dolarów, a na wykonaną pracę sporządzimy oddzielną umowę.

Zwróćmy uwagę na to, że żądania są dość niejasne i można je spełnić w różny sposób. Podstawowym zadaniem na tym etapie jest więc wyjaśnienie i sprecyzowanie wymagań oraz podział żądań bardziej złożonych na kilka prostszych. Numeracja wymagań użytkownika ułatwia ich późniejsze śledzenie. W tej fazie projektu nie należy zbyt mocno koncentrować się na wyniku końcowym, jednak warto określić w sposób ostateczny, czy niektórych z wymagań nie będzie można spełnić lub czy nie są one zbyt kosztowne.

Pierwotna lista wymagań wygląda całkiem nieźle, ale nie odpowiada na podstawowe pytanie: ile płyt DVD i ilu klientów obsługuje wypożyczalnia? Te dane musimy poznać z aktualnego stanu wypożyczalni.

Wprowadzamy więc kolejne wymagania:

UR7 — dysponuję pięcioma tysiącami tytułów na siedmiu tysiącach płyt.

UR8 — niedawno wydałem kartę klienta o numerze 9000; przypuszczam także, że kilku klientów zrezygnowało z usług mojej wypożyczalni, nie żądając usunięcia swoich danych.

Analiza wymagań klienta

Mamy już niektóre wymagania naszego klienta i możemy zostawić właściciela wypożyczalni w spokoju. Spróbujemy teraz zrozumieć żądania i zapisać je w sposób bardziej precyzyjny.

Rozpoczniemy od wymagań UR1 i UR7:

UR1 — klienci zwracają płyty DVD do skrytki jeszcze przed otwarciem wypożyczalni. Jeśli zwrócono kilka kopii tego samego filmu, to nie mogę ich rozróżnić.

UR7 — dysponuję pięcioma tysiącami tytułów na siedmiu tysiącach płyt.

W powyższych stwierdzeniach widzimy bardzo ważny fakt: wypożyczalnia ma wiele kopii wielu płyt i potrzebna jest informacja o tym, kto zwrócił daną kopię (nie wystarcza znajomość samego tytułu zwracanej płyty). Jeżeli nie dostrzeżemy faktu, że tytuł płyty DVD (np. film „2001”) musi być obsługiwany przez system inaczej niż dana płyta DVD (kopia nr 3 filmu „2001”), to czeka nas później pracochłonna przeróbka aplikacji.

Możemy przedstawić te wymagania w sposób bardziej sformalizowany, rozbijając je na więcej treściwych deklaracji:

[[[ramka]]]

R1: wypożyczalnia musi obsługiwać ponad 5000 różnych tytułów.

R2: wypożyczalnia musi obsługiwać ponad 7000 różnych płyt.

R3: trzeba obsłużyć co najmniej 5 różnych kopii każdego tytułu.

R4: na podstawie zwracanej płyty trzeba mieć możliwość określenia, który klient ją zwrócił.

[[[koniec ramki ]]]

Przejdźmy teraz do wymagania UR2:

UR2 — nie mam innego sposobu na sprawdzenie, które płyty są w danym momencie wypożyczone przez klientów, jak pójście na zaplecze i rzut oka na regał. Zniechęca to klientów, którzy muszą odstawić pudełko na półkę, ponieważ okazało się, że film został wypożyczony.

Jest to dość dziwny problem, który można rozwiązać wieloma metodami, nie posługując się przy tym komputerem. Rzecz polega na tym, że klienci wybierają pudełko płyty DVD z półki, podchodzą do lady, muszą czekać, aż ktoś z obsługi sprawdzi dostępność płyty na zapleczu i jeśli płyty nie ma — muszą odnieść pudełko na półkę. Na podstawie znajomości wcześniej zaobserowanych systemów rejestracji „zeszytowej” możemy też stwierdzić, że obsługa wypożyczalni na ogół nie wie, kiedy zostaną zwrócone wypożyczone kopie.

Jako rozwiązanie nie wymagające użycia komputera można zaproponować stosowanie przywieszek na pudełkach płyt, które oznaczałyby wypożyczenie wszystkich kopii. Coś takiego na pewno pomoże, ale jest dosyć pracochłonne.

Do naszego proponowanego systemu możemy dodać funkcję, która będzie informować klienta, że wszystkie kopie są wypożyczone oraz kiedy nastąpi zwrot. Powinno być to zupełnie proste, ponieważ trudno wyobrazić sobie sprawnie działający system, który nie udostępnia informacji o wypożyczonych płytach. Jedyną wadą takiego rozwiązania będzie to, że klient nadal będzie musiał podejść do lady z pudełkiem po płycie, aby uzyskać informację, że płyta nie jest dostępna. Usunięcie znacznika wypożyczenia będzie prostsze i może zmniejszyć kolejkę przy ladzie. Na podstawie osobistych doświadczeń wiemy jednak, że wcale nie musi tak być.

Jeżeli chcemy działać zdecydowanie, to możemy zaproponować następny krok. Załóżmy, że wstawimy do wypożyczalni terminal dla klientów, na którym sami będą mogli sprawdzić dostępność danej płyty. Mogłoby to zmniejszyć kolejkę przy ladzie i nakład pracy, a nawet liczbę personelu. A gdyby rozwinąć ten pomysł szerzej i zezwolić klientom na wyszukiwanie nowych tytułów z ich ulubionymi gwiazdami? Właściciel wypożyczalni mógłby przystać na takie rozwiązanie, jeżeli nie byłoby zbyt drogie... ale musimy pamiętać o drzemiącej możliwości rozrostu funkcji.

Aby uniknąć poszerzania własnych pomysłów, powinniśmy ponownie porozmawiać z właścicielem wypożyczalni i sprawdzić jego reakcję na nasze propozycje. Zostawiamy więc otwarte wymagania:

[[[ramka]]]

R5: potrzeba efektywnego sprawdzania, czy wszystkie kopie danego tytułu są wypożyczone i gdzie się one znajdują.

R6: potrzeba wyszukiwania dostępnych tytułów w bazie danych.

[[[koniec ramki]]]

 

Powyższe wymagania musimy uściślić później (i, być może, nadać im odpowiedni priorytet).

Przejdźmy teraz do wymagania UR3:

UR3 — system musi być przyjazny.

Nie jest to zagadnienie, nad którym można łatwo przejść do porządku dziennego. Nic nas nie upoważnia, aby takie żądanie zignorować. Czy oznacza to, że obsługa systemu ma być tak intuicyjna, że niepotrzebne będzie żadne szkolenie? Czy oznacza to, że system prowadzi użytkownika „za rękę” przy każdym podejmowanym przez niego działaniu? Prawdopodobnie są w tym żądaniu ukryte jakieś założenia na temat wydajności systemu — przecież system działający powoli nie będzie systemem przyjaznym! Być może, najlepiej byłoby zastosować interfejs graficzny ułatwiający obsługę poszczególnych funkcji, a następnie — po utworzeniu wstępnego projektu aplikacji — uzyskać od zamawiającego zgodę na przyjęte rozwiązania.

Zajmiemy się teraz wymaganiem UR4:

UR4 — chciałbym utrzymać kasę sklepową, ponieważ niedawno ją kupiłem.

Musimy wyjaśnić, co właściciel miał na myśli, formułując takie żądanie. Czy myślał, że system wymaga integracji z istniejącą kasą sklepową, czy nie chciał, aby system ją zastąpił, ponieważ mogłoby to kosztować drożej? Wyjaśnienie tych pytań jest ważne, ponieważ mogą one oznaczać zarówno brak wymagań, jak i ich nadmiar.

W rozmowie z właścicielem dowiedzieliśmy się, że spodziewa się on systemu, który będzie oddzielony od kasy sklepowej i na będzie jedynie wyświetlał na ekranie należną opłatę. Oznacza to duży sukces i mniejszą pracochłonność aplikacji, a więc formułujemy następujące wymaganie:

[[[ramka]]]

R7: system ma wyświetlać na ekranie kwotę należnej opłaty bez integracji z systemem kasowym.

[[[koniec ramki]]]

 

Można sobie wyobrazić, jak wiele pracy musieli...

Zgłoś jeśli naruszono regulamin