Wdro偶enie NGinn – case study
NGinn nie tak dawno temu przeszed艂 sw贸j chrzest bojowy – mianowicie doczeka艂 si臋 wdro偶enia produkcyjnego i to na ca艂kiem spor膮 skal臋. Poniewa偶 od wdro偶enia min臋艂o ju偶 troch臋 czasu a system jest ustabilizowany i mo偶na spokojnie powiedzie膰 偶e dzia艂a, to dzi艣 opowiem nieco o tym jak owo wdro偶enie wygl膮da艂o i jaka jest w nim rola NGinn.
Kr贸tko o procesie
NGinn zosta艂 u偶yty do zautomatyzowania procesu indeksowania dokument贸w w firmie telekomunikacyjnej kt贸ra jest jednym z operator贸w kom贸rkowych w Polsce. Indeksowanie dokument贸w jest to jeden z etap贸w procesu obs艂ugi wchodz膮cych do firmy dokument贸w papierowych (list贸w, um贸w i innych dokument贸w dotycz膮cych klient贸w firmy), kt贸ry przedstawia si臋 mniej wi臋cej tak:
- Przyj臋cie dokument贸w w kancelarii
- Sortowanie (wst臋pna klasyfikacja)
- Przygotowanie do skanowania (rozpakowanie, rozszycie etc)
- Skanowanie
- Indeksacja (klasyfikacja, opisanie dokumentu odpowiednimi danymi)
- Umieszczenie dokumentu w archiwum elektronicznym
- Dalsza obs艂uga dokumentu ju偶 w wersji elektronicznej (dalsze etapy s膮 realizowane w innych systemach, proces obs艂ugi jest r贸偶ny dla r贸偶nych dokument贸w)
W skr贸cie proces ten prowadzi do przekszta艂cenia dokumentu na jego obraz cyfrowy (skan) z odpowiednimi metadanymi, dzi臋ki czemu dalsza obs艂uga dokumentu mo偶e by膰 prowadzona za pomoc膮 system贸w informatycznych. Firma d膮偶y do maksymalnego zautomatyzowania tego procesu gdy偶 obs艂uguje dziesi膮tki tysi臋cy dokument贸w dziennie i ka偶da czynno艣膰 r臋czna generuje du偶e koszty (w obs艂ug臋 wchodz膮cych dokument贸w zaanga偶owane jest kilkadziesi膮t os贸b).
Celem naszego wdro偶enia by艂o zautomatyzowanie etapu indeksacji – czyli etapu w kt贸rym osoba skanuj膮ca dokument opisuje go odpowiednimi metadanymi. Te metadane zale偶膮 od rodzaju dokumentu, ale najcz臋艣ciej s膮 to podstawowe informacje jak rodzaj dokumentu, data wp艂yni臋cia do firmy, data skanowania, identyfikator klienta, nr telefonu tego klienta, nr dokumentu, kod kreskowy, segment klienta i kilka innych atrybut贸w. Do tej pory musia艂y by膰 odczytywane z dokumentu (lub wyszukiwane w innych systemach) i wpisywane r臋cznie przez pracownika skanuj膮cego dokument, co mia艂o swoje wady: wyd艂u偶a艂o czas obs艂ugi dokumentu i stwarza艂o ryzyko wyst膮pienia b艂臋d贸w w danych. W celu poprawienia efektywno艣ci tego etapu firma opracowa艂a jego wersj臋 zautomatyzowan膮 聽w kt贸rej praca r臋czna zosta艂a albo ca艂kowicie wyeliminowana, albo ograniczona do minimum. Automatyzacja polega艂a na zmianie aplikacji skanuj膮cej tak aby sama wype艂nia艂a pola kt贸re mo偶e (dat臋 skanowania, login osoby skanuj膮cej, kod kreskowy i kilka innych), za艣 reszta danych pozyskiwana jest automatycznie z system贸w zewn臋trznych. Na przyk艂ad: je艣li na dokumencie wyst臋puje kod kreskowy z systemu sprzeda偶y to 聽dane klienta s膮 pobierane z tego systemu. Je艣li kodu kreskowego brak to konsultant ma za zadanie wpisa膰 r臋cznie tylko identyfikator klienta – pozosta艂e dane klienta zostan膮 pobrane z systemu billingowego. Konsultant musi interweniowa膰 w sytuacjach wyj膮tkowych, np je艣li np kod kreskowy jest nieczytelny dla aplikacji skanuj膮cej (wtedy albo wpisuje go r臋cznie albo nakleja nowy kod i podaje numer dokumentu). Procedura zautomatyzowana obejmuje r贸wnie偶 walidacj臋 danych (wykrywanie brakuj膮cych lub b艂臋dnych numer贸w klienta/numer贸w dokumentu/kod贸w kreskowych). W przypadku wykrycia nieprawid艂owo艣ci odpowiedni pracownicy otrzymuj膮 zadanie poprawy indeks贸w w dokumencie.
Oszcz臋dno艣膰 na pojedynczym dokumencie jest rz臋du minuty-dw贸ch. Ale po pomno偶eniu tego przez ok 10-15 tysi臋cy dokument贸w dziennie wychodzi nam oszcz臋dno艣膰 na poziomie trzydziestu osobo-dni (ka偶dego dnia). Oznacza to trzydzie艣ci etat贸w kt贸rych nie trzeba tworzy膰 – czyli niewielkie w sumie usprawnienie w tak masowym procesie daje ca艂kiem niez艂y efekt finansowy.
Realizacja
Do zrealizowania tej zautomatyzowanej procedury indeksacji u偶yli艣my NGinn. Dzia艂a to tak 偶e po zeskanowaniu dokumentu jest on umieszczany w systemie EDMS (elektroniczne archiwum dokument贸w), kt贸ry to system powiadamia NGinn o pojawieniu si臋 nowego dokumentu. W tym momencie NGinn uruchamia proces automatycznej indeksacji kt贸ry odpowiada za uzupe艂nienie dokumentu o odpowiednie metadane. Oto schemat tego procesu:

- Pobranie dokumentu z systemu EDMS.
Po zeskanowaniu dokumentu i umieszczeniu go w systemie EDMS system ten powiadamia NGinn o pojawieniu si臋 nowego dokumentu przekazuj膮c wewn臋trzny identyfikator tego dokumentu. Na podstawie tego identyfikatora NGinn pobiera dane dokumentu z systemu EDMS. Pobierane s膮 m. in. typ dokumentu, nr dokumentu, kod kreskowy i identyfikator klienta. - Pobranie danych klienta z systemu bilingowego. Je艣li dokument zawiera identyfikator klienta a nie zawiera kodu kreskowego, odpytujemy system bilingowy o dane klienta na podstawie podanego numeru klienta. Odpytanie odbywa si臋 poprzez wywo艂anie odpowiedniego web service. Je艣li dane klienta zostan膮 odnalezione idziemy do kroku 4, w przeciwnym razie do kroku 5.
- Pobranie danych dokumentu z systemu sprzeda偶y – dokumenty z systemu sprzeda偶y zaopatrzone s膮 w odpowiedni kod kreskowy, identyfikowane s膮 te偶 numerem dokumentu. NGinn odpytuje system sprzeda偶owy o dane tego dokumentu na podstawie kodu kreskowego lub nr dokumentu, w艣r贸d danych zwracanych przez system sprzeda偶owy s膮 r贸wnie偶 informacje o kliencie. Je艣li dokument zostanie odnaleziony przechodzimy do kroku 4, w przeciwnym razie do kroku 5.
- Aktualizacja dokumentu w EDMS. Je艣li dane klienta/dokumentu zosta艂y odnalezione w odpowiednim systemie, NGinn aktualizuje dane dokumentu w EDMS dzi臋ki czemu jest on opisany pe艂nymi metadanymi.
- Zadanie ‘popraw indeksy’. Jest to zadanie r臋czne zak艂adane w systemie obs艂ugi zg艂osze艅. Zadanie to pojawia si臋 na li艣cie spraw odpowiedniej grupy konsultant贸w (system obs艂ugi zg艂osze艅 jest uniwersalnym systemem w kt贸rym rejestrowane s膮 zg艂oszenia klient贸w oraz inne rodzaje spraw, m.in. zadania). Zadanie zawiera odno艣nik do dokumentu w EDMS oraz informacje o tym kt贸re indeksy nale偶y poprawi膰. Po poprawieniu indeks贸w konsultant zg艂asza zako艅czenie realizacji zadania i proces powtarza si臋 od kroku 1. Istnieje mo偶liwo艣膰 zako艅czenia zadania z opcj膮 ‘pomi艅 walidacj臋’, kt贸ra powoduje przej艣cie do kroku 6 bez dalszej walidacji danych dokumentu – jest to potrzebne w wyj膮tkowych przypadkach, np gdy dane klienta w na dokumencie s膮 nieaktualne.
- Poprawny przebieg procesu indeksacji ko艅czy si臋 przekazaniem dokumentu do systemu obs艂ugi zg艂osze艅. NGinn przekazuje dane dokumentu do systemu obs艂ugi zg艂osze艅, kt贸ry na podstawie tych danych zak艂ada odpowiedniej tre艣ci zg艂oszenie i przypisuje je do Back Office, do grupy konsultant贸w odpowiedzialnych za obs艂ug臋 danego rodzaju zg艂osze艅. NGinn na kroku 6 ko艅czy swoj膮 rol臋 i nie bierze udzia艂u w obs艂udze zg艂oszenia.
W celu zaimplementowania tego procesu do standardowego zestawu zada艅 NGinn musia艂y zosta膰 do艂膮czone dwa typy zada艅 s艂u偶膮ce do integracji z systemem EDMS: zadanie “Pobierz dokument z EDMS” (krok 1) oraz “Zaktualizuj dokument EDMS”, czyli krok 4. Zadania te wykorzystuj膮 API integracyjne systemu EDMS. Pozosta艂e etapy procesu zosta艂y zrealizowane za pomoc膮 zada艅 standardowo udost臋pnianych przez NGinn. Dodatkowo, w systemie obs艂ugi zg艂osze艅 zosta艂 dodany interfejs integracyjny dla NGinn pozwalaj膮cy NGinn zak艂ada膰 zadania w tym systemie oraz raportowa膰 do NGinn zako艅czenie realizacji zada艅 przez konsultant贸w.
Jak 艂atwo policzy膰, proces indeksacji wykorzystuje funkcje czterech r贸偶nych system贸w: EDMS, billingu, systemu sprzeda偶owego oraz systemu obs艂ugi zg艂osze艅. Mo偶na powiedzie膰 zatem ze opr贸cz funkcji narz臋dzia ‘BPM’ NGinn pe艂ni te偶 rol臋 narz臋dzia integracyjnego zarz膮dzaj膮cego przep艂ywem danych mi臋dzy poszczeg贸lnymi aplikacjami.
Przebieg wdro偶enia
Projekt by艂 realizowany metod膮 szybkiego prototypowania. Klient bardzo szybko (w ci膮gu 2 tygodni) od rozpocz臋cia prac otrzyma艂 pierwsz膮 wersj臋 oprogramowania do test贸w. Podczas test贸w opr贸cz pewnej liczby b艂臋d贸w wykryto te偶 rozmaite przypadki nietypowe kt贸re nie by艂y przewidziane w wymaganiach. Ka偶dy taki wyj膮tek wymaga艂 modyfikacji procesu – praktycznie na bie偶膮co dostarczali艣my klientowi zmodyfikowan膮 wersj臋 procesu i testy mog艂y by膰 kontynuowane. W sumie testowane by艂o 7 albo 8 wersji procesu, ka偶da kolejna zawiera艂a obs艂ug臋 przypadk贸w nie przewidzianych przez poprzedni膮 iteracj臋. Testy trwa艂y oko艂o 3 tygodni, p贸藕niej nast膮pi艂o przeniesienie funkcjonalno艣ci na 艣rodowisko produkcyjne. W 艣rodowisku produkcyjnym wykryto jeszcze jeden albo dwa ‘nietypowe’ przypadki wymagaj膮ce pilnego obs艂u偶enia, co zaowocowa艂o dwiema kolejnymi wersjami procesu.
Podczas testowania niekt贸re z cech NGinn okaza艂y si臋 bardzo przydatne:
- mo偶liwo艣膰 u偶ywania kilku wersji procesu jednocze艣nie. W przypadku test贸w ‘na produkcji’ u偶ywana by艂a stabilna wersja procesu za艣 eksperymentalne by艂y uruchamiane tylko na potrzeby test贸w. Po przetestowaniu nast膮pi艂o prze艂膮czenie domy艣lnej wersji procesu na now膮 wed艂ug kt贸rej by艂y obs艂ugiwane kolejne dokumenty. Nie by艂o potrzeby migracji proces贸w w toku – doko艅czy艂y one sw贸j bieg wed艂ug starej wersji.
- zmiany definicji procesu ‘w locie’, bez zatrzymywania systemu pozwala艂y na bie偶膮co uwzgl臋dnia膰 uwagi tester贸w a na produkcji prze艂膮cza膰 si臋 mi臋dzy wersjami procesu w spos贸b niezauwa偶alny dla u偶ytkownik贸w
Po wdro偶eniu
Obserwacja systemu po wdro偶eniu pokaza艂a kilka fakt贸w:
- Mimo niezbyt rozbudowanej konfiguracji serwera nie ma 偶adnych problem贸w wydajno艣ciowych, NGinn obci膮偶a procesor i pami臋膰 w niewielkim stopniu. Baza danych bez problemu radzi sobie z obs艂ug膮 danych generowanych przez NGinn.
- Po ustabilizowaniu definicji procesu system dzia艂a praktycznie bezproblemowo 24 godziny na dob臋, 聽7 dni w tygodniu. Przez ponad miesi膮c nie by艂o 偶adnego problemu technicznego, wszystkie dokumenty zosta艂y zaindeksowane zgodnie z definicj膮 procesu. Mam do艣wiadczenie w pracy z r贸偶nymi systemami i naprawd臋 rzadko zdarza si臋 偶eby system dzia艂a艂 tak stabilnie zaraz po uruchomieniu produkcyjnym.
- NGinn jest bardzo odporny na awarie system贸w zewn臋trznych. W naszym procesie indeksacji bior膮 udzia艂 cztery systemy i do艣膰 cz臋sto zdarza si臋 偶e kt贸ry艣 z nich na jaki艣 czas ‘wypada’, np nie mo偶na si臋 z nim po艂膮czy膰 lub zg艂asza b艂臋dy. W takiej sytuacji NGinn jest w stanie przeczeka膰 okres niedost臋pno艣ci systemu i wznowi膰 procesy kiedy system zewn臋trzny zacznie odpowiada膰. Dzieje si臋 tak dzi臋ki mechanizmowi ponawiania w NGinn kt贸ry przez okres max. 3 dni pr贸buje ponownie wykona膰 nieudane operacje. Oznacza to te偶 偶e po ust膮pieniu awarii administrator systemu nie musi nic robi膰 偶eby obs艂uga proces贸w w NGinn by艂a kontynuowana.
- Standardowo NGinn przechowuje stan wszystkich zada艅 w bazie danych. Informacje te nie s膮 usuwane po zako艅czeniu zadania, dlatego ilo艣膰 gromadzonych danych jest bardzo du偶a. Proces indeksacji sk艂ada si臋 z 6-ciu zada艅, co prawda nie wszystkie wyst臋puj膮 w ka偶dym przebiegu, ale oznacza to 偶e dla ka偶dego indeksowanego dokumentu zapisywane jest 3-6 rekord贸w w bazie NGinn, co dziennie daje 50-100 tysi臋cy rekord贸w. Konieczny jest jaki艣 mechanizm czyszcz膮cy kt贸ry b臋dzie usuwa艂 stan zako艅czonych zada艅.
- Przy du偶ej ilo艣ci przetwarzanych dokument贸w potrzebne jest narz臋dzie monitoruj膮ce pozwalaj膮ce 艣ledzi膰 prac臋 NGinn i wykrywa膰 ewentualne problemy. Dobrze by te偶 by艂o mie膰 jakie艣 narz臋dzie pozwalaj膮ce na raportowanie przebiegu proces贸w. Na potrzeby tego konkretnie wdro偶enia zosta艂o uruchomione niezbyt rozbudowane narz臋dzie pozwalaj膮ce 艣ledzi膰 podstawowe informacje – np aktywno艣膰 w NGinn w ci膮gu ostatnich 24 godzin – poni偶ej obrazek z tego narz臋dzia:

