Szkopuł w projekcie ukryty

Istnieje opinia, że kluczem do sukcesu jest właściwe zaprojektowanie aplikacji. To niewątpliwie prawda, ale... co to znaczy "właściwe zaprojektowanie"?

Istnieje opinia, że kluczem do sukcesu jest właściwe zaprojektowanie aplikacji. To niewątpliwie prawda, ale... co to znaczy "właściwe zaprojektowanie"?

W Internecie można znaleźć szczegółowe informacje o tym, jak włamać się do automatów sprzedających napoje - urządzeń, których oprogramowanie jest banalnie proste. Mówimy o urządzeniu, które ma kilka przycisków typu "kawa czarna", "kawa z mlekiem", "dodaj cukier" itp. Jeśli nawet tak prostego automatu stanów nie da się zaprojektować bezbłędnie (połączenie błędów sprzętowo-programowych), trudno oczekiwać, że twory odrobinę bardziej skomplikowane, jak aplikacje biznesowe, będą błędów pozbawione. Skąd zatem biorą się dobre i złe projekty?

I tak źle, i tak niedobrze

Współczesne aplikacje w coraz mniejszym stopniu są wynikiem pracy programisty. Niezależnie od użytej technologii (może z wyłączeniem rozwiązań czysto open source) menedżer projektu ma dwie opcje: poświęcić czas własnego programisty albo kupić na rynku gotowe rozwiązanie (lub ewentualnie skorzystać z darmowego). W przypadku typowych aplikacji biznesowych zewnętrzna biblioteka obsługuje zwykle interfejs użytkownika (nawet gdy jest to rozwiązanie z interfejsem przeglądarkowym) oraz bazę danych, czy to w postaci ORM, czy po prostu pewnych "pomocniczych" procedur.

Coraz częściej zdarza się też, że do opisu logiki biznesowej wykorzystuje się gotowe, mniej lub bardziej formalne mechanizmy przepływu. Wszystko spina framework oparty na jednej z wielu koncepcji: MVC (Model-View-Controller), MVP (Model-View-Presenter) czy np. PAC. W konsekwencji już na starcie projektu mamy w nim kilka różnych koncepcji obiektowych. Wprawdzie producenci kontrolek interfejsu użytkownika dodatkowo oferują zwykle rozwiązania do współpracy z danymi, ale nierzadko zdarza się, że te propozycje projektantowi "nie pasują".

Tymczasem narzędzia do modelowania UML nie mają elastycznych metod uwzględniających "zewnętrzne" komponenty. Można definiować pakiet, tworzyć własne zestawy definicji API dla konkretnej platformy, ale to wciąż za mało. Większość producentów oferuje specjalne edycje z kodem źródłowym, ale po pierwsze są one droższe, a po drugie firmy często rozumują w ten sposób, że po to kupują gotowy kawałek oprogramowania, by nie zastanawiać się jak został napisany. Praca nad nowym rozwiązaniem polega dziś w dużej mierze na integracji różnych rozwiązań stworzonych samodzielnie i kupionych na rynku. To nie to samo co dziesięć lat temu. Praca programisty w tzw. cywilizowanych krajach stała się zbyt droga.

Tu pojawia się kolejny problem. Warstwa dostępu do danych każdej aplikacji ma swój styl definiowania struktury obiektowej - odmienny od tego, który przyjęli twórcy kontrolek użytkownika. Logika biznesowa korzysta z tego, co uzyskuje od warstwy dostępu do danych, a następnie musi to przekazać do warstwy interfejsu użytkownika. Może tego dokonać, definiując jakąś wspólną warstwę do wymiany danych, ale... nie jest to ani proste, ani eleganckie. Na wszystko to nakładają się własne standardy modelowania oprogramowania, które powstały podczas tworzenia modelu UML. A zatem którąkolwiek koncepcję obiektową programista wybierze, wybór nie będzie doskonały.

Wzorce i fabryki

