28/11/2008

Modelowanie procesów biznesowych

Home

Ostatnio zainteresowałem się modelowaniem procesów biznesowych. Spodziewałem się istnienie kilku standardów ale rzeczywistość naprawdę mnie zaskoczyła. Świat BPM okazał się naprawdę bogaty. Sądzę, że porównanie do dżungli będzie nawet bardziej odpowiednie. Mamy więc: BPDM, BPEL4WS, BPML, BPMN, UML Activity Diagram, WSFL, XLANG, XDPL i sporo więcej. W poście tym chciałbym troszeczkę usystematyzować ten bałagan i wyjaśnić jak jak to rozumiem.

Wstęp

Zacznijmy od tego, że w procesie BPM należy wyróżnić dwa zasadnicze poziomy:
  • Poziom modelowania – poziom, w którym działają analitycy, konsultanci itd.
  • Poziom wykonania – poziom, w którym pracują inżynierzy oprogramowania itd.
Na styku tych dwóch (ale moim zdaniem bardziej na poziomie modelowania) poziomów znajduje się analityk procesów biznesowych.

Poziom modelowania

Użytkownicy pracujący na tym poziomie posługują się wysoko poziomowymi narzędziami i notacjami do zamodelowania procesów biznesowych. Odpowiednich narzędzi jest bardzo dużo ale niewątpliwie najpopularniejszą i najbardziej rozpowszechnioną notacją jest BPMN – Business Process Modeling Notation, która została zaproponowana przez BPMI – Business Process Modeling Initiative (od 2005 połączone z OMG).

BPMN to nie tylko notacja. Definiuje nie tylko elementy diagramu ale również ich semantykę. Specyfikacja BPMN nie określa natomiast sposobu w jaki stworzony diagram ma zostać zapisany (zserializowany). Do tego celu bardzo często używa się innej specyfikacji zaproponowanej przez IBM i Microsoft: XDPL – XML Process Definition Language.

W tym miejscu należy wspomnieć o najnowszym członku rodziny BPM czyli o specyfikacji zaproponowanej przez OMG: BPDM – Business Process Definition Metamodel. Finalna wersja tej specyfikacji jest bardzo świeża - pochodzi z czerwca tego roku. BPDM stanowi w pewnym sensie połączenie wymienionych wcześniej standardów: XDPL oraz BPMN ale nie tylko. Przyszłość tego rozwiązania nie jest jeszcze określona i należy poczekać czy zdobędzie popularność. Z pewnością pokłada się w niej duże nadzieje.

Istnieje również kilka innych rozwiązań ale odnoszę wrażenie, że są mało popularne dlatego nie przytacza, ich opisu w tym poście.

Poziom wykonania

Po zdefiniowaniu procesu chcielibyśmy zapewne zasilić nim jakiś silnik, ktory go wykona. W tym celu należałoby przetłumaczyć diagram do formatu/opisu zrozumiałego przez określoną technologię. W obecnej chwili najpopularniejsze wydają się dwie specyfikacje (oparte o XML): BPEL – Business Process Execution Language oraz BPML4WS – Business Process Modeling Language For Web Services. Pierwsza została zaproponowana przez BPMI, a druga przez IBM, BEA Systems oraz Microsoft. Należy zauważyć, że BPML4WS to następca BPML, który nie jest już wspierany. BPEL został oparty o WSFL oraz XLANG.


Rysunek pochodzi z: The BPMN-XPDL-BPEL value chain

Do poczytania

Zarządzanie procesami biznesowymi – standardy notacji i nie tylko

http://modelowanie.wordpress.com/category/bpmnbpml/

Business Process Modeling and Standarization

XPDL,BEPL,JPDL,BPMNS,BPDM et al.. Standards and More Standards

The BPMN-XPDL-BPEL value chain

BPMN, BPEL, BPML and XPDL, an attempt to make some order in the business modeling jungle

A Comparison of XPDL, BPML and BPEL4WS Cape Visions

Business Process Model and Notation (BPMN) 2.0 Request For Proposal


27/11/2008

throw; vs. throw ex;

Home

Nie każdy zdaje sobie z tego sprawę ale poniższe dwie konstrukcje mają inną semantykę:

         try
         {
            ...
         }
         catch(Exception ex)
         {
            throw;
         }
         
         try
         {
            ...
         }
         catch(Exception ex)
         {
            throw ex;
         }
         
