niedziela, 7 lutego 2010

Inżynieria w służbie użyteczności

/*
 *Tytuł niczym wzięty ze sztandaru
 *z jakiegoś pochodu
 *z uprzedniej smutnej epoki:)
 */

Witam po długiej przerwie. Zaprezentuję dziś pewne ujęcie Usability oraz koncepcję technicznego rozwiązania użytecznej aplikacji - jej architekturę i dwa główne wzorce projektowe.

NOWICJUSZ vs EKSPERT
Użyteczność niejedno ma oblicze. Możemy mówić o przejrzystości, intuicyjności, ergonomii itd. Każdy z nas zapewne zdefiniuje dobre GUI jako takie, które oferuje to czego się spodziewamy. Ale co to znaczy? Oczywiście dla każdego coś innego.

Dziś skupimy się na problemie różnych potrzeb i oczekiwań użytkowników o różnym poziomie zaawansowania.

Analizując Model Rozwoju Kompetencji Braci Dreyfus
krótki opis
szerszy opis
możemy wywnioskować, że użytkownicy reprezentujący skrajne poziomy kompetencji potrzebują skrajnie odmiennego GUI.

Nowicjusz i Zaawansowany Początkujący są nastawieni na zadania ponieważ nie ogarniają jeszcze całości problemu. Potrzebują określonej ścieżki, przez którą będą prowadzeni za rękę a na każdym etapie dostaną jasne wytyczne odnośnie tego CO trzeba zrobić.

Z drugiej zaś strony Kompetentny, Biegły i Ekspert są nastawieni na osiągnięcie celu i mniej lub bardziej orientują się jak go osiągnąć.

Jak to w życiu bywa: "różni ludzie, różne potrzeby".

Mniej zaawansowani użytkownicy potrzebują aplikacji-asystenta zorientowanej na zadania. Aplikacja taka nie powinna atakować mnogością możliwości. Powinna w danym momencie sugerować (lub wręcz zmuszać) do zrobienia właściwej rzeczy. Przykładem mogą być nasze ulubione kretynatory (yyy kreatory).

Zaawansowany użytkownik potrzebuje aplikacji zorientowanej na możliwości. Dla niego wygodne będzie rozbudowane menu, bez sugerowania co kiedy kliknąć. Zaawansowany użytkownik dobrze wie co chce zrobić i nie potrzebuje aby mu podpowiadać. Mało tego, taki użytkownik ma wyrobiony swój własny styl pracy, zatem aplikacja-asystent jedynie przeszkadza. Najlepszym przykładem może być: IDE (np. Eclipse), zaawansowany edytor tekstu albo narzędzie typu CAD. Tysiące opcji w menu i biała kartka na dzień dobry.


Klasyczny problem występujący w aplikacjach biznesowych to nauka obsługi użytkowników. Stare systemy tej klasy orientowało się na możliwości (teraz powoli sytuacja ulega zmianie). Mamy zatem nieszczęsną użytkowniczkę, która zaczyna naukę obsługi systemu (może również jednocześnie "uczy się komputera"). Przytłoczenie mnogością opcji skutkuje jednym: tresurą. Użytkownik nie ma innego wyjścia jak opanowanie procesu biznesowego na zasadzie szympansa: klikam trzeci z lewej, później ok, później przedostatnia zakładka, później klikam drugi od dołu...

Wszyscy znamy też nietrafione rozwiązanie, które miało pomagać nowicjuszom w okiełzaniu eksperckiego narzędzia - spinacz w Office;)

PRZYKŁAD APLIKACJI
W przypadku aplikacji korporacyjnych jest łatwiej. Użytkownik nie ma innego wyjścia jak zacisnąć zęby i nauczyć się (pardon - wytresować się). Jest to po prostu przykre narzędzie jego pracy.

Natomiast gdy nasza aplikacja ma konkurować na wolnym rynku wówczas musimy nieco się wysilić. Użytkownik zirytowany autystycznym GUI aplikacji po prostu porzuci ją, zaklnie i pójdzie sobie do konkurencji:)

Użytkownicy są teraz niezbyt cierpliwi i mają wysokie wymagania odnośnie przyjemności - pokolenie MTV?


Aby ustalić kontekst aplikacji walczącej o klienta wysokim poziomem użyteczności wyobraźmy sobie system do projektowania wnętrz, np. wnętrz kuchni.
Niech zaprojektowanie wymaga między innymi: określenia obszaru pomieszczenia, ustalenia otworów i innych przeszkód, rozstawienia mebli i AGD, dopasowania wszystkich wymiarów, wyboru materiałów z których mają być wykonanie poszczególne elementy, itd. Dalej mamy rysunki techniczne, wyliczenia należności, umowy, itp.

Ustalmy wyzwanie: z aplikacji ma być wykorzystywana przez:
- klientów końcowych, którzy to raz na kilka(naście) lat kupują sobie "kuchnię"
- projektantów kuchni, którzy dziennie wyklikują po kilka takich zestawów.

Co z kompetencjami naszych użytkowników?
Jasne jest, że klient końcowy jest totalnym Nowicjuszem jeżeli chodzi o aplikację. Użyje jej raz (ew jako rodzinny "haker" pomoże szwagrowi wyklikać jego zestaw). Zatem nigdy nie nabędzie wyższych kompetencji. Co gorsza klient może być również niekompetentny w domenie problemu, czyli wszystkich zagadnieniach związanych z kuchniami.
Manual oczywiście odpada, bo zirytowany klient pójdzie sobie do konkurencji.