Jeżeli zakładamy, że rozwiązanie korzysta z zewnętrznego kodu, można rozważyć użycie trochę innych narzędzi, np. tzw. software factories. W pewnym sensie przypominają one biblioteki dołączane do programu, ale biblioteki specyficzne, które można konfigurować do realizacji określonych zadań. W przypadku Visual Studio .Net pakiet Data Access Guidance Package to rozwiązanie, które realizuje warstwę dostępu do danych zgodną z Enterprise Library Data Access Block. Dzięki temu programista korzysta z zewnętrznej biblioteki, ale dostosowanej do budowanego rozwiązania. To, jak bardzo jest ona dostosowana, zależy już od konkretnej implementacji.

Podstawą koncepcji software factories jest przeświadczenie, że tak naprawdę duża część aplikacji jest podobna. Nie identyczna, ale realizująca analogiczne funkcje, które w dużym stopniu można generować automatycznie, oczywiście przy założeniu, że twórca pakietu fabryki przewidział odpowiednią parametryzację. Tu można już mówić o modelowaniu w sensie DSL (Domain Specific Language), gdzie mamy do czynienia z językami modelowania bazującymi na pewnych obiektowych bytach podstawowych, z których konstruuje się diagram. DSL pozwala zbudować język dostosowany do konkretnej dziedziny wiedzy i używać symboli dla niej właściwych. W konsekwencji otrzymuje się rozwiązanie, w którym elementem modelu jest software factory sparametryzowana pod kątem danego projektu.

Zwróćmy uwagę na jeszcze jedno. Skoro część pracy to integracja różnych fragmentów kodu, nic nie stoi na przeszkodzie, by skorzystać z wzorców pokazujących, w jaki sposób poszczególne elementy mogą ze sobą współpracować. Tak jak istnieją wzorce projektowe, w przemyśle informatycznym funkcjonuje coraz więcej wzorców modelowych. Po prostu praktyka pokazała, że pewne rozwiązania architektoniczne są lepsze niż inne. Jeżeli więc np. system ma przekazywać komunikat pomiędzy różnymi kanałami w zależności od pewnych warunków (z uwzględnieniem chronologii itp.), to może sięgnąć po gotowy resequencer, czyli specyficzny "filtr stanów".

Bogaty indeks różnych wzorców można znaleźć pod adresem:http://www.patternshare.com/ , a także na stronie:http://wiki.java.net/bin/view/Javapedia/Patterns . Warto też zajrzeć do książek: "Enterprise Integration Patterns" (Gregor Hohpe, Bobby Woolf) oraz "Patterns of Enterprise Application Architecture" (Martin Fowler).

Z punktu widzenia nowej aplikacji biblioteką jest także kod już istniejący. Problem polega na tym, że powstawał on przez X lat i nie zawsze da się go dobrze zintegrować w nowym systemie. Można oczywiście klecić rozwiązanie, używając mniej lub bardziej eleganckich "sznurków", ale każde takie połączenie obniża bezpieczeństwo aplikacji. Jeżeli prześledzi się biuletyny zagrożeń, to większość z nich (na przestrzeni ostatnich 2-3 lat niemal wszystkie poza kilkoma spektakularnymi wyjątkami) dotyczy nie jednostkowych modułów, a raczej połączeń między modułami, które mogą zostać użyte w sposób nieprzewidziany przez producenta.

Refaktoring, czyli restrukturyzacja

Może warto przeprowadzać refaktoring rozwiązań, aby łączenie starych i nowych modułów odbywało się jak najmniejszym kosztem i przy minimalnym ryzyku. Refaktoring polega w praktyce na łączeniu lub dzieleniu modułów, upraszczaniu pewnych warunków, przekształcaniu operacji, tak by mogły być parametryzowane z zewnątrz, dodawaniu określonych interfejsów standaryzujących grupy operacji itp.

Refaktoring kodu wszedł już chyba do kanonu operacji wykonywanych przez programistę. Warto jednak podkreślić, że założeniem takiej czynności jest to, że w wyniku przekształcania struktury obiektowej kod przed i po operacji jest funkcjonalnie identyczny, a jedynie jego struktura jest inna. Nie znaczy to oczywiście, że refaktorowanego kodu nie należy ponownie testować, na takie ryzyko raczej nie można sobie pozwolić.

W przypadku refaktoringu na poziomie modułowym, gdzie de facto zmieniamy rozwiązanie czyniąc je bardziej elastycznym, pojawia się wiele różnych problemów Dobrze je podsumował Ian Sommerville już w 2000 r. Skupił się co prawda na problemie zmniejszenia kosztów utrzymania istniejącego oprogramowania, ale tak naprawdę analogiczne problemy pojawiają się też przy modularyzacji programu.

