Tuesday, November 29, 2011

Bounded Context

Jasne, że nie będę od teraz pisał o DDD, bo już inni o tym ciekawie piszą. Chciałbym się tylko trochę uzewnętrznić w temacie, który szczególnie mnie poruszył, gdyż rozwiązuje dość poważny problem z architekturą. Jeśli nie nie zetknąłeś się z filozofią (w moim rozumieniu to bardziej sposób myślenia niż toolbox; taka obiektowość podniesiona level wyżej - na poziom architektury) DDD to na wstępie proponuję:

O jakim problemie mowa?

Powiedzmy, że rozpoznajemy, co też dzieje się domenie sklepu internetowego (nie wiem dlaczego to sklep zazwyczaj przychodzi na myśl:)). Powiedzmy, że dzieje się jak poniżej:
Jest to jakaś interakcja pomiędzy obiektami w dziedzinie.

Gdy zaczynamy modelować, naturalnie pojawiają się klasy takie jak: Zamówienie, Koszyk, itd. Powstaje model złożony z powiedzmy 30-50 klas. Wszystko wygląda super świetnie, ale zbiegiem czasu coś zaczyna nie grać. Pojawiają się następujące symptomy:
  • W związku z kolejnymi wymaganiami, do obiektów dochodzi coraz więcej atrybutów i metod
  • Programista implementujący przypadek użycia związany ze złożeniem zamówienia z trudem odnajduje się w gąszczu atrybutów i metod dodanych przez kogoś, kto implementował realizację Zamówienia
  • Niektóre obiekty są używane w tak wielu miejscach systemu, że jakakolwiek w nich zmiana ma spore skutki w innych odległych miejscach
Co więcej: jeśli z wymagań wynika jakaś konkretna zmiana w jednym miejscu systemu, to obija się ona głośną czkawką w zupełnie innym właśnie z powodu "reużywania" obiektów modelu.

Niby wszystko zostało przygotowane zgodnie z regułami sztuki, ale jednak wszyscy czują, że coś śmierdzi...tylko nie wiadomo z jakiej przyczyny.

Powód jest taki, że ten sam obiekt modelu używany jest wielu różnych kontekstach. Zamówienie wynikające z interakcji użytkownika z Koszykiem jest nieco inną sprawą niż Zamówienie realizowane przez magazyn.

"Bounded context should have a name so that you can talk about them"

Rację mieli starzy Indianie, gdy twierdzili, że jeśli poznasz czyjeś imię, zyskujesz nad tym kimś władzę. Nie inaczej jest z bounded contexts. Jeśli nie zauważymy i nie nazwiemy kontekstów użycia modelu, to mogą nam zrobić krzywdę. Nienazwane lubią się mieszać i dokładać do obiektów modelu rożnego rodzaju dodatki właściwe dla swej specyfiki. W skutek czego powstaje model-potworek, który w założeniu miał być super, a w wykonaniu i tak jest kolejną wersją big ball of mud.

Jeden model w jednym kontekście

W związku z dokonanymi odkryciami warto zalecać:
  • Nazwij kontekst, w którym może być wykorzystywany model. Już sama próba nazwania sprawi, że kontekstów pojawi się kilka (o ile tam są).
  • Jeden model może być wykorzystywany tylko w jednym kontekście (bounded context). Zamówienie w kontekście Koszyka to nie dokładnie to samo, co zamówienie w kontekście Magazynu.
  • Odizoluj poszczególne konteksty i właściwe im modele od siebie

W powyższych zasadach można dopatrzyć się echa Single Resposibility Principle. Z odpowiedzialności modelu powinien wynikać jednoznaczny kontekst jego użycia. Tyle, że Bounded Context definiuje to wprost i wyraźnie, a z zasady odpowiedzialności trzeba sobie wywnioskować.

Jeżeli w konsekwencji mamy zdefiniowanych kilka zwartych modeli o jednoznacznie określonych kontekstach użycia, to musi istnieć coś, co będzie potrafiło skonwertować obiekty z jednego kontekstu w drugi (jeśli jest taka potrzeba). W DDD ta potrzeba jest zaspokajana poprzez zdefiniowanie Context map w postaci zestawu usług-translatorów (w apachowych commonsach nazywanych transformerami). Ich odpowiedzialność to właśnie konwersja.

Podsumowując zyski z wprowadzenia konceptu Bounded Context:
  • Redukcja echa w systemie - zmiana w modelu w jednym miejscu nie skutkuje oddźwiękiem w innym
  • Zmiany wynikające z biznesu mają na poziomie architektury ograniczony do kontekstu zasięg
  • Można lepiej zorganizować prace nad projektem (tutaj DDD proponuje kilka pomysłów w zależności od tego jakie relacje występują pomiędzy kontekstami).

Tuesday, November 22, 2011

Przeglądy kodu

Kilka słów o przeprowadzaniu code review. A zatem po co? Czy nie wystarczy podłączyć Sonara czy coś w tym stylu. Z pomocą przyszedł mi cytat zamieszczony na strone 33rd Degree Conference: A single conversation with a wise man is better than ten years of study. I właśnie dlatego warto przeprowadzać code review :) Prowadząc taką rozmowę z f2f robimy użytek efektu human infection, czyli przekazujemy sobie wiedzę i ideę w bardziej naturalny sposób niż na papierku, albo ciągiem bitów.

Informacje początkowe

Dalej streszczam mój sposób na przeprowadzanie przeglądu kodu, ale najpierw parę tematów wprowadzających.

Jak często przeprowadzać przeglądy?
Tu nic odkrywczego nie wymyślę, jeśli napiszę, że: raz na wydanie albo raz na iterację albo w regularnych odstępach czasu albo po zamknięciu zadania albo na żądanie :)

Kto przeprowadza przegląd?
Jestem fanem ról, a sceptykiem stanowisk więc sądzę, że przegląd powinien przeprowadzać lider. W żadnym razie lidero-kierownik mający pod sobą kilkanaście osób. Mówię o liderach np. konkretnych komponentów systemu, którzy przewodzą maksymalnie pięciu osobom. Jeśli brak takiego liderowato-centrycznego uporządkowania, to przegląd robią ludzie, którzy mają mandat od zespołu wskazujący, że "ten zna się na rzeczy". Rzecz jasna poszczególni programiści z biegiem czasu nabywają kompetencji do przeprowadzania przeglądów. Zespół żyje.

Jak szczegółowy ma być przegląd?
Ufam, że ludzie są mądrzy. Wystarczy pokazać im co i dlaczego robią źle, aby potem zgeneralizowali ideę i wprowadzali poprawki w reszcie kodu. Nie ma potrzeby pokazywania palcem absolutnie wszystkiego. Wiem, wiem pewnie, że są wyjątki. Ale co do zasady, wspomniane założenie ufności jest dość użyteczne.

Ile czasu zajmie przegląd?
Jeśli znasz i rozumiesz kod to w okolicach 30 min plus drugie tyle na rozmowę. Jeśli nie znasz kodu (bo na przykład analizujesz kod klienta) to już jest zupełnie inna bajka. Megaistotne jest zebranie informacji co z czym się je, żeby nie wydzwaniać do ludzi co parę minut. Sam późniejszy przegląd to 8h wzwyż.

Przegląd krok po kroku


1: Zdefiniuj w IDE tasktagi //SMELL i //REFACTOR
Będą potrzebne do oznaczania w kodzie różnych ciekawostek.

2: Ogranicz się do kodu: jednego user story | jednego zadania | jednej funkcjonalności
Generalnie mogę wpaść w cały moduł i nie wyjść z niego przez tydzień. Ale zgodnie z zasadą zaufania, chcemy wyłapać symptomatyczne niedociągnięcia delikwenta, a nie prześwietlić jego kod od A do Z. Który zatem kawałek kodu wybrać? Tu przyda się rozbudowany instynkt Dr Housa. Trzeba z premedytacją wybrać taki fragment kodu, który potencjalnie mógł programiście sprawić trudność. Przykład: ostatnim razem ustaliliście nad czym ma popracować, wiec teraz sprawdź podobne zadanie albo kątem ucha usłyszałeś jak rozmawia o jakimś trudnym zadaniu - sprawdź właśnie to. Jasne, że nie robimy tego z czystej złośliwości, lecz właśnie w tego typu zadaniach jest okazja, aby wyłapać największe niedociągnięcia i najszybciej skorygować styl pisania.

3: Wygeneruj diagram zależności między klasami/pakietami
Najczęściej korzystam z wbudowanych widoków Eclipse lub ficzerów ReSharpera, wspomagając się kartką. Teraz zaczynam zapoznawać się z CDA i jeszcze nie mam wniosków. Jeśli chodzi o C++ to Visual Assist X jest jakimś tam ułatwieniem. Ale konwencje utrzymywania projektów i plików w C++ są tak zróżnicowane, że niemal za każdym razem wymaga ode mnie kreatywnego podejścia. Zazwyczaj kończy się na Eclipse C/C++ oraz kartce i długopisie. (Nie, nie rysuję w tym przypadku diagramów w narzędziu UML, bo za długo to trwa; ewentualnie potem, gdy okazuje się na przykład, że dziesięciopoziomowa hierarchia dziedziczenia sprawia kłopoty, to coś tam przerysuję żeby efekciarsko wyglądało w raporcie).

4: Pobieżnie przyjrzyj się każdej klasie w wybranym fragmencie kodu
Przyglądamy się tu pod następującymi kątami:
  • ogólne wrażenie - elegancja kodu, czy woła o pomstę do nieba?
  • nazewnictwa - czy nazwa oddaje intencję?
  • wielkości klas i metod
  • Ilość współpracowników

5: Prześledź podstawową obsługę żądania
Chodzi o prześledzenie ścieżki od momentu, w którym ktoś zainicjował przetwarzanie

do chwili, gdy system odpowiedział na nie.

Oznacz //SMELL miejsca, w których kod wydaje Ci się niewłaściwy. Przez //REFACTOR oznacz miejsca, w których od razu wiesz, co należy zrefaktoryzować.

6: Przygotuj podsumowanie
Byle krótkie w punktach, które uwzględni relację kodu do: obowiązującego standardu kodowania, czystości kodu, przyjętych zasad architektury.

7: Przekaż informacje zwrotną
w rozmowie f2f oraz wskazuj kierunki poprawy, ewentualnie zaimprowizuj mikorszkolenie. Zanotuj sobie, aby zweryfikować, czy postanowienia z rozmowy zostały wdrożone. Jeśli ludzie będą zapominać, przeglądy nic nie wniosą i wszystkim odechce się w nie angażować.

Czy należy wnioskować, że nienawidzę narzędzi?

Absolutnie nie. Takie super gadżet jak Sonara przeanalizuje za Ciebie masę kodu i wskaże miejsca, w które warto zajrzeć osobiście. Jestem wielkim fantem użytecznych narzędzi z zastrzeżeniem, że nie wolno nam zafiksować, że narzędzia zrobią wszystko, a my będziemy mogli zwolnić się z myślenia.

Dodatkowo jestem entuzjastą minimalizowania ilości otwartych zadań (work in progress). Jeśli robię przegląd i używam fajnych okienek, wpisuję komentarze (które potem trzymane są w repo), to te komentarze tam sobie będą i będą, aż może ktoś się nimi zajmie, rośnie tendencja do odkładania. Jeśli teraz robię przegląd i mam kilka słów podsumowania na kartce, to będę dążył to tego, aby jak najszybciej złapać daną osobę, przekazać co mam do przekazania i niech ona to już zrobi. Problem zdiagnozowany, rozwiązany, można pisać dalej.

Thursday, November 10, 2011

Duch i litera


Trochę w nawiązaniu do posta W co gra się w projektach.