Różnica jest taka, że stosując pierwszą z nich nie tracimy informacji zawartej w stosie wywołań (stack trace). To znaczy, że jeśli ponownie rzucony przez nas wyjątek zostanie złapany w kolejnym bloku try/cacth to będzie tam dostępna pełna informacja o stosie wywołań począwszy od pierwotnego źródła wyjątku. W drugim przypadku stos wywołań będzie zawierał ograniczoną informację - będzie wyglądał tak, jakby pierwotnym źródłem wyjątku była metoda, w której został on złapany i ponownie rzucony!

24/11/2008

Zakamarki Visual Studio 2005/2008 (cz. 2)

Home

Zapraszam do zapoznania się z kolejną porcją ciekawych i mało znanych funkcji Visual Studio.

Breakpoint w pętli

Bardzo przydaną funkcją jest możliwość postawienia breakpoint'a w definicji pętli for lub foreach. Załóżmy, że mamy taki kod:
for(int i = GetValue(); i < GetLimit(); i++)
{
  ...
}
Domyślne zachowanie środowiska jest takie, że po kliknięciu linii, w której znajduje się początek pętli i naciśnięciu przycisku F9 breakpoint zostanie ustawiony na części inicjalizacyjnej pętli czyli uzyskamy taki efekt:
for(int i = GetValue(); i < GetLimit(); i++)
{
  ...
}
Czasami, a nawet częściej niż czasami chcielibyśmy aby debugger zatrzymał się w części sprawdzającej warunek pętli. Nic prostszego. Wystarczy przesunąć kursor i ponownie nacisnąć F9. Uzyskamy efekt jak poniżej:
for(int i = GetValue(); i < GetLimit(); i++)
{
  ...
}
Oczywiście debugger możemy zatrzymać również w instrukcji interacji. Podobnie możemy postąpić z pętlą foreach.

Testowanie przy pomocy okna Immediate

Ciekawym sposobem na szybkie testowanie metod statycznych jest użycie okna Immediate. Jeśli nie jest ono standardowo widoczne to znajdziemy je w Debug -> Windows. Po pierwsze okno to pozwala w czasie debugowania wywoływać metody obiektów, zmieniać ich właściwości itd. Po drugie, co jest nawet ciekawsze, umożliwia wywołanie metody statycznej kiedy środowisko nie znajduje się w trybie debugowania. Wykonanie takiej operacji spowoduje uruchomienie debugera i o ile, w metodzie statycznej znajduje się breakpoint, jego zatrzymanie. Dzięki temu nie musimy tracić czasu na pisanie krótkich programików tylko po to aby przetestować daną metodę statyczną. Po trzecie co jeszcze ciekawsze okno Immediate pozwala również w podobny sposób testować zwykłe metody klas. Załóżmy, że napisaliśmy klasę Test i zdefiniowaliśmy w niej metodę Fun(). W oknie Immediate może wpisać:
Test t = new Test(); 
t.Fun(); 
Podobnie jak wcześniej. Jeśli w metodzie znajdował się breakpoint debugger zatrzyma się na nim. Jesli nie, metoda zakończy swoje działanie. Oczywiście technika ta pozwala testować tylko stosunkowe proste scenariusze ale tak czy inaczej ułatwia i przyspiesza tworzenie dobrego kodu.

Opisane techniki testowałem w środowiskach Visual Studio 2005 oraz Visual Studio 2008.

22/11/2008

ADO.NET Data Services, Jak to ugryźć?

Home

Wszystkich zainteresowanych rozpoczęciem zabawy z technologią Microsoft'u ADO.NET Data Services (nazwa kodowa Astoria) chciałbym zachęcić do zapoznania się z serią filmików spod znaku How Do I:
Astoria umożliwia naprawdę łatwy i szybki sposób udostępniania danych z różnych źródeł w sieci (w szczególności może to być oczywiście baza relacyjna). Dostęp do danych został zorganizowany zgodnie z podejściem typu REST czyli upraszczając aby uzyskać dostęp do zasobu musimy znać jego URI. Każdy z filmików pokazuje krok po kroku jak coś zrobić przy pomocy ADO.NET Data Services. Obejrzenie każdego z nich zajmie wam kilkanaście minut (oczywiście trzeba znać język angielski). Bardziej dogłębne (i znacznie dłuższe) wprowadzenie znajdziemy tutaj Developing Applications Using Data Services. Aby rozpocząć używanie Astorii potrzebujemy Visual Studio 2008 z Service Pack 1. Wersję Express już z Service Pack 1 znajdziemy tutaj.