Pierwszy problem, który się pojawia przy takich zmianach, to dokumentacja, która i tak zwykle nie jest najlepsza, bo dokumentowanie to ten etap projektu, na który zawsze brakuje czasu. Gdy wprowadzamy zmianę w organizacji modułów, zazwyczaj zapisywane są informacje tylko o tym, co ulega zmianie. Nie powstaje dokument syntetyczny, pokazujący jak wygląda cały system. Ostatecznie więc "czas dostępu" do potrzebnej informacji zamiast zmniejszać się, zostaje wydłużony. Co z tego, że moduły są zbudowane bardziej sensownie, skoro nie wiadomo który za co odpowiada?

Jeśli nie ma dokumentacji i trzeba odtwarzać rozwiązanie na nowo na podstawie funkcjonalności produktu istniejącego, sprawa wygląda jeszcze gorzej. Dotyczy to zwłaszcza systemów tworzonych własnymi siłami działu IT, których autorzy dawno już nie pracują w firmie, albo też rozwiązań zewnętrznych, których dostawca "ulotnił się" lub zbankrutował.

Za bezpieczną Sommerville uważa zmianę w obrębie pojedynczego modułu. Szkopuł w tym, że przy nadawaniu rozwiązaniu nowej struktury trzymanie się takiej zasady jest raczej niemożliwe. Przyczyną restrukturyzacji może być też proces biznesowy. Ale tu warto podkreślić to, o czym się często zapomina, traktując informatykę jako dziedzinę służebną wobec biznesu. Czasami jest tak, że w wyniku tworzenia czy zmiany struktury rozwiązania informatyka uwypukla słabość koncepcji biznesowej. Wtedy trzeba się zastanowić, czy lepiej reorganizować pracę, czy budować nielogiczne rozwiązanie.

Jeżeli mamy formalny model aplikacji (MDA lub dowolny inny), przebudowa jest łatwiejsza, bo znamy zależności pomiędzy wymaganiami, modelem koncepcyjnym (np. PIM) i implementacją. Ale pełnego automatyzmu nie ma się co spodziewać - to jest niestety żmudna praca programisty (przede wszystkim) i analityka, który określi podstawowe zasady.

Gdy firma dysponuje dużą bazą przetestowanego kodu, a chce skorzystać z nowszych technologii, pojawia się pokusa, by dokonać translacji starego kodu na któryś z nowoczesnych języków programowania. Taki proces zawsze jest trudny, co nie znaczy, że niemożliwy. Współczesne technologie pozwalają na to, by obok bieżących języków funkcjonowały także fragmenty napisane w starszych narzeczach.

Dużą zmianę przyniosło w tej dziedzinie środowisko .Net. W ramach CLR można wykonywać kod napisany w różnych językach, co ułatwia wspólny dla nich system typów. Obecnie również dla Javy powstały rozwiązania pozwalające wykorzystać JVM jako "uniwersalną maszynę wirtualną". Dzięki takim zabiegom "stare" rozwiązanie nie jest zmieniane, lecz zyskuje nowoczesną otoczkę. Problemy pojawiają się przede wszystkim wtedy, gdy równocześnie z przepisywaniem kodu wprowadzane są do niego nowe funkcjonalności.

Z rozważań Sommerville'a wynika, że mimo wszystkich wad restrukturyzacji sumarycznie jest ona tańsza niż stworzenie zupełnie nowego oprogramowania. Chociażby dlatego, że ryzyko takiej operacji jest mniejsze. To może być prawda, ale nie musi - jego praca została opublikowana w 2000 r., a od tamtego czasu dokonał się niewątpliwie duży postęp w technologii. Dzisiaj w wielu przypadkach stare funkcjonalności można napisać za pomocą znacznie mniejszej liczby linii kodu.

Jakość, pieniądze i oczekiwania