W okolicach wyborów słyszałem w radiu zażartą dyskusję nt. czy obecnemu rządowi wolno rządzić do końca roku czy nie. Premier się upierał, że chce spokojnie dokończyć prezydencję w UE i argumentował, że jest to zgodne z konstytucją, natomiast konstytucjonaliści ripostowali, że owszem jest to zgodne z konstytucją, lecz nie jest zgodne z jej duchem.

Otóż to, pomyślałem. Wdrażanie procedur/procesów/standardów w zespole kończy się niepowodzeniem, gdyż ludzie rozumieją ich literę, ale nie widzą ducha. Autorzy procedur mieli oczywiście bliski kontakt z duchem, a literę stworzyli po to, aby przekazać swoje odmienne stany świadomości. Ergo - przy okazji wdrażania czegokolwiek ludzie muszą nawiązać kontakt z duchem.

Zostawiwszy w spokoju spirytualistyczne metafory, trzeba wyraźnie powiedzieć, że ludzie muszą znać intencję wdrażania nowych standardów, czyli: po co to robimy, dlaczego to jest ważne, co z tego będziemy mieli. Dobrym pomysłem, w tym obszarze jest standaryzowanie tego co już działa. Jeśli w zespole samoczynnie wykształciła się jakaś praktyka, która przynosi dobre rezultaty, to wartą ją zinstytucjonalizować w postaci obowiązującego standardu - dwie pieczenie na jednym ogniu.

Thursday, October 20, 2011

Inspiracja fantasy

U jednego z lubiących mnie na facebooku znalazłem cytat z jednej z najlepszych sag fantasy jakie czytałem. Mowa rzecz jasna o Sadze o Wiedźminie. Cytat pochodzi z dzieła Jaskra, w którym wyjaśnia czytelnikowi, na czym polega prowadzenie działań wojennych.

Poznałem w życiu wielu wojskowych. Znałem marszałków, generałów, wojewodów i hetmanów, triumfatorów licznych kampanii i bitew. Przysłuchiwałem się ich opowieściom i wspomnieniom. Widywałem ich schylonych nad mapami, rysujących na nich różnokolorowe kreski, robiących plany, obmyślających strategie. W tej papierowej wojnie wszystko grało, wszystko było jasne i wszystko funkcjonowało we wzorowym porządku. Tak być musi, wyjaśniali wojskowi. Armia to przede wszystkim porządek i ład. Wojsko nie może istnieć bez porządku i ładu.
Tym dziwniejsze jest, że prawdziwa wojna - a kilka prawdziwych wojen widziałem - pod względem porządku i ładu do złudzenia przypomina ogarnięty pożarem burdel.


Pomyślałem złośliwie, że gdyby zdefiniować następujące zmienne:
  • marszałek, wojewoda, hetman, triumfator, wojskowy := menadżer
  • wojna, bitwa := projekt
  • wojsko, armia := zespół projektowy

to sumie też ma jakiś sens...

Tuesday, October 18, 2011

Nic tak nie zaciemnia sprawy jak dobry przykład

jak ponoć mawiał szacowny nauczyciel.

Czasem mam wrażenie, że to powiedzenie odbija się echem w trakcie zbierania wymagań (w sumie odbija się echem w ogóle w kontaktach międzyludzkich, ale do zbierania wymagań się zawężę).

Próbujesz się dogadać, dowiedzieć co trzeba zrobić, aż tu nagle pojawia się tekst "to ja może podam Panu taki przykład....", który to przykład dokumentnie burzy moje zrozumienie problemu.

Podam taki przykład :), żeby doprecyzować o co mi chodzi. W ramach treningu poprosiłem osobę biznesową o opisanie "myszki do kompa" (rzecz jasna bez używania słów "mysz" i "komputer"). Otrzymałem odpowiedź: „To jest miłe w dotyku jak moje kapcie pluszowe. Jak to głaskam to sprawia mi to przyjemność. Służy to do wyrażania myśli. Wygląda jak zwierze ale na wyższym stopniu ewolucji. Jest większe od biedronki ale mniejsze od psa”.

Wychodzę z założenia, że za efektywność zbierania wymagań odpowiada zbierający. To jego zadaniem jest w porę zauważyć, że przykład/metafora zmierza z zaawansowane pułapy abstrakcji. Tylko co trzeba umieć, żeby na taki przykład się nie złapać?

Przypomina mi się jeden wykładowca matematyki, który słynął z pytań pomocniczych zwanych również pogrążającymi. Student męczy się przy tablicy z przebiegiem zmienności funkcji wykładniczej. Męczy się męczy. A wykładowca na to: "No, no to może ja pomogę. Niech Pan się zastanowi jak wygląda krzywa ładowania kondensatora"....

Friday, October 7, 2011

Planowanie to nie problem

To miał być długi, pracowity wieczór. Nazbierało mi się sporo zadań do wykonania. Gdy tylko drzwi hotelowego pokoju za mną się zamknęły, przystąpiłem do działania według najlepszych prawideł sztuki planowania. Komputer zostawiłem w spokoju dla uniknięcia rozproszeń. Czystą kartę zapełniała powoli acz konsekwentnie rosnąca lista tudusów. Lista to została następnie starannie przepisana na nową kartkę, w już posortowanym według priorytetów porządku.

Tak uzbrojony, włączyłem notebooka i rozpocząłem działania. Pomyślałem, że zerknę co tam przed wyborami. Nic nowego. Ok, zabieram się do pracy. Ponieważ najpierw musiałem odszukać mail na podstawie, którego mam coś tam opracować - odpalam TB. Zaraz po uruchomieniu klienta poczty, automatycznie ściągają się czekające maile. No, tylko rzucę oczkiem....O, siostra przysłała mi przepis na zupę dyniową. Hmm, że niby ja mam to gotować? O, Grzesiek odpisał na facebooku. O, ktoś ma dla mnie ofertę pracy...ups nie, tam już pracowałem. Kurcze, ten mail to mnie wkurzył, muszę odpisać, bo nie zdzierżę!

Ok, jeszcze tylko załączę piosenkę na rozpęd i już się zabieram do pracy. Odnajduję na youtube stary teledysk Ronniego Dio. Naprawdę, koleś miał głos jak dzwon. Szkoda, ze zmarł. Kiedy to było? A, 16 maja..o wtedy, kiedy urodziny mojej siostry. Tak na marginesie o co chodzi z tą zupą dyniową? Jeść mi się zachciało. Jedno jabłuszko tylko, bo wieczór. Na noc jeść nie zdrowo. Nightwith - włączę cicho. O, ciekawe czy są jakieś nowe wtyczki do foobar2000. Zaraz zaraz, która godzina. Północ? A moje zadania? Szlag!


Zadania dryfują

Już nie raz łapię się na tym, że planowanie to bułka z masłem w porównaniu z konsekwentnym podążaniem za planem. Obstawiam, że gdyby nawet najmizerniejsze plany były realizowane w 100%, to osiągalibyśmy znacznie więcej niż obecnie. Kłopot w tym, że zaraz po przystąpieniu do działania, naszą uwagę przykuwa wiele rzeczy, które wywołują serię skojarzeń, które to z kolei kuszą nas do zajęcia się wszystkim tylko akurat nie tym, czym planowaliśmy się zajmować.

Ktoś mi kiedyś powiedział, że przedmioty "wysyłają" do ludzi oferty. Przedmioty starają namówić Cię, abyś z nich skorzystał, wszedł w interakcję. Ładna metafora i chyba oddaje istotę rzeczy. Największym wrogiem dotrzymywania terminów (zakładam, ze sensownych :)) nie jest wcale nieumiejętność planowania, lecz nieumiejętność realizowania planu. Cierpimy na chroniczny brak umiejętności skupienia się i utrzymywania skupienia, choć dawni belfrzy z twardą trzciną w łapie powiedzieliby, że to brak samodyscypliny.

Wielokrotne powtarzanie opisanego na wstępie schematu prowadzi do nawyku silnego jak u mitycznego psa Pawłowa. Po jakimś czasie okazuje się, że po prostu nie sposób zacząć pracy bez godzinnego onetowego rytuału.

Weź pigułkę

Przyczyna tkwi chyba w pigułkowatej mentalności otaczającego świata. Zewsząd wmawia się nam, że istnieją proste rozwiązania na wszystkie problemy. Wcale nie potrzeba pracy nad sobą, wyrzeczeń, poświęcenia. Wystarczy wziąć "pigułkę"np:. przeczytać książkę, która odkrywa sekret, pójść na szkolenie, gdzie wleją nam wszystko do głowy albo pić ziółka i chudnąć 5kg/tydzień. Ostatnio nawet widziałem w TV reklamę, której sens można oddać następująco: "żryj do woli, jak się rozchorujesz to weź pastylkę X i żryj dalej".

Nie inaczej jest z planowaniem i wykonywaniem zadań. Karykaturalnie wykrzywiając powiedzenie "chcieć to móc" wmawia się nam, że po zastosowaniu sprytnych tricków, poradzimy sobie z każą ilością zadań. Gdyby wyobrazić sobie dobę jako koło, to każde z jego wycinków oznacza część doby przeznaczoną na coś.

Przeciętny człowiek ma zajęte całe koło, bo zawsze coś tam robi mniej lub bardziej aktywnie. A tu nagle każą nam sprawić, aby kąt pełny miał więcej niż 360 stopni. Brutalna prawda jest taka, że aby zacząć coś robić, coś trzeba przestać robić albo czegoś robić mniej. To nie żadne hokus pokus, tylko zdrowy rozsądek.

Niestety zaczynamy wierzyć w taką pigułkowatą naturę rzeczywistości. Zaczynamy oczekiwać, że można coś osiągnąć bezkosztowo, że można zjeść ciastko i mieć ciastko jednocześnie. Efektem nie jest jednak natychmiastowy i oszałamiający sukces lecz frustracja, miernota i rozczarowanie.

Terapia

Leczenie z nadmiernego pobudzenia otaczającym światem, które sprzyja rozproszeniu i odciąga od tego, co rzeczywiście należy zrobić, jest możliwe.
Wydaje mi się, że warto zacząć od paru praktyk ograniczających wspomniane oferty przedmiotów:
  • Zadania zaczynaj od pierwszego na liście. Nie od RSS, newsów, maili itp. (wrzucanie RSSów do listy się nie liczy:))
  • Wyłącz komunikator, klienta poczty i włączaj je tylko w ściśle ustalonych porach (wiem, że to czelendż, ale warto spróbować)
  • W kliencie poczty wyłącz automatyczne odbieranie poczty przy starcie i co 10 minut
  • Z umiarem stosuj smartfony. Naprawdę nie musisz być on-line non stop.
  • Jeśli już koniecznie musisz poczytać newsy zrób to na końcu listy zadań, nie na początku
  • Słuchanie muzyki podczas pracy nie jest takie dobre jak się o tym mówi; Jest ok przy prostych powtarzalnych zdaniach. Jeśli zdania wymagają kreatywności, to angażują prawą półkulę mózgu, tą samą co muzyka. Zatem Twoje zadanie konkuruje o zasoby fooobarem2000
  • Jak najszybciej zamykaj zadania i jak ognia unikaj zostawiania ich rozgrzebanych i niedokończonych. Lepiej jest mieć 50% czegoś konkretnego niż 100% świetnych niezrealizowanych pomysłów

Friday, September 30, 2011

Dług techniczny, opcja call czy lokata długoterminowa?

Standardowy kłopot z refaktoryzacją: my chcemy, a z góry leci głośnie NIE! Łaj? W moim odczuciu są dwie główne przyczyny. Pierwsza wynika z definicji. Skoro refaktoryzacja, to "ulepszenie wewnętrznej struktury oprogramowania, bez zmiany jego funkcjonalności", to skoro nie dodaje funkcjonalności, a zatem nie dodaje wartości biznesowej, a zatem nie pozwala efektywniej zarabiać, a zatem nie warto jej wykonywać. Podsumowując - kasa.
Drugi problem jest związany z przekonaniem, że jak już refaktoryzować, to rewolucyjnie i musi to zająć mnóstwo czasu. Skoro czasu to i pieniędzy. Za drogo i nie warto tego robić. Znów kasa. Nie zbłądzę zbytnio, gdy stwierdzę, że tarcia o refaktoryzację obijają się o pieniądze.