Podsumowuj膮c, my艣l臋 偶e uda艂o si臋 pokaza膰 偶e za pomoc膮 NGinn mo偶na realizowa膰 rzeczywiste wdro偶enia i narz臋dzie to potrafi wspiera膰 procesy biznesowe nie tylko na papierze. Mam nadziej臋 na uruchomienie kolejnych proces贸w dla tego samego klienta i my艣l臋 偶e to pozwoli rozbudowa膰 NGinn o kolejne przydatne funkcje.
Jak wywo艂a膰 dowolny web service bez WSDL i bez generowania kodu
W dzisiejszym artykule zajmiemy si臋 wywo艂ywaniem web services z poziomu procesu NGinn, przy okazji poznaj膮c alternatywny spos贸b korzystania z web services. Jak pewnie doskonale wszyscy wiedz膮, web services s膮 komponentami (uslugami) dost臋pnymi zdalnie, za po艣rednictwem niezale偶nego od platformy protoko艂u SOAP. Wywo艂anie web service jest niczym innym jak przekazaniem komunikatu SOAP oraz odebraniem odpowiedzi (te偶 SOAP), najcz臋艣ciej za pomoc膮 protoko艂u http.
Jednak gdy programista chce w swojej aplikacji wywo艂a膰 jaki艣 web service zwykle nie pos艂uguje si臋 on bezpo艣rednio SOAPem, ale u偶ywa dost臋pnych w danym j臋zyku narz臋dzi 鈥榦pakowuj膮cych鈥 kt贸re pozwalaj膮 mu wywo艂ywa膰 web service tak jakby to by艂o wywo艂anie lokalnej funkcji . W Microsoft.Net pos艂ugujemy si臋 na przyk艂ad narz臋dziem WSDL.exe kt贸re na podstawie XML-owego opisu us艂ugi (WSDL) generuje nam kod w C#聽 (lub VB) kt贸ry opakowuje nam web service do postaci 鈥榮trawnej鈥 dla .Net, czyli obiektu okre艣lonej klasy z interfejsem zgodnym z definicj膮 web service. Jest to na tyle wygodne i uniwersalne 偶e w typowych zastosowaniach mo偶emy polega膰 tylko na wsdl.exe i w og贸le zapomnie膰 o XML-u i http pod spodem. Ale czasami wsdl.exe nie wystarcza 鈥 na przyk艂ad gdy nie wiemy z g贸ry jaki web service b臋dziemy wywo艂ywa膰.
WSDL.exe generuje kod opakowuj膮cy web service, co oznacza 偶e struktura web service jest wkompilowana w program kt贸ry z danej us艂ugi korzysta 鈥 i gdy us艂uga si臋 zmieni to nale偶y ponownie wygenerowa膰 kod wsdl.exe鈥檓 i skompilowa膰 aplikacj臋 od nowa. 艢wietnie, ale gdy aplikacja musi si臋 komunikowa膰 z web service kt贸rego nie znamy na etapie kompilacji to WSDL.exe do niczego si臋 nie przyda. 聽NGinn jest w艂a艣nie takim przypadkiem poniewa偶 oferuje mo偶liwo艣膰 wywo艂ywania web services w ramach proces贸w. Wszelkie potrzebne do wywo艂ania informacje czerpie z definicji procesu a na podstawie tych informacji tworzy聽 i wysy艂a komunikaty SOAP.
呕eby wywo艂a膰 web service z procesu NGinn trzeba pos艂u偶y膰 si臋 zadaniem 鈥榅mlHttp鈥. Jest to zadanie pozwalaj膮ce na wykonywanie wywo艂a艅 http, mi臋dzy innymi takich kt贸re zawieraj膮 XML. 呕eby wywo艂a膰 web service trzeba tylko zadba膰 o to aby ten XML by艂 SOAP-em o strukturze kt贸rej spodziewa si臋 nasz web service 鈥 czyli zapewni膰 鈥榖inding鈥 mi臋dzy danymi na kt贸rych operuje nasz proces a odpowiednimi polami w komunikacie SOAP. Na aktualnym etapie rozwoju NGinn robi si臋 to za pomoc膮 transformacji XSLT. 呕eby by艂o 艂atwiej to wszystko przyswoi膰 pos艂u偶my si臋 przyk艂adem. Jest taka publicznie dost臋pna us艂uga http://aspspider.info/trutech/MarketWatch.asmx kt贸ra pozwala m.in . zapyta膰 si臋 o kursy akcji, indeksy gie艂dowe i kursy metali szlachetnych. 聽Udost臋pnia ona operacj臋 鈥楪etQuote鈥 za pomoc膮 kt贸rej b臋dziemy odpytywa膰 si臋 o kursy akcji. Po wej艣ciu na w/w stron臋 ukazuje si臋 nam opis us艂ugi (standardowo wygenerowany przez ASP.Net) z WSDL oraz z przyk艂adami komunikat贸w SOAP. No i przyk艂adowy komunikat SOAP dla zapytania o kurs akcji Microsoftu wygl膮da tak:
<?xml version="1.0" encoding="utf-8"?>
<soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://www.w3.org/2003/05/soap-envelope">
<soap12:Body>
<GetQuote xmlns="http://trutech.com/marketwatch/">
<credValidate>
<Email>trutech.shared@gmail.com</Email>
<Password>trutech.shared@gmail.com</Password>
</credValidate>
<MyScript>
<sScriptCode>MSFT</sScriptCode>
</MyScript>
</GetQuote>
</soap12:Body>
</soap12:Envelope>
Gdy wy艣lemy taki XML POST-em na adres http://aspspider.info/trutech/MarketWatch.asmx dostaniemy odpowied藕 kt贸ra wygl膮da mniej-wi臋cej tak:
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<GetQuoteResponse xmlns="http://trutech.com/marketwatch/">
<GetQuoteResult>true</GetQuoteResult>
<MyScript>
<sScriptCode>MSFT</sScriptCode>
<sScriptName>MSFT - Microsoft Corpora</sScriptName>
<sScriptNameFromServer>Microsoft Corpora</sScriptNameFromServer>
<sScriptStockExchange>NasdaqNM</sScriptStockExchange>
<sScriptLastPrice>28.22 Rs</sScriptLastPrice>
<sScriptPreviousClose>28.22 Rs</sScriptPreviousClose>
<sScriptChangeInRupees>0.00 Rs</sScriptChangeInRupees>
<sScriptChangeInPercentage>0.00 %</sScriptChangeInPercentage>
<sScriptVolume>0 Sh</sScriptVolume>
<sScriptDaysRange>N/A - N/A</sScriptDaysRange>
<sScriptYearRange>14.87 Rs - 29.35 Rs</sScriptYearRange>
<sScriptToolTipText>
Registration Code : MSFT
Company Name : MSFT - Microsoft Corpora
Exchange : NasdaqNM ( 2009-10-29 )
Last Price : 28.22 Rs
Previous Close : 28.22 Rs
Change (INR) : 0.00 Rs
Change (%) : 0.00 %
Trading Volume : 0 Shares
Price Range (Day) : N/A - N/A
Price Range (52 Weeks) : 14.87 Rs - 29.35 Rs
Query Time : 2009-10-30 17:02:57
</sScriptToolTipText>
<sScriptWebLink>http://in.finance.yahoo.com/q?s=MSFT</sScriptWebLink>
<sScriptLastTradeDate>2009-10-29</sScriptLastTradeDate>
<sScriptLastTradeTime>4:00pm</sScriptLastTradeTime>
<sScriptQueryDateTime>2009-10-30 17:02:57</sScriptQueryDateTime>
<bScriptDataFound>true</bScriptDataFound>
<lScriptRowId>0</lScriptRowId>
</MyScript>
</GetQuoteResponse>
</soap:Body>
</soap:Envelope>
Interesuj膮ca nas cena jest w polu 鈥榮ScriptLastPrice鈥. Niekt贸rzy pewnie si臋 zastanawiaj膮 co oznacza 鈥楻s鈥 obok ceny 鈥 ot贸偶 jest to indyjski web service podaj膮cy ceny w Rupiach. Bardzo przepraszam ale innego nie znalaz艂em.
Skoro ju偶 wiemy jak wyci膮gn膮膰 cen臋 akcji Microsoftu w Rupiach to zbudujmy proces NGinn kt贸ry dok艂adnie to robi 鈥 tj na wej艣ciu bierze symbol sp贸艂ki gie艂dowej i odpytuje si臋 o cen臋 akcji tej sp贸艂ki. Proces ten b臋dzie mia艂 jedn膮 zmienn膮 wej艣ciow膮 鈥 symbol sp贸艂ki, i jedn膮 zmienn膮 wyj艣ciow膮 鈥 kurs akcji wyra偶ony w rupiach.
<?xml version="1.0" encoding="utf-8"?>
<process version="1" name="RupeeStockQuote" xmlns="http://www.nginn.org/WorkflowDefinition.1_0.xsd">
<variables>
<variable name="symbol" type="string" required="true" dir="In" />
<variable name="price" type="string" required="true" dir="Out" />
</variables>
<body>
<places>
<place id="start" type="Start" />
<place id="end" type="End" />
</places>
<tasks>
<task id="T1" type="XmlHttp">
<variables>
<variable name="symbol" type="string" dir="In" required="true"/>
<variable name="price" type="string" required="true" dir="Out" />
</variables>
<parameters>
<param variable="Url"><value>http://aspspider.info/trutech/MarketWatch.asmx</value></param>
<param variable="RequestType"><value>SOAP</value></param>
<param variable="ResponseType"><value>SOAP</value></param>
<param variable="HttpMethod"><value>POST</value></param>
<param variable="RequestBodyXsl"><value>GetQuote_Request.xsl</value></param>
<param variable="ResponseBodyXsl"><value>GetQuote_Response.xsl</value></param>
<param variable="RequestHeaders"><expr>{"Content-Type": "application/soap+xml; charset=utf-8"}</expr></param>
</parameters>
</task>
</tasks>
<flows>
<flow from="start" to="T1" />
<flow from="T1" to="end" />
</flows>
</body>
</process>
Proces ten jest bardzo uproszczony 鈥 ma tylko jedno zadanie. W normalnej sytuacji mia艂by on dalszy ci膮g, czyli logik臋 kt贸ra w jaki艣 spos贸b dzia艂a w oparciu o cen臋 akcji i np. wysy艂a do kogo艣 powiadomienie. Ale to tylko przyk艂ad wi臋c musi by膰 prosty.
Wida膰 tu 偶e zadanie 鈥楾1鈥 pos艂uguje si臋 dwiema transformacjami XSL 鈥 pierwsza z nich jest zapisana w pliku 鈥楪etQuote_Request.xsl鈥 i s艂u偶y do wygenerowania komunikatu SOAP wywo艂uj膮cego web service, druga, w pliku 鈥楪etQuote_Response.xsl鈥 s艂u偶y do przetworzenia odpowiedzi web service na posta膰 zrozumia艂膮 dla NGinn. Oto te transformacje:
GetQuote_Request.xsl
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" encoding="utf-8" indent="yes" />
<xsl:template match="/data">
<soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://www.w3.org/2003/05/soap-envelope">
<soap12:Body>
<GetQuote xmlns="http://trutech.com/marketwatch/">
<credValidate>
<Email>trutech.shared@gmail.com</Email>
<Password>trutech.shared@gmail.com</Password>
</credValidate>
<MyScript>
<sScriptCode><xsl:value-of select="symbol" /></sScriptCode>
</MyScript>
</GetQuote>
</soap12:Body>
</soap12:Envelope>
</xsl:template>
</xsl:stylesheet>
Na wej艣ciu dostaje ona XML zawieraj膮cy dane zadania 鈥楾1鈥, czyli co艣 w rodzaju
<data><symbol>MSFT</symbol></data>
Na wyj艣ciu natomiast powstaje komunikat SOAP o strukturze opisanej wcze艣niej 鈥 nasza transformacja po prostu wstawia zmienn膮 鈥榮ymbol鈥 w polu 鈥榮ScriptCode鈥. Po wygenerowaniu komunikatu SOAP zadanie T1 wysy艂a go w tre艣ci requestu 聽鈥楶OST鈥 pod adres web service. Nast臋pnie odbiera odpowied藕, czyli opisany wy偶ej komunikat 鈥楪etQuoteResponse鈥, kt贸ry z kolei poddaje transformacji 鈥楪etQuote_Response.xsl鈥:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:soap="http://www.w3.org/2003/05/soap-envelope"
xmlns:quot="http://trutech.com/marketwatch/">
<xsl:output method="xml" encoding="utf-8" indent="yes" />
<xsl:template match="/soap:Envelope/soap:Body/quot:GetQuoteResponse">
<data>
<price><xsl:value-of select="quot:MyScript/quot:sScriptLastPrice" /></price>
</data>
</xsl:template>
</xsl:stylesheet>
Wida膰 偶e na wyj艣ciu otrzymamy bardzo prosty XML w rodzaju
<data><price>28.08 Rs</price></data>
NGinn na podstawie tego XML zaktualizuje zmienne zadania T1, czyli przypisze otrzyman膮 od web service warto艣膰 kursu akcji do zmiennej 鈥榩rice鈥. Na tym zadanie 鈥楾1鈥 si臋 ko艅czy,聽 a razem z nim ca艂y przyk艂adowy proces.
Jest to bardzo elastyczna metoda wywo艂ywania web services, mamy praktycznie ca艂kowit膮 kontrol臋 nad struktur膮 przekazywanych komunikat贸w. Niestety, dzieje si臋 to kosztem do艣膰 偶mudnego przygotowywania XSL-i 鈥 nie ma 偶adnego narz臋dzia kt贸re by to zrobi艂o za nas (pewnie takie narz臋dzie korzysta艂o by z WSDL, my nie musimy bo mamy przyk艂ady XML-i). Warto tu wspomnie膰 o narz臋dziach kt贸re przydaj膮 si臋 do tworzenia w/w xsl-i i w og贸le do test贸w web services. Pierwszym z tych narz臋dzi jest pakiet 鈥楥url鈥 (http://curl.haxx.se/ ) umo偶liwiaj膮cy wysy艂anie po http dowolnych 偶膮da艅 (a w szczeg贸lno艣ci naszych komunikat贸w SOAP). Drugim聽 jest pakiet 鈥榥xslt鈥 (http://www.xmllab.net/downloads/nxslt/) umo偶liwiaj膮cy testowanie dzia艂ania transformacji XSLT. Pos艂uguj膮c si臋 tymi dwoma narz臋dziami jeste艣my w stanie szybko ustali膰 jaka powinna by膰 struktura komunikat贸w SOAP i wygenerowa膰 odpowiednie arkusze XSL. W ten sam spos贸b mo偶emy obs艂u偶y膰 nie tylko wywo艂ania web services, ale np protok贸艂 XML-RPC czy inne, oparte na XML/HTTP protoko艂y komunikacji co czyni zadanie XmlHttp do艣膰 uniwersalnym narz臋dziem.
Taki spos贸b u偶ywania web services nie jest oczywi艣cie zarezerwowany dla NGinn 鈥 mo偶na to robi膰 w ka偶dej innej sytuacji, nawet gdy mamy do dyspozycji Visual Studio z automatycznym generowaniem kodu klienta web service. Po co? Ot贸偶 s膮 pewne typy danych kt贸rych standardowa serializacja SOAP oferowana przez Microsoft.Net nie potrafi obs艂u偶y膰 鈥 na przyk艂ad typy nullable, nieprawid艂owo te偶 s膮 obs艂ugiwane pola typu 鈥楧ateTime鈥 w innej ni偶 UTC strefie czasowej. Innym przyk艂adem s膮 niestandardowe nag艂贸wki http lub rozszerzenia SOAP 鈥 za pomoc膮 opisanego tu sposobu mo偶emy generowa膰 wywo艂ania z dowolnymi nag艂贸wkami i z dowoln膮 tre艣ci膮, podczas gdy w 鈥榥ormalny鈥 spos贸b musieli by艣my pisa膰 w C#/VB dodatkowy kod obs艂uguj膮cy przypadki niestandardowe. No a poza tym jest to 艣wietny spos贸b testowania web services bez pisania kodu.
Poniewa偶 opisany tu mechanizm wywo艂ywania web services jest bardzo prosty, mo偶na wr臋cz powiedzie膰 偶e prymitywny, rodzi si臋 pytanie czy jest to rozwi膮zanie docelowe czy tylko prowizoryczne? Na pewno brakuje mu kilku rzeczy – mi臋dzy innymi automatycznej kontroli zgodno艣ci schemat贸w danych z definicj膮 web service, mo偶na by si臋 te偶 pokusi膰 o jaki艣 graficzny edytor pozwalaj膮cy mapowa膰 zmienne zadania na parametry we/wy us艂ugi lub te偶 automatycznie generowa膰 XSL-e na podstawie jakiego艣 prostszego mapowania. Ale mimo to uwa偶am 偶e jest to elastyczne i proste w u偶yciu narz臋dzie kt贸re da si臋 zastosowa膰 w wielu sytuacjach.
Jakie powinno by膰 oprogramowanie dla du偶ych organizacji?
Poniewa偶 od wielu lat zajmuj臋 si臋 realizacj膮 i wdro偶eniami oprogramowania聽wspieraj膮cego procesy biznesowe w du偶ych organizacjach zebra艂o mi si臋 sporo przemy艣le艅 na temat specyfiki tej pracy, trudno艣ci kt贸re najcz臋艣ciej wdro偶eniowc贸w czekaj膮 oraz sposob贸w radzenia sobie z typowymi przy takich projektach problemami. Dzi艣 zatem b臋dzie o tym w jaki spos贸b dobrze zaprojektowane oprogramowanie mo偶e pomaga膰 nam w realizacji skomplikowanych projekt贸w. Artyku艂 ten jest wyja艣nia te偶 dlaczego projektuj膮c NGinn stara艂em si臋 uwzgl臋dni膰 聽pewne cechy oprogramowania kt贸re uwa偶am za pomocne przy realizacji potrzeb naszych klient贸w.
Wdro偶enie
M贸wi膮c o wdro偶eniu systemu w du偶ej organizacji mam na my艣li firmy licz膮ce kilka tysi臋cy pracownik贸w gdzie wdra偶any system ma spory ‘zasi臋g ra偶enia’, czyli obejmuje istotn膮 cz臋艣膰 personelu firmy i w jaki艣 spos贸b dotyczy istotnych dla biznesu tej firmy proces贸w. Przyk艂adem takiego oprogramowania s膮 systemy CRM, wsparcia klient贸w, obs艂ugi zam贸wie艅/zlece艅 lub te偶 systemy wspieraj膮ce wewn臋trzne procesy w du偶ych firmach – HR, zakupy wewn臋trzne, helpdesk IT etc. W takim 艣rodowisku wymagania najcz臋艣ciej nie pochodz膮 od jednej osoby ale s膮 jak膮艣 wypadkow膮 potrzeb i plan贸w rozwojowych wielu os贸b z r贸偶nych dzia艂贸w danej firmy. Oznacza to 偶e prowadz膮c wdro偶enie musimy wsp贸艂pracowa膰 z wieloma ‘w艂a艣cicielami biznesowymi’ jednocze艣nie, najcz臋艣ciej b臋d膮 to managerowie jednostek organizacyjnych w kt贸rych wprowadzamy nasz system. Wiele 藕r贸de艂 wymaga艅 oznacza potencjalne rozbie偶no艣ci w specyfikacji potrzeb no i r贸偶ne sposoby interpretacji tego co zosta艂o ustalone 聽- prawdopodobnie nie da si臋 wszystkiego uzgodni膰 tak 偶eby specyfikacja by艂a sp贸jna, kompletna, niesprzeczna i na dodatek tak samo rozumiana przez wszystkie strony. Oczywi艣cie nale偶y do tego d膮偶y膰, ale wg mnie trzeba na jakim艣 etapie odpu艣ci膰 i uzna膰 偶e tak po prostu jest 偶e ka偶dy chce czego innego i na co innego zwraca uwag臋. Problem jest taki 偶e system musi by膰 oparty na niesprzecznej wewn臋trznie logice no i zapewnienie logiczno艣ci tej logiki to w艂a艣nie nasze zadanie, ale my艣l臋 偶e aby prac臋 w og贸le da艂o si臋 zacz膮膰 to wystarczy ustali膰 kwestie podstawowe, z艂apa膰 jaki-taki obraz ca艂o艣ci i pilnowa膰 偶eby ka偶dy w艂a艣ciciel biznesowy na ko艅cu dosta艂 to na czym mu zale偶y. Przy takim podej艣ciu musimy dopu艣ci膰 mo偶liwo艣膰 robienia wyj膮tk贸w od ustalonych przez wszystkich regu艂, na przyk艂ad ustalaj膮c 偶e system zaoferuje inn膮 ni偶 dla ca艂ej reszty firmy procedur臋 pracy lub zawarto艣膰 formatki dla pracownik贸w jakiego艣 dzia艂u X bo akurat manager tego dzia艂u chce inaczej zarz膮dza膰 u siebie prac膮. Zamiast zmusza膰 wszystkich w艂a艣cicieli biznesowych do uzgodnienia jednego wsp贸lnego stanowiska w tej sprawie po prostu uwzgl臋dniamy potrzeby X w budowanym systemie tak aby nie mia艂o to wp艂ywu na pozosta艂ych.
A co ze stron膮 techniczn膮 przy takim podej艣ciu? W sumie to ka偶dy system mo偶e uwzgl臋dni膰 rozbie偶ne wymagania i wyj膮tki (oraz wyj膮tki od wyj膮tk贸w) w logice biznesowej, r贸偶nice s膮 tylko w sposobie implementacji takich wymaga艅, stopniu komplikacji wynikowego systemu oraz nak艂adzie pracy koniecznym do implementacji i p贸藕niejszego utrzymania systemu. Jest natomiast kilka cech oprogramowania kt贸re takie zadania u艂atwiaj膮:
- oddzielenie logiki biznesowej od infrastruktury. Oprogramowanie powinno w przejrzysty spos贸b dzieli膰 si臋 na infrastruktur臋 (czyli komponenty odpowiedzialne za podstawowe funkcje systemu kt贸re si臋 nie zmieniaj膮 z wdro偶enia na wdro偶enie) oraz na ‘logik臋 biznesow膮’ czyli specyficzne dla klienta struktury danych, GUI, formularze, szablony dokument贸w i regu艂y wed艂ug kt贸rych system realizuje funkcje uzgodnione z klientem. Najlepiej 偶eby podzia艂 na infrastruktur臋 i logik臋 by艂 silny, tzn ka偶dy komponent powinien by膰 jednoznacznie przypisany do jednej z tych grup, a dodatkowo infrastruktura powinna by膰 na tyle dobrze zaprojektowana 偶eby implementacja kolejnych funkcji biznesowych nie wymaga艂a omijania ani modyfikacji infrastruktury.
- mo偶liwo艣膰 wprowadzania lokalnych zmian w logice. To szeroki temat, ale chodzi o to aby uwzgl臋dniaj膮c czyje艣 specjalne potrzeby mo偶na by艂o dzia艂a膰 ‘lokalnie’ nie wp艂ywaj膮c na pozosta艂e funkcje systemu, na przyk艂ad zaoferowa膰 dla wybranych u偶ytkownik贸w specjaln膮 wersj臋 formatki bez modyfikowania formatki ‘og贸lnej’, tj tej dost臋pnej dla wszystkich, albo zmieni膰 regu艂y rz膮dz膮ce przep艂ywem okre艣lonego typu dokument贸w bez modyfikowania regu艂 og贸lnych kt贸rym podlegaj膮 wszystkie inne dokumenty. 聽I odwrotnie 聽- system w kt贸rym ca艂a logika jest zapisana w jednym pliku z kodem 藕r贸d艂owym w postaci gigantycznego i wielokrotnie zagnie偶d偶onego if-else na pewno nie spe艂nia tej regu艂y i jest bardzo trudny do modyfikacji.
- zwi臋z艂y, przejrzysty i najlepiej samo-dokumentuj膮cy si臋 spos贸b zapisu logiki biznesowej. Struktura musi by膰 艂atwa do zrozumienia i zobrazowania, dzi臋ki temu b臋dziemy w stanie zapanowa膰 nad wielo艣ci膮 regu艂 i wyj膮tk贸w od nich. Mo偶na taki cel osi膮gn膮膰 np przez wprowadzenie specjalizowanego j臋zyka ‘wy偶szego poziomu’ do zapisywania logiki biznesowej, np w postaci regu艂 if-then-else albo proces贸w w okre艣lonej notacji, tudzie偶 opartego o XML j臋zyka opisu wygl膮du formatek
Zmiana
Wracaj膮c do samego wdro偶enia, chyba najwa偶niejszym problemem z kt贸rym sobie musimy poradzi膰 jest zmiana. Zmiany w du偶ych organizacjach to norma, mo偶emy by膰 pewni 偶e w momencie uruchomienia systemu po raz pierwszy zacznie p艂yn膮膰 strumyczek wniosk贸w racjonalizatorskich, 偶膮da艅 zmian i pomys艂贸w na kolejne zastosowania systemu. Dla nas powinna to by膰 okazja do robienia biznesu a nie rzecz z kt贸r膮 nale偶y walczy膰 – nale偶y klienta zach臋ca膰 do zmian i je realizowa膰, problem tylko w tym jak to zrobi膰 偶eby nie wpa艣膰 przy okazji po szyj臋 w bagno. A bagno pojawia si臋 kiedy na skutek radosnej tw贸rczo艣ci klienta 聽(przy naszym wsp贸艂udziale) system robi si臋 bardzo skomplikowany, regu艂y niejasne, niesp贸jne i czasami si臋 wykluczaj膮ce i pojawiaj膮 si臋 dziwne ‘b艂臋dy’ za kt贸re jeste艣my obarczani odpowiedzialno艣ci膮. A wina nie zawsze jest po naszej stronie – no bo po kilku latach rozwoju systemu w firmie sytuacja zwykle przedstawia si臋 tak:
- nikt po stronie klienta nie ma pe艂nego obrazu tego jakie funkcje i w jaki spos贸b system realizuje. Po prostu nie ma takiej osoby bo r贸偶ne wymagania pochodzi艂y od r贸偶nych ludzi, w r贸偶nym czasie i nie ma nikogo kto by to potrafi艂 albo chcia艂 uzgodni膰
- ludzie kt贸rzy definiowali jakie艣 funkcje i ustalali z nami spos贸b ich dzia艂ania albo ju偶 nie pracuj膮, albo nie pami臋taj膮, albo nie chc膮 pami臋ta膰, albo dostali inne zadania i ju偶 nie bior膮 udzia艂u w projekcie
- nowi managerowie nie bior膮 odpowiedzialno艣ci za nic bo ‘to nie oni ustalali’. M贸wi膮 tylko 偶e w systemie jest b艂膮d bo nie pasuje do ich koncepcji.
- Dokumentacja nic nam nie pomo偶e, po prostu jest zbyt og贸lna i fragmentaryczna. Nie spos贸b spisa膰 ka偶dego szczeg贸艂u.
- Je艣li si臋 pilnowali艣my to mamy rejestr wprowadzanych zmian. 艢wietnie, ale to nic nam nie pomo偶e bo jest tego tyle 偶e trzeba nadludzkich mo偶liwo艣ci 偶eby analizuj膮c poszczeg贸lne zmiany ustali膰 jaki powinien by膰 aktualny stan systemu. Poza tym wiele drobiazg贸w by艂o za艂atwiane na g臋b臋/telefon/maila i nie ma ju偶 po tym 艣ladu
- Mo偶e nawet mamy specyfikacj臋 systemu i wiemy co i dlaczego w nim dzia艂a tak jak dzia艂a (o, super!) ale system i tak ‘藕le dzia艂a’ bo w mi臋dzyczasie u klienta by艂a reorganizacja, np cze艣膰 procesu zosta艂a ‘outsorcowana’, wprowadzono nowe grupy, inne zasady rozlicze艅 itp itd. Oczywi艣cie to nasz problem a nie klienta, no bo przecie偶 wymagania m贸wi膮 偶e system ma realizowa膰 jaki艣 tam cel a nagle przesta艂.
W艂a艣ciwie wszystkie powy偶sze punkty przerabia艂em, my艣l臋 偶e ka偶dy informatyk kt贸ry pracuje z klientami r贸wnie偶 by艂by got贸w si臋 z wi臋kszo艣ci膮 zgodzi膰. I my艣l臋 te偶 偶e nie ma skutecznego sposobu kt贸ry by pozwala艂 sobie z tym poradzi膰. Ale trzeba zacisn膮膰 z臋by i z tym 偶y膰 (albo zmieni膰 prac臋 na jak膮艣 mniej stresuj膮c膮), dobrze te偶 jest mie膰 jakie艣 oparcie w oprogramowaniu – a oto cechy kt贸re uwa偶am za bardzo po偶膮dane w takiej sytuacji:
- Wszystkie 3 punkty o kt贸rych pisa艂em wy偶ej przy okazji specyfikacji wymaga艅, oraz:
- Mo偶liwo艣膰 wsp贸艂istnienia kilku wersji logiki biznesowej. Na przyk艂ad jednoczesnego dzia艂ania w oparciu o star膮 logik臋 i now膮 logik臋 – po prostu, stare sprawy biegn膮 wg starych regu艂, nowo zak艂adane – wg nowych. To bardzo u艂atwia migracje. To pozwala te偶 na robienie zmian lokalnych o kt贸rych pisa艂em wcze艣niej – czyli takich co obejmuj膮 tylko niekt贸rych u偶ytkownik贸w nie wprowadzaj膮c zamieszania u pozosta艂ych. No i u艂atwia ewentualny rollback do poprzednich wersji je艣li nowa nie oka偶e si臋 takim sukcesem jak si臋 wydawa艂o.
- Samo-dokumentacja (r贸wnie偶 wspomniany wcze艣niej). Logika biznesowa powinna by膰 zapisana tak, 偶eby 艂atwo mo偶na by艂o ustali膰 aktualny spos贸b dzia艂ania systemu. Na przyk艂ad strukturalny zapis w postaci regu艂 if-then-else pozwala nam narysowa膰 drzewo decyzyjne wg kt贸rego system podejmuje jakie艣 dzia艂ania, a np zapis proces贸w biznesowych w jakiej艣 strukturalnej notacji pozwala uzyska膰 diagram aktualnego przep艂ywu dokument贸w w firmie.
- Mo偶liwo艣膰 wprowadzania zmian w locie. To jest istotne bo du偶e organizacje cz臋sto pracuj膮 24×7 i system jest tak samo potrzebny zar贸wno w dzie艅 jak i w nocy. Nie mo偶na sobie pozwoli膰 na d艂ugie przestoje, zw艂aszcza kiedy zmian jest du偶o i s膮 wprowadzane bardzo cz臋sto, nawet ad-hoc gdy kto艣 zaobserwuje 偶e system dzia艂a niezgodnie z oczekiwaniami i trzeba to szybko naprawi膰.
- Mo偶liwo艣膰 wprowadzania zmian lokalnie, bez zatrzymywania pozosta艂ych komponent贸w systemu – troch臋 zwi膮zane z poprzednim, ale chodzi o to aby do wprowadzenia zmian w jakiej艣 funkcji systemu nie trzeba by艂o 聽wy艂膮cza膰 ca艂ego systemu a zasi臋g naszych dzia艂a艅 by艂 tak ma艂y jak to tylko mo偶liwe.
- Ca艂a logika biznesowa powinna by膰 przechowywana w postaci plik贸w tekstowych. Dlatego 偶e w ten spos贸b 艂atwo 艣ledzi膰 zmiany np za pomoc膮 systemu kontroli wersji. Wszelkie formaty binarne (np z graficznych designer贸w), bloby w bazie danych, 聽bardzo utrudniaj膮 prac臋.
- Strukturalny podzia艂 logiki biznesowej wed艂ug funkcji realizowanych przez system a nie czego艣 innego (chocia偶by np obiekt贸w w bazie relacyjnej). Biznesowo widziane funkcje systemu maj膮 charakter przekrojowy – obejmuj膮 wiele fragment贸w aplikacji, takich jak struktura danych w bazie, GUI, uprawnienia, specyficzn膮 dla danej funkcji logik臋, powiadomienia email, szablony dokument贸w, raporty itp itd. Wszystko to mo偶e sk艂ada膰 si臋 na jedn膮 logiczn膮 funkcj臋, o nazwie np ‘obs艂uga p艂atno艣ci’ albo ‘obs艂uga komunikacji z dostawcami’. Dobrze by by艂o 偶eby struktura systemu grupowa艂a te elementy w pakiety wed艂ug logicznych funkcji, wtedy 艂atwo ustali膰 kt贸re elementy systemu bior膮 udzia艂 w realizacji okre艣lonych wymaga艅 i jaki b臋dzie zakre zmian w systemie przy modyfikacji okre艣lonej funkcji. Istotna jest te偶 separacja – dwie r贸偶ne funkcje raczej nie powinny wykorzystywa膰 tych samych fragment贸w logiki biznesowej czy GUI, nawet je艣li s膮 one bardzo podobne. A to dlatego 偶e wprowadzaj膮c zmiany dla jednej grupy u偶ytkownik贸w nie chcemy przy okazji psu膰 czego艣 pozosta艂ym. ‘Code reuse’ to dobra rzecz ale nie tutaj.
- Preferuj臋 systemy ‘mi臋kkie’ – tzn skryptowe, interpretowane, dynamiczne – w przeciwie艅stwie do statycznie typowanych, kompilowanych, buildowanych, package’owanych i deployowanych. Chodzi o modyfikacje logiki biznesowej, konfiguracji, uprawnie艅 czy GUI. Infrastruktura mo偶e by膰 kompilowana i niezmienialna po wdro偶eniu, wa偶ne aby logika by艂a modyfikowalna. Dzi臋ki temu mo偶emy dokonywa膰 szybkich poprawek, mini-wdro偶e艅, szybkich test贸w nowej funkcjonalno艣ci itp. Generalnie uwa偶am 偶e logika biznesowa powinna by膰 zapisywana w j臋zykach skryptowych (przy czym wybieramy takie j臋zyki kt贸re najlepiej si臋 nadaj膮 do okre艣lonego celu), za艣 infrastruktura w j臋zykach ni偶szego poziomu – C#, C++, Java itp.
- Cechy powy偶sze pozwalaj膮 nam te偶 zmieni膰 podej艣cie do testowania i prototypowania nowych funkcji. Maj膮c mo偶liwo艣膰 wrzucenia nowej wersji logiki bez wy艂膮czania starej mo偶emy przeprowadza膰 testy nowych czy zmodyfikowanych funkcji na produkcji – po prostu udost臋pniaj膮c je wybranej grupie tester贸w. Po potwierdzeniu poprawnego dzia艂ania w艂膮czamy funkcj臋 dla wszystkich u偶ytkownik贸w. Bardzo cz臋sto testy obejmuj膮 nie tylko zmiany w systemie, ale r贸wnie偶 zmiany w organizacji – klient po prostu chce realizowa膰 nowy proces pos艂uguj膮c si臋 naszym narz臋dziem i chce go sobie przetestowa膰 na jakiej艣 ma艂ej grupie ludzi. W takim przypadku testowanie na produkcji jest czym艣 naturalnym i bardzo u艂atwia p贸藕niejsze uruchomienie ‘oficjalne’. Jest to te偶 zach臋ta dla klienta do eksperymentowania – zwykle sprawdzenie czego艣 ‘na 偶ywo’ jest lepsze, szybsze i ta艅sze ni偶 pisanie dokument贸w z wymaganiami i analizowanie tematu ‘na sucho’.
Wydajno艣膰
Sprawa wydajno艣ci jest bardzo wa偶na – mo偶emy dowolnie rozwija膰 i modyfikowa膰 nasz system, ale musi on zapewnia膰 wydajno艣膰 wystarczaj膮c膮 do obs艂u偶enia wszystkich nowych pomys艂贸w. A je艣li odnie艣li艣my sukces to klient b臋dzie chcia艂 obj膮膰 wdro偶eniem jakie艣 nowe obszary organizacji co oznacza wi臋cej danych, wi臋cej u偶ytkownik贸w no i wi臋cej funkcji w aplikacji. W niekt贸rych przypadkach rozw贸j systemu jest tak szybki 偶e przerasta to nasze oczekiwania oraz mo偶liwo艣ci systemu kt贸ry nie by艂 projektowany do tak du偶ego obci膮偶enia. W tym miejscu kilka uwag na temat potencjalnych ‘min’ wydajno艣ciowych:
Uwaga na聽relacyjne bazy danych. Mimo 偶e relacyjna baza danych to podstawa bez kt贸rej nikt nie wyobra偶a sobie aplikacji biznesowej to jednak jest to narz臋dzie kt贸re ma swoje ograniczenia. Po pierwsze jest ’sztywna’ – wymaga uzgodnienia struktur danych i trzymania si臋 ich. Tabela w bazie jest taka sama dla wszystkich przechowywanych w niej obiekt贸w, nawet je艣li r贸偶ni膮 si臋 one od siebie na poziomie aplikacji. Bazy danych nie obs艂uguj膮 dziedziczenia. Nie mo偶na wprowadza膰 zmian lokalnie – albo zmieniasz ca艂膮 tabel臋 albo nic, zmiana struktury danych dotyczy wszystkich miejsc systemu kt贸re si臋 do niej odwo艂uj膮. Druga sprawa to wielko艣膰 bazy danych – je艣li chcesz wprowadzi膰 zmiany w tabeli kt贸ra liczy sobie miliony rekord贸w licz si臋 z tym 偶e mo偶e to by膰 bardzo d艂ugotrwa艂y proces albo nawet i niewykonalny (!). Na przyk艂ad dodanie nowej kolumny do rekordu aktualizuje nam wszystkie stare rekordy kt贸re ju偶 s膮 w bazie – rozmiar rekordu si臋 zwi臋ksza i nast臋puje reorganizacja ca艂ej tabeli kt贸ra mo偶e trwa膰 nawet kilka godzin. A nasz czas na serwis to 30 minut… niby prosta zmiana a nie do zrobienia. Trzecia sprawa to wydajno艣膰 samej bazy – rozw贸j systemu to coraz wi臋ksza jego komplikacja i coraz bardziej z艂o偶one transakcje w bazie danych. Transakcyjno艣膰 to bardzo fajna rzecz ale potrafi r贸wnie偶 mocno ograniczy膰 wydajno艣膰 aplikacji poprzez nak艂adanie blokad wykluczaj膮cych wsp贸艂bie偶ne wykonywanie operacji. Na dodatek nie bardzo mo偶na zwi臋ksza膰 wydajno艣膰 systemu przez do艂o偶enie kolejnej bazy danych – najcz臋艣ciej baza musi by膰 jedna no bo chcemy dzia艂a膰 na jednej, aktualnej wersji danych a nie na kilku niezsynchronizowanych kopiach. Dobrze jest przemy艣le膰 te rzeczy na jakim艣 wczesnym etapie bo im wi臋cej danych si臋 nagromadzi tym mniejsze mamy mo偶liwo艣ci manewru.
Kolejna sprawa to komunikacja mi臋dzy komponentami systemu oraz mi臋dzy systemem a innymi aplikacjami z kt贸rymi jest zintegrowany. Nale偶y uwa偶a膰 na komunikacj臋 synchroniczn膮 – mimo 偶e wydaje si臋 fajnym pomys艂em na pocz膮tku to mo偶e nam mocno obci膮膰 wydajno艣膰 ca艂ej aplikacji. Kluczowe operacje w systemie nale偶y rozbi膰 na jak najmniejsze kawa艂ki, tak aby transakcje mia艂y niewielki zasi臋g i wykonywa艂y si臋 szybko. Reszt臋 operacji mo偶na doko艅czy膰 asynchronicznie. Przyk艂ad: podczas rejestracji nowego dokumentu przez u偶ytkownika pozyskujemy wymagane dane od u偶ytkownika i rejestrujemy dokument w bazie. Wszelkie operacje dodatkowe, takie jak powiadomienie o nowym dokumencie innych system贸w, wys艂anie emaili, indeksowanie dokumentu itp robimy p贸藕niej, offline, po zako艅czeniu interakcji z u偶ytkownikiem i zamkni臋ciu tej pierwszej transakcji w bazie danych. 聽Komunikacj臋 z systemami zewn臋trznymi robimy w tle bo nigdy nie wiadomo jak d艂ugo przyjdzie nam czeka膰 na odpowied藕. Tak samo je艣li oferujemy jak膮艣 us艂ug臋 (np web service) dla system贸w zewn臋trznych – gdy zrobimy to w wersji synchronicznej mo偶e si臋 okaza膰 偶e zewn臋trzne aplikacje po prostu ‘zarzynaj膮’ nasz system. Bardzo dobrym pomys艂em jest wykorzystanie architektury opartej o ‘message bus’ tj mechanizm asynchronicznego przekazywania komunikat贸w mi臋dzy komponentami systemu – w takiej architekturze naturalne jest podej艣cie asynchroniczne. Temat jest godny jakiego艣 rozwini臋cia, ale to kiedy indziej.
NGinn
Oczywi艣cie nie mog臋 tutaj pomin膮膰 NGinn – jest to narz臋dzie kt贸re projektowa艂em bior膮c pod uwag臋 wszystko co napisa艂em wy偶ej (i pewnie jeszcze troch臋 spraw o kt贸rych nie napisa艂em). NGinn jest moj膮 odpowiedzi膮 na problem realizacji skomplikowanych i ci膮gle zmiennych wymaga艅 w rozbudowanych systemach. Oczywi艣cie jeden NGinn nie za艂atwi wszystkiego, jest to tylko workflow engine 聽i nie obejmuje na przyk艂ad GUI systemu, ale skutecznie stosuje opisane tu regu艂y do realizacji logiki biznesowej systemu. A to dlatego 聽偶e:
- Proces w NGinn opisuje nam logik臋 systemu potrzebn膮 do realizacji okre艣lonego procesu biznesowego, tj zawiera opis konkretnej funkcji biznesowej systemu, od pocz膮tku do ko艅ca. Procesy grupowane s膮 w pakiety kt贸re opr贸cz samej definicji procesu mog膮 przenosi膰 dodatkowe elementy potrzebne do realizacji danej funkcji biznesowej – np szablony powiadomie艅, logik臋 integracyjn膮, etc
- NGinn obs艂uguje wersjonowanie proces贸w – procesy mog膮 wsp贸艂istnie膰 w wielu wersjach jednocze艣nie, wprowadzanie nowej wersji procesu nie wymaga wy艂膮czenia starej ani migracji
- Mo偶na modyfikowa膰 istniej膮ce procesy bez zatrzymywania systemu.
- Struktury danych w NGinn s膮 dynamiczne – modyfikuj膮c proces mo偶na zmienia膰 definicj臋 jego danych, nie poci膮ga to za sob膮 konieczno艣ci modyfikacji struktury bazy danych lub aktualizacji innych proces贸w kt贸re ju偶 si臋 tocz膮.
- Asynchroniczny w za艂o偶eniach – NGinn polega g艂贸wnie na asynchronicznej komunikacji mi臋dzy komponentami oraz mi臋dzy NGinn a 艣wiatem zewn臋trznym. Wewn臋trznie NGinn u偶ywa kolejki komunikat贸w do przesy艂ania informacji pomi臋dzy procesami.
- Definicja procesu jest jednocze艣nie dokumentacj膮 logiki systemu – maj膮c definicj臋 mo偶na wygenerowa膰 graficzny schemat procesu.
- NGinn pozwala u偶ywa膰 ‘rules engine’ do zapisu drzew decyzyjnych w postaci regu艂 if-then-else. Mo偶e si臋 to przyda膰 tam gdzie istnieje potrzeba podejmowania r贸偶nych dzia艂a艅 w oparciu o rozmaite atrybuty danych wej艣ciowych.
- W jasny spos贸b oddzielona jest infrastruktura NGinn od logiki biznesowej. Logika biznesowa jest przechowywana w definicji procesu w oparciu o kt贸r膮 infrastruktura ten proces realizuje.
Na koniec…
Podsumowuj膮c to wszystko, my艣l臋 偶e najefektywniejsz膮 technik膮 tworzenia oprogramowania na zam贸wienie dla wymagaj膮cych klient贸w (hm, czy s膮 klienci niewymagaj膮cy?) jest聽szybkie prototypowanie wsparte odpowiednio dostosowanym narz臋dziem. Pomaga to zar贸wno przy ustalaniu wymaga艅 jak i przy p贸藕niejszej ich realizacji. Klientom bardzo przydaje si臋 mo偶liwo艣膰 zobaczenia tego co chc膮 zam贸wi膰 i skonfrontowania swoich wyobra偶e艅 z rzeczywisto艣ci膮, a my dzi臋ki temu mamy wymagania lepszej jako艣ci i bardziej odpowiadaj膮ce mo偶liwo艣ciom systemu. No i szybciej mo偶emy wystawi膰 faktur臋.
Oczywi艣cie nie jest to jakie艣 rewolucyjne podej艣cie – w 艣wiecie informatyki funkcjonuj膮 rozmaite metodyki prowadzenia projekt贸w maj膮ce w za艂o偶eniach szybkie prototypowanie – na przyk艂ad Extreme Programming czy rozmaite Agile – ale zostawmy ten temat, w ko艅cu nie zajmujemy si臋 tu teori膮 tylko robieniem softu. Reprezentuj臋 punkt widzenia go艣cia kt贸ry w艂asnymi (lub zespo艂u) r臋kami tworzy oprogramowanie 聽a w艂asn膮 g艂ow膮 odpowiada za dostarczenie go klientowi zgodnie z zam贸wieniem i w terminie i mam nadziej臋 偶e takie spojrzenie od strony warsztatu jest dobrym uzupe艂nieniem ‘best practices’ prowadzenia projekt贸w informatycznych.
Wyszukiwanie danych w procesach
Dzi艣 zajm臋 si臋 spraw膮 wyszukiwania danych procesu w NGinn. Problemem w tym przypadku jest spos贸b przechowywania danych procesu przez NGinn – ot贸偶 dane s膮 przechowywane jako fragment dokumentu JSON zawieraj膮cego stan procesu. Taki spos贸b przechowywania danych nie u艂atwia ich przeszukiwania – nawet je艣li dokumenty s膮 zapisywane w relacyjnej bazie danych to i tak nie da si臋 za pomoc膮 SQL zadawa膰 zapyta艅 o poszczeg贸lne pola w dokumencie.
Rozwi膮zaniem jest odpowiednie indeksowanie dokument贸w, przy czym nie mam tu na my艣li indeks贸w znanych z relacyjnych baz danych a zewn臋trzny indeks pe艂notekstowy pozwalaj膮cy na umieszczanie w nim dowolnych danych. Jednym z narz臋dzi tego typu jest Apache Lucene oraz jego port do 艣rodowiska .Net pod nazw膮 Lucene.Net. Lucene pozwala na budow臋 indeks贸w o dowolnej zawarto艣ci (ka偶dy wpis w indeksie mo偶e zawiera膰 dowolny zestaw p贸l) kt贸re potem mog膮 by膰 przeszukiwane za pomoc膮 prostych zapyta艅.
Po艣wi臋ci艂em ostatnio troch臋 czasu na pr贸b臋 po艂膮czenia NGinn i Lucene i wyniki s膮 bardzo zach臋caj膮ce. Przede wszystkim wra偶enie robi wydajno艣膰 Lucene.Net – wyniki s膮 zwracane w mgnieniu oka a mechanizm wyszukiwania jest bardzo sprytny i ma wiele interesuj膮cych mo偶liwo艣ci. Wystarczy w aplikacji umie艣ci膰 jedno pole wyszukiwania i mo偶emy szuka膰 po dowolnych danych w procesie a nawet konstruowa膰 bardziej zaawansowane zapytania zbudowane z kilku predykat贸w po艂膮czonych operatorami logicznymi. Dodatkowo Lucene w naturalny spos贸b obs艂uguje paging co znacznie u艂atwia budow臋 aplikacji. Nie b臋d臋 tu wchodzi艂 w techniczne szczeg贸艂y, ale mechanizm indeksowania danych NGinn za pomoc膮 Lucene dzia艂a w trybie offline, tzn indeksuje dane z pewnym niewielkim op贸藕nieniem dzi臋ki czemu indeksowanie nie ma negatywnego wp艂ywu na szybko艣膰 dzia艂ania NGinn. Komponent indeksuj膮cy uaktywnia si臋 tylko po zmianie stanu jakiego艣 procesu i wtedy wpis w indeksie dla tego procesu jest aktualizowany. Nie robi艂em test贸w na milionach rekord贸w, ale przy w艂a艣ciwym poindeksowaniu danych wyszukiwanie za pomoc膮 Lucene powinno by膰 o wiele szybsze ni偶 jakiekolwiek zapytania SQLowe. Je艣li chodzi o wielko艣膰 indeksu to jest ona zaskakuj膮co ma艂a bior膮c pod uwag臋 ilo艣膰 danych kt贸r膮 mo偶na w nim umie艣ci膰.
Je艣li chodzi o plany rozwojowe to w najbli偶szym czasie nie zamierzam umieszcza膰 w NGinn komponentu indeksuj膮cego – jest to fajny dodatek ale poniewa偶 nie jest bezpo艣rednio zwi膮zany z funkcjami workflow engine to na razie nie b臋d臋 go rozwija艂 w ramach projektu Open Source – no chyba 偶e pojawi si臋 perspektywa jakiego艣 interesuj膮cego wdro偶enia.
Poni偶ej zamieszczam przyk艂adowy ekran wyszukiwania z prostej aplikacji kt贸r膮 posi艂kuj臋 si臋 przy pracach nad NGinn. 艁膮cz膮c framework Ext JS oraz Lucene uda艂o si臋 bardzo szybko rozbudowa膰 t臋 aplikacj臋 o funkcj臋 wyszukiwania proces贸w na podstawie ich wewn臋trznych danych. Tak wi臋c szukaj膮cym dobrego search engine dla swojego systemu bardzo polecam Lucene.

O dokumentach, procesach, bazach danych i JSON. No i o przysz艂o艣ci.

M贸wi膮c o jakichkolwiek procesach biznesowych wcze艣niej czy p贸藕niej trafiamy na poj臋cie dokumentu. To wok贸艂 dokumentu buduje si臋 procesy – dokumentem mo偶e by膰 jaki艣 papier w臋druj膮cy przez organizacj臋, faktura, sprawa zarejestrowana w jakim艣 systemie, nades艂any przez klienta email z za偶aleniami i tak dalej. Je艣li chcemy taki proces ‘zinformatyzowa膰’ to r贸wnie偶 dokumenty musz膮 zosta膰 w jaki艣 spos贸b przetworzone na posta膰 cyfrow膮 i zarejestrowane w jakim艣 systemie.
W przypadku NGinn nastawi艂em si臋 na maksymaln膮 elastyczno艣膰 w temacie dokument贸w do kt贸rych odnosz膮 si臋 procesy – mianowicie elastyczno艣膰 wynika z ca艂kowitego pomini臋cia tego tematu. Procesy w NGinn operuj膮 na danych (zosta艂o to opisane we wcze艣niejszych artyku艂ach) i te dane zawieraj膮 wszystkie informacje istotne z punktu widzenia dzia艂ania procesu. W szczeg贸lno艣ci za艂o偶y艂em 偶e b臋d膮 mog艂y zawiera膰 odno艣nik do odpowiedniego dokumentu聽 w systemie聽zewn臋trznym – na przyk艂ad numer faktury w systemie ksi臋gowym albo numer zg艂oszenia w systemie wsparcia klient贸w. Sam system NGinn nie wnika w to w jakim systemie i w jaki spos贸b s膮 te dokumenty przechowywane, natomiast oferuje mechanizmy integracyjne pozwalaj膮ce na wymian臋 danych z takimi systemami i pobieranie odpowiednich informacji o dokumencie je艣li to konieczne. To pozwala twierdzi膰 偶e NGinn znakomicie nadaje si臋 do rozszerzania mo偶liwo艣ci istniej膮cych w firmie system贸w oraz do ich integrowania, ale zupe艂nie pomija przypadek gdy odpowiedniego systemu nie ma w firmie a dokumenty dopiero czekaj膮 na baz臋 danych kt贸ra je przechowa. No w艂a艣nie, co wtedy?
Pierwszy pomys艂 to wykorzystanie danych procesu. NGinn pozwala na definiowanie w艂asnych struktur danych dla proces贸w, wi臋c nic nie stoi na przeszkodzie 偶eby danymi procesu by艂 ca艂y dokument. Projektujemy struktur臋 danych tak 偶eby uwzgl臋dni膰 wszystkie pola dokumentu聽i wtedy zawarto艣膰 naszego ‘dokumentu’ jest przechowywana przez NGinn razem z innymi informacjami o procesie. Zalet膮 jest to 偶e nie musimy si臋 martwi膰 o przechowywanie tych danych, wad za to jest kilka – przede wszystkim dokument istnieje tylko razem z procesem i ‘zamiera’ gdy proces si臋 ko艅czy, dodatkowo NGinn bardzo ogranicza to co mo偶na zrobi膰 z danymi procesu. Tak wi臋c ten spos贸b jest dobry tylko dla prostych struktur danych, nieistotnych poza procesem kt贸ry ich dotyczy.
Druga mo偶liwo艣膰 wi膮偶e si臋 z pewn膮 rozbudow膮 NGinn. Ot贸偶 w tej chwili NGinn przechowuje stan proces贸w i zada艅 w postaci JSON. Ka偶de zadanie zapisywane jest w postaci pojedynczego dokumentu JSON zawieracj膮cego wszystkie jego dane i informacje potrzebne do dzia艂ania procesu. Dzi臋ki temu mamy elastyczno艣膰 i dowolno艣膰 w definiowaniu struktury procesu聽i jego danych.聽No i je艣li by艣my chcieli聽rozszerzy膰聽NGinn o baz臋 dokument贸w to mo偶emy po prostu wykorzysta膰聽ten sam mechanizm i przechowywa膰 dowolne dokumenty w postaci聽JSON – wtedy zar贸wno dokument聽jak i proces tocz膮cy si臋 wok贸艂 niego by艂y by聽obs艂ugiwane w ten sam spos贸b, jako dokumenty JSON. Pomys艂 interesuj膮cy wed艂ug mnie, ale czy s膮 z nim jakie艣 problemy?
S膮, ale to raczej ‘wyzwania’ ni偶 problemy. Chodzi o to 偶e w tej chwili do przechowywania dokument贸w JSON ze stanem procesu jest wykorzystywana baza danych (MSSQL) – jest tam jedna tabela z polem tekstowym (ntext) do kt贸rej wrzucany jest ca艂y dokument JSON. Dla NGinn to jest wystarczaj膮ce, ale gdyby艣my w ten spos贸b chcieli przechowywa膰 dokumenty z danymi kt贸re chcemy przeszukiwa膰 to szybko si臋 oka偶e 偶e szukanie odpada, nie da si臋 efektywnie takiej postaci danych przeszukiwa膰 a i aktualizacja jest mocno ograniczona. Rozwi膮zaniem wed艂ug mnie jest przej艣cie na nierelacyjn膮 baz臋 danych, na przyk艂ad tak膮 przeznaczon膮 do obs艂ugi dokument贸w JSON. Takich baz danych jest bardzo wiele, komercyjnych i darmowych. Powsta艂y jako ‘back-end’ dla serwis贸w internetowych obs艂uguj膮cych bardzo du偶y ruch i wymagacj膮cych ogromnej skalowalno艣ci bazy danych – np bardzo popularnych serwis贸w spo艂eczno艣ciwych i sprawdzaj膮 si臋 w takich zastosowaniach o wiele lepiej ni偶 bazy relacyjne. Dodatkowo s膮 bardzo elastyczne je艣li chodzi o struktury danych,聽 a to jest wg mnie kluczowa sprawa przy obs艂udze du偶ych (raczej bardzo du偶ych) ilo艣ci dokument贸w. Wystarczy pomy艣le膰 co si臋 dzieje gdy chcemy np zmieni膰 struktur臋 istniej膮cej bazy relacyjnej:
- czas: je艣li tabela jest bardzo du偶a (miliony rekord贸w) to dodanie nowej kolumny mo偶e trwa膰 bardzo d艂ugo gdy偶 mo偶e wywo艂a膰 zwi臋kszenie rozmiaru rekordu i reorganizacj臋 ca艂ego pliku bazy danych. D艂ugo to znaczy np 5 godzin, gdy nasze ‘okienko serwisowe’ to 30 minut.
- dost臋pno艣膰: na czas aktualizacji bazy relacyjnej musimy wy艂膮czy膰 aplikacj臋 gdy偶 operacje modyfikacji bazy wykluczaj膮 jej odczyt (blokada dost臋pu do tabel na czas aktualizacji)
- inne problemy: np konieczno艣膰 zdejmowania i ponownego zak艂adania constraint贸w przy operacjach na danych, czasami prosta aktualizacja wymaga niezmiernie skomplikowanych operacji na wi臋zach integralno艣ci i indeksach
- no w艂a艣nie, indeksowanie, nie mo偶na z nim przesadzi膰 gdy偶 nadmierne poindeksowanie danych spowalnia ich aktualizacj臋
W przypadku bazy dokument贸w JSON nie musimy w 偶aden spos贸b zmienia膰 jej struktury gdy modyfikujemy struktur臋 naszych dokument贸w, za艣 indeksowanie jest w trybie ‘offline’ czyli nie wp艂ywa na wydajno艣膰 aktualizacji. Dodaj膮c do tego fakt 偶e JSON jest podstawowym formatem dokumentu w NGinn u偶ycie tekstowej bazy dokument贸w wydaje si臋 naturalnym pomys艂em. A dobrym kandydatem wydaje mi si臋 baza ‘Persevere’ 聽(http://www.persvr.org/) – jest to kompletna baza danych dokument贸w JSON z dost臋pem poprzez HTTP/REST i z rozbudowanymi funkcjami ‘bazodanowymi’ takimi jak indeksowanie, przeszukiwanie czy zarz膮dzanie zawarto艣ci膮 bazy. Polecam zapoznanie si臋 cho膰 pobie偶nie z jego mo偶liwo艣ciami oraz potencjalnymi zastosowaniami, wg mnie to bardzo otwiera oczy na mo偶liwo艣ci tych ‘nowych’ baz danych oraz ich potencjalne zastosowania. Jak by wygl膮da艂 NGinn po przej艣ciu na baz臋 Persevere (lub inn膮 tego typu)? Przede wszystkim my艣l臋 偶e wtedy nie b臋dzie u偶ywa艂 偶adnej bazy relacyjnej, a po drugie my艣l臋 偶e by艂by wydajniejszy i bardziej elastyczny, zw艂aszcza gdyby da膰 mo偶liwo艣膰 dowolnego indeksowania dokument贸w i danych w procesach w celu ich 艂atwego przeszukiwania. Na pewno po艣wi臋c臋 temu nied艂ugo wi臋cej czasu.
P.S. Bazy w rodzaju Persevere zwykle nie obs艂uguj膮 transakcji rozproszonych ani two-phase commit. To jest du偶e ograniczenie dla NGinn i g艂贸wny problem do przezwyci臋偶enia. Chodzi o to 偶e w tej chwili NGinn wykorzystuje transakcje rozproszone (transactionscope) do zapewnienia sp贸jno艣ci stanu procesu w razie jakich艣 problem贸w.
Kr贸tki update
W czerwcu nie by艂o 偶adnego wpisu o NGinn, a to dlatego 偶e mam ostatnio ma艂o czasu. Z powod贸w r贸偶nych w tej chwili przechodz臋 z pracy etatowej na dzia艂alno艣膰 gospodarcz膮 i musialem od艂o偶y膰 nieco aktywno艣膰 poza-zawodow膮. Ale w zwi膮zku z rozpocz臋ciem pracy na w艂asny rachunek planuj臋 z NGinn uczyni膰 projekt ‘profesjonalny’ co powinno dobrze wp艂yn膮膰 na jego rozw贸j. Wi臋cej informacji nied艂ugo.
Definicja procesu (5) – obs艂uga b艂臋d贸w
Dzi艣 poruszymy temat obs艂ugi b艂臋d贸w w procesach. Zacznijmy od tego, 偶e w NGinn ka偶de zadanie, je艣li zostanie uruchomione, mo偶e zako艅czy膰 si臋 z nast臋puj膮cymi rezultatami:
- zako艅czenie normalne (prawid艂owe, na wyj艣ciu otrzymujemy dane wyj艣ciowe z zadania)
- anulowanie
- zako艅czenie na skutek b艂臋du
Zako艅czenie normalne to przypadek omawiany ju偶 wcze艣niej – po zako艅czeniu zadania s膮 produkowane tokeny w miejscach do kt贸rych prowadz膮 po艂膮czenia wychodz膮ce (oczywi艣cie je艣li mamy split XOR lub OR to s膮 jeszcze sprawdzane warunki dla tych przej艣膰). Po anulowaniu tokeny wyj艣ciowe nie s膮 produkowane (jest taka opcja, ale o tym kiedy indziej). Po zako艅czeniu z b艂臋dem natomiast mamy pewne mo偶liwo艣ci zareagowania na ten b艂膮d i odpowiedniego dostosowania dalszego biegu procesu – w tym celu u偶ywamy ‘error handler贸w’ czyli specjalnych przej艣膰 uaktywnianych tylko w 聽razie b艂臋du:

Obs艂uga b艂臋du (1)
聽
W tym procesie normalny przebieg jest taki: start->T1->T2->end. Natomiast zadanie T1 ma dodatkowe przej艣cie wychodz膮ce, oznaczone na rysunku dwoma czerwonymi uko艣nikami. To przej艣cie jest uruchamiane w razie zako艅czenia zadania T1 z b艂臋dem (tzn je艣li T1 si臋 ‘wywali’ to token pojawi si臋 na przej艣ciu T1->T1 error a nie na T1->T2), czyli kolejnym uruchomionym zadaniem b臋dzie ‘T1 error’ – nasz ‘error handler’ dla T1.
No dobra, 艣wietnie: potrafimy ju偶 przyczepi膰 obs艂ug臋 b艂臋d贸w do jakiego艣 zadania. Ale przecie偶 w procesie wiele rzeczy mo偶e si臋 nie uda膰, je艣li zaczniemy wsz臋dzie doczepia膰 obs艂ug臋 b艂臋d贸w to szybko nasz diagram zamieni si臋 w chaotyczn膮 pl膮tanin臋 strza艂ek. A poza tym: co si臋 stanie je艣li zadanie si臋 ‘wywali’ a nie ma zdefiniowanej obs艂ugi b艂臋d贸w? 呕eby odpowiedzie膰 na powy偶sze w膮tpliwo艣ci zobaczmy kolejny diagram:
聽

Obs艂uga b艂臋d贸w (2)
聽
Na tym schemacie mamy zadanie blokowe (to z przerywan膮 ramk膮) do kt贸rego do艂膮czona jest obs艂uga b艂臋du (T1 error). Zapis taki oznacza 偶e w przypadku wyst膮pienia jakiegokolwiek b艂臋du w zadaniu blokowym obs艂ugujemy ten b艂膮d w ‘T1 error’. A dok艂adnie: je艣li w trakcie wykonania zadania blokowego pojawi si臋 b艂膮d w zadaniu ‘Task1′ lub ‘Task2′ to ca艂e zadanie blokowe zostanie zako艅czone z b艂臋dem. Je艣li by艂y w nim jakie艣 inne aktywne zadania w momencie wyst膮pienia b艂臋du to zostan膮 one anulowane – wszystko co by艂o wewn膮trz zadania blokowego zostaje zako艅czone i dopiero wtedy ca艂e zadanie blokowe ko艅czy si臋 z b艂臋dem. Informacje o b艂臋dzie s膮 propagowane w g贸r臋 od zadania kt贸re spowodowa艂o b艂膮d – czyli kod b艂臋du w zadaniu blokowym b臋dzie taki sam jak kod b艂臋du zwr贸cony przez zadanie wewn臋trzne kt贸re zako艅czy艂o si臋 b艂臋dem. M臋tne? Czy jeste艣 czytelniku programist膮? To pomy艣l o konstrukcji try-catch: wszystko co jest wewn膮trz zadania blokowego to ‘try’, za艣 error handler z czerwonymi uko艣nikami to ‘catch’.
A co je艣li zadanie blokowe tak偶e nie ma swojej obs艂ugi b艂臋d贸w? Wtedy NGinn propaguje b艂膮d dalej w g贸r臋 a偶 dojdzie na poziom zadania blokowego kt贸re ju偶 ma error handler – czyli ta konstrukcja mo偶e by膰 dowolnie g艂臋boko zagnie偶d偶ona. Tylko 偶e do tej pory zak艂adam 偶e w ko艅cu wyjdziemy na taki poziom gdzie ta obs艂uga b艂臋du jest. A co gdy nie ma? W ko艅cu id膮c w g贸r臋 dojdziemy na poziom ca艂ego procesu – do procesu ju偶 nie mo偶na sobie doczepi膰 ‘error handlera’ bo nie ma do czego. Czyli wtedy mamy sytuacj臋 偶e nasz ‘wyj膮tek’ nie jest obs艂ugiwany w ramach procesu 聽(dla programist贸w: unhandled exception). W normalnych programach taka sytuacja jest awari膮 – system wy艣wietla informacj臋 o b艂臋dzie i natychmiast ko艅czy dzia艂anie programu. A u nas? NGinn m贸g艂by wtedy wpisa膰 do logu 偶e ‘proces XYZ niespodziewanie zako艅czy艂 si臋 z powodu nieobs艂u偶onego b艂臋du’ i usun膮膰 ten proces, ale to nie jest dzia艂anie cywilizowane w 艣wiecie proces贸w biznesowych – pami臋tajmy 偶e ten proces reprezentuje jakie艣 dokumenty, ludzkie dzia艂ania, decyzje w firmie i nie mo偶e tak sobie znikn膮膰.
Dlatego w NGinn tak膮 sytuacje traktujemy jako typow膮. To znaczy: normalne jest 偶e definicja procesu nie zawiera obs艂ugi b艂臋d贸w聽i takie procesy te偶 powinny dzia艂a膰 i dawa膰 spodziewane wyniki. A je艣li wyst膮pi b艂膮d to ma zosta膰 o tym powiadomiony administrator systemu i powinien on mie膰 szans臋 r臋cznej interwencji w celu usuni臋cia lub obej艣cia problemu. Jak to si臋 dzieje? Ot贸偶 gdy NGinn w trakcie obs艂ugi b艂臋du stwierdzi 偶e w ca艂ym procesie brak jakiejkolwiek obs艂ugi tego b艂臋du to b艂膮d ten nie b臋dzie propagowany w g贸r臋. Zamiast tego winowajca (zadanie kt贸re ten b艂膮d wygenerowa艂o) jest oznaczane jako ‘FailedActive’ – tzn zako艅czone z b艂臋dem, ale jeszcze nie wiadomo co z nim zrobi膰. Zadanie takie ju偶 si臋 zako艅czy艂o, ale dla zadania nadrz臋dnego jest nadal aktywne i nie generuje 偶adnych dalszych zdarze艅. Administrator systemu mo偶e sobie takie przypadki odszuka膰 (albo nawet zosta膰 automatycznie powiadomiony) i wtedy mo偶e przeprowadzi膰 nast臋puj膮ce dzia艂ania:
- ponownie uruchomi膰 zadanie (np gdy b艂膮d to tylko przej艣ciowy problem)聽
- potwierdzi膰 偶e to zadanie to rzeczywi艣cie b艂膮d i przekaza膰 jego obs艂ug臋 NGinn (ale wtedy proces rzeczywiscie zostanie zako艅czony z b艂臋dem)
- ‘oszuka膰’ NGinn i powiedzie膰 偶e to zadanie jednak zako艅czy艂o si臋 sukcesem (wtedy musi jednak dostarczy膰 prawid艂owe dane wyj艣ciowe dla tego zadania, tak jakby rzeczywi艣cie zako艅czy艂o si臋 ono poprawnie)
Czasami b臋dzie jeszcze musia艂 poprawi膰 definicj臋 procesu je艣li b艂膮d powsta艂 na skutek nieprawid艂owo艣ci w definicji.聽
Spos贸b udost臋pniana w/w operacji dla administratora mo偶e by膰 r贸偶ny. NGinn oferuje API do tego celu a udost臋pnienie tego w postaci GUI lub command line to zadanie dla aplikacji u偶ywaj膮cej NGinn.
Acha, oto definicja pierwszego procesu z dzisiejszego artyku艂u. W sekcji ‘flows’ jest zdefiniowana obs艂uga b艂臋du dla zadania T1 – chodzi o przej艣cie z taskOutPort=”Error”:
<?xml version="1.0" encoding="utf-8"?>
<process version="1" name="Failure" xmlns="http://www.nginn.org/WorkflowDefinition.1_0.xsd" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<dataTypes>
</dataTypes>
<variables>
<variable name="v1" type="int" dir="In" required="true" />
</variables>
<body>
<places>
<place id="start" type="Start" />
<place id="end" type="End" />
</places>
<tasks>
<task id="T1" type="ReceiveMessage">
</task>
<task id="T2" type="Timer" splitType="AND">
</task>
<task id="T3_F" label="T1 error" type="Empty" splitType="AND">
</task>
</tasks>
<flows>
<flow from="start" to="T1" />
<flow from="T1" to="T2" />
<flow from="T1" taskOutPort="Error" to="T3_F" />
<flow from="T3_F" to="end" />
<flow from="T2" to="end" />
</flows>
</body>
</process>
Castle Windsor zamiast Spring
Poprzednia wersja NGinn zosta艂a zbudowana w oparciu o kontener Spring. I to by艂o dobre, Spring jest naprawd臋 艣wietnym narz臋dziem z doskona艂膮 dokumentacj膮, przyk艂adami oraz funkcjonalno艣ci膮. Ale okaza艂o si臋 偶e wiele 聽komponent贸w kt贸re wykorzystuj臋 w NGinn bazuje na innym kontenerze – Castle Windsor. Poniewa偶 u偶ywanie dw贸ch r贸偶nych kontener贸w w jednym projekcie to troch臋 kiepski pomys艂, postanowi艂em przej艣膰 na Castle Windsor. Pierwsze pr贸by by艂y trudne, bo Windsor jest o wiele s艂abiej udokumentowany ni偶 Spring a poza tym ma ewidentnie skromniejsze mo偶liwo艣ci je艣li chodzi o konfiguracj臋 komponent贸w. Ale ma te偶 dobre cechy – jest bardzo ‘lekki’ i nadaje si臋 dobrze do konfiguracji programistycznej (Spring g艂贸wnie poprzez XML). W dodatku jest dla niego rozszerzenie o nazwie Binsor, pozwalaj膮ce konfigurowa膰 komponenty w oparciu o j臋zyk Boo (Binsor jest przyk艂adem DSL, czyli Domain Specific Language, zbudowanego w oparciu o Boo). Boo jest tak偶e wykorzystywany jako podstawowy j臋zyk skryptowania proces贸w w NGinn – zatem decyzja mog艂a by膰 tylko jedna: wchodz臋 w to. I na razie nie 偶a艂uj臋, cho膰 pojawi艂o sie kilka trudno艣ci na horyzoncie – przede wszystkim brak mo偶liwo艣ci wystawienia komponent贸w z kontenera poprzez .Net remoting tak jakbym chcia艂. Ale my艣l臋 偶e da si臋 to 艂atwo przeskoczy膰.
A co na horyzoncie: wykorzystanie prawdziwego ESB do przekazywania komunikat贸w w NGinn – flirtuj臋 z projektem Rhino Service Bus. To on w艂a艣nie wymaga Castle Windsora. A poni偶ej mo偶na zobaczy膰 jak wygl膮da konfiguracja NGinn w Boo:
import System.IO
import Castle.Facilities.FactorySupport from Castle.MicroKernel
import Castle.Facilities.Startable from Castle.MicroKernel
import Rhino.ServiceBus.Impl from Rhino.ServiceBus
import NGinnBPM.Lib.Interfaces
import NGinnBPM.Lib.Interfaces.MessageBus
import NGinnBPM.Services
import NGinnBPM.Lib.Services
import NGinnBPM.Dao
import System.Collections.Generic
cfg = Kernel.Resolve(NGinnBPM.Lib.Util.DefaultConfigProvider)
baseDir = cfg.ResolveVariable("ng.configdir")
endp = cfg.ResolveVariable("NGinn.MessageQueue")
connstr = cfg.ResolveVariable("NGinn.ConnectionString")
Facility FactorySupportFacility
Facility StartableFacility
Facility ("remoting", Castle.Facilities.Remoting.RemotingFacility, {
@isServer: true,
@registryUri: "nginn.kernel.rem",
@remotingConfigurationFile: "NGinnBPM.Engine.WindsorHost.exe.config"
})
Facility("rhino.esb", RhinoServiceBusFacility, {
bus: {
@endpoint: endp,
@threadCount: 1
},
messages: {
add: {@name: "NGinnBPM.Runtime.Events", @endpoint: endp}
}
})
Component("TaskInstanceFactory", ITaskInstanceFactory, TaskInstanceFactory)
Component("TaskDefinitionFactory", ITaskDefinitionFactory, TaskDefinitionFactory)
Component("ProcessScriptManager", IProcessScriptManager, NGinnBPM.Services.Scripting.BooScript.BooProcessScriptManager, LifestyleType.Singleton,
BaseDirectory: "${baseDir}\\temp\\BooProcessScriptManager")
Component("TaskInstanceRepository", ITaskInstanceRepository, RawSqlTaskInstanceRepository, LifestyleType.Singleton,
ConnectionString: connstr)
Component("MessageBus", IMessageBus, NGinnBPM.Services.MessageBus.SqlMessageHub, LifestyleType.Singleton,
Endpoint: "sql://nginn/MQueue", ConnectionStrings: {"nginn": connstr})
Component("PackageRepository", IProcessPackageRepository, NGinnBPM.Services.FSProcessPackageRepository, LifestyleType.Singleton,
BaseDirectory: "${baseDir}\\PackageRepository")
Component("MessageCorrelationResolver", IMessageCorrelationIdResolver, NGinnBPM.Dao.RawSqlMessageCorrelationIdResolver, LifestyleType.Singleton,
ConnectionString: connstr)
Component("LockManager", IProcessInstanceLockManager, LocalProcessInstanceLockManager, LifestyleType.Singleton)
Component("Environment", INGEnvironment, NGinnBPM.Runtime.NGEnvironment, LifestyleType.Singleton)
Component("NGEngine", NGinnBPM.Runtime.NGEngine)
Konfiguruj膮c nasze komponenty w pliku konfiguracyjnym, czy jest to XML czy Boo, zyskujemy wa偶n膮 rzecz – nie wprowadzamy zale偶no艣ci w kodzie, nawet gdy komponenty pochodz膮 z jakich艣 zewn臋trznych assembly. Czyli nie musimy ju偶 mie膰 w kodzie miejsca kt贸re odwo艂uje si臋 do wszystkich wykorzystywanych bibliotek, takie miejsce jest tylko w konfiguracji. I nie my艣lmy za du偶o o tym 偶e Boo to te偶 kod, tylko w innym j臋zyku.
Operacja na 偶ywym organi藕mie czyli wprowadzanie zmian w procesach
Je艣li zajmujemy si臋 tworzeniem oprogramowania na zam贸wienie, zw艂aszcza oprogramowania u偶ywanego do obs艂ugi jakich艣 proces贸w w firmach, wcze艣niej czy p贸藕niej stajemy przed konieczno艣ci膮 dokonywania zmian w istniej膮cych funkcjach systemu. Najwi臋ksze problemy w takich przypadkach wynikaj膮 z niekompatybilno艣ci膮 wstecz – gdy nowa logika systemu jest istotnie r贸偶na od tej kt贸ra by艂a wcze艣niej, a dane zebrane w aplikacji do tej pory maj膮 ’star膮’ struktur臋 i trzeba je jako艣 zaktualizowa膰 aby system m贸g艂 dzia艂a膰 dalej po wdro偶eniu zmian. Je艣li aplikacja jest intensywnie modyfikowana a nie zapewnia jakiego艣 sensownego podej艣cia do aktualizacji to raczej szybko doprowadzimy do koszmarnej sytuacji kiedy 5% czasu po艣wi臋camy na implementacj臋 zmiany, a pozosta艂e 95% na migracj臋 istniej膮cych danych oraz obs艂ug臋 wygenerowanych przy tej okazji problem贸w. Dzi艣 spr贸buj臋 podpowiedze膰 jak wykorzystuj膮c NGinn mo偶na sobie u艂atwi膰 przysz艂y rozw贸j systemu.
W przypadku NGinn m贸wimy o aktualizacji proces贸w. Za艂贸偶my 偶e dzia艂amy w firmie i mamy zaimplementowany proces kt贸ry jest w u偶yciu od d艂u偶szego czasu – to oznacza 偶e mamy mn贸stwo spraw obs艂ugiwanych tym procesem, cz臋艣膰 z tych spraw jest zako艅czona a cz臋艣膰 jest w trakcie realizacji na r贸偶nych etapach. Je艣li tak po prostu zmodyfikujemy definicj臋 tego procesu to prawdopodobnie spowodujemy 偶e tocz膮ce si臋 sprawy stan膮 si臋 niekompatybilne z now膮 definicj膮 i z powodu b艂臋d贸w nie b臋d膮 mog艂y si臋 zako艅czy膰. Tego bardzo nie chcemy, bo je艣li to my dostarczamy oprogramowanie to po takim wdro偶eniu zostaniemy zmuszeni do posprz膮tania ca艂ego ba艂aganu. O tej strategii nie b臋d臋 wi臋cej pisa艂, wszyscy wiedz膮 偶e mo偶na jej u偶y膰 w ka偶dym przypadku ale lepiej wiedzie膰 co si臋 robi. Przyjrzyjmy si臋 lepiej innym sposobom:
1. Wersjonowanie procesu
NGinn pozwala u偶ywa膰 kilku wersji definicji tego samego procesu (w tym celu jest numerek wersji w nazwie pliku z definicj膮), wi臋c w wielu przypadkach najpro艣ciej jest zdefiniowa膰 now膮 wersj臋 procesu kt贸ra b臋dzie u偶ywana dla spraw kt贸re dopiero zostan膮 zarejestrowane. Aktualnie tocz膮ce si臋 sprawy pozostaj膮 na starej definicji procesu i mog膮 spokojnie si臋 zako艅czy膰 ‘po staremu’. Unikamy w ten spos贸b jakiejkolwiek migracji danych wi臋c je艣li uda si臋 klienta przekona膰 do takiego rozwi膮zania sprawy to mamy sukces gwarantowany.
2. Anulowanie i ponowne uruchomienie
W niekt贸rych przypadkach mo偶na rozwi膮za膰 problem aktualizacji poprzez anulowanie aktualnie tocz膮cych si臋 spraw i ponowne ich uruchomienie ju偶 na nowej definicji procesu. Jak to zrobi膰 w NGinn? Ano, narz臋dzia do tego nie ma, ale jest API pozwalaj膮ce anulowa膰 procesy i je uruchamia膰 oraz ‘grzeba膰’ w danych proces贸w i zada艅. Zatem mo偶na stworzy膰 sobie narz臋dzie kt贸re nam tak膮 migracj臋 obs艂u偶y. Problem mo偶e wyst膮pi膰 je艣li do uruchomienia procesu w nowej wersji konieczne s膮 inne dane wej艣ciowe – wtedy trzeba te偶 dokona膰 konwersji i ewentualnego uzupe艂nienia danych. Istotna rzecz: NGinn nie zapami臋tuje oryginalnych warto艣ci danych wej艣ciowych procesu – pami臋ta tylko ich aktualne warto艣ci. Zatem je艣li podczas dzia艂ania procesu zmienne wej艣ciowe s膮 modyfikowane to mo偶e si臋 okaza膰 偶e stracimy informacje potrzebne do uruchomienia tego samego procesu w nowej wersji. Taka sytuacja jednak jest do艣膰 rzadka, zwykle dane wej艣ciowe istotne dla sprawy nie zmieniaj膮 si臋 w trakcie jej realizacji.
3. U偶ycie Barier
Je艣li koniecznie chcemy aktualizowa膰 tocz膮ce si臋 sprawy ‘na 偶ywca’, to bardzo nam przeszkadza fakt 偶e znajduj膮 si臋 one na rozmaitych etapach realizacji i trzeba to uwzgl臋dni膰 wprowadzaj膮c poprawk臋 – po prostu musi by膰 艣cie偶ka migracji dla ka偶dego etapu na kt贸rym mo偶e si臋 znajdowa膰 sprawa. W niekt贸rych przypadkach nie trzeba nic robi膰 – na przyk艂ad je艣li sprawa znajduje si臋 na pocz膮tku procesu, a my modyfikujemy jego ko艅c贸wk臋 to nic z艂ego si臋 nie wydarzy. Zatem je艣li mieli by艣my tak膮 sytuacj臋 偶e wszystkie sprawy znajduj膮 si臋 poza regionem procesu kt贸ry modyfikujemy – tzn albo jeszcze do tego regionu nie dosz艂y, albo ju偶 go opu艣ci艂y – to zwykle migracja by艂a by o wiele 艂atwiejsza albo wr臋cz niepotrzebna.
呕eby stworzy膰 tak膮 mo偶liwo艣膰 w NGinn zosta艂a wprowadzona funkcja “barier”. Bariera zatrzymuje nam dzia艂anie proces贸w w okre艣lonym miejscu i pozwala je wznowi膰 po usuni臋ciu bariery. Barier臋 stawiamy w wybranym miejscu, b膮d藕 miejscach, w procesie (chodzi o te k贸艂eczka, czyli places).Je艣li w danym miejscu postawiona jest bariera to tokeny z tego miejsca nie mog膮 i艣膰 dalej, czyli nie jest uruchamiane zadanie wychodz膮ce z tego miejsca. Tokeny czekaj膮 na usuni臋cie bariery czyli ca艂a sprawa jest wstrzymana, natomiast sprawy kt贸re zd膮偶y艂y p贸j艣膰 dalej zanim postawili艣my barier臋 kontynuuj膮 proces bez przeszk贸d.
Jak tego u偶y膰? Stawiamy barier臋 przed regionem w procesie kt贸ry modyfikujemy i czekamy a偶 wszystkie sprawy opuszcz膮 ten region (czyli tokeny we wszystkich instancjach tego procesu znajd膮 si臋 poza modyfikowanym regionem). Bariera gwarantuje 偶e 偶adne nowe tokeny nie nap艂yn膮 wi臋c oczyszczenie naszego pola dzia艂ania jest tylko kwesti膮 czasu. Wtedy zmieniamy definicj臋 procesu i zdejmujemy barier臋 – wypuszczone sprawy potocz膮 si臋 ju偶 wg zaktualizowanej definicji.
Czy to znaczy 偶e w艂a艣nie opisa艂em stuprocentowo skuteczny spos贸b na aktualizacj臋 logiki systemu? No nie do ko艅ca… Przede wszystkim nie by艂o mowy o danych. Co z tego 偶e zaktualizujemy definicj臋 procesu, kiedy w nowej wersji b臋d膮 potrzebne dodatkowe dane (kt贸rych przecie偶 nie ma w aktualnie tocz膮cych si臋 sprawach)? Nie b臋dziemy w stanie ruszy膰 do przodu bez uzupe艂nienia tych danych. Do uzupe艂nienia czy modyfikacji danych musimy jednak zbudowa膰 w艂asne narz臋dzie – NGinn daje do tego API, ale to jakie zmiany wprowadzi膰 w danych musimy wymy艣li膰 sami. Bariera mo偶e si臋 te偶 tutaj przyda膰 – je艣li sobie ’spi臋trzymy’ sprawy w okre艣lonym miejscu to przynajmniej b臋dziemy wiedzieli w kt贸rych zadaniach nale偶y zaktualizowa膰 dane.
Definicja procesu (4) – anulowanie zada艅
Dzisiejszy artyku艂 b臋dzie o sposobach anulowania zada艅 w procesie – to znaczy o tym, jak spowodowa膰 aby jakie艣 zadanie kt贸re jest w trakcie realizacji zosta艂o anulowane po wyst膮pieniu okre艣lonego zdarzenia. Mo偶e nie jest to oczywiste na pierwszy rzut oka, ale taka funkcjonalno艣膰 jest bardzo cz臋sto potrzebna. Jednym z takich przypadk贸w jest decyzja post factum (deferred choice), om贸wiona w tym artykule. Deferred choice jest jednak do艣膰 szczeg贸lnym przypadkiem stosowanym w okre艣lonej sytuacji, a w NGinn mamy do dyspozycji troch臋 wi臋cej konstrukcji z anulowaniem.
Jako przyk艂ad na dzi艣 we藕my sobie taki scenariusz ‘biznesowy’:
Do firmy wp艂ywaj膮 reklamacje od klient贸w. Ka偶da reklamacja powinna zosta膰 obs艂u偶ona w ci膮gu 30 dni. Reklamacja jest wci膮gana do systemu ‘Trouble Ticketing’ i w tym systemie przypisywana do odpowiedniej jednostki organizacyjnej. Chcemy aby system automatycznie przypomina艂 tym ludziom 偶e zbli偶a si臋 termin na rozpatrzenie reklamacji – na przyk艂ad poprzez wys艂anie wiadomo艣ci email na 10 dni przed terminem rozpatrzenia, potem na 3 dni przed terminem no i 聽w momencie up艂ywu terminu rozpatrzenia – wtedy z kopi膮 do szefa dzia艂u obs艂ugi reklamacji. Kiedy reklamacja zostanie rozpatrzona (niezale偶nie od tego z jakim wynikiem), system powinien zaprzesta膰 wysy艂ania e-maili z eskalacjami.
Jest to prosty przyk艂ad i mo偶na go zaimplementowa膰 na wiele r贸偶nych sposob贸w – na przyk艂ad tak:
聽

Proces reklamacji
W momencie startu tego procesu wykonywane jest zadanie ‘fork’ – nie robi ono nic opr贸cz uruchomienia czterech r贸wnoleg艂ych 艣cie偶ek w procesie. Pierwsza 艣cie偶ka ko艅czy si臋 zadaniem ‘Obs艂u偶 reklamacj臋’ – jest to zlecenie obs艂ugi reklamacji przekazywane do Dzia艂u Obs艂ugi Reklamacji. Pozosta艂e trzy 艣cie偶ki odpowiadaj膮 za eskalacje. Na ka偶dej z nich jest zadanie ‘Timeout’ odliczaj膮ce odpowiedni okres czasu (odpowiednio 20, 27 i 30 dni od daty startu), po up艂ywie tego czasu uruchamiane s膮 zadania eskalacyjne wysy艂aj膮ce odpowiedniej tre艣ci email.
Bez u偶ycia anulowania 艣cie偶ki te wykonuj膮 si臋 niezale偶nie od siebie, czyli eskalacje b臋d膮 wysy艂ane nawet gdy zadanie ‘Obs艂u偶 reklamacj臋’ si臋 zako艅czy. Aby przerwa膰 wysy艂anie eskalacji po zako艅czeniu obs艂ugi reklamacji wprowadzamy przej艣cia anuluj膮ce, oznaczone na rysunku czerwon膮 przerywan膮 lini膮. Ka偶de takie przej艣cie po zako艅czeniu zadania ‘Obs艂u偶 reklamacj臋’ zabiera wszystkie tokeny z miejsca do kt贸rego prowadzi (o ile te tokeny tam s膮) – w tym przypadku chodzi o miejsca e1, e2 i e3. Zabranie token贸w z miejsc e1, e2 i e3 oznacza 偶e je艣li kt贸re艣 z zada艅 ‘Timeout’ jest aktywne to straci ono wymagany token na wej艣ciu i zostanie anulowane. Oczywi艣cie je艣li kt贸ry艣 z Timeout贸w ju偶 si臋 wykona艂 to zjad艂 token ze swojego wej艣cia, wtedy przej艣cie anuluj膮ce nie b臋dzie mia艂o 偶adnego efektu. 聽Osi膮gamy w ten spos贸b sw贸j cel – po zako艅czeniu zadania ‘Obs艂u偶 reklamacj臋’, je艣li by艂y jakie艣 oczekuj膮ce eskalacje to zostan膮 anulowane a proces b臋dzie si臋 m贸g艂 zako艅czy膰 bo ju偶 nie b臋dzie token贸w poza miejscem ko艅cowym.
Definicja naszego procesu wygl膮da tak:
<?xml version="1.0" encoding="windows-1250"?>
<process version="1" name="Reklamacje" xmlns="http://www.nginn.org/WorkflowDefinition.1_0.xsd" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<dataTypes>
</dataTypes>
<variables>
<variable name="v1" type="int" dir="In" required="true" />
</variables>
<body>
<places>
<place id="start" type="Start" />
<place id="end" type="End" />
<place id="e1" />
<place id="e2" />
<place id="e3" />
</places>
<tasks>
<task id="T0" type="Empty" splitType="AND" label="fork">
</task>
<task id="T1" type="Manual" label="Obsluz reklamacje">
<parameters>
</parameters>
</task>
<task id="TE1" type="Timer" label="Timeout - 10 dni">
<parameters>
<param variable="ExpirationDate"><expr>DateTime.Now.AddDays(20)</expr></param>
</parameters>
</task>
<task id="TE2" type="Timer" label="Timeout - 3 dni">
<parameters>
<param variable="ExpirationDate"><expr>DateTime.Now.AddDays(27)</expr></param>
</parameters>
</task>
<task id="TE3" type="Timer" label="Timeout">
<parameters>
<param variable="ExpirationDate"><expr>DateTime.Now.AddDays(30)</expr></param>
</parameters>
</task>
<task id="ESK1" label="Eskalacja 1" type="SendNotification" splitType="AND">
</task>
<task id="ESK2" label="Eskalacja 2" type="SendNotification" splitType="AND">
</task>
<task id="ESK3" label="Eskalacja 3" type="SendNotification" splitType="AND">
</task>
</tasks>
<flows>
<flow from="start" to="T0" />
<flow from="T0" to="T1" />
<flow from="T0" to="e1" />
<flow from="T0" to="e2" />
<flow from="T0" to="e3" />
<flow from="T1" to="e1" cancelling="true" />
<flow from="T1" to="e2" cancelling="true" />
<flow from="T1" to="e3" cancelling="true" />
<flow from="e1" to="TE1" />
<flow from="e2" to="TE2" />
<flow from="e3" to="TE3" />
<flow from="TE1" to="ESK1" />
<flow from="TE2" to="ESK2" />
<flow from="TE3" to="ESK3" />
<flow from="ESK1" to="end" />
<flow from="ESK2" to="end" />
<flow from="ESK3" to="end" />
<flow from="T1" to="end" />
</flows>
</body>
</process>
Przej艣cia anuluj膮ce s膮 zapisane w sekcji ‘flows’, to te z atrybutem cancelling=”true”. Mam nadziej臋 偶e ten przyk艂ad odpowiednio ilustruje przeznaczenie przej艣膰 anuluj膮cych.
Dzisiejszy przyk艂ad pokazuje jeszcze jedn膮 fajn膮 rzecz. Wyobra藕my sobie 偶e zamiast zadania ‘Obs艂u偶 reklamacj臋’ mamy tam ca艂y podproces obs艂ugi reklamacji – z etapami, przechodzeniem przez r贸偶ne dzia艂y, wysy艂aniem pism itp. Wida膰 wtedy, 偶e gdy chcemy do takiego procesu doda膰 eskalacje mo偶emy to zrobi膰 w og贸le w niego nie ingeruj膮c – procedura eskalacyjna jest zupe艂nie zewn臋trzna w stosunku do procesu ni膮 obj臋tego.