20/11/2008

Tajemnica yield

Home

Czy zastanawialiście się kiedyś jak działa słowo kluczowe yield? Jeśli ktoś nie kojarzy tej konstrukcji to w telegraficznym skrócie pozwala ona (między innymi) w bardzo łatwy sposób zaimplementować interfejs IEnumerable. Interfejs ten wymagana dostarczenia tylko jednej metody, która powinna zwrócić instancję klasy implementującej IEnumerator. Zaimplementowanie tego interfejsu nie powinno przysporzyć znacznych trudności ale wymaga już trochę większego nakładu pracy. Przykładowe, uproszczone użycie yield mogłoby wyglądać tak:
public class Counter : IEnumerable
{
  private int i = 0;

  public Counter(int i)  
  {
    this.i = i;
  }

  public IEnumerator GetEnumerator()
  {
    while(i>0)
      yield return i--;
  }
}
Tylko tyle i aż tyle. Nie musimy pisać kodu dla metod MoveNext, Reset czy też właściwości Current wymaganych przez IEnumerator. Zamiast tego otrzymujemy kilkulinijkowy elegancki kod. Możemy oczywiście napisać teraz coś w tym rodzaju:
foreach (int i in new Counter(10))
  Console.WriteLine(i);
Zanim zaczniecie czytać dalej zastanówcie się teraz przez chwilę w jaki sposób to działa. Teraz możemy przejść do clue tego posta. Otóż okazuje się, że słowo kluczowe yield to nic innego jak lukier syntaktyczny. Nie kryje się zanim żadna magia. Po prostu kompilator po napotkaniu yield generuje dynamicznie kod enumeratora. Możemy to bardzo łatwo zobaczyć korzystając z reflektora Lutz Roeder’s Reflector. To co zobaczymy będzie koncepcyjnie podobne do kodu poniżej.
public class Counter
{
...
  public IEnumerator GetEnumerator()
  {
    //Utworzenie enumeratora
    InnerEnumerator ie = new InnerEnumerator(0);
    //Ustawienie wskazania na obiekt, po którym będziemy enumerować
    ie.current = this;

    reutrn ie;
  }

  private sealed class InnerEnumerator : IEnumerator
  {
    //Stan w jakim znajduje się enumerator
    //0 - stan początkowy
    //1 - stan pośredni
    //-1 - stan końcowy
    private int state;
    //Ostatnia wartość zwrócona przez enumerator
    private int current;
    //Obiekt, po którym będziemy enumerować
    public Counter counter;

    public InnerEnumerator(int state)
    {
      //Ustawienie stanu inicjalnego
      this.state = state;
    }

    public bool MoveNext()
    {
      switch (this.state)
      {
        case 0:
        //Jeśli warunek początkowy rozpoczęcia działania enumeratora 
        //nie będzie spełniony to przechodzimy do stanu końcowego
        this.state = -1;
        //Jeśli są jeszcze jakieś wartości do odwiedzenia przez enumerator
        while (this.counter.i > 0)
        {
          //Wyznacz kolejną wartość
          this.current = this.counter.i--;
          //Być może są jeszcze jakieś wartości do odwiedzenia
          //dlatego ustawiamy stan pośredni
          this.state = 1;
          return true;
          LABEL:
          //Jeśli nie będzie już wartości do odwiedzenia to 
          //należy zakończyć pracę enumeratora
          this.state = -1;
        }
        break;

        case 1:
          //Kontynuujemy pracę enumeratora
          goto LABEL;
      }

      //Enumerator odwiedził wszystkie elementy
      return false;
    }

    public object Current
    {
      get{ return this.current; }
    }
    ...  
  }
...
}
Z kodu usunąłem niepotrzebne w tym kontekście fragmenty i zmieniłem go, żeby był prostszy w zrozumieniu. Wygenerowany kod jest prawidłowy jako MSIL ale jako C# nie skomiluje się ze względu niedozwolone użycie instrukcji goto. Całość jest chyba łatwa do zrozumienia, a najistotniejsza jest metoda MoveNext(), w której tak naprawdę możemy zobaczyć to co napisaliśmy w GetEnumerator. Każda iteracja pętli powoduje przejście do następnego elementu. Polecenia skoku użyto aby przy kolejnych wywołaniach MoveNext wskoczyć do środka pętli i kontynuować jej wykonanie. Proste, nie :)