All we do is looking for some way to fulfill our needs.

środa, 9 lutego 2011

Tagged under:

Kilka nowych koncepcji - Mantra architektoniczna, Design Retrospective, Współdzielony kontekst, Naturalny porządek refaktoryzacji

Ostatnio wyewoluowało mi się w głowie kilka nazwanych koncepcji, a w zasadzie może po prostu je dobrze zrozumiałem :) Kilka notatek poniżej, które traktuje jako alpha draft ;-)

Mantra architektoniczna (ang. architectonic mantra)
To co dzieje się praktycznie w każdym projekcie to dryfowanie architektury, tak że po kilku (nastu) miesiącach trwania projektu mało kto w zespole jest w stanie dobrze określić, jakie operacje powinny być wykonywane np. przez kontroller (lub managedbean lub whatever), jakie przez obiekty dziedzinowe, jakie przez fasady, usługi. Z czasem mieszane są odpowiedzialności tychże klas i coraz trudniej z rozwojem systemu. Jedyną opcją w tym przypadku jest tzw. mantra architektoniczna, która jest wariacją nt. techniki zdartej płyty znanej z psychologii komunikacji. Polega ona na tym, że należy w prace zespołu włączyć ciągłe przypominanie jakie mamy w architekturze główne bloki i jakie są też ich odpowiedzialności. W tym przypadku również sugeruję zespołom, aby wprowadziły regularne spotkania (raz/mc, raz/sprint), które nazywam Design Retrospective podczas których zespół:
a) przypomina mantrę architektoniczną;
b) analizuje sytuacje, w których niejasne jest, gdzie powinny się znaleźć konkretne klasy, operacje, pola - na bazie tego co się działo ostatnio w projekcie
c) zbiera przypadki zdryfowania architektury i tworzy "program naprawczy"
d) podejmuje decyzję o świadomej restrukturyzacji architektury (to akurat rzadziej).

Współdzielony kontekst (ang. shared context)
Nie, nie, nie... bynajmniej nie chodzi tu o żadne wzorce projektowe czy architektoniczne. A o komunikację... Jak to powiedział Kent Beck gdzieś kiedyś "Większość problemów w projektach wynika z tego, że ktoś komuś czegoś nie powiedział". Zwolennicy Agile'a źródło problemów widzą w tzw. relay race, czyli przekazywaniu pracy między ludźmi (pewnie to znacie m. in. w takiej metaforze www.projectcartoon.com/).
Problem polega w tym, że w sytuacji przekazywania produktów (dokumentacji, kodu, wymagań itp.) pracy jednej osoby (grupy osób) innej, nie jest przekazywany kontekst informacji, który doprowadził do powstania tego produktu, często mylnie zakładając, że jest on nieistotny. Ja twierdzę, że jest kluczowy.
Ostatnio uczestniczyłem w takiej sytuacji. Jedna z osób dokonała wstępnej analizy wymagań i stworzyła podstawowy model systemu (model dziedzinowy). Mieliśmy przeanalizować ten model. Jednak nie posiadając kontekstu
(pewne przymyślenia, wnioski, informacje, mikrodecyzje), który powstał w głowie osoby, która go stworzyła dość trudno na głębszym poziomie niż tylko poprawność UMLowa, ocenić poprawność modelu. Taką sytuację nazywam brakiem współdzielonego kontekstu.
Dopiero zaczęliśmy wspólnie analizować wymagania w projekcie (User stories) i wspólnie budować model od nowa. Doszliśmy do podobnego modelu (z kilkoma subtelnymi różnicami), jednak w czasie "wspólnej pracy" powstał współdzielony kontekst (czyli uspójnione przemyślenia i rozumienie tematu). Współdzielony kontekst umożliwia trafniejsze podejmowanie decyzji oraz efektywniejszą kontynuację prac. To dlatego w Agile'u tak duży nacisk kładzie się na ścisłą współpracę - aby budować współdzielony kontekst.
I stąd jedna przestroga: Nie zarzucaj nikogo produktem swojej pracy, będącej efektem wielu godzin działań i/lub przemyśleń, oczekując, że go dobrze zrozumie. Przynajmniej pójdź i razem z nim go (ten produkt) przeanalizuj i wytłumacz jak do tego doszedłeś. A najlepiej wypracowuj to wspólnie :) Oszczędzisz wiele pracy sobie i tej osobie, a w szczególności unikniesz wielu zniekształceń komunikacyjnych (które to właśnie generują bardzo dużo dodatkowej, niepotrzebnej pracy).