Producenta nie tyle interesuje bezbłędne oprogramowanie, co raczej dopracowanie go na tyle, by mogło być używane i aby klient był skłonny za nie zapłacić. Tak naprawdę większość "błędów operacyjnych" wynika z połączenia błędu ludzkiego i błędu oprogramowania. W wielu przypadkach w danej aplikacji można wykonać potrzebne czynności - może tylko w inny sposób. Podobną tendencję można obserwować wśród producentów sprzętu, bo przecież i tak trzeba utrzymać sieć serwisową, w związku z tym bierze się pod uwagę określony odsetek zwrotów. Koszty doskonalenia jakości stają się od pewnego momentu astronomiczne.

Wypada jeszcze wspomnieć, że tym za co klient rzeczywiście płaci, są często funkcje jedynie w rozumieniu marketingowym, nie zaś wysublimowane funkcje rzeczywiście nowatorskie. Takich "funkcji marketingowych" często nie da się zmieścić w formalnej analizie podczas wstępnego projektowania oprogramowania. To co jest projektowane, często nie przypomina ostatecznej wersji produktu, który trafia do klienta. W związku z tym rozważanie o zarządzaniu cyklem rozwoju oprogramowania (ALM - Application Lifecycle Management) staje trochę teoretyczne.

Rozwój oprogramowania jest obecnie coraz częściej sterowany marketingiem, a więc rzeczywistymi potrzebami klienta bądź potrzebami mu wmówionymi. Trendy na rynku ulegają zmianie, konkurencja pokazała analogiczny produkt o szerszej funkcjonalności lub specyficznej specjalizacji i w związku z tym trzeba własne rozwiązanie jakoś wyróżnić. Jest w tym wiele racji, bo po co tworzyć doskonały produkt, którego ostatecznie nikt nie kupi? Umiar jak zwykle ma tu zastosowanie - dodawanie funkcji w ostatniej chwili zaburza bądź co bądź uporządkowany (mimo wszystko) proces tworzenia oprogramowania.

Kolejna fala oprogramowania do zarządzania projektami będzie zapewne uwzględniać proces sprzedaży, pozwalając definiować moduły użytkowe, które niekoniecznie będą bezpośrednio powiązane z konkretnym fragmentem projektu. Dzięki temu nawet w długo trwającym projekcie będzie można przestawiać elementy, tak by dzieło nadal było atrakcyjne dla rynku.

A może model jest niepotrzebny?

Czy szczegółowe, formalne modelowanie aplikacji jest uzasadnione? Nie ulega wątpliwości, że wypada dokładnie wiedzieć co ma być stworzone oraz że dzieło należy przetestować. Trzeba jednak brać pod uwagę, że architektura jest wypadkową użytych komponentów i doświadczenia zespołu. Można stworzyć uporządkowany i logiczny projekt, którego implementacja będzie kosztowna. Jednak da się także ustalić tylko pewne ogólne zasady, bloki funkcjonalne, narzucić co i jak ma być wymieniane i dać programiście swobodę w dziedzinie implementacji. Niestety, w dużych projektach takie podejście raczej się nie sprawdzi.

Produkt czy usługa

Oprogramowanie jako produkt do zainstalowania powoli odchodzi do lamusa. Coraz częściej nieodłącznym składnikiem produktu jest usługa, najczęściej online. Dobrym tego przykładem są gry. Z jednej strony instaluje się je na danym komputerze, kupuje w pudełku. Z drugiej strony bez połączenia z Internetem wiele gier traci na atrakcyjności, a czasami w ogóle nie działa. To od infrastruktury - serwerów gier, jakości sieci w okolicy - zależy, czy produkt się sprzeda. Było kilka tytułów, które z uwagi na niedostatki infrastruktury nie zyskały popularności pomimo ciekawego pomysłu.

Mimo to zaniku produktów "pudełkowych" nie należy się raczej spodziewać, przynajmniej w najbliższym czasie. Aby model "software as service" stał się realny, konieczne jest opracowanie skutecznej metody dystrybucji oprogramowania przez Internet - takiej, która dostarczy aplikację w pełni wykorzystującą moc komputera klienta i zapewni mu dużą wygodę pracy. Co by nie mówić, nawet AJAX połączony z Flashem i najnowszymi standardami w przeglądarkach nie zapewnia takiej wygody pracy jak dobrze napisana aplikacja Windows Forms.

W celu komercyjnej reprodukcji treści Computerworld należy zakupić licencję. Skontaktuj się z naszym partnerem, YGS Group, pod adresem [email protected]

TOP 200