Kłopot z metaforami

Aby zdobyć choć trochę posłuchu u biznesu community wykombinowało jak na razie dwie metafory: Długu technicznego oraz (najświeższa) Niezabezpiecznonej opcji typu call.
Gdy się w nie wczytać, to każda z nich mówi mniej więcej coś takiego: Pamiętaj biznes-ludku, że jak nie będziemy refaktoryzować, to stanie się COŚ strasznego!. Obie metafory odwołują się do rzeczy, która jak nam się zdaje, najlepiej do biznesu przemówi, czyli do pieniędzy.

Dług techniczny mówi: zabraniając refaktoryzacji zaciągasz duże zobowiązanie, w kolejnym wydaniu rollujesz ten dług kolejnym długiem, i kolejnym, i kolejnym. W końcu zbankrutujesz i klops.
Niezabezpieczona opcja call mówi: nie pozwoliłeś na refaktoryzację, nabyłeś najbardziej ryzykowny instrument finansowy we Wszechświecie. Jedyne co możesz robić, to się modlić.

Skoro te metafory tak dokładnie wyłuszczają konsekwencje zaniedbywania jakości kodu, to dlaczego nic się nie zmienia? Nieco światła rzuca na to psychologia społeczna, wg której bardziej preferujemy natychmiastową gratyfikację niż długoterminowe korzyści oraz bardziej obawiamy się nieprzyjemności bliższych i namacalnych niż odległych i nieco abstrakcyjnych.

Podsumowując, twierdzę, że obojętność na prorefaktoryzacyjne błagania ma następujące przyczyny
  • korzyść z refaktoryzacji jest zbyt odroczona w czasie
  • korzyść z refaktoryzacji bardzo trudno wykazać jest w pieniądzach
  • zaniedbanie refaktoryzacji ma negatywne skutki w bliżej nieokreślonym kiedyś; a dopóki programiści mogą ratować projekt, to go ratują; czasem bardzo długo
  • robienie tak, "aby działało" ma szybkie odczuwalne korzyści
Powyższe fakty sprawiają, że na refaktoryzację przychodzi zgoda, gdy już w zasadzie jest za późno. I wtedy to już na prawdę jest od cholery roboty.

Lokata długoterminowa

Dobitna metafora dla refaktoryzacji powinna charakteryzować się następującymi cechami:
  • korzyści można łatwo wyrazić w pieniądzach
  • korzyści finansowe są szybko odczuwalne, powiedzmy w perspektywie tego samego albo najbliższego wydania
Zauważmy, że jest to metafora pozytywna. Dług techniczny oraz opcja call były metaforami negatywnymi w takim sensie, że straszyły tym, co złego się wydarzy jeśli nie będziesz grzeczny. Nasza nowa metafora jest sformułowana pozytywnie, bo pokazuje korzyści jakie uzyskasz, gdy będziesz się dobrze sprawować.

Szukałem tego typu metafory również w świecie finansów (no, bo dlaczego nie?) i znalazłem ja w postaci lokaty długoterminowej. Korzystając z tej metafory można w stronę Biznesu perorować, że:
  • refaktoryzacja jest jak wpłata pieniędzy na lokatę, już po pierwszym okresie rozliczeniowym następuje kapitalizacja odsetek i otrzymujesz swój procent
  • im dłużej oszczędzasz tym więcej zyskujesz
  • żeby osiągnąć maksymalną korzyść musisz wpłacać regularnie
  • jeśli zerwiesz lokatę, właściwie tracisz większość zarobku
  • no i w przypadku refaktoryzacji nie ma podatku Belki:), same korzyści!

A jak pokazać korzyści finansowe?

Tu popuszczam trochę wodze fantazji. Można spokojnie założyć, że na refaktoryzacyjnej lokacie odsetki procentują razem z początkowym kapitałem. Weźmy sobie zatem wzorek:
gdzie: V - obecna wartość, V0 - początkowy kapitał, r - stopa procentowa, n - liczba okresów rozliczeniowych.

No, to teraz spróbujmy zinterpretować wzór w kontekście refaktoryzacji. Vx - liczmy dalej w pieniądzach, n - liczba iteracji, a r? Skoro finansowo odpowiada to zyskowności (potencjałowi wzrostu kapitału?), to co jest tego odpowiednikiem w projekcie? Mam feeling, że coś z jakością kodu, ale nie bardzo wiem co.

Thursday, September 29, 2011

User friendly

Właśnie dostałem poniższy komunikat....to się nazwa user friendly UI :)


What do we play in projects?

Once upon a time there was a team consisting of a few developers. They got down to their project with real passion.

They believed that the best way to learn is to learn from mistakes, so they regularly had retrospection sessions to discuss issues such as:
  • consistency of estimating and expectations
  • test coverage and its effectiveness
  • number of bugs detected in the test phase
  • code readability
and a few other things. They had real fun, because they felt that they developed in their specialty. Based on those retrospections they came up with some rules and standards. All the team members agreed that these regularities enable them to work more effectively, so they employ them eagerly. They set up their own Wiki, in which they listed all the standards to be applied by the team, and which they later modified to keep pace with the changing needs and experiences.

Due to the fact that their work was exceptionally smooth, the project sponsor started to hire new and new and new developers to join this team. The first team members became its leaders and then managers. Everything went off really smoothly. Of course, the new people in the department (because, naturally, the team developed into a department) were obliged to learn the existing and proven standards, and apply them in a strict manner.

After some time our managers noticed that these requirements were not fully met. They had problems with forcing the developers to apply the standards. It took them a long time to come up with a solution to this situation. Because they were seasoned engineers, they approached this issue in a strictly analytic way and came up with a formula. According to this formula the employees’ premium depended on the degree to which they conformed to the standards. For example: for 80% test coverage you get +2% of premium, for 50 tester-reported bugs you get +1.3% of premium, and for estimating maintained +3.2% of premium… What a bright idea…

And then the GAME started.

Rules

The intention of the managers was to reward the team for keeping conformity with standards and to encourage the employees to apply them. Nevertheless, the managers completely unconsciously started a GAME with the following rules:
  • team members are the player
  • you win once you earn the biggest amount of money
  • the rules for getting money are specified by the standards applicable to the team
It soon turned out that developers and testers were seasoned players. They would often win…, but:
  • test coverage was perfect, but: getters and setters were tested, the tests were disturbing instead of being helpful
  • developers provided perfect estimating every day, but they were very, very, very pessimisti
  • testers found dozens of bugs, but most of them were about double spaces in labels, missing full stops, etc.
  • coding standards were obeyed, but whenever possible, the developers coded as they deemed fit
  • retrospections declined; standards were not further developed, they finally became inapplicable to the then situation and impeded the work
What the heck happened? - the managers asked - We really meant well!

Conflict of values

A fellow methodology expert who specializes in analyzing the value hierarchy among employees (it happens that the companies want to know what counts for you: development, professionalism, safety, career, and in what order) was so kind as to tell me in detail that no serious test collates professionally-valid values with values such as family or health, because in such a case the former ones always fail.

When the test does not fulfill this rule, we end up with falsificated data, because the test results will always sway in the direction of family, health, etc. It seems logical that when I have to choose between my career and a permanent damage to health, I will always be driven by my self-preservation instinct, and I will protect my health even at the expense of my professional development.

In this particular team the managers made this specific methodological mistake. Because, if I choose between fitting in with estimating (even if we have to overestimate a little bit) and Christmas gifts, the former one is the perfect choice – no matter what! This is not about us being bad or cheating. Nothing of the sort. That's how we are construed. The borderline between just estimating and overestimating is quite fluid and we easily find the rationale for crossing it. In my opinion, the one to blame is the one who has made such goings-on possible rather then the one who really does it.

Disastrous consequences

Due to the fact that conformity with standards was only the managers’ means to achieve a different goal, the standards were neither further developed nor improved. Nobody felt that it was necessary. Why should we change and complicate the ways to earn money if we already know how to win?

Cash motivation is OK, but only on condition that all human activity boils down to earning money. Take salespeople. In simple terms, a salesperson deals with selling products/services and gets a commission for any bill that he/she brings to the employer. It will work. But what if a salesperson gets commission for the number of meetings that he/she arranges? Then, again, the GAME starts. It may turn out that, OK, there are meetings, but with companies that will never become our clients. Who is responsible for that? First and foremost, the one who developed the GAME.

When your employees have a creative type of work (in this case these are programmers) and the rules and standard must evolve and improve with them, you mustn’t make their salary dependent on the degree to which they conform to the standards. Otherwise you will kill their creativity and work rules will soon become stiff.

Obey standards, because it’s worthwhile

For the standards to work and evolve, they have to be important simply because they are standards. People have to be aware of their value, want to obey them, and see that they make their work better. This is the way our first team members from the image above had worked.

In such a surrounding the standards will evolve and the people will be willing to develop them. Otherwise you will run the risk of implementing the standards on your own, forcibly or through the newly employed members of Committees for Standardization, which will only complicate the rules of the GAME. Then no one will know what is the general idea of it.

And what about money?

We can summarize the situation that I have described here in the following words: Motivate not by cash, but pay them well…:) There’s nothing awkward in it – when the basic needs are not satisfied, there’s no sense to think about the higher ones. Of course, we all need a sort of a golden mean, because any budget is limited.

“To pay well” does not mean “to pay more than a competitive company does.” It may be even less than in the competitive company, but if you give your employees some non-cash incentives, it will work. Still, I agree that this is a very individual case and it makes no sense to generalize, as it may be unjustified.

Tuesday, September 27, 2011

Ludzie książki piszą



Wydaliśmy naszą drugą książkę. Pierwszą próbą był ebook Jak całkowicie odmienić sposób programowania używając refaktoryzacji. Najnowsza książka nosi tytuł Eseje o efektywności programistów. Opiera się na artykułach, które opublikowaliśmy w SDJ w ciągu ostatnich dwóch lat. (tak na marginesie: książka ma 143 strony, na zdjęciu wygląda nieco grubiej:) )

Zaskakujące jest to, że redagując ponownie artykuły do książki stwierdzaliśmy, że wciąż są aktualne. O czym więc jest ta książka? O zespołach, trochę o projektach, o zarządzaniu czasem, nieco o refaktoryzacji. W tej chwili przygotowaliśmy nakład ok. tysiąca egzemplarzy, gdyż książka (podobnie jak poprzednia) wstępnie przeznaczona jest dla uczestników naszych szkoleń. Jeśli uważasz, że książka powinna być dostępna dla każdego, to daj znać pod postem:)

Dalej, w przygotowaniu (w trakcie pisania) jest kolejna książka o roboczym tytule Między Biznesem a IT, czyli sztuka zadawania pytań. Dedykowana jest wszystkim osobom (programistom, analitykom, liderom), którzy w procesie wytwarzania oprogramowania mają przyjemność bezpośredniego współpracowania z klientem/sponsorem/użytkownikiem. Książka uwypukla aspekt, który jest nagminnie marginalizowany w publikacjach nt: requirements management - mianowicie sam etap pozyskiwania wymagań. Ramowy outline tej książki wygląda następująco:

O postępach będę informował na bieżąco.


Tuesday, September 13, 2011

Tuesday, August 9, 2011

Interfejs budowniczego