Projektant jest zwykle w miarę kompetentny w domenie problemu;) Będzie też Nowicjuszem jako użytkownik, ale ponieważ będzie miał motywację i częstą styczność z aplikacją to szybko osiągnie poziom Kompetentny a z czasem dojdzie do Eksperta.

ARCHITEKTURA ROZWIĄZANIA
Mamy zatem dwie klasy użytkowników, którzy potrzebują diametralnie różnego interfejsu. Początkujący użytkownik wymaga przeprowadzenia go przez cały proces projektowania krok po kroku, bez zbędnych pytań, defalutowo, szybko, gładko i bez irytacji. Zaawansowany użytkownik potrzebuje natomiast wolności, możliwości i tysięcy szczegółowych opcji.

Jak to pogodzić? Czy musimy tworzyć niemal 2 osobne aplikacje?
Niekoniecznie, jeżeli podejdziemy do problemu racjonalnie to możemy zredukować narzut związany z przygotowaniem 2 wersji.

Możemy podejść do problemu następująco:

Wydzielamy CORE aplikacji, który zawiera klasy odpowiedzialne za główną funkcjonalność, czyli projektowanie wnętrz (wraz ze wszystkimi regułami z tym związanymi) oraz wizualizację projektu.
Core jest dostępny przez API.

Mamy 2 zestawy GUI: jeden prosty i intuicyjny oraz zorientowany na zadania przeznaczony dla początkujących. Drugi to klasyczny potwór dla eksperta oferujący niezliczone możliwości w rozbudowanych menu.

Oba rodzaje GUI komunikują cię z Corem wysyłając polecenia zhermetyzowane przy użyciu wzorca projektowego Command. Idea wzorca jest taka, że czynności nie są metodami (jak w klasycznym podejściu proceduralnym). Czynności są obiektami. Dla wszystkich klas poleceń istnieje wspólny interfejs zawierający jedną metodę - jest to sygnał do polecenia aby wykonało ono zawartą w sobie logikę.

Konkretny command zawiera w sobie zestaw instrukcji operujących na API Cora. Oczywiście commandy wysyłane z GUI Nowicjusza będą zawierać więcej kodu operującego na API. Jedna czynność takiego użytkownika wykonuje więcej operacji. Commandy wysyłane z GUI Eksperta będą bardziej elementarne. Commandy mogą po sobie dziedziczyć, mogą się na wzajem dekorować z wykorzystaniem wzorca Dekratora w celu reużycia logiki.

W przedstawionej architekturze mamy dodatkowo wzorzec Mediatora. Został on wprowadzony jako "środowisko uruchomieniowe" dla poleceń oraz "hub" spinający wiele komponentów. GUI wysyła commadny do Mediatora, a to mediator wykonuje otrzymane polecenie (uruchamiając wspólną metodę interfejsu) przekazując do nich kontekst uruchomienia, czyli core.
Mediator może również przy okazji manipulować stanem GUI, które nie należy do Core (np nakładać przeźroczystą chmurę na czas długotrwałych operacji bądź włączać dostępność opcji w menu). Mediator może też generować zdarzenia aplikacyjne, które będą obsługiwane przez pewne komponenty graficzne prezentujące zajście danego zdarzenia. Można bawić się do woli z Mediatorem, ale trzeba uważać aby nie stał się boską klasą o zbyt dużej odpowiedzialności.

ZWIĘKSZAMY USABILITY
Każdy użyteczny system, którego idea zasadzą się na bogatej interakcji użytkownika powinien oferować funkcjonalność "Cofnij". Wprowadzenie tej funkcjonalności jest generalnie bardzo kłopotliwe. Kto zmagał się z tym problemem ten zapewne próbował niewydajnego rozwiązania polegającego na "zrzucie" aktualnego stanu do pamięci podczas wykonywania każdej operacji modyfikującej stan.

Ogólnie jest to problematyczna funkcjonalność, chyba że...


...posiłkujemy się wzorcem Command:)

Możemy wówczas rozszerzyć go o anti-command.
Każde polecenie zawierające logikę zawiera w sobie anty polecenie (jako obiekt dostępny przez getter - a getter w interfejsie Command). Antypolecenie zawiera logikę odwrotną do polecenie.

Teraz w naszym przypadku Mediator wykonując polecenie, pobiera z niego anty-polecenie i odkłada je na stosie. W razie potrzeby, czyli gdy użytkownik kliknie cofnij (ctrl+z) wołamy Mediatora, który pobierze polecenie ze stosu anty-poleceń i wykonana go. Proste:)


//==============================

O ile omawiana problematyka usability w kontekście kompetencji użytkownika jest ogólna, to przedstawione rozwiązanie nie aplikuje się do aplikacji webowych z cienkim klientem. Zresztą taki klient ma zastosowanie do innej klasy problemów.

Natomiast rosnąca popularność grubszych klientów (opartych o: flex, javafx, silverligh, stare-dobre-niedoinwestowane-przez-matołów-suna applety czy nawet GWT) pozwala przewidywać, że coraz częściej będziemy spotykać się problemami tej klasy.