Naturalny porządek refaktoryzacji (ang. natural order of refactoring) albo inaczej co to naprawdę znaczy ewolucyjny design lub architektura.
Jest to temat na osobny artykuł, tutaj więc pokrótce.
Od pewnego czasu krystalizuje mi się koncept systematyzacji procesu refaktoryzacji od najniższego poziomu abstrakcji do najwyższego - naturalny sposób na ewolucyjny rozwój designu (projektu systemu).
Idea jest taka - zaczynasz od najprostszego rozwiązania, które następnie refaktoryzujesz (jeśli potrzeba) na różnych poziomach abstrakcji (w pewnym ustalonym porządku). Oto porządek przekształceń (rozpoczynamy od niskopoziomowych).

0. Transformacje (triangulizacje) - jeśli używasz TDD (http://cleancoder.posterous.com/the-transformation-priority-premise)
1. Refaktoryzacje typu
Compose method (http://www.industriallogic.com/xp/refactoring/composeMethod.html) (czyli seria refaktoryzacji typu Extract method)
Czyli pierwszą implementację złożonej metody rozbijam na serię wywołań kilku metod składowych na tym samym poziomie abstrakcji. Z jednego bloku kodu powstaje kilka metod.
2. Refaktoryzacje typu Extract class, Extract interface, Move method, Move field na podstawie analizy odpowiedzialności klasy.
Z czasem wyodrębnionych metod w powyższym kroku jest coraz więcej, więc klasa zaczyna być zbyt duża i często przestaje spełniać regułę SRP (pojedynczej odpowiedzialności). Zatem zaczynasz myśleć o przeniesieniu tychże metod gdzieś indziej. Do innej klasy, do nowej klasy, być może temu będzie towarzyszyć wyodrębnienie się interfejsu, być może będzie trzeba poprzesuwać pola w klasie.
3. Refaktoryzacje do wzorców projektowych (http://www.industriallogic.com/xp/refactoring/)
W sytuacjach, kiedy musisz przygotować się na zmienność w projekcie (np. różne wersje algorytmów, przetwarzanie zdarzeń, adaptowanie struktur czy zachowania), wprowadzasz w projekcie wzorce projektowe.
4. Refaktoryzacja do wzorców architektonicznych (podstawowy opis wzorców http://martinfowler.com/eaaCatalog/)
Z czasem jeśli obecna architektura nie radzi sobie ze zmieniającymi się wymaganiami systemu albo potrzeba innej koncepcji, to modyfikujemy założenia architektoniczne - a zatem również musi ulec zmianie Mantra architektoniczna. Może to być: dodatnie warstwy, usunięcie warstwy, zmiana architektury dziedziny (Domain Model, Active Record, Exposed Domain Model) itp.


Heurystyka zwinnego modelowania systemu (czyli jak zacząć i mieć pewien zgrubny koncept)

Jak dojść zwinnie do wstępnego modelu, który pozwoli ruszyć z implementacją, a jednocześnie pozwoli uniknąć podstawowych błędów związanych z nieprzemyślaną architekturą? Jak i kiedy zaplanować architekturę? Zrobić wstępny projekt w podejściu zwinnym?
Oto propozycja zwinnej "drogi" :) Jest to miks praktyk Scrumowych/Agilowych, ICONIXa i naszych doświadczeń BNSowych.
1. Zdefiniuj (jeśli jeszcze nie masz) User Stories/Epics.
Zazwyczaj wystarczy pokrycie 80% systemu. Pamiętaj, żeby nie przesadzać ze szczegółami. Jeśli twój system ma UI - koniecznie korzystaj z draftów ekranów. Jeśli nie ma przydadzą się uproszczone diagramy określające interakcje systemu. Jakie diagramy? To już zależy od Twojej dziedziny :)
2. Przeanalizuj interakcje z systemami zewnętrznymi. Z nich też będą wynikać US. W efekcie usługi czy elementy modelu.
3. Określ priorytety i zgrubnie określ co wejdzie do Realeasu (wersji wdrożeniowej - czyli zazwyczaj efekt kilku miesięcy prac).
Pamiętaj, najbardziej będą interesować Cię rzeczy o wyższych priorytetach. Te o niższych nie są warte zbyt dużej uwagi.
4. Analizując po kolei User Stories, buduj model dziedziny (docelowo diagram klas dziedzinowych).
Skupiaj się przede wszystkim na nazwach klas i powiązaniach. Jest to najbardziej naturalny słownik dziedzinowy (bardziej definicja nazw).
5. Analizując po kolei User Stories (US), wyodrębniaj usługi (operacje) systemu.
Najlepiej, żeby były sformułowane w języku biznesowym. Na początku nie dziel ich specjalnie. Nawet wrzucaj do wspólnego worka. Dla ułatwienia możesz powiązać je z odpowiednimi US.
6. Określ złożoność operacji.
Określ, które operacje są bardziej złożone (wychodzą poza klasyczny CRUD). Będzie to podstawa do określenia kierunku architektury.
7. Wybierz kierunek architektury (w oparciu o model dziedzinowy)
(m. in. Domain Model, Anemic Domain Model, Active Record, Exposed Domain Model). Uwzględnij technologie, jeśli jest już wybrana lub ją wybierz.
8. Z wyróżnionych usług wybierz te o największym poziomie złożoności i ryzyku w celu analizy.
Zrób proste szkice klas, interakcji, które pozwolą przeanalizować złożoność. Wybieraj tylko te usługi do analizy, które przynależą do US o wysokich priorytetach lub też mogą znacząco wpłynąć na wykonalność projektu.
9. Osadź architekturę w technologii. Spartycjonuj usługi.
Rozrysuj bloki architektury i typowe klasy. Na bazie listy usług - podziel je grupując wg zbliżonych odpowiedzialności (spójnych dziedzinowo).
10. Przeanalizuj 1-2 US (koncept implementacji), które pozwolą zweryfikować założenia koncepcji.
Jeśli weryfikacja się nie powiedzie, wróć do 7 lub 8.
11. Zaimplementuj wybrane 1-2 US, aby zweryfikować koncepcje.
Może to wymagać wstępnego setupu projektu, środowiska. Może to być podstawa to tzw. Iteracji 0, Sprintu 0,
Elaboration phase (?? nie jestem ekspertem RUPa).
Jeśli weryfikacja się nie powiedzie lub koncept ma luki przejdź do 7 lub 8.
12. Zdefiniuj Mantrę architektoniczną.
13. Realizuj inkrementacyjnie projekt (to dalej definiuje metodyka).

Powiązany OFFTOPIC:
Zapodam pewną mądra myśl, która może kogoś natchnie do myślenia:
"W architekturze nie chodzi o rysunki, diagramy, powiązania z innymi systemami, ale o głębokie zrozumienie dziedziny i kontekstu systemu, z którym pracujesz. Zapomnij o UMLu, zapomnij o supernarzędziach wspierających Cię w projektowaniu, włącz myślenie. Włóż najwięcej energii w zrozumienie dziedziny. Ta wiedza już po nitce poprowadzi Cię do odpowiednich konstrukcji projektowych".
Tak, tak, to niewiele mówi. Na razie mogę odesłać do koncepcji Domain Driven Design oraz Lean Architecture (vide: Google).

2 komentarze:

Unknown pisze...

Nie wiem czy nie lepiej byłoby podzielić wpis na kilka mniejszych, pewnie większość (a może tylko ja) napotykając na dłuższy wpis, wrzuca go do "worka na później" co wielokrotnie niestety oznacza - nigdy. Pewnie zasada 2 minut z GTD byłaby odpowiednia. Zmierzyłem, przeczytanie dwóch pierwszych punktów zajęło mi ok 2m30s. A gdzie reszta, i czas na przemyślenia ;o).

Pozdrawiam.

Unknown pisze...

No cóż, życie jest brutalne ... czasami ;-)
Kiedy siadałem do tego posta, miało to być 10 minut i krótki wpis... ale nie mogłem się powstrzymać...