Na przykład tutaj można dowiedzieć się o niezwykłych korzyściach stosowania wzorca Builder (na przykład do wypiekania pizzy:)). Używam zatem, ale ten budowniczy mi więcej przeszkadza niż pomaga. Można pokusić się o stwierdzenie, że to tylko dodatkowa i nad wyraz rozdmuchana warstwa pośrednia, która niczego użytecznego nie wnosi. Ot, tworzy kilka obiektów i już.

Jak wspomniałem plusy dodatnie i ujemne budowniczego były już nie raz szeroko omawiane. Mnie interesuje odpowiedź na inne pytanie: W jaki sposób zaprojektować interfejs budowniczego?. To znaczy:
  • Jak zdecydować jakie metody powinien mieć budowniczy?
  • Jak go sensownie używać (pragmatycznie, nie sztuka dla sztuki), aby pomagał, a nie przeszkadzał?


Ponieważ debugowałem blog Sławka, żeby podłączyć syntaxhighlightera, to pożyczyłem sobie Order i OrderItem do przykładu:).

Koncept jest następujący: mamy aplikację do składania zamówień na produkty. Zamówienie składa się z grup produktowych, a te składają się z produktów, jak na rysunku.

Dla uproszczenia załóżmy, że jest to aplikacja konsolowa. Właściciel oczekuje, że będzie pracował z aplikacją następująco:
Podaj identyfikator zamówienia: Paczka-E112
Podaj priorytet zamówienia: 1
Podaj nazwy grup produktowych: spożywcze chemia zabawki
Podaj ilość porduktów dla grupy 'spożywcze': 2
Dodaj produkt dla grupy 'spożywcze': sałata 2,45zł 2
Dodaj produkt dla grupy 'spożywcze': morele 6,79zł 1
Podaj ilość porduktów dla grupy 'chemia': 3
...


Startuję z następującym zestawem klas:
public class Order {
private String id;
private int priority;
private Set itemGroups = new HashSet();
}
public class ItemGroup {
private String name;
private Set items = new HashSet();
}
public class Item {
private String name;
private Money price;
private int quantity;
}


Za wykonanie zadania Dodawanie zamówienia, odpowiedzialną uczyńmy klasę:
public class UserInterface { 
private Set orders = new HashSet();
public void addOrder() {
// TOIMPL
} 
public static void main(String[] args) {
new UserInterface().addOrder();
}
}

W pierwszym podejściu kod, który działa, mógłby wyglądać na przykład tak:
public void addOrder() {
Scanner scanner = new Scanner( System.in );
System.out.print( "Podaj identyfikator zamówienia: " );
String orderId = scanner.nextLine();
System.out.print( "Podaj priorytet zamówienia: " );
int orderPriority = Integer.parseInt( scanner.nextLine() );
Order order = new Order( orderId, orderPriority );
System.out.print( "Podaj nazwy grup produktowych: " );
String[] itemGroupsNames = scanner.nextLine().split( " " );
for ( int i = 0; i < itemGroupsNames.length; ++i ) {
ItemGroup itemGroup = new ItemGroup( itemGroupsNames[ i ] );
System.out.print( "Podaj ilość produktów dla grupy '" + itemGroupsNames[ i ] + "' : " );
int itemsAmount = Integer.parseInt( scanner.nextLine() );
for( int j = 0; j < itemsAmount; ++j ) {
System.out.print( "Dodaj produkt dla grupy '" + itemGroupsNames[ i ] + "' : " );
String[] itemParams = scanner.nextLine().split( " " );
String itemName = itemParams[ 0 ];
Money itemPrice = Money.parseMoney( itemParams[ 1 ] );
int itemQuantity = Integer.parseInt( itemParams[ 2 ] ); 
Item item = new Item( itemName, itemPrice, itemQuantity );  
itemGroup.addItem( item );
}
order.addItemGrup( itemGroup );
}
orders.add( order ); 
}
Po pobieżny przyjrzeniu się temu rozwiązaniu, można zauważyć, że nastąpiło tu pewne pogmatwanie. Komunikowanie się z użytkownikiem (wyświetlanie komunikatów i odbieranie wpisanych danych) zostało zmiksowane z kodem biznesowym (budowanie zamówienia). W pierwszym zachwycie nad wzorce Builder mam ogromną ochotę go użyć! UWAGA jeśli przychodzi ci go głowy napisać klasę OrderBuilder z jedną metodą build mającą kilkanaście parametrów, to nie tędy droga. Wyszedł by z tego nie budowniczy ale jakieś fabrykoniewiadomoco. Wracając do tematu: wprowadźmy zatem ad hoc budowniczego (bo ponoć to dobra praktyka). Budowniczy ten mógłby wyglądać następująco:
public class OrderBuilder {
private Order order;
public void newOrder( String orderId, int orderPriority ) {
order = new Order( orderId, orderPriority );
}
public Order getOrder() {
return order;
}
public void addItemGroup( String name ) {
order.addItemGrup( new ItemGroup( name ) );
}
public void addItem( String groupName, String name, Money price, int qty ) {
ItemGroup group = order.findItemGroup( name );
group.addItem( new Item( name, price, qty ) );
}
}

Kluczowe pytanie: Czy ten budowniczy jest pomocny?

Już zerkając na kod budowniczego, można mieć wątpliwości. Właściwie nie robi nic ponad, enkaspulację wywołań konstruktorów oraz metod dodających. Ok, można go sobie mokować i dodawać nowe implementacje, ale zobaczmy jak wygląda kod, który użytkuje tego budowniczego:
public void addOrder() {
Scanner scanner = new Scanner( System.in );
System.out.print( "Podaj identyfikator zamówienia: " );
String orderId = scanner.nextLine();
System.out.print( "Podaj priorytet zamówienia: " );
int orderPriority = Integer.parseInt( scanner.nextLine() );
OrderBuilder builder = new OrderBuilder();
builder.newOrder( orderId, orderPriority );
System.out.print( "Podaj nazwy grup produktowych: " );
String[] itemGroupsNames = scanner.nextLine().split( " " );
for ( int i = 0; i < itemGroupsNames.length; ++i ) {
builder.addItemGroup( itemGroupsNames[ i ] );
System.out.print( "Podaj ilość produktów dla grupy '" + itemGroupsNames[ i ] + "' : " );
int itemsAmount = Integer.parseInt( scanner.nextLine() );
for( int j = 0; j < itemsAmount; ++j ) {
System.out.print( "Dodaj produkt dla grupy '" + itemGroupsNames[ i ] + "' : " );
String[] itemParams = scanner.nextLine().split( " " );
String itemName = itemParams[ 0 ];
Money itemPrice = Money.parseMoney( itemParams[ 1 ] );
int itemQuantity = Integer.parseInt( itemParams[ 2 ] ); 
builder.addItem( itemGroupsNames[ i ], itemName, itemPrice, itemQuantity );
}
}
orders.add( builder.getOrder() );
}
Jest tak samo brzydki jak był! Budowniczy nie wniósł znaczącego wkładu do tego kodu. Moim zdaniem interfejs budowniczego należy projektować z perspektywy klienta. Pisząc klient mam na myśli usługę, która akurat budowniczego będzie wykorzystywać - w tym przypadku jest to klasa UserIterface. Interfejs budowniczego powinien być wygodny dla klienta.

Krok 1: Dlaczego ItemGroup i Item trzeba dodawać pojedynczo?

Wcale nie trzeba...Przecież budowniczy może mieć metody, które przyjmą input, który przyszedł od użytkownika i samodzielnie go zinterpretuje. Pytanie: Czy czasem znów nie dojdzie do pomieszania warstw? Nie nie dojdzie. Przeanalizujmy odpowiedzialności poszczególnych klas:
  • Order, ItemGroup, Item - to model dziedziny, reprezentuje rzeczywistość
  • UserInterface - komunikuje się z użytkownikiem; odbiera od niego żądania (wpisy z konsoli) i przekazuje je do odpowiednich elementów niżej; prezentuje użytkownikowi wynik działania systemu
  • OrderBuilder - służy do złożenia zamówienia z mniejszych elementów
Zatem jeśli budowniczy może spokojnie przyjąć stringi podane przez użytkownika, a potem je zinterpretować. Dopóki budowniczy nie zacznie pisać na konsolę, to odpowiedzialność klas zostanie zachowana. Zobaczmy jak to mogłoby wyglądać:
public class OrderBuilder {
private Order order;
public void newOrder( String orderId, int orderPriority ) {
order = new Order( orderId, orderPriority );
}
public void addItemGroups( String itemsGroupsInput ) {
String[] itemGroupsNames = itemsGroupsInput.split( " " ); 
for ( int i = 0; i < itemGroupsNames.length; ++i ) {   
order.addItemGrup( new ItemGroup( itemGroupsNames[ i ] ) );
}
}
public void addItem( String itemParamsInput ) {
String[] itemParams = itemParamsInput.split( " " );
String groupName = itemParams[ 0 ];
ItemGroup group = order.findItemGroup( groupName );
Money price = Money.parseMoney( itemParams[ 1 ] );
int qty = Integer.parseInt( itemParams[ 2 ] );   
group.addItem( new Item( groupName, price, qty ) );
}
public Order getOrder() {
return order;
}
}
Jak widać budowniczy zmądrzał nieco, potrafi zrobić coś więcej niż proste dodawanie. A jak wygląda korzystanie z niego?
public void addOrder() {
Scanner scanner = new Scanner( System.in ); 
System.out.print( "Podaj identyfikator zamówienia: " );
String orderId = scanner.nextLine();
System.out.print( "Podaj priorytet zamówienia: " );
int orderPriority = Integer.parseInt( scanner.nextLine() );
OrderBuilder builder = new OrderBuilder();
builder.newOrder( orderId, orderPriority );
System.out.print( "Podaj nazwy grup produktowych: " );
String itemsGroupsInput = scanner.nextLine();
builder.addItemGroups( itemsGroupsInput );
String[] itemGroupsNames = itemsGroupsInput.split( " " );
for ( int i = 0; i < itemGroupsNames.length; ++i ) {
System.out.print( "Podaj ilość produktów dla grupy '" + itemGroupsNames[ i ] + "' : " );
int itemsAmount = Integer.parseInt( scanner.nextLine() );
for( int j = 0; j < itemsAmount; ++j ) {
System.out.print( "Dodaj produkt dla grupy '" + itemGroupsNames[ i ] + "' : " );
String itemParamsInput = scanner.nextLine();
builder.addItem( itemParamsInput );
}
}
orders.add( builder.getOrder() );
}
Choć nie idealnie to jednak jest nieco lepiej - metoda mieści się na jednym ekranie:)

Krok 2: Chodzenie po strukturze zamówienia

To, co nam bruździ to fakt, trze trzeba dodać Items do każdej z ItemGroup. Więc najpierw za pomocą OrderBuilder.addItemGroups tworzone są wszystkie grupy, ale jeszcze dodatkowo UserInterface przetrzymuje sobie jeszcze tablicę nazw grup produktowych, że by po nich przeiterować i dodać pozycje zamówienia. Wydaje się to trochę nienaturalne, ponieważ ta sama informacja jest przechowywana w dwóch różnych formach (String[] i Set) w dwóch różnych miejscach (UserInterface i OrderBuilder). Skoro chcemy tylko chodzić po wewnętrznej strukturze zamówienia (przesuwać się do kolejnych grup i dodawać produkty), to dlaczego nie wyposażyć budowniczego w tę możliwość. Niech budowniczy udostępni zestaw metod do chodzenia po grupach produktowych. Zobaczmy:
public class OrderBuilder {
private Order order;
private Iterator groupIterator; 
private ItemGroup currentGroup;
public void newOrder( String orderId, int orderPriority ) {
order = new Order( orderId, orderPriority );
}
public void addItemGroups( String itemsGroupsInput ) {
String[] itemGroupsNames = itemsGroupsInput.split( " " );  
for ( int i = 0; i < itemGroupsNames.length; ++i ) {   
order.addItemGrup( new ItemGroup( itemGroupsNames[ i ] ) );
}
groupIterator = order.getItemGroups();
}
public void addItem( String itemParamsInput ) {
String[] itemParams = itemParamsInput.split( " " );
String groupName = itemParams[ 0 ];
Money price = Money.parseMoney( itemParams[ 1 ] );
int qty = Integer.parseInt( itemParams[ 2 ] );   
currentGroup.addItem( new Item( groupName, price, qty ) );
}
public Order getOrder() {
return order;
} 
public boolean hasNextItemGroup() {
if ( groupIterator == null ) {
return false;
}  
return groupIterator.hasNext();
}
public void moveNextItemGroup() {
currentGroup = groupIterator.next();
} 
public String getCurrentItemGroupName() {
return currentGroup.getName();
} 
}
Natomiast korzystanie z budowniczego wygląda następująco:
public void addOrder() {
Scanner scanner = new Scanner( System.in ); 
System.out.print( "Podaj identyfikator zamówienia: " );
String orderId = scanner.nextLine();
System.out.print( "Podaj priorytet zamówienia: " );
int orderPriority = Integer.parseInt( scanner.nextLine() );
OrderBuilder builder = new OrderBuilder();
builder.newOrder( orderId, orderPriority );
System.out.print( "Podaj nazwy grup produktowych: " );
builder.addItemGroups( scanner.nextLine() );
while ( builder.hasNextItemGroup() ) {
builder.moveNextItemGroup();
System.out.print( "Podaj ilość produktów dla grupy '" +       builder.getCurrentItemGroupName() + "' : ");
int itemsAmount = Integer.parseInt( scanner.nextLine() );
for( int j = 0; j < itemsAmount; ++j ) {
System.out.print( "Dodaj produkt dla grupy '" + builder.getCurrentItemGroupName() + "' : " );
builder.addItem( scanner.nextLine() );
}
}
orders.add( builder.getOrder() );
}
Teraz już klasa UserInterface zajmuje się wyłącznie komunikacją z użytkownikiem, natomiast budowniczy zajmuje się składaniem zamówienia do kupy. Każda z klas zachowała swoją odpowiedzialność, a z używanie budowniczego rzeczywiście przynosi korzyści klientowi większe niż tylko enkapsulacja konstruktorów i dodawania do list. Dzięki wykorzystaniu budowniczego kod kliencki staje się prostszy i bardziej przejrzysty. Dla porządku trzeba dodać, że odpowiedzialność budowniczego została zwiększona. Potrafi on teraz również chodzić po strukturze zamówienia. Jest więc jednocześnie Iteratorem. Dalej warto metody iterator wydzielić do osobnego interfejsu, ale to już nieco inna historia.

Monday, July 11, 2011

Ogłoszenie: Będę w Gdańsku :)

Nawiązując do posta , na temat współpracy z BNS IT w charakterze Trenera/Konsultanta:

Będę w Gdańsku w dniach 12-13 lipca br. Jeśli mieszkasz w tamtych okolicach i masz ochotę porozmawiać o potencjalnej współpracy daj mi znać pod nr (wycięte,bo nieaktualne:)) lub moje_imię kropka moje_nazwisko na serwerze bnsit kropka pl.

Wednesday, July 6, 2011

Poza wzorcami projektowymi

To jest odległa kontynuacja artykułu Język wzorców.

Nie pamiętam już u kogo, ale wyczytałem, że jedną z przyczyn powstania wzorców projektowych, było rozwiązanie różnego rodzaju bolączek technologicznych albo bolączek konkretnych języków programowania. Zacząłem się nad tym zastanawiać. I tak:
  • Null Object - bo w C++ referencja musi być zainicjowana; wyeliminowane przez Java, C# (nieścisłość, @see Komentarz pod postem Chrisphera Daniela)
  • State - bo implementacja maszyny stanów oparta o tablicę wskaźników do funkcji oraz serię switch/case
  • jest dość trudna w utrzymaniu
  • Interpreter - jaki tam wzorzec;)? sposób na parsowanie ustrukturyzowanych gramatyk i tyle; wyeliminowane przez tony bibliotek narzędziowych
  • Flyweigh - bo nie ma kasy na więcej pamięci
  • Command - w C# wykoszony przez delegaty (mam na myśli ten kontekst użycia, w którym robimy execute(), a nie przechowujemy komendę, aby ją potem handle() )
  • Właściwie wszystkie wzorce opisane w Core J2EE Patterns i PoEAA - zastąpione przez biblioteki, frameworki i technologie


Czym zatem są wzorce projektowe? Mówi się, że rozwiązaniami typowych problemów. Rozwiązaniami, które wg Alexandra, można stosować za każdym razem nieco inaczej (nieco inna implementacja), ale otrzyma się poprawne rozwiązanie konkretnego problemu. W porządku - może postęp technologiczny modyfikuje tylko implementacje wzorców, lecz idea zostaje podobna. Może jednak nie - czy w wzorzec zamknięty w wszytywne API biblioteki wciąż jest wzorcem, czy tylko zwyczajnym narzędziem pomocniczym?

Jak powstają?
Skąd się biorą i jak powstają? Istnieją trzy elementarne zasady postępowania, które prędzej czy później doprowadzą do dobrego rozwiązania obiektowego:
Przestrzegaj opodwiedzialności
Jeśli nie potrafimy czegoś nazwać, to prawdopodobnie nie rozumiemy jak to działa. Nie znamy odpowiedzialności tego czegoś. W swoim kodzie dbaj o to, aby każda: zmienna, metoda, klasa, interfejs, pakiet, moduł miały określoną tylko jedną opodwiedzialność, która będzie wyrażona nazwą
Enkapsuluj
To, co podlega zmianom, powinno zostać opakowane (w metodę lub w klasę - w zależności od potrzeby). Enkapsulacja pozwala na łatwiejsze zarządzanie zmianą w kodzie. Nie mówiac już o testowaniu.
Preferuj kompozycję ponad dziedziczenie
Związki używania czynią kod bardziej elastycznym, czytelnym i testowalnym. Dodatkowo pozwalają na rozszerzanie funkcjonalności kodu run-time, a nie tylko poprzez przekompilowanie.


Jeśli przestrzegamy tych zasad, prawie na pewno powstanie dobry kod. Jest jeden warunek: trzeba stosować je bardzo skrupulatnie. Żadnego wkuwania nazw wzorców, diagramów, definicji, itd. Zamiast tego: żelazna dyscyplina w stosowaniu w/w zasad.

Wymienione reguły są dość niskopoziomowe, w całościowy proces ujmuje koncept, który nazwaliśmy roboczo Nautralnym porządkiem refaktoryzacji.
Koncept Nautralnego porządku refaktoryzacji


Pisał już o tym sporo Mariusz w artykułach: NPR - Idea rysunkowa, NPR - pod lupą, NPR: Compose Method, NPR: Extract Method, NPR: Refaktoryzacja do wzorców, NPR: Ewolucja architektury, więc nie będę się powtarzał.

Powtarzając konsekwentnie ten proces i stosując wspomniane już trzy metody, otrzymujemy naprawdę porządny kod. Zaczynają pojawiać się dobre rozwiązania. Dość często są to znane wzorce projektowe.

Morfizmy w kodzie
Zauważmy, że w charakterystyka wzorca projektowego zawiera między innymi Motywację/Intencję, Kontekst, Problem. Według definicji wzorzec to rozwiązanie problemu w danym kontekście. Ale przecież nieustanie zmienia się zarówno kontekst, jak i nasze zrozumienie problemu. Wszystko się zmienia!

Aktualne dobre rozwiązanie, które przywykliśmy nazywać wzorcem projektowym, jest tak naprawdę lokalnym optimum, jakieś funkcji (powiedzmy, że Funkcji kodu) w której zmiennymi są przynajmniej: Kontekst oraz Problem.

Tak zwany wzorzec rozwiązuje problem tylko na chwilę, dopóki Funkcja kodu nie ulegnie zmianie, a optimum nie wystrzeli w inną stronę. Mamy wiec do czynienia nie tyle z wzorcami, co z optymalnymi morfizmami w kodzie (niech, Ockham mi wybaczy). Zmiana Funkcji kodu, po której programując się ślizgamy powoduje, że dany morfizm przestaje być optymalny i musimy poszukać nowego optimum właśnie poprzez refaktoryzację.
Optymalne morfizmy


Wnioski
Czy poza gimnastyką umysłu wypływają stąd jakieś wnioski? Owszem, kilka.
  1. Istnieje nieskończenie wiele optymalnych morfizmów w kodzie - ponieważ zakres zmienności Problemów oraz Kontekstów jest również nieskończony; w związku z tym publikacje i dywagacje na temat nowych wzorców projektowych nigdy się nie skończą
  2. Refaktoryzacja musi trwać - ponieważ Funkcja kodu wciąż się przekształca, wciąż musimy poszukiwać optymalnych morfizmów; zaprzestanie tych działań spowoduje takie zniekształcenie tej funkcji, że znalezienie optymalnych morfizmów będzie niemożliwe i trzeba będzie ją wyrysować na nowo - czytaj napisać system raz jeszcze
  3. Ważniejsze jest zdyscyplinowane posługiwanie się wspomnianymi wyżej zasadami i procesem refaktoryzacji niż szastanie kolekcjami nazw wzorców
  4. Nie jest możliwe stworzenie czegoś takiego jak patterns language (por: On Patterns and Pattern Languages), bo optymalne morfizmy wciąż się przekształcają podążając za zmianami Funkcji Kodu

Monday, June 27, 2011

PEA(3): Wyodrębnianie user stories

To jest artykuł z serii Proces ewolucji architektury.

Po dość zgrubnym rozeznaniu się w środowiskowym kontekście systemu, jest czas na nieco więcej konkretów na temat funkcjonalności.

Część I - Przygotowanie


Dobór grupy
Do wyodrębnienia user stories świetnie nadają się spotkania focusowe. I ty pytanie z kim?
Najlepiej, aby grupa była różnorodna. Jednorodne grupy mają tendencję do "krzywienia" user stories. Na przykład programiści formułują je bardzo crudowo.

Aktorzy
Jeśli to możliwe, już na samym początku zidentyfikuj aktorów. Zadaj sobie pytanie Kto będzie wołał ten system?. W tym momencie masz już wstępnie rozpoznanych na następujących aktorów:
  • inne systemy - ponieważ poznałeś kontekst pracy systemu
  • użytkownik - na razie to dość ogólne sformułowanie, taki metaaktor, którego pojęcie będzie dokonkretyzowywać się w trakcie dalszych rozmów
  • dla porządku warto dorzucić jeszcze jednego: Time ; bojownicy o czystość UMLa mnie przeklną, ale wygodnie mieć tych aktorów dla spraw wyzwalanych czasem; jest to wygodne tylko i wyłącznie z tego powodu, aby nie bawić się w dodatkowe tabelki, gdy zajdzie potrzeba wysmarowania pięknego diagramu

Rysunek 1: Wstępny szkic aktorów w systemie
Wstępne nazwanie aktorów pomaga konkretnej zadawać pytania. Głównie o to tu chodzi. Konwencja nazewnicza Ustal ramową konwencję nazewniczą, zazwyczaj są dwie konkurencyjne alternatywy:
  • anglojęzyczna - działa proporcjonalnie do swobody językowej
  • polskojęzyczna - często jeden do jednego przekłada słownictwo binzesowe, ale w kodzie będą wychodzić zabawane pongliszowe kwiatki
Najkorzystniej jest promować taką konwencję nazewniczą, która zmienia jak najmniej przyzwyczajeń. Najczęściej słownictwo biznesowe jest zlepkiem z polskiego, angielskiego, a czasem i z innych języków i trudno je uspójniać. Zmiana organizacyjnej nowomowy trochę boli, ale przynosi niepomierne korzyści w postaci wzajemnego zrozumienia. Wypraktykowałem, że zamiast próbować udowadniać ludziom, że mają złe przyzwyczajenia, o wiele lepiej działa zadawanie pytań uwypuklające niejednoznaczność słownictwa. Na przykład: Co ma Pan na myśli mówiąc <<szkolenie>>. To <<program>> szkolenia, czy <<czynność>> prowadzenia szkolenia? Acha, rozumiem, czyli możemy mówić o szkoleniu <<możliwym do zorganizowania>> oraz <<zorganizowanym>> szkoleniu? Pułapką uspójniania słownictwa jest synonimia nomenklaturze organizacji. Śmiało można zaryzykować stwierdzenie, że każdy dział ma nieco inne nazwy na te same rzeczy i procesy.

Rysunek 2: różne nazwy na te same rzeczy, to jedna z większych trudności
Tego typu różnice dość szybko wychodzą, jeśli zadbasz o wspomnianą wcześniej różnorodność grupy. Kto nazywa ten rządzi Jak najszybciej ustalcie nazwę dla systemu. W przeciwnym razie, będziesz rozmawiać o oderwanych funkcjonalnościach, co sprawi, że zakres systemu będzie stale i nieograniczenie się powiększał. Najlepiej, aby nazwa wzięła się z rzeczywistości np.: kalendarz elektroniczny, aby występowała w informatyzowanym procesie. Łatwo wtedy eliminować wodotryski, zadając proste pytanie Czy dotychczas w kalendarzu również miał Pan możliwość dodawania awatarów? Nic nie mówiące i zbyt ogólne nazwy z kategorii Zintegrowany System Informatyczny, to otwarta furtka do wylądowania poza budżetem lub terminem lub oboma jednocześnie.

Część I - Prowadzenie sesji wyodrębniania user stories

Zasady ogólne Przed przystąpieniem do sesji wygodnie jest mieć jakiś szkic interfejsu użytkownika, żeby skupić uwagę osób. Jeśli ich nie ma to je rysuj. Rysowanie dobrze ogniskuje uwagę i często lepiej pozwala wyrazić myśli. Historycznie user storier spisywane są na małych kartkach. Powiedzmy sobie jednak szczerze, że arkuszem Excela o wiele lepiej się zarządza. Jak to zatem jest z tymi karteczkami? Z całego serca polecam karteczki (żółte, samoprzylepne :) ). Mają one tę wielką zaletę, że budują zaangażowanie interesariuszy. Osoby na spotkaniu są często przytłoczeni dużą liczbą obowiązków, nieco zmęczeni i teraz jeszcze muszą odbębnić z nami spotkanie. Mimo, że rzeczywiście chcą tego systemu, to nie chcą na niego poświęcać czasu - nielogiczne, ale prawdziwe. Jeśli będziesz zachęcać ludzi, aby sami pisali user stories na karteczkach i dodatkowo przyklejali je na fipcharcie, to "wciągną się" w spotkanie, będą bardziej kreatywni. Budując zaangażowanie, zwiększasz swoje szanse na wyodrębnienie rzeczywistych oczekiwań co do systemu zamiast ogólników, które czasem ktoś może chcieć Ci wcisnąć, żebyś tylko dał mu spokój. Zaangażowanie - to jest rzeczywisty cel karteczek. Rzecz jasna, że po spotkaniu możesz przepisać je do Excela, skoro w ten sposób łatwiej nimi zarządzać. Nie jestem fanem zbyt szybkiego wprowadzania narzędzi. Narzędzia (zwłaszcza takie, które narzucają swój proces pracy) częściej przeszkadzają niż pomagają. Fanom narzędzi chętnie polecam Scrum Do. Jest bardzo grywalne, zawiera wszystko co potrzeba, a jednocześnie jest kompletnie nieinwazyjne. Minusem jest to, że działa on-line. Formułowanie historyki Ogólny algorytm prowadzenia sesji wygląda tak:
  1. Ustal uwagę na pierwszym ekranie
  2. Zadaj pytanie: Co można zrobić na tym ekranie?
  3. Skłoń ludzi, aby sformułowali swoje oczekiwania w następujący sposób: Jako <<kto?>>mogę <<funkcjonalność>>, aby <<po co?>>
Struktura zdania, za pomocą którego formułujemy historyjki, jest bardzo chytra. Każda z części tego zdania ma swój ściśle określony cel. Przyjrzyjmy się jej bliżej.
  1. Jako <<kto?>> - tu konkretyzujemy aktorów (role); funkcjonalności nie są zawieszone w powietrzu; dzięki przyporządkowaniu historyjek do ról, łatwiej na późniejszym etapie ogarnąć zasady bezpieczeństwa dostępu do systemu
  2. mogę <<funkcjonalność>> - tu precyzujemy konkretną funkcjonalność, do której dany użytkownik ma mieć dostęp
  3. aby <<po co?>> - ta bardzo ważna część, pomaga użytkownikom uświadomić sobie potrzeby oraz problemy, które zamierzają zaspokoić i rozwiązać za pomocą tej funkcjonalności; dodanie tej części eliminuje sporo niepotrzebnych funkcjonalności, bo gdy ludzie zaczynają zastanawiać się po co coś będzie potrzebne, to czasem dochodzą do wniosku, że po nic
Ogólniki i szczególiki Podczas spisywania historyjek, możemy otrzymać efekt dwojakiego rodzaju:
konkretne user stories
np.: Jako U mogę zobaczyć listę swoich zamówień, aby wiedzieć co już otrzymałem, a czego jeszcze nie; do takich sformułowań zmierzamy podczas pracy z interesariuszami
niekonkretne user stories
np. Jako P mogę zarządzać dokumentami?; słowo "zarządzać" niewiele mówi o tym co właściwie należy zrobić, być może kryje się za tym jakiś ogromniasty epic;

Prawdopodobnie będziesz mieć chęć, aby drążyć niekonkretne historyki, gdy tylko użytkownicy je sformułują. Kłopot w tym, że prawdopodobnie oni sami jeszcze nie przemyśleli co to konkretnie ma być. Proponuję, by chwilowo zostawić je w spokoju. Zapisz je i wróć do nich później, już po sformułowaniu wszystkich user stories.

Dodatkowe porady
Podczas sesji ludzie spierają się o to, co właściwie ma robić dana rola i dość szybko zaczynają roztrząsać kwestie techniczne. Nie daj się wciągnąć w tę dyskusję, ucinaj ją natychmiast i prowadź spotkanie dalej. Na tym etapie eksploracja "w szerz" zamiast w "głąb" zagadnienia, pozwoli Ci szybciej przyswoić sobie wiedzę domenową.

Tego typu spotkania wygodnie jest prowadzić w dwie osoby. Jedna aktywnie moderuje rozmowę, druga nieco mniej zaangażowana zachowuje big picture i wkracza w razie kłopotów.

Thursday, June 16, 2011

Obiektowość dla embedded?

Często zdarza mi się wypełzać poza Javę, z której wyrosłem i ze zdziwieniem stwierdzam, że są inne obszary, w których ludzie mają podobne do naszych problemy i z utęsknieniem spoglądają w stronę gadżetów którymi dysponujemy.

Jakiś czas temu, konstruktywnie krytykując mój wpis, Sławek powiedział mniej więcej coś takiego: "Kto w obecnych czasach podaje w książkach przykłady w C++? Od razu widać, że old school"

Rzeczywiście, większość koncepcji związanych z: refaktoryzacją, TDD, clean code itd. nabrała obecnego kształtu w okół Javy i C# i ich community (tak, tak, pamiętam: Small Talk, C++, GoF - byli pierwsi :)). Jakby te języki były jedyne, dominujące, a inne to tylko marginalne ekstrawagancje. Zerknijmy na ten ranking. Jak widać Java i C# mają towarzystwo i to całkiem spore.

RTS, Entertainment
Mówię o systemach embedded, ale nie telefonach, grach i smartach, gdyż im (wg programistów embedded) bliżej raczej do PC-tów. Mówię o: systemach czasu rzeczywistego, systemach sterowania produkcją, oprogramowaniu obsługującym stacje bazowe w sieciach komórkowych, o komputerach pokładowych w samochodach, o sofcie który jest zainstalowany na naszych kartach kredytowych. Kto by pomyślał, że na takiej karcie jest procesor, a na nim system operacyjny, a na nim dziarsko działa maszyna wirtualna Javy? (@see Java Card)

C rządzi!
We wspomnianych wyżej domenach często króluje język C. Po pierwsze z powodów historycznych - ktoś zaczął pisać w C i tak już zostało.

W miarę rozrostu tego typu systemów, pojawiają poważne problemy z ich utrzymaniem. Miliony wierszy kodu, gęsto pociętych przez dyrektywy kompilatora, kompilacje warunkowe, ifdefy, makra tam, gdzie to tylko możliwe oraz specyficzny sposób oszczędnego nazywania zmiennych zdecydowanie utrudniają rozwijanie tego kodu. Te problemy powodują, że środowisko embedded coraz częściej rozgląda się za podejściem obiektowym, które pomoże tworzyć łatwiejszy w utrzymaniu kod. Napotykają jednak na pewne przeszkody, które budują przekonanie, że obiektowość nie jest dla embedded. Zebrałem nieco informacji nt. tych przeszkód. Niektóre z nich są rzeczywiscie zaskakujące, inne to raczej przekonania.

Brak kompilatorów
Do pewnego momentu nie było zwyczajnie technicznej możliwości skomplikowania kodu. Jeśli już jakieś istniały, to były tak zabugowane, że dyskwalifikowały się same przez się. Sytuację poprawił gcc, który popchnął sprawę nieco do przodu.

Koszt wejścia
O ile maszyna wirtualna Javy jest dla PC-tów darmowa, to za wersję na embedded trzeba płacić grube pieniądze. Doświadczenia zaprzyjaźnionych firm pokazują, że ta implementacja JVM jest koszmarnie wolna. Istnieją sprzętowe implementacje (tak! sprzętowe) maszyny wirtualnej, ale niewiele o nich wiem.

Niedoskonałość sprzętu
W porównaniu do procesorów z kategorii ix86, procesory dla systemów wbudowanych są dość proste (tylko w porównaniu :)). Pisząc usługę EJB nie zastanawiamy się, czy aby procesor działa poprawnie, czy nie będzie błędu w działaniu urządzenia. W aplikacjach embedded niedoskonałość sprzętu jest częstym kłopotem.

Trudności w poszukiwaniu błędów
Tak powszechne zadanie jak poszukiwanie błędów również może nastręczać trudności, gdyż odbywa się to poprzez debugowanie oraz analizę kodu asemblera. Taka analiza jest zdecydowanie łatwiejsza dla kodu napisanego w C niż w C++.

Koronny argument - wydajność
Hmmm, trochę prawda, trochę mit. Tak myślę. Przeanalizujmy.

Po pierwsze:
Jak wspomniałem JVM jest rzeczywiście wolna. Z drugiej strony istnieje przekonanie, że kod napisany w C++ będzie działa duuuuużo wolniej. Tylko czy ktoś to rzeczywiście zmierzył? Czy ktoś napisał dwie tożsame implementacje, jedną w C, drugą w C++ i stwierdził to jednoznacznie?

Po drugie:
Przyczyną mogą być ograniczenia programowe i sprzętowe. Sporo zależy od tego jak jest napisany sam kompilator, czy potrafi wykorzystywać automagiczne sztuczki optymalizacyjne. Innym i często skutecznym sposobem zwiększania wydajności jest zmiana sprzętu. Ten jednak przenika do branży dosyć wolno. Powód jest trywialny - koszty. Nowy sprzęt - większe pieniądze, kolejny kompilator, kolejne bugi itd.

Po trzecie:
W rozwiązaniach embedded rzadko kiedy brakuje np. 5%, 10%, 20% wydajności. Jeśli już trzeba zwiększyć wydajność, bo powiedzmy, nie nadążamy z pomiarem temperatury pieca i grozi wybuchem, to trzeba ją zwiększyć kilkukrotnie. W takim przypadku obniżenie wydajności o parę, paręnaście procent, w związku z konstrukcjami obiektowymi, jest do przyjęcia. Jeśli efektem tego narzutu będzie łatwość utrzymania i rozbudowywania dylemat jest wart uwagi. Tak doszliśmy to wysłużonego już hasła: czytelność ponad wydajność. Nie oznacza to bynajmniej nonszalancji w szafowaniu pamięcią, lecz to aby w pierwszej kolejności koncentrować się na tworzeniu czytelnego kodu, a dopiero w drugiej mierzyć, profajlować i optymalizować.

Co dalej?
Jakie wyzwania stoją przed technikami refaktoryzacji i wzorcami, które w swoim najbardziej światowym wydaniu, utknęły gdzieś pomiędzy Javą a C#?
  • Jak pracować z hybrydowym legacy code, pisanym trochę w C trochę w C++?
  • Jak bezpiecznie przepisywać kod proceduralny na obiektowy?
  • Jakie standardy kodowania przyjąć dla C++, aby uniknąć pułapek wynikających z bogactwa języka
  • Jak sensownie rozwinąć narzędzia wspierające refaktoryzację. Sorki, ale VC++ i wsparcie dla refaktoryzacji to porażka. Visual Assist X jest super, ale to jeszcze nie to. Eclipse C/C++ nie próbowałem, Wind River Workbench jest ponoć dobry, ale i kosztuje słono
  • i cała reszta bajerów, których się w okół Javy i C# dorobiliśmy

Za różnymi problemami oraz przekonaniami kryją się ludzie, którzy poszukują skutecznych rozwiązań swoich problemów. Na pewno coś da się zrobić.

Thursday, June 9, 2011

Value Stream i zarządzanie wymaganiami w korporacji

Małe firmy często opracowują własne efektywne procesy. Programiści i analitycy z jednej z zaprzyjaźnionych firm sami wymyślili Scruma. Serio! Wpadli na dosłownie wszystkie scrumowe praktyki i przestrzegali ich z pedantyczną dokładnością. Co ciekawe, wcale nie uważali, że zrobili coś nadzwyczajnego. Ot, zwykłe zdroworozsądkowe podejście. Kompletnie inaczej jest w korporacjach.

Podczas warsztatów z zarządzania wymaganiami największy challenge mam z pracownikami departamentów IT w korporacjach. Złożoność organizacyjna rodzi kilka dodatkowych problemów.

Hipertraceability
Pisałem na ten temat tutaj. Nie dajmy się zwieść, że pragnienie hipertraceability jest potrzebą organizacji. Nie jest to potrzeba lecz rozwiązanie problemu związanego z bałaganem w wymaganiach. Rozwiązanie to daje złudzenie, że wszystko jest pod kontrolą. Zazwyczaj nie jest.

Wstrzymałbym się chwilowo ze skłanianiem się ku temu rozwiązaniu dopóki dokładnie nie zrozumiemy natury problemu. (tak tak wiem, focus on solutions, not on problems; ale czy można zaproponować rozwiązania nie rozumiejąc problemu? - moim zdaniem nie).

Niech nieco światła na problem zarządzania wymaganiami w korporacjach rzuci parę poniższych akapitów.

Time to market
To, że prace programistyczne rozpoczynają się rok po zebraniu wymagań, to norma. Niestety przez ten czas, konkurencja poszła do przodu, priorytety się zmieniły i zebrane wymagania są (delikatnie mówiąc) średnio przystające do rzeczywistość. Szkoda jednak tracić zabukowane mendejsy, więc parce wrą. Co prawda dzieje się co innego niż pierwotnie planowano, ale dzieje się!

Harmonogram wdrożeń i rezerwacja mendejsów
W organizacji systemów jest od groma i jakość trzeba nad nimi zapanować. Więc w trosce o jak najlepszą organizację prac definiuje się harmonogram wdrożeń. Harmonogram jak harmonogram musi być rygorystycznie przestrzegany, więc jeśli projekt nie wstrzeli się w swój termin, to czeka na następny termin (zatem ewentualna obsuwa nie jest ciągła lecz dość grubo skwantyfikowana).

Ponieważ projekty konkurują ze sobą o miejsce w harmonogramie wdrożeń, a Biznes ma wskaźniki do osiągnięcia, więc przezornie rezerwuje sobie miejsce dwa lata w przód na Jakiś Bardzo Ważny Projekt. Dla uzasadnienia rezerwacji, odbywa się nawet zbieranie wymagań. Jest to jednak sprytny wybieg taktyczny mający na celu zaalokowanie zasobów Departamentu IT "na wszelki wypadek".

Pigułka: Nowy System
Nowe potrzeby = nowy system. Rzesza programistów podejmuje trud stworzenia czegoś nowego, co powiela część funkcjonalności z już istniejących systemów. Jasne, że ktoś powinien pójść po rozum do głowy i wyłożyć co jest grane. Ale kto?: Główny Architekt, Enterprise Architect, Architekt Funkcjonalny, Architekt Systemowy, System Designer, Backend System Designer ???

Mimo szczegółowej procedury decyzyjnej oraz masy zebrań, komitetów, analiz i opinii, powstaje pięćset szósty system, który sprawia, że:
  • potrzeba kolejnego etatu do jego utrzymania,
  • SOA staje się naprawdę jedynym sensownym rozwiązaniem,
  • skomplikowanie procedur organizacyjnych dąży do nieskończoności,
  • końcowi użytkownicy ze starymi przyzwyczajeniami próbują korzystać ze starego systemu na nowy sposób i klną na czym świat stoi.


Paraliż decyzyjny
Wyobraźmy sobie następującą, powiedzmy, że hipotetyczną, sytuację:
  • Komitet sterujący projektu IT składa się z: Prezesa oraz członków Zarządu
  • Komitet spotyka się z Kierownikiem Projektu, aby podjąć decyzję o zmianie harmonogramu tworzenia projektu

Rozmowa przebiega następująco:
  • Kierownik: Czy zmieniamy harmonogram?
  • Prezes: Zmieniamy?
  • Członkowie Zarządu: hmm...
  • Prezes: Tak! Zmieniamy!
  • Kierownik: A zatem wpisuję w protokole: "Komitet sterujący podjął decyzję o zmianie harmonogramu"
  • Prezes: Zaraz, zaraz...Jaką decyzję? Proszę napisać: "Komitet sterujący rekomenduje zmianę harmonogramu". Niech zostanie to zatwierdzone na zebraniu Zarządu.

yyyyy????

Obosieczny miecz standardów
Buy, don't write Wiele kawałków systemu, można kupić taniej niż wykonać. Wiele kawałków do wykonania, można szybko napisać w konkretnych technologiach, bibliotekach, itp. Ale stop! W organizacji standardem jest technologia X i kropka. Z jednej strony ma to sens (na przykład finansowy), z drugiej jest pewnym marnotrawstwem zasobów.

Zmęczony Biznes znajduje drogę na skróty
Ponieważ biznes napotyka powyższe trudności w dogadaniu się z Departamentem IT, radzi sobie w sprytny sposób - zatrudnia jednego lub dwóch programistów we własnym dziale, na własny koszt.

W pewnej firmie jeden z takich "partyzanckich" programistów, w krótkiego czasu naskrobał w pehapie CRM, który zrobił sporą furorę w organizacji. Dostarczał dokładnie takich funkcjonalności jakich było potrzeba. Jak powiedział jeden z programistów z Departamentu IT: ktoś tam siedział, słuchał biznesu i zrobił. Oczywiście CRM był na bakier z: harmonoramem wdrożeń, bezpieczeństwem testami i stosem innych procedur, aczkolwiek miał podstawową zaletę: adresował wszystkie potrzeby Biznesu.

Problem z takim "kukułczym jajem" jest taki, że Departament IT nie chce go tknąć, bo: "nie mamy kontroli nad opensource'owymi bebechami i jak coś się stanie to będzie na nas". Dodatkowo między Biznesem a IT rośnie napięcie ponieważ estymacje Departamentu IT są kilkukrotnie większe niż programisty-partyzanta.

Value Stream
Ktoś kiedyś napisał bądź powiedział: "Informatyzacja efektywnego procesu zwielokrotnia jego efektywność. Optymalizacja procesu nieefektywnego zwielokrotnia jego nieefektywność".

W powyższych przykładach organizacja sterowana jest procedurami, brak jest zorientowania na wartość biznesową. Jasne, że są plany, wskaźniki itd. Ale czy opisane sytuacje nie wskazują, że wartość biznesowa zniknęła gdzieś między procedurami? Brakowało zdefiniowania strumienia wartości biznesowej, czyli zoptymalizowanego procesu zarabiania pieniędzy.

Tajemniczy Dział Optymalizacji Procesów
Organizacje mają świadomość opisanych sytuacji. Jednym ze sposobów jest powoływanie do życia Tajemniczego Działu Optymalizacji Procesów (ew. zatrudniania do tego kosztownych konsultantów). Dział ów to kilka osób, zamkniętych w malutkim pokoiku, które co jakiś czas
objawiają Organizacji nowe i ulepszone procedury. Nie tędy droga, ponieważ procedury procedurami, a ludzie ludźmi. Formalizowanie i standaryzowanie jest ok i przynosi wiele korzyści, ale zaangażowanie i orientacja na wartość biznesową przynosi ich więcej. Trudno mi w tej chwili podać konkretny przepis na to co z tym fantem zrobić. Temat w inkubacji.

Jako zajawkę w pokrewnej tematyce polecam prezentację. (nie wiem ile powisi, więc kiedyś link może się zdezaktualizować)

Tuesday, June 7, 2011

Jak wykorzystać swoje doświadczenie i jeszcze wiele się nauczyć?

Jako że nasza działalność (BNS IT http://www.bnsit.pl) nabiera coraz większego rozmachu, pojawia się miejsce dla osób, które są chętne, aby pracować z innymi w celu dzielenia się wiedzą i doświadczeniem oraz chcą wspierać zespoły w zwiększaniu efektywności pracy.
Zatem jeśli masz doświadczenie praktyczne w pracy na projektami programistycznymi, jesteś kompetentny w PRZYNAJMNIEJ W JEDNYM z następujących obszarów:
- wzorce projektowe
- dobre praktyki pracy z kodem (refaktoryzacja, czysty kod, obiektowość (SOLID, GRASP, interfejsy))
- test-driven development
- domain-driven design
- scrum (agile)
- komunikacja w zespole (w kontekście projektów programistycznych),
- zarządzanie czasem dla programistów,
- zarządzanie projektami,
- zarządzanie wymaganiami, analiza.

Ważna jest wiedza i doświadczenie projektowe, co do warsztatu trenera, jesteśmy w stanie odpowiednio do tego przygotować.

Jesteśmy głównie zainteresowani stałą współpracą. Aczkolwiek ewentualnie opcja współpracy od czasu do czasu też wchodzi w grę.

Pisz śmiało: m [kroppka] bartyzel [mauppa] bnsit [kropkka] pl

Friday, June 3, 2011

Grunt, to prostota

Dostałem ostatnio grę edukacyjną dot. szybkiego czytania. Tak się podekscytowałem nową zabawką, że aż straciłem nad nią kontrolę. Było to tak:

czwartek: Dostałem zestaw płytek. Zaraz po szkoleniu pobiegłem do hotelu i pierwsze co zrobiłem, to szybko rozpakowałem CD1 i chcę uruchamiać.
Nie idzie. Zorientowałem się, że zmieniłem notebooka na mniejszego i nie mam CD.

piątek 16.30: Ciągle myślę o nowej grze. Znam już na pamięć instrukcje i teksty z okładki. Już bym pograł, a tu jeszcze parę godzin podróży z Wrocławia. Wykombinowałem, że wezmę laptopa żony, zgram zawartość płytki, przekopiuję na swojego nooteboka i już. Zaraz potem pomyślałem, że pewnie taka gra zajmuje sporo miejsca i potrzebuje płytki do rozruchu. Wpadłem więc na pomysł, że na drugim laptopie zrobię obrazy, które potem przegram i podmontuję u siebie. Genialne!

piątek 22.00: Znalazłem darmowy program do emulowania napędu DVD. Odpalam Nero...hmm moja wersja robi tylko obrazy *nrg. Obrazów ISO nie robi. Ściągam inny program, który robi już obrazy ISO.
Już miałem kliknąć, ale program informuje mnie, że ma własny bardziej skompresowany. format zapisu obrazów i że ISO jest do bani. Googluję. Ok, więc dla testu przygotowałem dwa różne obrazy: ISO i ten drugi: różnica w rozmiarze = 2MB. Zdecydowałem się jednak na ISO.

piątek 23.50: Obrazy gotowe idę spać.

sobota 13.00: Obrazy mają ponad 4GB. Na mojego pendrive nie wejdą. Szlag! Spróbuję udostępnić pliki poprzez sieć.

sobota 13.45: Dwa Win7 za nic w świecie nie chcą się zobaczyć przez sieć. Powyłączałem wszystkie antywirusy, zapory, filtry i takie tam. Nic. Wygooglałem, że z moim routerm WiFi jest coś nie tak i nici z udostępniania. No trudno. Wystawię przez FTP.

sobota 14.15: Też lipa. Nagle mnie olśniło. Mam dysk zewnętrzny! Przekopiuję na dysk a potem do siebie.

sobota 14:17: No tak. Kiedyś chciałem się łączyć z tym dyskiem przez WiFi i producent zmusił mnie do sformatowania go jako FAT32. Przygotowane ponad czterogigowe obrazy tam nie wejdą. (Zaczynam żałować, że zająłem się informatyką. Gdybym znał tylko ofisa oraz guziki power i reset, to bym komuś za to zapłacił i miałbym z głowy, no trudno).
Podjąłem męską decyzję: przekonwertuję dysk na NTFS i po kłopocie. Google mówi, że polecenie winda ma wbudowane polecenie convert i po kłopocie.

sobota 16.00: Polecenie convert zgłasza błędne sektory dysku, co uniemożliwia konwersję. W eleganckim komunikacie zapewnia mnie, że po wykonaniu polecenia chkdsk będzie ok.

No więc wykonuję polecenie chkdsk, które raportuje błędy i pyta czy naprawić? No, pytanie! Naprawiam. Znów odpalam convert. I znów lipa. Nie można przekonwertować z powodu błędów. Partition Magic napewno sobie poradzi! (żona zaczyna domagać się zwrotu laptopa, jeszczę chwilunia)

sobota 16.30: Sciągam Partition Magic. Odpalam, wybieram partycję, konwertuj na NTFS, ok.....Partition Magic odpala program convert! Efekt do przewidzenia. Grrr!!!!!

sobota 17.00: Po chwili poszukiwania ściągam Norton Disk Doctor. Teraz już będzie ok! Zaznaczam autofix Disk Doctor leniwie rozpoczyna naprawę niemal terabajtowego dysku. Dla uspokojenia tematu poszliśmy z żoną na zakupy.

sobota 21.13: Wciaż naprawia...

sobota 23.40: Dalej naprawia...

niedziela 9.07: Naprawił. Odpalam convert. AAAaaaaaaaaaa!!! Wciąż to samo. Googluję, googluję, googluję. Mam! mój dysk ma ustawiony dirty bit i stąd te kłopoty. Znalazłem jakieś polecenie windozy, które sprawdza ten dirty bit. Odpalam - brak praw do wykonania operacji.

Olśniło mnie, wszystie poprzednie sztuczki nie działały bo programy nie wprowadzały zmian na dysku z powodu braku uprawnień. Tylko dlaczego o tym nie informowały? Tajemnica.

niedziela 11:30: Odpaliłem konsolę na prawach administratora i chkdsk a potem convert. Robi się.

niedziela 12.00: Taaak! Przekonwertowane. Przegrywam obrazy, montuję, instaluję, działa. Na wszelki wypadek sprawdzam rozmiar danych na płytce: 154 MB....!@#*&Y#*! Dlaczego nie robiłem tego na początku?

Wnioski


Chwila refleksji nad moją przygodą, która do złudzenia przypomina mi sytuację, których doświadczam podczas prac programistycznych.

Błąd 1: Brak planu
Nie przygotowałem się do akcji. Nie określiłem jakie działania podejmę - robiłem wszystko jak leci. Nie ustaliłem czasu, który mogę przeznaczyć na to zadanie. Wszystko, co robiłem było totalnie nieuporządkowane.

Błąd 2: Zosia Samosia
Plusem i minusem jednocześnie programistów jest kompetencja. Cokolwiek jest związane z IT potrafimy się w tym odnaleźć. Napisać program - ok!, Postawić sieć - no problem!, poskładać komputer - pewnie! Ponieważ, czujemy się kompetentni w niemal całej branży i mamy feeling jak się zabrać do większośći tych rzeczy, to niechętnie prosimy o pomoc. Ignorujemy zasadę buy, don't write.

Błąd 3: Brak feedbacku
Podejmowałem coraz to nowe działania, mające dość znaczny wpływ na stan mojego przedsięwzięcia, bez rozważania neatywnych konwekwencji. Działałem na chybił-trafił.

Błąd 4: Ignorowanie intuicji
Pierwsza myśl była dobra. Mogłem przynajmniej sprawdzić, czy to zadziała.

KARDYNALNY Błąd 5: Brak koncentracji na wartości biznesowej
Koncentrowałem się na rozwiązywaniu lokalnych problemów technicznych. Już na samym początku zapomniałem o gównym celu tego przedsięwzięcia, czyli: zagraniu w grę edukacyjną. Żadne z moich działań nie dodawała wartości biznesowej. To był marsz ku klęsce.

Wednesday, April 20, 2011

Gadżety Javy

Jeszcze parę lat temu mówiło się, że Spring i EJB wcale ze sobą nie konkurują. Każde z nich miało swoje obszary zastosowań, w których się sprawdzało, a drugiemu nie wchodziło w paradę. Wyhodowany na bolączkach EJB2 Spring Framework, rozwijany przez genialnych programistów z Interface21, świadomie pozbawiony był nadmiarowych bajerów EJB, przez co wypełnił tą niszę, w której potrzeba było minimalistycznego kontenera.

Z biegiem czasu dochodziły coraz to nowe dodatki: kolejne moduły, kolejne podprojekty, własny serwer aplikacji, SpringSource ToolSuite. Czy wciąż Spring i EJB mają swoje obszary stosowalności? Czy może stały się nawzajem dla siebie alternatywami? Porównajmy:

SpringFrameworkEJB3.*
bierzesz, co chcesz; w razie potrzeb dokładasz kolejne modułybierzesz wszystko albo nic; klejony na siłę koncept profili moim zdaniem tak bezsensowny, że nawet nie warto się rozpisywać
częste wydaniaw bólach i na drodze kompromisów rodząca się specyfikacja jest sporo w tyle za nowinkami ze świata OpenSource
nastawiony na bezinwazyjne sklejanie fragmentów aplikacji oraz na integrowanie się z bibliotekami i frameworkami, które już istnieją i dobrze się sprawdzająmityczna przenośność aplikacji pomiędzy serwerami
staje się coraz cięższy; może nie sam kontener ale włączając kolejne ficzery robi się coraz ciężejzmierz w stronę odchudzania (JPA poza kontenerem, koncept profili)
Projekt OpenTerracotta spierający skalowanie aplikacji opartych o Springakontener EJB dostarcza możliwości skalowania aplikacji
można tworzyć aplikacje wielowątkowezakaz własnoręcznego korzystania z wątków; wątkami zarządza wyłącznie kontener
brak standardu dot. zarządzania aplikacją; istnieją projekty SpringSource dedykowane do tego celuspójny sposób zarządzania aplikacją


Okazuje się, że Spring wsparty bibliotekami zewnętrznymi potrafi zapewnić dokładnie te same funkcjonalności, że EJB. Być może jeszcze jedną różnicą jest to, że w przypadku Spring trzeba dokładnie wiedzieć jaki efekt chce się uzyskać, gdyż oferuje on bogactwo różnych opcji na rozwiązanie tego samego problemu i trzeba wiedzieć, która jest najodpowiedniejsza dla naszego projektu. W przypadku EJB, mamy wszystko out of the box.

Kontynuując tyradę narzekania
Kontynuując tę tyradę narzekanie trzeba wspomnieć jeszcze wiele genialnych frejmłorków i bibliotek, które świetnie wyglądają w 10 minutes tutorial, rozwiązują parę problemów i wprowadzają szereg nowych.
Wymieniam parę wad:

JSFciężkie drzewo komponentów, pokręcony mechanizm renderowania; wersja 1.2 - toporna i wymagająca paru dodatków, aby sensownie pracować; wersja 2.0 - niby fajnie ale poużywamy-zobaczymy; RichFaces 4.0 wspierajace JSF 2.0 już jest
JPAwolno rozwijająca się specyfikacja, plus wszystkie wady O/RMów
GWTdostawca monopolista, ciężki klient, brak standardu, po stronie widoku obsługiwana jest tylko część maszyny wirtualnej
Struts2"prawie" wsparcie dla Ajaxa, koszmarne adnotacji
Spring WebFlowfajny, gdy GUI ma charakter procesowo-kreatorowy, poza tym przerost formy nad treścią
Oracle ADFw tutorialach genialny, w użyciu prowadzi do prawie takiego samego bałaganu w kodzie jak przy bezmyślnym klikaniu w Borland Delphi Buildera

Co zamiast w/w?
Jakie mamy zatem mamy alternatywy? Co można używać zamiast powyższych rozwiązań. Spotkałem się z następującymi konfiguracjami:
  • Stripes + dojo + Hibernate - wychodzimy z założenia, że nie ma co liczyć na automagiczne ajaxy i jeśli chce się mieć fajne GUI to trzeba w JavaScript popracować
  • Freemarker + SpringMVC + myBatis - całkowita rezygnacja z JSP oraz pogodzenie się z faktem, że schemat bazy jest czasem tak prosty, że nie ma co przekombinowywać
  • Oracle Forms, PowerBuilder - w architekturze dwuwarstwowej
  • PHP - tak po prostu... to o wiele bardziej dojrzała technologia, niż jawowcom może się wydawać, mają nawet swoje automagiczne frejmłorki


Do czego właściwie nadaje się się JEE
Nie chcę za bardzo wyrokować, ale JEE rozważałbym wtedy, gdy...nie ma innego wyjścia, gdy z powodów historycznych (zastany stan systemu), ludzkich (umiejętności programistów) albo politycznych trzeba się decydować na tą konkretną technologię. Bardzo, ale to bardzo byłbym ostrożny, przy rozważaniu JEE dla aplikacji webowej. Dzisiaj jestem zdania, że do aplikacji strice webowych (i nic ponad to) JEE się nie nadaje: zbyt wolne, zbyt kosztowne (chociażby ze względu na wynagrodzenia programistów).

Do czego się nadaje. Oprócz wymienionych na wstępie powodów można jeszcze dorzuć szeroko rozumiany backend przy tworzeniu dużych i długotrwałych projektów o bogatym modelu - wtedy można doszukiwać się korzyści w inwestowaniu w JEE.



P.S. Wpis wyraża prywatne myśli autora, a autor nie zarzeka się, że myśli tych kiedyś nie zmieni:)