<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-1759916214638009707</id><updated>2012-01-25T15:34:31.832+01:00</updated><category term='wizje'/><category term='embedded'/><category term='antywzorce'/><category term='analiza'/><category term='ddd'/><category term='pea'/><category term='wydarzenia'/><category term='agile'/><category term='zarządzanie'/><category term='orm'/><category term='dsl'/><category term='refaktoring'/><category term='praca z klientem'/><category term='tdd'/><category term='wzorce'/><category term='efektywność'/><category term='książki'/><category term='info'/><category term='rozwój'/><category term='code review'/><category term='architektura'/><title type='text'>Touching the Void</title><subtitle type='html'>O czym jest ten blog? O tworzeniu oprogramowania, o zarządzaniu projektami IT, o efektywności programistów, o zespołach programistycznych. 
&lt;br&gt;&lt;br&gt;
Zazwyczaj spisywany wieczorami w hotelach, po całodniowej wizycie u klienta, ma raczej charakter odręcznych notatek. Rezerwuję sobie więc prawo do luźnego stylu, braku precyzji, zaśmiecania języka polskiego i ewentualnej późniejszej zmiany zdania:)
&lt;br&gt;&lt;br&gt;

&lt;em&gt;Albo odnajdziemy drogę albo ją zbudujemy&lt;/em&gt;,&lt;b&gt;Hannibal&lt;/b&gt;&lt;br&gt;</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://mbartyzel.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://mbartyzel.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Michał Bartyzel</name><uri>http://www.blogger.com/profile/03968505875451301931</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>65</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-1759916214638009707.post-7151575322116725492</id><published>2011-11-29T00:16:00.001+01:00</published><updated>2011-12-01T15:10:42.567+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='architektura'/><category scheme='http://www.blogger.com/atom/ns#' term='ddd'/><title type='text'>Bounded Context</title><content type='html'>Jasne, że nie będę od teraz pisał o &lt;a href="http://domaindrivendesign.org/resources/what_is_ddd"&gt;DDD&lt;/a&gt;, bo już &lt;a href="http://ddd-cqrs-leaven.blogspot.com/"&gt;inni&lt;/a&gt; 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) &lt;a href="http://domaindrivendesign.org/resources/what_is_ddd"&gt;DDD&lt;/a&gt; to na wstępie proponuję:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Pierwszą część książki: &lt;a href="http://domaindrivendesign.org/books/evans_2003"&gt;Domain Driven Design&lt;/a&gt; &lt;/li&gt;&lt;li&gt;albo &lt;a href="http://art-of-software.blogspot.com/search/label/Domain%20Driven%20Design"&gt;po polsku&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;h3&gt;O jakim problemie mowa?&lt;/h3&gt;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:&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-wCx5CpLzBVo/TtQZgIIJJAI/AAAAAAAAA5I/H3VbZNU6UJU/s1600/Przechwytywanie.PNG" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="108" width="400" src="http://4.bp.blogspot.com/-wCx5CpLzBVo/TtQZgIIJJAI/AAAAAAAAA5I/H3VbZNU6UJU/s400/Przechwytywanie.PNG" /&gt;&lt;/a&gt;&lt;/div&gt;Jest to jakaś interakcja pomiędzy obiektami w dziedzinie.&lt;br /&gt;&lt;br /&gt;Gdy zaczynamy modelować, naturalnie pojawiają się klasy takie jak: &lt;i&gt;Zamówienie, Koszyk&lt;/i&gt;, 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:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;W związku z kolejnymi wymaganiami, do obiektów dochodzi coraz więcej atrybutów i metod&lt;/li&gt;&lt;li&gt;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&lt;/li&gt;&lt;li&gt;Niektóre obiekty są używane w tak wielu miejscach systemu, że jakakolwiek w nich zmiana ma spore skutki w innych odległych miejscach&lt;/li&gt;&lt;/ul&gt;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.&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-hVRgwBrMEW8/TtQfIDAenwI/AAAAAAAAA5U/ZwSjyzMTdzc/s1600/Przechwytywanie.PNG" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="167" width="400" src="http://1.bp.blogspot.com/-hVRgwBrMEW8/TtQfIDAenwI/AAAAAAAAA5U/ZwSjyzMTdzc/s400/Przechwytywanie.PNG" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Niby wszystko zostało przygotowane zgodnie z regułami sztuki, ale jednak wszyscy czują, że coś śmierdzi...tylko nie wiadomo z jakiej przyczyny.&lt;br /&gt;&lt;br /&gt;Powód jest taki, że ten sam obiekt modelu używany jest wielu różnych kontekstach. &lt;i&gt;Zamówienie&lt;/i&gt; wynikające z interakcji użytkownika z &lt;i&gt;Koszykiem &lt;/i&gt;jest nieco inną sprawą niż &lt;i&gt;Zamówienie&lt;/i&gt; realizowane przez magazyn.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;&lt;i&gt;"Bounded context should have a name so that you can talk about them"&lt;/i&gt;&lt;/h3&gt;Rację mieli starzy Indianie, gdy twierdzili, że jeśli poznasz czyjeś imię, zyskujesz nad tym kimś władzę. Nie inaczej jest z &lt;i&gt;bounded contexts&lt;/i&gt;. 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ą &lt;i&gt;big ball of mud&lt;/i&gt;.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Jeden model w jednym kontekście&lt;/h3&gt;W związku z dokonanymi odkryciami warto zalecać:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;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ą).&lt;/li&gt;&lt;li&gt;&lt;b&gt;Jeden model może być wykorzystywany tylko w jednym kontekście&lt;/b&gt; (&lt;i&gt;bounded context&lt;/i&gt;). Zamówienie w kontekście &lt;i&gt;Koszyka&lt;/i&gt; to nie dokładnie to samo, co zamówienie w kontekście &lt;i&gt;Magazynu&lt;/i&gt;.&lt;/li&gt;&lt;li&gt;Odizoluj poszczególne konteksty i właściwe im modele od siebie&lt;/li&gt;&lt;/ul&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-PyN0KMZZ_3E/TtQk0fMLqCI/AAAAAAAAA5g/iqODgxc3SWI/s1600/Przechwytywanie.PNG" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="266" width="400" src="http://3.bp.blogspot.com/-PyN0KMZZ_3E/TtQk0fMLqCI/AAAAAAAAA5g/iqODgxc3SWI/s400/Przechwytywanie.PNG" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;W powyższych zasadach można dopatrzyć się echa &lt;i&gt;Single Resposibility Principle&lt;/i&gt;. Z odpowiedzialności modelu powinien wynikać jednoznaczny kontekst jego użycia. Tyle, że &lt;i&gt;Bounded Context&lt;/i&gt; definiuje to wprost i wyraźnie, a z zasady odpowiedzialności trzeba sobie wywnioskować.&lt;br /&gt;&lt;br /&gt;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 &lt;a href="http://domaindrivendesign.org/resources/what_is_ddd"&gt;DDD&lt;/a&gt; ta potrzeba jest zaspokajana poprzez zdefiniowanie &lt;i&gt;Context map&lt;/i&gt; w postaci zestawu usług-translatorów (w apachowych commonsach nazywanych &lt;a href="http://commons.apache.org/collections/api-2.1.1/org/apache/commons/collections/Transformer.html"&gt;transformerami&lt;/a&gt;). Ich odpowiedzialność to właśnie konwersja.&lt;br /&gt;&lt;br /&gt;Podsumowując zyski z wprowadzenia konceptu &lt;i&gt;Bounded Context&lt;/i&gt;:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Redukcja echa w systemie - zmiana w modelu w jednym miejscu nie skutkuje oddźwiękiem w innym&lt;/li&gt;&lt;li&gt;Zmiany wynikające z biznesu mają na poziomie architektury ograniczony do kontekstu zasięg&lt;/li&gt;&lt;li&gt;Można lepiej zorganizować prace nad projektem (tutaj &lt;a href="http://domaindrivendesign.org/resources/what_is_ddd"&gt;DDD&lt;/a&gt; proponuje kilka pomysłów w zależności od tego jakie relacje występują pomiędzy kontekstami). &lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1759916214638009707-7151575322116725492?l=mbartyzel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mbartyzel.blogspot.com/feeds/7151575322116725492/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1759916214638009707&amp;postID=7151575322116725492' title='Komentarze (5)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/7151575322116725492'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/7151575322116725492'/><link rel='alternate' type='text/html' href='http://mbartyzel.blogspot.com/2011/11/bounded-context.html' title='Bounded Context'/><author><name>Michał Bartyzel</name><uri>http://www.blogger.com/profile/03968505875451301931</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-wCx5CpLzBVo/TtQZgIIJJAI/AAAAAAAAA5I/H3VbZNU6UJU/s72-c/Przechwytywanie.PNG' height='72' width='72'/><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1759916214638009707.post-5798197274510696239</id><published>2011-11-22T00:07:00.001+01:00</published><updated>2011-11-22T01:40:19.912+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='code review'/><title type='text'>Przeglądy kodu</title><content type='html'>Kilka słów o przeprowadzaniu &lt;i&gt;code review&lt;/i&gt;. A zatem po co? Czy nie wystarczy podłączyć &lt;a href="http://www.sonarsource.org/"&gt;Sonara&lt;/a&gt; czy coś w tym stylu. Z pomocą przyszedł mi cytat zamieszczony na strone &lt;a href="http://2012.33degree.org/main/contact"&gt;33rd Degree Conference&lt;/a&gt;: &lt;i&gt;A single conversation with a wise man is better than ten years of study&lt;/i&gt;. I właśnie dlatego warto przeprowadzać &lt;i&gt;code review&lt;/i&gt; :) Prowadząc taką rozmowę z f2f robimy użytek efektu &lt;i&gt;human infection&lt;/i&gt;, czyli przekazujemy sobie wiedzę i ideę w bardziej naturalny sposób niż na papierku, albo ciągiem bitów.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Informacje początkowe&lt;/h3&gt;Dalej streszczam mój sposób na przeprowadzanie przeglądu kodu, ale najpierw parę tematów wprowadzających.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Jak często przeprowadzać przeglądy?&lt;/b&gt;&lt;br /&gt;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 :)&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Kto przeprowadza przegląd?&lt;/b&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Jak szczegółowy ma być przegląd?&lt;/b&gt; &lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Ile czasu zajmie przegląd?&lt;/b&gt;&lt;br /&gt;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ż.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Przegląd krok po kroku&lt;/h3&gt;&lt;br /&gt;&lt;b&gt;1: Zdefiniuj w IDE tasktagi //SMELL i //REFACTOR&lt;/b&gt;&lt;br /&gt;Będą potrzebne  do oznaczania w kodzie różnych ciekawostek.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;2: Ogranicz się do kodu: jednego user story | jednego zadania | jednej funkcjonalności&lt;/b&gt;&lt;br /&gt;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. &lt;br /&gt;&lt;br /&gt;&lt;b&gt;3: Wygeneruj diagram zależności między klasami/pakietami&lt;/b&gt;&lt;br /&gt;Najczęściej korzystam z wbudowanych widoków Eclipse lub ficzerów ReSharpera, wspomagając się kartką. Teraz zaczynam zapoznawać się z &lt;a href="www.dependency-analyzer.org"&gt;CDA &lt;/a&gt; i jeszcze nie mam wniosków. Jeśli chodzi o C++ to &lt;a href="http://www.wholetomato.com/"&gt;Visual Assist X&lt;/a&gt; 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).&lt;br /&gt;&lt;br /&gt;&lt;b&gt;4: Pobieżnie przyjrzyj się każdej klasie w wybranym fragmencie kodu&lt;/b&gt;&lt;br /&gt;Przyglądamy się tu pod następującymi kątami:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;ogólne wrażenie - elegancja kodu, czy woła o pomstę do nieba?&lt;/li&gt;&lt;li&gt;nazewnictwa - czy nazwa oddaje intencję?&lt;/li&gt;&lt;li&gt;wielkości klas i metod&lt;/li&gt;&lt;li&gt;Ilość współpracowników&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;b&gt;5: Prześledź podstawową obsługę żądania&lt;/b&gt;&lt;br /&gt;Chodzi o prześledzenie ścieżki od momentu, w którym ktoś zainicjował przetwarzanie&lt;br /&gt;&lt;a href="http://2.bp.blogspot.com/-gYJkWFbukYw/Tsro93feAFI/AAAAAAAAA48/D3NO7Ah8ZxE/s1600/Przechwytywanie.PNG" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="100" width="131" src="http://2.bp.blogspot.com/-gYJkWFbukYw/Tsro93feAFI/AAAAAAAAA48/D3NO7Ah8ZxE/s400/Przechwytywanie.PNG" /&gt;&lt;/a&gt;&lt;br /&gt;do chwili, gdy system odpowiedział na nie.&lt;br /&gt;&lt;br /&gt;Oznacz //SMELL &lt;komentarz&gt; 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ć.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;6: Przygotuj podsumowanie&lt;/b&gt;&lt;br /&gt;Byle krótkie w punktach, które uwzględni relację kodu do: obowiązującego standardu kodowania, czystości kodu, przyjętych zasad architektury.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;7: Przekaż informacje zwrotną&lt;/b&gt;&lt;br /&gt;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ć.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Czy należy wnioskować, że nienawidzę narzędzi?&lt;/h3&gt;Absolutnie nie. Takie super gadżet jak &lt;a href="http://www.sonarsource.org/"&gt;Sonara&lt;/a&gt; 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.&lt;br /&gt;&lt;br /&gt;Dodatkowo jestem entuzjastą minimalizowania ilości otwartych zadań (&lt;i&gt;work in progress&lt;/i&gt;). 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.&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1759916214638009707-5798197274510696239?l=mbartyzel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mbartyzel.blogspot.com/feeds/5798197274510696239/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1759916214638009707&amp;postID=5798197274510696239' title='Komentarze (1)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/5798197274510696239'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/5798197274510696239'/><link rel='alternate' type='text/html' href='http://mbartyzel.blogspot.com/2011/11/przeglady-kodu.html' title='Przeglądy kodu'/><author><name>Michał Bartyzel</name><uri>http://www.blogger.com/profile/03968505875451301931</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/-gYJkWFbukYw/Tsro93feAFI/AAAAAAAAA48/D3NO7Ah8ZxE/s72-c/Przechwytywanie.PNG' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1759916214638009707.post-1535787256578818552</id><published>2011-11-10T14:56:00.000+01:00</published><updated>2011-11-10T14:59:47.374+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><category scheme='http://www.blogger.com/atom/ns#' term='zarządzanie'/><category scheme='http://www.blogger.com/atom/ns#' term='efektywność'/><title type='text'>Duch i litera</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-jBbUAHAqoe0/TrvUQUuWRgI/AAAAAAAAA4w/tLQ122h29t4/s1600/Przechwytywanie.PNG" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="304" width="400" src="http://1.bp.blogspot.com/-jBbUAHAqoe0/TrvUQUuWRgI/AAAAAAAAA4w/tLQ122h29t4/s400/Przechwytywanie.PNG" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Trochę w nawiązaniu do posta &lt;a target="_blank" href="http://mbartyzel.blogspot.com/2011/09/w-co-gra-sie-w-projektach.html"&gt;W co gra się w projektach&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;Zostawiwszy w spokoju spirytualistyczne metafory, trzeba wyraźnie powiedzieć, że ludzie muszą znać intencję wdrażania nowych standardów, czyli: &lt;i&gt;po co to robimy, dlaczego to jest ważne, co z tego będziemy mieli&lt;/i&gt;. Dobrym pomysłem, w tym obszarze jest &lt;b&gt;standaryzowanie tego co już działa&lt;/b&gt;. 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.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1759916214638009707-1535787256578818552?l=mbartyzel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mbartyzel.blogspot.com/feeds/1535787256578818552/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1759916214638009707&amp;postID=1535787256578818552' title='Komentarze (1)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/1535787256578818552'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/1535787256578818552'/><link rel='alternate' type='text/html' href='http://mbartyzel.blogspot.com/2011/11/duch-i-litera.html' title='Duch i litera'/><author><name>Michał Bartyzel</name><uri>http://www.blogger.com/profile/03968505875451301931</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-jBbUAHAqoe0/TrvUQUuWRgI/AAAAAAAAA4w/tLQ122h29t4/s72-c/Przechwytywanie.PNG' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1759916214638009707.post-8523188112050186708</id><published>2011-10-20T21:19:00.000+02:00</published><updated>2011-10-20T21:20:17.983+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='wizje'/><title type='text'>Inspiracja fantasy</title><content type='html'>U jednego z &lt;i&gt;lubiących mnie&lt;/i&gt; na facebooku znalazłem cytat z jednej z najlepszych sag fantasy jakie czytałem. Mowa rzecz jasna o &lt;i&gt;Sadze o Wiedźminie&lt;/i&gt;. Cytat pochodzi z dzieła Jaskra, w którym wyjaśnia czytelnikowi, na czym polega prowadzenie działań wojennych.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;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. &lt;br /&gt;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.&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;Pomyślałem złośliwie, że gdyby zdefiniować następujące zmienne:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;marszałek, wojewoda, hetman, triumfator, wojskowy := menadżer&lt;/li&gt;&lt;li&gt;wojna, bitwa := projekt&lt;/li&gt;&lt;li&gt;wojsko, armia := zespół projektowy&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;to sumie też ma jakiś sens...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1759916214638009707-8523188112050186708?l=mbartyzel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mbartyzel.blogspot.com/feeds/8523188112050186708/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1759916214638009707&amp;postID=8523188112050186708' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/8523188112050186708'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/8523188112050186708'/><link rel='alternate' type='text/html' href='http://mbartyzel.blogspot.com/2011/10/inspiracja-fantasy.html' title='Inspiracja fantasy'/><author><name>Michał Bartyzel</name><uri>http://www.blogger.com/profile/03968505875451301931</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1759916214638009707.post-5606447452473276364</id><published>2011-10-18T13:01:00.000+02:00</published><updated>2011-10-18T13:02:15.917+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='praca z klientem'/><title type='text'>Nic tak nie zaciemnia sprawy jak dobry przykład</title><content type='html'>jak ponoć mawiał szacowny nauczyciel. &lt;br /&gt;&lt;br /&gt;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ężę). &lt;br /&gt;&lt;br /&gt;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. &lt;br /&gt;&lt;br /&gt;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ź: &lt;i&gt;„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”&lt;/i&gt;.&lt;br /&gt;&lt;br /&gt;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ć?&lt;br /&gt;&lt;br /&gt;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: &lt;i&gt;"No, no to może ja pomogę. Niech Pan się zastanowi jak wygląda krzywa ładowania kondensatora"....&lt;/i&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1759916214638009707-5606447452473276364?l=mbartyzel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mbartyzel.blogspot.com/feeds/5606447452473276364/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1759916214638009707&amp;postID=5606447452473276364' title='Komentarze (1)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/5606447452473276364'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/5606447452473276364'/><link rel='alternate' type='text/html' href='http://mbartyzel.blogspot.com/2011/10/nic-tak-nie-zaciemnia-sprawy-jak-dobry.html' title='Nic tak nie zaciemnia sprawy jak dobry przykład'/><author><name>Michał Bartyzel</name><uri>http://www.blogger.com/profile/03968505875451301931</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1759916214638009707.post-7814566145291333235</id><published>2011-10-07T00:26:00.000+02:00</published><updated>2011-10-07T00:26:22.006+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='wizje'/><category scheme='http://www.blogger.com/atom/ns#' term='efektywność'/><title type='text'>Planowanie to nie problem</title><content type='html'>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. &lt;br /&gt;&lt;br /&gt;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żę! &lt;br /&gt;&lt;br /&gt;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!&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Zadania dryfują&lt;/h3&gt;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ć.&lt;br /&gt;&lt;br /&gt;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. &lt;b&gt;Cierpimy na chroniczny brak umiejętności skupienia się i utrzymywania skupienia&lt;/b&gt;, choć dawni belfrzy z twardą trzciną w łapie powiedzieliby, że to brak samodyscypliny.&lt;br /&gt;&lt;br /&gt;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. &lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Weź pigułkę&lt;/h3&gt;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".&lt;br /&gt;&lt;br /&gt;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ś.&lt;br /&gt;&lt;a href="http://1.bp.blogspot.com/-94RoYDVc_rI/To4h_ISwweI/AAAAAAAAA4o/0bHygfkAx3s/s1600/Przechwytywanie.PNG" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="343" width="400" src="http://1.bp.blogspot.com/-94RoYDVc_rI/To4h_ISwweI/AAAAAAAAA4o/0bHygfkAx3s/s400/Przechwytywanie.PNG" /&gt;&lt;/a&gt; &lt;br /&gt;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 &lt;b&gt;aby zacząć coś robić, coś trzeba przestać robić&lt;/b&gt; albo czegoś robić mniej. To nie żadne hokus pokus, tylko zdrowy rozsądek.&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Terapia&lt;/h3&gt;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.&lt;br /&gt;Wydaje mi się, że warto zacząć od paru praktyk ograniczających wspomniane oferty przedmiotów:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Zadania zaczynaj od pierwszego na liście. Nie od RSS, newsów, maili itp. (wrzucanie RSSów do listy się nie liczy:))&lt;/li&gt;&lt;li&gt;Wyłącz komunikator, klienta poczty i włączaj je tylko w ściśle ustalonych porach (wiem, że to czelendż, ale warto spróbować)&lt;/li&gt;&lt;li&gt;W kliencie poczty wyłącz automatyczne odbieranie poczty przy starcie i co 10 minut&lt;/li&gt;&lt;li&gt;Z umiarem stosuj smartfony. Naprawdę nie musisz być on-line non stop.&lt;/li&gt;&lt;li&gt;Jeśli już koniecznie musisz poczytać newsy zrób to na końcu listy zadań, nie na początku&lt;/li&gt;&lt;li&gt;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&lt;/li&gt;&lt;li&gt;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&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1759916214638009707-7814566145291333235?l=mbartyzel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mbartyzel.blogspot.com/feeds/7814566145291333235/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1759916214638009707&amp;postID=7814566145291333235' title='Komentarze (2)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/7814566145291333235'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/7814566145291333235'/><link rel='alternate' type='text/html' href='http://mbartyzel.blogspot.com/2011/10/planowanie-to-nie-problem.html' title='Planowanie to nie problem'/><author><name>Michał Bartyzel</name><uri>http://www.blogger.com/profile/03968505875451301931</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-94RoYDVc_rI/To4h_ISwweI/AAAAAAAAA4o/0bHygfkAx3s/s72-c/Przechwytywanie.PNG' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1759916214638009707.post-4525869803647905611</id><published>2011-09-30T02:21:00.001+02:00</published><updated>2011-09-30T02:21:47.801+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='wizje'/><category scheme='http://www.blogger.com/atom/ns#' term='refaktoring'/><title type='text'>Dług techniczny, opcja call czy lokata długoterminowa?</title><content type='html'>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.&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Kłopot z metaforami&lt;/h3&gt;Aby zdobyć choć trochę posłuchu u biznesu community wykombinowało jak na razie dwie metafory: &lt;a href="http://martinfowler.com/bliki/TechnicalDebt.html"&gt;Długu technicznego&lt;/a&gt; oraz (najświeższa) &lt;a href="http://jaxenter.com/bad-code-isn-t-technical-debt-35471.html"&gt;Niezabezpiecznonej opcji typu call&lt;/a&gt;. &lt;br /&gt;Gdy się w nie wczytać, to każda z nich mówi mniej więcej coś takiego: &lt;i&gt;Pamiętaj biznes-ludku, że jak nie będziemy refaktoryzować, to stanie się COŚ strasznego!&lt;/i&gt;. Obie metafory odwołują się do rzeczy, która jak nam się zdaje, najlepiej do biznesu przemówi, czyli do pieniędzy.&lt;br /&gt;&lt;br /&gt;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. &lt;br /&gt;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ć.&lt;br /&gt;&lt;br /&gt;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. &lt;br /&gt;&lt;br /&gt;Podsumowując, twierdzę, że obojętność na prorefaktoryzacyjne błagania ma następujące przyczyny&lt;br /&gt;&lt;ul&gt;&lt;li&gt;korzyść z refaktoryzacji jest zbyt odroczona w czasie&lt;/li&gt;&lt;li&gt;korzyść z refaktoryzacji bardzo trudno wykazać jest w pieniądzach&lt;/li&gt;&lt;li&gt;zaniedbanie refaktoryzacji ma negatywne skutki w bliżej nieokreślonym &lt;i&gt;kiedyś&lt;/i&gt;; a dopóki programiści mogą ratować projekt, to go ratują; czasem bardzo długo&lt;/li&gt;&lt;li&gt;robienie tak, "aby działało" ma szybkie odczuwalne korzyści&lt;/li&gt;&lt;/ul&gt;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.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Lokata długoterminowa&lt;/h3&gt;Dobitna metafora dla refaktoryzacji powinna charakteryzować się następującymi cechami:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;korzyści można łatwo wyrazić w pieniądzach&lt;/li&gt;&lt;li&gt;korzyści finansowe są szybko odczuwalne, powiedzmy w perspektywie tego samego albo najbliższego wydania&lt;/li&gt;&lt;/ul&gt;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ć.&lt;br /&gt;&lt;br /&gt;Szukałem tego typu metafory również w świecie finansów (no, bo dlaczego nie?) i znalazłem ja w postaci &lt;b&gt;lokaty długoterminowej&lt;/b&gt;. Korzystając z tej metafory można w stronę Biznesu perorować, że:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;refaktoryzacja jest jak wpłata pieniędzy na lokatę, już po pierwszym okresie rozliczeniowym następuje kapitalizacja odsetek i otrzymujesz swój procent&lt;/li&gt;&lt;li&gt;im dłużej oszczędzasz tym więcej zyskujesz&lt;/li&gt;&lt;li&gt;żeby osiągnąć maksymalną korzyść musisz wpłacać regularnie&lt;/li&gt;&lt;li&gt;jeśli zerwiesz lokatę, właściwie tracisz większość zarobku&lt;/li&gt;&lt;li&gt;no i w przypadku refaktoryzacji nie ma podatku Belki:), same korzyści!&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;h3&gt;A jak pokazać korzyści finansowe?&lt;/h3&gt;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:&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-oze-79Ntywo/ToUH4TNMiYI/AAAAAAAAA4g/K2uBUmtSNjg/s1600/Przechwytywanie.PNG" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="37" width="200" src="http://1.bp.blogspot.com/-oze-79Ntywo/ToUH4TNMiYI/AAAAAAAAA4g/K2uBUmtSNjg/s400/Przechwytywanie.PNG" /&gt;&lt;/a&gt;&lt;/div&gt;gdzie: &lt;i&gt;V&lt;/i&gt; - obecna wartość, &lt;i&gt;V0&lt;/i&gt; - początkowy kapitał,&lt;i&gt; r&lt;/i&gt; - stopa procentowa, &lt;i&gt;n&lt;/i&gt; - liczba okresów rozliczeniowych. &lt;br /&gt;&lt;br /&gt;No, to teraz spróbujmy zinterpretować wzór w kontekście refaktoryzacji. &lt;i&gt;Vx&lt;/i&gt; - liczmy dalej w pieniądzach, &lt;i&gt;n&lt;/i&gt; - liczba iteracji, a&lt;i&gt; r&lt;/i&gt;? 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.&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1759916214638009707-4525869803647905611?l=mbartyzel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mbartyzel.blogspot.com/feeds/4525869803647905611/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1759916214638009707&amp;postID=4525869803647905611' title='Komentarze (5)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/4525869803647905611'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/4525869803647905611'/><link rel='alternate' type='text/html' href='http://mbartyzel.blogspot.com/2011/09/dug-techniczny-opcja-call-czy-lokata.html' title='Dług techniczny, opcja call czy lokata długoterminowa?'/><author><name>Michał Bartyzel</name><uri>http://www.blogger.com/profile/03968505875451301931</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-oze-79Ntywo/ToUH4TNMiYI/AAAAAAAAA4g/K2uBUmtSNjg/s72-c/Przechwytywanie.PNG' height='72' width='72'/><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1759916214638009707.post-4118018896893295622</id><published>2011-09-29T22:17:00.000+02:00</published><updated>2011-09-29T22:17:21.397+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='info'/><category scheme='http://www.blogger.com/atom/ns#' term='praca z klientem'/><title type='text'>User friendly</title><content type='html'>Właśnie dostałem poniższy komunikat....to się nazwa user friendly UI :)&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-QvaN-Jx09Fg/ToTSGn2R8FI/AAAAAAAAA4Y/-I5hOGMU3mI/s1600/Przechwytywanie.PNG" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="346" width="400" src="http://2.bp.blogspot.com/-QvaN-Jx09Fg/ToTSGn2R8FI/AAAAAAAAA4Y/-I5hOGMU3mI/s400/Przechwytywanie.PNG" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1759916214638009707-4118018896893295622?l=mbartyzel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mbartyzel.blogspot.com/feeds/4118018896893295622/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1759916214638009707&amp;postID=4118018896893295622' title='Komentarze (3)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/4118018896893295622'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/4118018896893295622'/><link rel='alternate' type='text/html' href='http://mbartyzel.blogspot.com/2011/09/user-friendly.html' title='User friendly'/><author><name>Michał Bartyzel</name><uri>http://www.blogger.com/profile/03968505875451301931</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/-QvaN-Jx09Fg/ToTSGn2R8FI/AAAAAAAAA4Y/-I5hOGMU3mI/s72-c/Przechwytywanie.PNG' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1759916214638009707.post-9215113536841216777</id><published>2011-09-29T01:22:00.000+02:00</published><updated>2011-09-29T14:07:27.470+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='antywzorce'/><category scheme='http://www.blogger.com/atom/ns#' term='zarządzanie'/><title type='text'>W co się gra w projektach?</title><content type='html'>Był sobie zespół programistyczny złożony z paru osób. Wszyscy z żyłką pasji zabrali się do projektu. Ponieważ wychodzili założenia, że dobrze się uczyć na własnych błędach, przeprowadzali regularne retrospekcje. W trakcie retrospekcji analizowali sprawy takie jak:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;zgodność szacowania z oczekiwaniami&lt;/li&gt;&lt;li&gt;pokrycie testami i ich skuteczność&lt;/li&gt;&lt;li&gt;ilość błędów znalezionych w fazie testów&lt;/li&gt;&lt;li&gt;czytelność kodu&lt;/li&gt;&lt;/ul&gt;i jeszcze parę innych rzeczy. Świetnie się przy tym bawili, bo mieli poczucie, że się rozwijają w obszarze, w którym pracują. Na bazie wspomnianych retrospekcji zaczęły wyodrębniać się różne rodzaju reguły i standardy. Wszyscy w zespole zgodnie uznawali, że odkryte zasady pozwalają efektywniej pracować i chętnie się im podporządkowywali. Postawili własne wiki, na którym spisywali standardy przyjmowane w zespole, i które potem stopniowo modyfikowali, dopasowując je do aktualnych potrzeb i doświadczenia.&lt;br /&gt;&lt;br /&gt;Ponieważ praca szła wyjątkowo sprawnie, sponsor zespołu począł rekrutować kolejnych programistów i kolejnych i kolejnych. Pierwsi członkowie zespołu zostali liderami, potem kierownikami. Wszystko szło sprawnie. Naturalnie nowe osoby w dziale (tak, tak zespół stał się Działem, a jakże!) były zapoznawane z obowiązującymi i sprawdzonymi standardami i zobligowane do ich przestrzegania.&lt;br /&gt;&lt;br /&gt;Po jakimś czasie nasi kierownicy zauważyli, że standardy są kiepsko przestrzegane. Trudno im było zmobilizować programistów do ich stosowania. Długo zastanawiali się jak zaradzić tej sytuacji. Ponieważ byli wytrawnymi inżynierami, podeszli do sprawy stricte analitycznie. Wykombinowali wcale skomplikowany wzór, który uzależniał dodatek premiowy od stopnia przestrzegania standardów. Na przykład: za 80% pokrycia testami +2%premii, za każde 50 błędów zgłoszonych przez testerów + 1,3%premii, za utrzymanie szacowania +3,2% premii....pomysł genialny...&lt;br /&gt;&lt;br /&gt;i wtedy zaczęła się &lt;b&gt;GRA&lt;/b&gt;.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Zasady gry&lt;/h3&gt;Intencją kierowników było nagradzanie osób z zespołu za przestrzeganie standardów i zachęcanie do ich stosowania. Jednak zupełnie nieświadomie stworzyli GRĘ, o następujących zasadach:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;uczestnikami gry są członkowie zespołu projektowego&lt;/li&gt;&lt;li&gt;wygrywasz wtedy, gdy zdobywasz jak największą ilość pieniędzy&lt;/li&gt;&lt;li&gt;reguły zdobywania pieniędzy określone są poprzez standardy obowiązujące w zespole&lt;/li&gt;&lt;/ul&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-XOIOHpOEKiM/ToOpyf2bXqI/AAAAAAAAA4Q/3b9gWeCVNiA/s1600/rysunek.PNG" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="161" width="400" src="http://2.bp.blogspot.com/-XOIOHpOEKiM/ToOpyf2bXqI/AAAAAAAAA4Q/3b9gWeCVNiA/s400/rysunek.PNG" /&gt;&lt;/a&gt;&lt;/div&gt;Szybko okazało się, że programiści i testerzy są bardzo wytrawnymi graczami. Często wygrywali...,ale:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;pokrycie testami było idealne, lecz: testowane były gettery, settery, testy bardziej przeszkadzały niż pomagały&lt;/li&gt;&lt;li&gt;programiści szacowali idealnie co do dnia, lecz bardzo, ale to bardzo pesymistycznie&lt;/li&gt;&lt;li&gt;testerzy znajdowali tysiące błędów, lecz większość z nich dotyczyła nadmiarowych spacji w labelkach, braku kropek itp&lt;/li&gt;&lt;li&gt;standard kodowania był przestrzegany, lecz tam gdzie było można programiści i tak pisali po swojemu&lt;/li&gt;&lt;li&gt;retrospekcje upadły; standardy przestały się rozwijać, w końcu stały się nieadekwatne do obecnej sytuacji i przeszkadzały w pisaniu&lt;/li&gt;&lt;/ul&gt;Co się u licha stało? - zapytali kierownicy. Przecież chcieliśmy dobrze :(&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Konflikt wartości&lt;/h3&gt;Znajomy metodolog zajmujący się badaniem hierarchii wartości u pracowników (bywa, że firmy chcą wiedzieć co jest dla Ciebie ważne: rozwój, profesjonalizm, bezpieczeństwo, kariera i w jakiej kolejności) wyłożył mi cierpliwie, że w żadnym poważnym teście nie zestawia się wartości istotnych w miejscu pracy z wartościami typu: rodzina, zdrowie, gdyż te pierwsze zawsze muszą przegrać. Gdy test nie szanuje tej zasady, to otrzymujemy zafałszowane dane, gdyż wyniki testu będą "skrzywione" w kierunku właśnie rodziny, zdrowia itp. W sumie logiczne, że gdy mam do wyboru karierą versus trwały uszczerbek na zdrowiu, to motywowany samozachowawczym instynktem, będę chronił swoje zdrowie, nawet kosztem kariery.&lt;br /&gt;&lt;br /&gt;W omawianym wyżej zespole, kierownicy popełnili właśnie ten metodologiczny błąd No, bo jeśli wybieram między zmieszczeniem się w szacowaniach (nawet jeśli trzeba by ociupinkę je zawyżyć), a gwiazdkowymi prezentami dla rodziny, to szacowanie będzie idealne - choćby nie wiem co! I wcale nie w tym rzecz, że jesteśmy źli, upadli, oszuści. Nic z tych rzeczy. Tak jesteśmy skonstruowani, a granica między rzetelnym oszacowaniem a nieco zawyżonym jest tak płynna, tak rozmyta, że bardzo łatwo i bardzo szybko racjonalizujemy sobie drobne jej przekroczenia. Myślę, że większą winę ponosi ten, kto doprowadził do sytuacji sprzyjającej takiemu postępowaniu, niż ten kto rzeczywiście tak postępuje.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Opłakane skutki&lt;/h3&gt;Ponieważ przestrzeganie standardów było tylko środkiem do celu, standardy przestały się rozwijać, przestały żyć. W niczyim interesie nie było modyfikowanie standardów i ulepszanie ich. Po zmieniać i komplikować sposób na zarabianie, skoro już mam opracowane sposoby wygrywania?&lt;br /&gt;&lt;br /&gt;Motywowanie pieniędzmi jest w porządku, gdy w działaniu ludzi o pieniądze przede wszystkim chodzi. Weźmy takich na przykład sprzedawców. W uproszczeniu: sprzedawca sprzedaje produkt/usługę i przynosi pracodawcy fakturę, od której otrzymuje procent. To będzie działać. Ale jeśli sprzedawca będzie dostawał premię za ilość spotkań, to znów zaczyna się GRA. Bo oto może się okazać, że spotkania są i owszem, ale z firmami, które prawdopodobnie nigdy nie zostaną naszymi klientami. Kto za to ponosi odpowiedzialność? Przede wszystkim ten, kto stworzył GRĘ.&lt;br /&gt;&lt;br /&gt;Gdy Twoi pracownicy pracują kreatywnie (tu programiści) i zasady pracy muszą dojrzewać i ulepszać się wraz z nimi, to &lt;b&gt;nigdy przenigdy nie wolno&lt;/b&gt; uzależniać wynagrodzenia od ich przestrzegania. Takie działanie zabije kreatywność i zasady pracy szybko się usztywnią.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Przestrzegaj standardów "bo warto"&lt;/h3&gt;By standardy w zespole działały i ewoluowały muszą być ważne tak po prostu. Ludzie muszą widzieć w nich wartość, muszą chcieć ich przestrzegać, muszą dostrzegać, że dzięki nim stają się lepsi. Tak właśnie działali pierwsi członkowie zespołu z naszego obrazka. Wtedy standardy będą ewoluowały, a ludzie będą chętnie je rozwijać. W przeciwnym razie ryzykujesz, że standardy będziesz wprowadzał sam, siłowo, albo za pomocą nowo zatrudnionych członków Komitetów Standaryzacyjnych i tak skomplikujesz zasady GRY, że już nikt nie połapie się o co w ogóle na samym początku chodziło.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;A co z pieniędzmi?&lt;/h3&gt;Opisaną scenę można by streścić następująco: Motywuj ludzi pozafinansowo, ale płać im dobrze...:) W sumie nic dziwnego - jeśli podstawowe potrzeby nie są zaspokojone, to nie ma co myśleć o tych wyższych. Oczywiście, że potrzeba tu wyważenia, złotego środka, w końcu każdy budżet jest ograniczony. "Płacić dobrze" zazwyczaj nie oznacza "więcej niż konkurencja". Może być nawet mniej w zamian za inne pozafinansowe dobra. To jest sprawa bardzo indywidualna i chcę robić nieuprawnionych uogólnień.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1759916214638009707-9215113536841216777?l=mbartyzel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mbartyzel.blogspot.com/feeds/9215113536841216777/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1759916214638009707&amp;postID=9215113536841216777' title='Komentarze (3)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/9215113536841216777'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/9215113536841216777'/><link rel='alternate' type='text/html' href='http://mbartyzel.blogspot.com/2011/09/w-co-gra-sie-w-projektach.html' title='W co się gra w projektach?'/><author><name>Michał Bartyzel</name><uri>http://www.blogger.com/profile/03968505875451301931</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/-XOIOHpOEKiM/ToOpyf2bXqI/AAAAAAAAA4Q/3b9gWeCVNiA/s72-c/rysunek.PNG' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1759916214638009707.post-381924821552623269</id><published>2011-09-27T09:04:00.000+02:00</published><updated>2011-09-27T09:04:40.920+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='info'/><category scheme='http://www.blogger.com/atom/ns#' term='książki'/><title type='text'>Ludzie książki piszą</title><content type='html'>&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/-IHR5vTuWpvQ/ToFvDS5iCFI/AAAAAAAAA4I/_VLE7-xL7_c/s1600/eseje_3d_box_transparent.png" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="400" width="400" src="http://3.bp.blogspot.com/-IHR5vTuWpvQ/ToFvDS5iCFI/AAAAAAAAA4I/_VLE7-xL7_c/s400/eseje_3d_box_transparent.png" /&gt;&lt;/a&gt;&lt;br /&gt;Wydaliśmy naszą drugą książkę. Pierwszą próbą był ebook &lt;i&gt;Jak całkowicie odmienić sposób programowania używając refaktoryzacji&lt;/i&gt;. Najnowsza książka nosi tytuł &lt;i&gt;Eseje o efektywności programistów&lt;/i&gt;. Opiera się na artykułach, które opublikowaliśmy w &lt;a href="http://sdjournal.pl"&gt;SDJ&lt;/a&gt; w ciągu ostatnich dwóch lat. (tak na marginesie: książka ma 143 strony, na zdjęciu wygląda nieco grubiej:) )&lt;br /&gt;&lt;br /&gt;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:)&lt;br /&gt;&lt;br /&gt;Dalej, w przygotowaniu (w trakcie pisania) jest kolejna książka o roboczym tytule &lt;i&gt;Między Biznesem a IT, czyli sztuka zadawania pytań&lt;/i&gt;. 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: &lt;i&gt;requirements management&lt;/i&gt; - mianowicie sam etap pozyskiwania wymagań. Ramowy outline tej książki wygląda następująco:&lt;br /&gt;&lt;br /&gt;O postępach będę informował na bieżąco.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1759916214638009707-381924821552623269?l=mbartyzel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mbartyzel.blogspot.com/feeds/381924821552623269/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1759916214638009707&amp;postID=381924821552623269' title='Komentarze (1)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/381924821552623269'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/381924821552623269'/><link rel='alternate' type='text/html' href='http://mbartyzel.blogspot.com/2011/09/ludzie-ksiazki-pisza.html' title='Ludzie książki piszą'/><author><name>Michał Bartyzel</name><uri>http://www.blogger.com/profile/03968505875451301931</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/-IHR5vTuWpvQ/ToFvDS5iCFI/AAAAAAAAA4I/_VLE7-xL7_c/s72-c/eseje_3d_box_transparent.png' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1759916214638009707.post-7346926893315312439</id><published>2011-09-13T06:29:00.002+02:00</published><updated>2011-09-13T06:29:37.923+02:00</updated><title type='text'>Dzień programisty</title><content type='html'>Podobno dziś jest dzień programisty. Wszystkiego naj* zatem:)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1759916214638009707-7346926893315312439?l=mbartyzel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mbartyzel.blogspot.com/feeds/7346926893315312439/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1759916214638009707&amp;postID=7346926893315312439' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/7346926893315312439'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/7346926893315312439'/><link rel='alternate' type='text/html' href='http://mbartyzel.blogspot.com/2011/09/dzien-programisty.html' title='Dzień programisty'/><author><name>Michał Bartyzel</name><uri>http://www.blogger.com/profile/03968505875451301931</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1759916214638009707.post-4950226740235495530</id><published>2011-08-09T22:52:00.023+02:00</published><updated>2011-08-10T23:40:47.773+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='wzorce'/><category scheme='http://www.blogger.com/atom/ns#' term='refaktoring'/><title type='text'>Interfejs budowniczego</title><content type='html'>Na przykład &lt;a href="http://en.wikipedia.org/wiki/Builder_pattern"&gt;tutaj &lt;/a&gt; można dowiedzieć się o niezwykłych korzyściach stosowania wzorca &lt;a href="http://en.wikipedia.org/wiki/Builder_pattern"&gt;Builder&lt;/a&gt; (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ż.&lt;br /&gt;&lt;br /&gt;Jak wspomniałem plusy dodatnie i ujemne budowniczego były już nie raz szeroko omawiane. Mnie interesuje odpowiedź na inne pytanie: &lt;span style="font-style:italic;"&gt;W jaki sposób zaprojektować interfejs budowniczego?&lt;/span&gt;. To znaczy:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Jak zdecydować jakie metody powinien mieć budowniczy?&lt;/li&gt;&lt;li&gt;Jak go sensownie używać (pragmatycznie, nie sztuka dla sztuki), aby pomagał, a nie przeszkadzał?&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Ponieważ debugowałem blog &lt;a href="http://art-of-software.blogspot.com/search?updated-max=2011-06-06T19%3A34%3A00%2B02%3A00&amp;max-results=7"&gt;Sławka&lt;/a&gt;, żeby podłączyć syntaxhighlightera, to pożyczyłem sobie &lt;span style="font-style:italic;"&gt;Order &lt;/span&gt;i &lt;span style="font-style:italic;"&gt;OrderItem &lt;/span&gt;do przykładu:).&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/-yUN4te1q6bU/TkGj4lciDAI/AAAAAAAAA4A/jnZfRCvUwk0/s1600/model.PNG"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 157px;" src="http://4.bp.blogspot.com/-yUN4te1q6bU/TkGj4lciDAI/AAAAAAAAA4A/jnZfRCvUwk0/s400/model.PNG" border="0" alt=""id="BLOGGER_PHOTO_ID_5638968400964357122" /&gt;&lt;/a&gt;&lt;br /&gt;Dla uproszczenia załóżmy, że jest to aplikacja konsolowa. Właściciel oczekuje, że będzie pracował z aplikacją następująco:&lt;code&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Podaj identyfikator zamówienia:&lt;/span&gt; Paczka-E112 &lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Podaj priorytet zamówienia:&lt;/span&gt; 1&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Podaj nazwy grup produktowych:&lt;/span&gt; spożywcze chemia zabawki&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Podaj ilość porduktów dla grupy 'spożywcze':&lt;/span&gt; 2&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Dodaj produkt dla grupy 'spożywcze':&lt;/span&gt; sałata 2,45zł 2&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Dodaj produkt dla grupy 'spożywcze':&lt;/span&gt; morele 6,79zł 1&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Podaj ilość porduktów dla grupy 'chemia':&lt;/span&gt; 3&lt;br /&gt;...&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Startuję z następującym zestawem klas:&lt;br /&gt;&lt;div&gt;&lt;pre class="brush: java"&gt;public class Order {&lt;br /&gt;  private String id;&lt;br /&gt;  private int priority;&lt;br /&gt;  private Set&lt;ItemGroup&gt; itemGroups = new HashSet&lt;ItemGroup&gt;();&lt;br /&gt;}&lt;br /&gt;public class ItemGroup {&lt;br /&gt;  private String name;&lt;br /&gt;  private Set&lt;Item&gt; items = new HashSet&lt;Item&gt;();&lt;br /&gt;}&lt;br /&gt;public class Item {&lt;br /&gt;  private String name;&lt;br /&gt;  private Money price;&lt;br /&gt;  private int quantity;&lt;br /&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Za wykonanie zadania &lt;span style="font-style:italic;"&gt;Dodawanie zamówienia&lt;/span&gt;, odpowiedzialną uczyńmy klasę:&lt;br /&gt;&lt;div&gt;&lt;pre class="brush: java"&gt;public class UserInterface { &lt;br /&gt;  private Set&lt;Order&gt; orders = new HashSet&lt;Order&gt;();&lt;br /&gt;  public void addOrder() {&lt;br /&gt;    // TOIMPL&lt;br /&gt;  }	&lt;br /&gt;  public static void main(String[] args) {&lt;br /&gt;    new UserInterface().addOrder();&lt;br /&gt;  }&lt;br /&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;W pierwszym podejściu kod, który działa, mógłby wyglądać na przykład tak:&lt;br /&gt;&lt;div&gt;&lt;pre class="brush: java"&gt;public void addOrder() {&lt;br /&gt;  Scanner scanner = new Scanner( System.in );&lt;br /&gt;  System.out.print( "Podaj identyfikator zamówienia: " );&lt;br /&gt;  String orderId = scanner.nextLine();&lt;br /&gt;  System.out.print( "Podaj priorytet zamówienia: " );&lt;br /&gt;  int orderPriority = Integer.parseInt( scanner.nextLine() );&lt;br /&gt;  Order order = new Order( orderId, orderPriority );&lt;br /&gt;  System.out.print( "Podaj nazwy grup produktowych: " );&lt;br /&gt;  String[] itemGroupsNames = scanner.nextLine().split( " " );&lt;br /&gt;  for ( int i = 0; i &lt; itemGroupsNames.length; ++i ) {&lt;br /&gt;    ItemGroup itemGroup = new ItemGroup( itemGroupsNames[ i ] );&lt;br /&gt;    System.out.print( "Podaj ilość produktów dla grupy '" + itemGroupsNames[ i ] + "' : " );&lt;br /&gt;    int itemsAmount = Integer.parseInt( scanner.nextLine() );&lt;br /&gt;    for( int j = 0; j &lt; itemsAmount; ++j ) {&lt;br /&gt;      System.out.print( "Dodaj produkt dla grupy '" + itemGroupsNames[ i ] + "' : " );&lt;br /&gt;      String[] itemParams = scanner.nextLine().split( " " );&lt;br /&gt;      String itemName = itemParams[ 0 ];&lt;br /&gt;      Money itemPrice = Money.parseMoney( itemParams[ 1 ] );&lt;br /&gt;      int itemQuantity = Integer.parseInt( itemParams[ 2 ] ); &lt;br /&gt;      Item item = new Item( itemName, itemPrice, itemQuantity );		&lt;br /&gt;      itemGroup.addItem( item );&lt;br /&gt;    }&lt;br /&gt;    order.addItemGrup( itemGroup );&lt;br /&gt;  }&lt;br /&gt;  orders.add( order ); &lt;br /&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;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).&lt;br /&gt;&lt;br /&gt;W pierwszym zachwycie nad wzorce &lt;a href="http://en.wikipedia.org/wiki/Builder_pattern"&gt;Builder&lt;/a&gt; mam ogromną ochotę go użyć! &lt;span style="font-weight:bold;"&gt;UWAGA&lt;/span&gt; jeśli przychodzi ci go głowy napisać klasę &lt;span style="font-style:italic;"&gt;OrderBuilder &lt;/span&gt;z jedną metodą &lt;span style="font-style:italic;"&gt;build&lt;/span&gt; mającą kilkanaście parametrów, to nie tędy droga. Wyszedł by z tego nie budowniczy ale jakieś &lt;span style="font-style:italic;"&gt;fabrykoniewiadomoco&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;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:&lt;br /&gt;&lt;div&gt;&lt;pre class="brush: java"&gt;public class OrderBuilder {&lt;br /&gt;  private Order order;&lt;br /&gt;  public void newOrder( String orderId, int orderPriority ) {&lt;br /&gt;    order = new Order( orderId, orderPriority );&lt;br /&gt;  }&lt;br /&gt;  public Order getOrder() {&lt;br /&gt;    return order;&lt;br /&gt;  }&lt;br /&gt;  public void addItemGroup( String name ) {&lt;br /&gt;    order.addItemGrup( new ItemGroup( name ) );&lt;br /&gt;  }&lt;br /&gt;  public void addItem( String groupName, String name, Money price, int qty ) {&lt;br /&gt;    ItemGroup group = order.findItemGroup( name );&lt;br /&gt;    group.addItem( new Item( name, price, qty ) );&lt;br /&gt;  }&lt;br /&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;h4&gt;Kluczowe pytanie: Czy ten budowniczy jest pomocny?&lt;/h4&gt;&lt;br /&gt;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:&lt;br /&gt;&lt;div&gt;&lt;pre class="brush: java"&gt;public void addOrder() {&lt;br /&gt;  Scanner scanner = new Scanner( System.in );&lt;br /&gt;  System.out.print( "Podaj identyfikator zamówienia: " );&lt;br /&gt;  String orderId = scanner.nextLine();&lt;br /&gt;  System.out.print( "Podaj priorytet zamówienia: " );&lt;br /&gt;  int orderPriority = Integer.parseInt( scanner.nextLine() );&lt;br /&gt;  OrderBuilder builder = new OrderBuilder();&lt;br /&gt;  builder.newOrder( orderId, orderPriority );&lt;br /&gt;  System.out.print( "Podaj nazwy grup produktowych: " );&lt;br /&gt;  String[] itemGroupsNames = scanner.nextLine().split( " " );&lt;br /&gt;  for ( int i = 0; i &lt; itemGroupsNames.length; ++i ) {&lt;br /&gt;    builder.addItemGroup( itemGroupsNames[ i ] );&lt;br /&gt;    System.out.print( "Podaj ilość produktów dla grupy '" + itemGroupsNames[ i ] + "' : " );&lt;br /&gt;    int itemsAmount = Integer.parseInt( scanner.nextLine() );&lt;br /&gt;    for( int j = 0; j &lt; itemsAmount; ++j ) {&lt;br /&gt;      System.out.print( "Dodaj produkt dla grupy '" + itemGroupsNames[ i ] + "' : " );&lt;br /&gt;      String[] itemParams = scanner.nextLine().split( " " );&lt;br /&gt;      String itemName = itemParams[ 0 ];&lt;br /&gt;      Money itemPrice = Money.parseMoney( itemParams[ 1 ] );&lt;br /&gt;      int itemQuantity = Integer.parseInt( itemParams[ 2 ] ); &lt;br /&gt;      builder.addItem( itemGroupsNames[ i ], itemName, itemPrice, itemQuantity );&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;  orders.add( builder.getOrder() );&lt;br /&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Jest tak samo brzydki jak był! Budowniczy nie wniósł znaczącego wkładu do tego kodu. Moim zdaniem &lt;span style="font-weight:bold;"&gt;interfejs budowniczego należy projektować z perspektywy klienta&lt;/span&gt;. Pisząc &lt;span style="font-weight:bold;"&gt;klient&lt;/span&gt; mam na myśli usługę, która akurat budowniczego będzie wykorzystywać - w tym przypadku jest to klasa &lt;span style="font-style:italic;"&gt;UserIterface&lt;/span&gt;. &lt;span style="font-weight:bold;"&gt;Interfejs budowniczego powinien być wygodny dla klienta&lt;/span&gt;. &lt;br /&gt;&lt;h4&gt;Krok 1: Dlaczego ItemGroup i Item trzeba dodawać pojedynczo?&lt;/h4&gt;&lt;br /&gt;Wcale nie trzeba...Przecież budowniczy może mieć metody, które przyjmą input, który przyszedł od użytkownika i samodzielnie go zinterpretuje. &lt;span style="font-weight:bold;"&gt;Pytanie:&lt;/span&gt; Czy czasem znów nie dojdzie do pomieszania warstw? Nie nie dojdzie. Przeanalizujmy odpowiedzialności poszczególnych klas:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-style:italic;"&gt;Order, ItemGroup, Item&lt;/span&gt; - to model dziedziny, reprezentuje rzeczywistość&lt;/li&gt;&lt;li&gt;&lt;span style="font-style:italic;"&gt;UserInterface &lt;/span&gt;- 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&lt;/li&gt;&lt;li&gt;&lt;span style="font-style:italic;"&gt;OrderBuilder&lt;/span&gt; - służy do złożenia zamówienia z mniejszych elementów&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;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ć:&lt;br /&gt;&lt;div&gt;&lt;pre class="brush: java"&gt;public class OrderBuilder {&lt;br /&gt;  private Order order;&lt;br /&gt;  public void newOrder( String orderId, int orderPriority ) {&lt;br /&gt;    order = new Order( orderId, orderPriority );&lt;br /&gt;  }&lt;br /&gt;  public void addItemGroups( String itemsGroupsInput ) {&lt;br /&gt;    String[] itemGroupsNames = itemsGroupsInput.split( " " );	&lt;br /&gt;    for ( int i = 0; i &lt; itemGroupsNames.length; ++i ) {			&lt;br /&gt;      order.addItemGrup( new ItemGroup( itemGroupsNames[ i ] ) );&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;  public void addItem( String itemParamsInput ) {&lt;br /&gt;    String[] itemParams = itemParamsInput.split( " " );&lt;br /&gt;    String groupName = itemParams[ 0 ];&lt;br /&gt;    ItemGroup group = order.findItemGroup( groupName );&lt;br /&gt;    Money price = Money.parseMoney( itemParams[ 1 ] );&lt;br /&gt;    int qty = Integer.parseInt( itemParams[ 2 ] ); 	 &lt;br /&gt;    group.addItem( new Item( groupName, price, qty ) );&lt;br /&gt;  }&lt;br /&gt;  public Order getOrder() {&lt;br /&gt;    return order;&lt;br /&gt;  }&lt;br /&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Jak widać budowniczy zmądrzał nieco, potrafi zrobić coś więcej niż proste dodawanie. A jak wygląda korzystanie z niego?&lt;br /&gt;&lt;div&gt;&lt;pre class="brush: java"&gt;public void addOrder() {&lt;br /&gt;  Scanner scanner = new Scanner( System.in );	&lt;br /&gt;  System.out.print( "Podaj identyfikator zamówienia: " );&lt;br /&gt;  String orderId = scanner.nextLine();&lt;br /&gt;  System.out.print( "Podaj priorytet zamówienia: " );&lt;br /&gt;  int orderPriority = Integer.parseInt( scanner.nextLine() );&lt;br /&gt;  OrderBuilder builder = new OrderBuilder();&lt;br /&gt;  builder.newOrder( orderId, orderPriority );&lt;br /&gt;  System.out.print( "Podaj nazwy grup produktowych: " );&lt;br /&gt;  String itemsGroupsInput = scanner.nextLine();&lt;br /&gt;  builder.addItemGroups( itemsGroupsInput );&lt;br /&gt;  String[] itemGroupsNames = itemsGroupsInput.split( " " );&lt;br /&gt;  for ( int i = 0; i &lt; itemGroupsNames.length; ++i ) {&lt;br /&gt;    System.out.print( "Podaj ilość produktów dla grupy '" + itemGroupsNames[ i ] + "' : " );&lt;br /&gt;    int itemsAmount = Integer.parseInt( scanner.nextLine() );&lt;br /&gt;    for( int j = 0; j &lt; itemsAmount; ++j ) {&lt;br /&gt;      System.out.print( "Dodaj produkt dla grupy '" + itemGroupsNames[ i ] + "' : " );&lt;br /&gt;      String itemParamsInput = scanner.nextLine();&lt;br /&gt;      builder.addItem( itemParamsInput );&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;  orders.add( builder.getOrder() );&lt;br /&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Choć nie idealnie to jednak jest nieco lepiej - metoda mieści się na jednym ekranie:)&lt;br /&gt;&lt;h4&gt;Krok 2: Chodzenie po strukturze zamówienia&lt;/h4&gt;&lt;br /&gt;To, co nam bruździ to fakt, trze trzeba dodać &lt;span style="font-style:italic;"&gt;Item&lt;/span&gt;s do każdej z &lt;span style="font-style:italic;"&gt;ItemGroup&lt;/span&gt;. Więc najpierw za pomocą &lt;span style="font-style:italic;"&gt;OrderBuilder.addItemGroups&lt;/span&gt; tworzone są wszystkie grupy, ale jeszcze dodatkowo &lt;span style="font-style:italic;"&gt;UserInterface &lt;/span&gt;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 (&lt;span style="font-style:italic;"&gt;String[]&lt;/span&gt; i &lt;span style="font-style:italic;"&gt;Set&lt;ItemGroup&gt;&lt;/span&gt;) w dwóch różnych miejscach (&lt;span style="font-style:italic;"&gt;UserInterface &lt;/span&gt; i &lt;span style="font-style:italic;"&gt;OrderBuilder&lt;/span&gt;).&lt;br /&gt;&lt;br /&gt;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:&lt;br /&gt;&lt;div&gt;&lt;pre class="brush: java"&gt;public class OrderBuilder {&lt;br /&gt;  private Order order;&lt;br /&gt;  private Iterator&lt;ItemGroup&gt; groupIterator;	&lt;br /&gt;  private ItemGroup currentGroup;&lt;br /&gt;  public void newOrder( String orderId, int orderPriority ) {&lt;br /&gt;    order = new Order( orderId, orderPriority );&lt;br /&gt;  }&lt;br /&gt;  public void addItemGroups( String itemsGroupsInput ) {&lt;br /&gt;    String[] itemGroupsNames = itemsGroupsInput.split( " " );		&lt;br /&gt;    for ( int i = 0; i &lt; itemGroupsNames.length; ++i ) {			&lt;br /&gt;      order.addItemGrup( new ItemGroup( itemGroupsNames[ i ] ) );&lt;br /&gt;    }&lt;br /&gt;    groupIterator = order.getItemGroups();&lt;br /&gt;  }&lt;br /&gt;  public void addItem( String itemParamsInput ) {&lt;br /&gt;    String[] itemParams = itemParamsInput.split( " " );&lt;br /&gt;    String groupName = itemParams[ 0 ];&lt;br /&gt;    Money price = Money.parseMoney( itemParams[ 1 ] );&lt;br /&gt;    int qty = Integer.parseInt( itemParams[ 2 ] ); 	 &lt;br /&gt;    currentGroup.addItem( new Item( groupName, price, qty ) );&lt;br /&gt;  }&lt;br /&gt;  public Order getOrder() {&lt;br /&gt;    return order;&lt;br /&gt;  }	&lt;br /&gt;  public boolean hasNextItemGroup() {&lt;br /&gt;    if ( groupIterator == null ) {&lt;br /&gt;      return false;&lt;br /&gt;    }		&lt;br /&gt;    return groupIterator.hasNext();&lt;br /&gt;  }&lt;br /&gt;  public void moveNextItemGroup() {&lt;br /&gt;    currentGroup = groupIterator.next();&lt;br /&gt;  }	&lt;br /&gt;  public String getCurrentItemGroupName() {&lt;br /&gt;    return currentGroup.getName();&lt;br /&gt;  }	&lt;br /&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Natomiast korzystanie z budowniczego wygląda następująco:&lt;br /&gt;&lt;div&gt;&lt;pre class="brush: java"&gt;public void addOrder() {&lt;br /&gt;  Scanner scanner = new Scanner( System.in );	&lt;br /&gt;  System.out.print( "Podaj identyfikator zamówienia: " );&lt;br /&gt;  String orderId = scanner.nextLine();&lt;br /&gt;  System.out.print( "Podaj priorytet zamówienia: " );&lt;br /&gt;  int orderPriority = Integer.parseInt( scanner.nextLine() );&lt;br /&gt;  OrderBuilder builder = new OrderBuilder();&lt;br /&gt;  builder.newOrder( orderId, orderPriority );&lt;br /&gt;  System.out.print( "Podaj nazwy grup produktowych: " );&lt;br /&gt;  builder.addItemGroups( scanner.nextLine() );&lt;br /&gt;  while ( builder.hasNextItemGroup() ) {&lt;br /&gt;    builder.moveNextItemGroup();&lt;br /&gt;    System.out.print( "Podaj ilość produktów dla grupy '" +       builder.getCurrentItemGroupName() + "' : ");&lt;br /&gt;    int itemsAmount = Integer.parseInt( scanner.nextLine() );&lt;br /&gt;    for( int j = 0; j &lt; itemsAmount; ++j ) {&lt;br /&gt;      System.out.print( "Dodaj produkt dla grupy '" + builder.getCurrentItemGroupName() + "' : " );&lt;br /&gt;      builder.addItem( scanner.nextLine() );&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;  orders.add( builder.getOrder() );&lt;br /&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Teraz już klasa &lt;span style="font-style:italic;"&gt;UserInterface&lt;/span&gt; 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. &lt;br /&gt;&lt;br /&gt;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 &lt;a href="http://en.wikipedia.org/wiki/Iterator"&gt;Iteratorem&lt;/a&gt;. Dalej warto metody iterator wydzielić do osobnego interfejsu, ale to już nieco inna historia.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1759916214638009707-4950226740235495530?l=mbartyzel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mbartyzel.blogspot.com/feeds/4950226740235495530/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1759916214638009707&amp;postID=4950226740235495530' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/4950226740235495530'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/4950226740235495530'/><link rel='alternate' type='text/html' href='http://mbartyzel.blogspot.com/2011/08/interfejs-budowniczego.html' title='Interfejs budowniczego'/><author><name>Michał Bartyzel</name><uri>http://www.blogger.com/profile/03968505875451301931</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-yUN4te1q6bU/TkGj4lciDAI/AAAAAAAAA4A/jnZfRCvUwk0/s72-c/model.PNG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1759916214638009707.post-7545659677626645982</id><published>2011-07-11T09:23:00.004+02:00</published><updated>2011-07-12T23:35:20.636+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='info'/><title type='text'>Ogłoszenie: Będę w Gdańsku :)</title><content type='html'>Nawiązując do &lt;a href="http://mbartyzel.blogspot.com/2011/06/jak-wykorzystac-swoje-doswiadczenie-i.html"&gt;posta &lt;/a&gt;, na temat współpracy z &lt;a href="http://bnsit.pl/"&gt;BNS IT&lt;/a&gt; w charakterze Trenera/Konsultanta:&lt;br /&gt;&lt;br /&gt;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 &lt;span style="font-style:italic;"&gt;moje_imię kropka moje_nazwisko na serwerze bnsit kropka pl&lt;/span&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1759916214638009707-7545659677626645982?l=mbartyzel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mbartyzel.blogspot.com/feeds/7545659677626645982/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1759916214638009707&amp;postID=7545659677626645982' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/7545659677626645982'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/7545659677626645982'/><link rel='alternate' type='text/html' href='http://mbartyzel.blogspot.com/2011/07/ogoszenie-bede-w-gdansku.html' title='Ogłoszenie: Będę w Gdańsku :)'/><author><name>Michał Bartyzel</name><uri>http://www.blogger.com/profile/03968505875451301931</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1759916214638009707.post-2698221543036240024</id><published>2011-07-06T22:43:00.011+02:00</published><updated>2011-07-07T18:28:11.779+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='wzorce'/><category scheme='http://www.blogger.com/atom/ns#' term='wizje'/><title type='text'>Poza wzorcami projektowymi</title><content type='html'>&lt;span style="font-style:italic; font-size:80%"&gt;To jest odległa kontynuacja artykułu &lt;a href="http://mbartyzel.blogspot.com/2008/11/jzyk-wzorcw.html" target="_blank"&gt;Język wzorców&lt;/a&gt;&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;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:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Null_Object_pattern"&gt;Null Object&lt;/a&gt; - bo w C++ referencja musi być zainicjowana; wyeliminowane przez Java, C# (nieścisłość, @see Komentarz pod postem Chrisphera Daniela)&lt;/li&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/State_pattern"&gt;State&lt;/a&gt; - bo implementacja maszyny stanów oparta o tablicę wskaźników do funkcji oraz serię switch/case&lt;/li&gt; jest dość trudna w utrzymaniu&lt;/li&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/State_pattern"&gt;Interpreter &lt;/a&gt;- jaki tam wzorzec;)? sposób na parsowanie ustrukturyzowanych gramatyk i tyle; wyeliminowane przez tony bibliotek narzędziowych&lt;/li&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Flyweight_pattern"&gt;Flyweigh&lt;/a&gt; - bo nie ma kasy na więcej pamięci&lt;/li&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Command_pattern"&gt;Command&lt;/a&gt; - w C# wykoszony przez delegaty (mam na myśli ten kontekst użycia, w którym robimy &lt;span style="font-style:italic;"&gt;execute()&lt;/span&gt;, a nie przechowujemy komendę, aby ją potem &lt;span style="font-style:italic;"&gt;handle()&lt;/span&gt; )&lt;/li&gt;&lt;li&gt;Właściwie wszystkie wzorce opisane w &lt;a href="http://java.sun.com/blueprints/corej2eepatterns/Patterns/"&gt;Core J2EE Patterns&lt;/a&gt; i &lt;a href="http://www.amazon.com/Patterns-Enterprise-Application-Architecture-Martin/dp/0321127420"&gt;PoEAA&lt;/a&gt; - zastąpione przez biblioteki, frameworki i technologie&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Czym zatem są wzorce projektowe? Mówi się, że &lt;span style="font-style:italic;"&gt;rozwiązaniami typowych problemów&lt;/span&gt;. 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?&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Jak powstają?&lt;/b&gt;&lt;br /&gt;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:&lt;br /&gt;&lt;dl&gt;&lt;dt&gt;&lt;span style="font-weight:bold;"&gt;Przestrzegaj opodwiedzialności&lt;/span&gt;&lt;/dt&gt;&lt;dd&gt;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ą &lt;span style="font-weight:bold;"&gt;tylko jedną opodwiedzialność&lt;/span&gt;, która będzie &lt;span style="font-weight:bold;"&gt;wyrażona nazwą&lt;/span&gt;&lt;/dd&gt;&lt;dt&gt;&lt;span style="font-weight:bold;"&gt;Enkapsuluj&lt;/span&gt;&lt;/dt&gt;&lt;dd&gt;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.&lt;/dd&gt;&lt;dt&gt;&lt;span style="font-weight:bold;"&gt;Preferuj kompozycję ponad dziedziczenie&lt;/span&gt;&lt;/dt&gt;&lt;dd&gt;Związki używania czynią kod bardziej elastycznym, czytelnym i testowalnym. Dodatkowo pozwalają na rozszerzanie funkcjonalności kodu &lt;span style="font-style:italic;"&gt;run-time&lt;/span&gt;, a nie tylko poprzez przekompilowanie.&lt;/dd&gt;&lt;/dl&gt;&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;Wymienione reguły są dość niskopoziomowe, w całościowy proces ujmuje koncept, który nazwaliśmy roboczo &lt;a href="http://msieraczkiewicz.blogspot.com/2011/02/naturalny-porzadek-refaktoryzacji-idea.html"&gt;Nautralnym porządkiem refaktoryzacji&lt;/a&gt;.&lt;br /&gt;&lt;table&gt;&lt;tr&gt;&lt;td&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/-C_Hf06R_MR0/ThTYGmWEUaI/AAAAAAAAA3w/8Tc8kWRW7dw/s1600/Obraz1.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 227px;" src="http://1.bp.blogspot.com/-C_Hf06R_MR0/ThTYGmWEUaI/AAAAAAAAA3w/8Tc8kWRW7dw/s400/Obraz1.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5626359442376511906" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Koncept &lt;a href="http://msieraczkiewicz.blogspot.com/2011/02/naturalny-porzadek-refaktoryzacji-idea.html"&gt;Nautralnego porządku refaktoryzacji&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;Pisał już o tym sporo &lt;a href="http://msieraczkiewicz.blogspot.com"&gt;Mariusz&lt;/a&gt; w artykułach: &lt;a href="http://msieraczkiewicz.blogspot.com/2011/02/naturalny-porzadek-refaktoryzacji-idea.html"&gt;NPR - Idea rysunkowa&lt;/a&gt;, &lt;a href="http://msieraczkiewicz.blogspot.com/2011/05/naturalny-porzadek-refaktoryzacji-pod.html"&gt;NPR - pod lupą&lt;/a&gt;, &lt;a href="http://msieraczkiewicz.blogspot.com/2011/06/naturalny-porzadek-refaktoryzacji-pod.html"&gt;NPR: Compose Method&lt;/a&gt;, &lt;a href="http://msieraczkiewicz.blogspot.com/2011/06/naturalny-porzadek-refaktoryzacji-pod_11.html"&gt;NPR: Extract Method&lt;/a&gt;, &lt;a href="http://msieraczkiewicz.blogspot.com/2011/06/naturalny-porzadek-refaktoryzacji-pod_29.html"&gt;NPR: Refaktoryzacja do wzorców&lt;/a&gt;, &lt;a href="http://msieraczkiewicz.blogspot.com/2011/06/naturalny-porzadek-refaktoryzacji-pod_5301.html"&gt;NPR: Ewolucja architektury&lt;/a&gt;, więc nie będę się powtarzał.&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Morfizmy w kodzie&lt;/span&gt;&lt;br /&gt;Zauważmy, że w charakterystyka wzorca projektowego zawiera między innymi &lt;span style="font-style:italic;"&gt;Motywację/Intencję&lt;/span&gt;, &lt;span style="font-style:italic;"&gt;Kontekst&lt;/span&gt;, &lt;span style="font-style:italic;"&gt;Problem&lt;/span&gt;. 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!&lt;br /&gt;&lt;br /&gt;Aktualne dobre rozwiązanie, które przywykliśmy nazywać wzorcem projektowym, jest tak naprawdę &lt;span style="font-weight:bold;"&gt;lokalnym optimum&lt;/span&gt;, jakieś funkcji (powiedzmy, że &lt;span style="font-style:italic;"&gt;Funkcji kodu&lt;/span&gt;) w której zmiennymi są przynajmniej: &lt;span style="font-style:italic;"&gt;Kontekst &lt;/span&gt;oraz &lt;span style="font-style:italic;"&gt;Problem&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Tak zwany wzorzec rozwiązuje problem tylko na chwilę, dopóki &lt;span style="font-style:italic;"&gt;Funkcja kodu&lt;/span&gt; nie ulegnie zmianie, a optimum nie wystrzeli w inną stronę. Mamy wiec do czynienia nie tyle z wzorcami, co z &lt;span style="font-weight:bold;"&gt;optymalnymi morfizmami w kodzie&lt;/span&gt; (niech, Ockham mi wybaczy). Zmiana &lt;span style="font-style:italic;"&gt;Funkcji kodu&lt;/span&gt;, po której programując się ślizgamy powoduje, że dany morfizm przestaje być optymalny i musimy poszukać nowego optimum właśnie poprzez refaktoryzację.&lt;br /&gt;&lt;table&gt;&lt;tr&gt;&lt;td&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/-QmVxx0fmspc/ThTmV8x5CAI/AAAAAAAAA34/GJWMcvGbp2c/s1600/Przechwytywanie.PNG"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 228px;" src="http://3.bp.blogspot.com/-QmVxx0fmspc/ThTmV8x5CAI/AAAAAAAAA34/GJWMcvGbp2c/s400/Przechwytywanie.PNG" border="0" alt=""id="BLOGGER_PHOTO_ID_5626375099259619330" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Optymalne morfizmy&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Wnioski&lt;/span&gt;&lt;br /&gt;Czy poza gimnastyką umysłu wypływają stąd jakieś wnioski? Owszem, kilka.&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Istnieje nieskończenie wiele optymalnych morfizmów w kodzie - ponieważ zakres zmienności &lt;span style="font-style:italic;"&gt;Problemów&lt;/span&gt; oraz &lt;span style="font-style:italic;"&gt;Kontekstów &lt;/span&gt;jest również nieskończony; w związku z tym publikacje i dywagacje na temat nowych wzorców projektowych nigdy się nie skończą&lt;/li&gt;&lt;li&gt;Refaktoryzacja musi trwać - ponieważ &lt;span style="font-style:italic;"&gt;Funkcja kodu&lt;/span&gt; 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&lt;/li&gt;&lt;li&gt;Ważniejsze jest zdyscyplinowane posługiwanie się wspomnianymi wyżej zasadami i procesem refaktoryzacji niż szastanie kolekcjami nazw wzorców&lt;/li&gt;&lt;li&gt;Nie jest możliwe stworzenie czegoś takiego jak &lt;span style="font-style:italic;"&gt;patterns language&lt;/span&gt; (por: &lt;a href="http://www.amazon.com/gp/product/0471486485/ref=pd_lpo_k2_dp_sr_1?pf_rd_p=1278548962&amp;pf_rd_s=lpo-top-stripe-1&amp;pf_rd_t=201&amp;pf_rd_i=0195019199&amp;pf_rd_m=ATVPDKIKX0DER&amp;pf_rd_r=09B546HNFDN8KFN3TANA"&gt;On Patterns and Pattern Languages&lt;/a&gt;), bo optymalne morfizmy wciąż się przekształcają podążając za zmianami Funkcji Kodu&lt;/li&gt;&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1759916214638009707-2698221543036240024?l=mbartyzel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mbartyzel.blogspot.com/feeds/2698221543036240024/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1759916214638009707&amp;postID=2698221543036240024' title='Komentarze (5)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/2698221543036240024'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/2698221543036240024'/><link rel='alternate' type='text/html' href='http://mbartyzel.blogspot.com/2011/07/poza-wzorcami-projektowymi.html' title='Poza wzorcami projektowymi'/><author><name>Michał Bartyzel</name><uri>http://www.blogger.com/profile/03968505875451301931</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-C_Hf06R_MR0/ThTYGmWEUaI/AAAAAAAAA3w/8Tc8kWRW7dw/s72-c/Obraz1.jpg' height='72' width='72'/><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1759916214638009707.post-3120602869323553644</id><published>2011-06-27T22:30:00.012+02:00</published><updated>2011-06-28T11:32:01.261+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='pea'/><title type='text'>PEA(3): Wyodrębnianie user stories</title><content type='html'>&lt;span style="font-style:italic; font-size:80%"&gt;To jest artykuł z serii &lt;a href="http://mbartyzel.blogspot.com/search/label/pea" target="_blank"&gt;Proces ewolucji architektury&lt;/a&gt;&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Po dość zgrubnym rozeznaniu się w &lt;a href="http://mbartyzel.blogspot.com/2011/03/pea2-kontekst-srodowiskowy-systemu.html"&gt;środowiskowym kontekście systemu&lt;/a&gt;, jest czas na nieco więcej konkretów na temat funkcjonalności.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Część I - Przygotowanie&lt;/h3&gt;&lt;br /&gt;&lt;b&gt;Dobór grupy&lt;/b&gt;&lt;br /&gt;Do wyodrębnienia &lt;span style="font-style:italic;"&gt;user stories&lt;/span&gt; świetnie nadają się spotkania focusowe. I ty pytanie z kim? &lt;br /&gt;Najlepiej, aby grupa była różnorodna. Jednorodne grupy mają tendencję do "krzywienia" &lt;span style="font-style:italic;"&gt;user stories&lt;/span&gt;. Na przykład programiści formułują je bardzo &lt;span style="font-style:italic;"&gt;crudowo&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Aktorzy&lt;/b&gt;&lt;br /&gt;Jeśli to możliwe, już na samym początku zidentyfikuj aktorów. Zadaj sobie pytanie &lt;span style="font-style:italic;"&gt;Kto będzie wołał ten system?&lt;/span&gt;. W tym momencie masz już wstępnie rozpoznanych na następujących aktorów:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;inne systemy - ponieważ poznałeś &lt;a href="http://mbartyzel.blogspot.com/2011/03/pea2-kontekst-srodowiskowy-systemu.html"&gt;kontekst &lt;/a&gt;pracy systemu&lt;/li&gt;&lt;li&gt;użytkownik - na razie to dość ogólne sformułowanie, taki &lt;span style="font-style:italic;"&gt;metaaktor&lt;/span&gt;, którego pojęcie będzie dokonkretyzowywać się w trakcie dalszych rozmów&lt;/li&gt;&lt;li&gt;dla porządku warto dorzucić jeszcze jednego: &lt;span style="font-style:italic;"&gt;Time &lt;/span&gt;; 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&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;table&gt;&lt;tr&gt;&lt;td&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/-oO8iidDn3p0/TgmZkaMa4ZI/AAAAAAAAA3g/F05vRp0V0EM/s1600/aktorzy.PNG"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 241px;" src="http://3.bp.blogspot.com/-oO8iidDn3p0/TgmZkaMa4ZI/AAAAAAAAA3g/F05vRp0V0EM/s400/aktorzy.PNG" border="0" alt=""id="BLOGGER_PHOTO_ID_5623194460534530450" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;Rysunek 1: Wstępny szkic aktorów w systemie&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;Wstępne nazwanie aktorów pomaga konkretnej zadawać pytania. Głównie o to tu chodzi.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Konwencja nazewnicza&lt;/b&gt;&lt;br /&gt;Ustal ramową konwencję nazewniczą, zazwyczaj są dwie konkurencyjne alternatywy:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;anglojęzyczna - działa proporcjonalnie do swobody językowej&lt;/li&gt;&lt;li&gt;polskojęzyczna - często jeden do jednego przekłada słownictwo binzesowe, ale w kodzie będą wychodzić zabawane &lt;span style="font-style:italic;"&gt;pongliszowe &lt;/span&gt;kwiatki&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Najkorzystniej jest promować taką konwencję nazewniczą, która zmienia jak najmniej przyzwyczajeń. &lt;br /&gt;&lt;br /&gt;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 &lt;span style="font-weight:bold;"&gt;wzajemnego zrozumienia&lt;/span&gt;. 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:&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Co ma Pan na myśli mówiąc &amp;lt;&amp;lt;szkolenie&amp;gt;&amp;gt;. To &amp;lt;&amp;lt;program&amp;gt;&amp;gt; szkolenia, czy &amp;lt;&amp;lt;czynność&amp;gt;&amp;gt; prowadzenia szkolenia? Acha, rozumiem, czyli możemy mówić o szkoleniu &amp;lt;&amp;lt;możliwym do zorganizowania&amp;gt;&amp;gt; oraz &amp;lt;&amp;lt;zorganizowanym&amp;gt;&amp;gt; szkoleniu?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;table&gt;&lt;tr&gt;&lt;td&gt; &lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/-WTVjCo7vgXQ/TgmV7v_qEwI/AAAAAAAAA3Y/sjDNujDEhRM/s1600/rozne_slownictwo.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 134px;" src="http://4.bp.blogspot.com/-WTVjCo7vgXQ/TgmV7v_qEwI/AAAAAAAAA3Y/sjDNujDEhRM/s400/rozne_slownictwo.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5623190463477060354" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;span style="font-style:italic;"&gt;Rysunek 2: różne nazwy na te same rzeczy, to jedna z większych trudności&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;Tego typu różnice dość szybko wychodzą, jeśli zadbasz o wspomnianą wcześniej różnorodność grupy.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Kto nazywa ten rządzi&lt;/b&gt;&lt;br /&gt;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ł.&lt;br /&gt;&lt;br /&gt;Najlepiej, aby nazwa wzięła się z rzeczywistości np.: &lt;span style="font-style:italic;"&gt;kalendarz elektroniczny&lt;/span&gt;, aby występowała w informatyzowanym procesie. Łatwo wtedy eliminować wodotryski, zadając proste pytanie &lt;span style="font-style:italic;"&gt;Czy dotychczas w kalendarzu również miał Pan możliwość dodawania awatarów?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Nic nie mówiące i zbyt ogólne nazwy z kategorii &lt;span style="font-style:italic;"&gt;Zintegrowany System Informatyczny&lt;/span&gt;, to otwarta furtka do wylądowania poza budżetem lub terminem lub oboma jednocześnie.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Część I - Prowadzenie sesji wyodrębniania &lt;span style="font-style:italic;"&gt;user stories&lt;/span&gt;&lt;/h3&gt;&lt;br /&gt;&lt;b&gt;Zasady ogólne&lt;/b&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;Historycznie &lt;span style="font-style:italic;"&gt;user storier&lt;/span&gt; spisywane są na małych kartkach. Powiedzmy sobie jednak szczerze, że arkuszem Excela o wiele lepiej się zarządza.&lt;br /&gt;Jak to zatem jest z tymi karteczkami? Z całego serca polecam karteczki (żółte, samoprzylepne :) ). Mają one tę wielką zaletę, że &lt;span style="font-weight:bold;"&gt;budują zaangażowanie&lt;/span&gt; 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.&lt;br /&gt;&lt;br /&gt;Jeśli będziesz zachęcać ludzi, aby sami pisali &lt;span style="font-style:italic;"&gt;user stories&lt;/span&gt; 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.&lt;br /&gt;&lt;br /&gt;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 &lt;a href="http://www.scrumdo.com"&gt;Scrum Do&lt;/a&gt;. Jest bardzo grywalne, zawiera wszystko co potrzeba, a jednocześnie jest kompletnie nieinwazyjne. Minusem jest to, że działa on-line.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Formułowanie historyki&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/-7001lWovDRU/TgmVbWIZgUI/AAAAAAAAA3Q/h1B6WEuzurc/s1600/sesja-us.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 194px;" src="http://2.bp.blogspot.com/-7001lWovDRU/TgmVbWIZgUI/AAAAAAAAA3Q/h1B6WEuzurc/s400/sesja-us.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5623189906778587458" /&gt;&lt;/a&gt;&lt;br /&gt;Ogólny algorytm prowadzenia sesji wygląda tak:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Ustal uwagę na pierwszym ekranie&lt;/li&gt;&lt;li&gt;Zadaj pytanie: &lt;span style="font-style:italic;"&gt;Co można zrobić na tym ekranie?&lt;/span&gt;&lt;/li&gt;&lt;li&gt;Skłoń ludzi, aby sformułowali swoje oczekiwania w następujący sposób:&lt;span style="font-style:italic;"&gt; Jako &lt;/span&gt;&amp;lt;&amp;lt;kto?&amp;gt;&amp;gt;&lt;span style="font-style:italic;"&gt;mogę &lt;/span&gt;&amp;lt;&amp;lt;funkcjonalność&amp;gt;&amp;gt;, &lt;span style="font-style:italic;"&gt;aby &lt;/span&gt;&amp;lt;&amp;lt;po co?&amp;gt;&amp;gt;&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;ol&gt;&lt;li&gt;&lt;span style="font-style:italic;"&gt;Jako &lt;/span&gt;&amp;lt;&amp;lt;kto?&amp;gt;&amp;gt; - 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&lt;/li&gt;&lt;li&gt;&lt;span style="font-style:italic;"&gt;mogę &lt;/span&gt;&amp;lt;&amp;lt;funkcjonalność&amp;gt;&amp;gt; - tu precyzujemy konkretną funkcjonalność, do której dany użytkownik ma mieć dostęp&lt;/li&gt;&lt;li&gt;&lt;span style="font-style:italic;"&gt;aby &lt;/span&gt;&amp;lt;&amp;lt;po co?&amp;gt;&amp;gt; - 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ę &lt;span style="font-style:italic;"&gt;po co&lt;/span&gt; coś będzie potrzebne, to czasem dochodzą do wniosku, że po nic&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Ogólniki i szczególiki&lt;/b&gt;&lt;br /&gt;Podczas spisywania historyjek, możemy otrzymać efekt dwojakiego rodzaju:&lt;br /&gt;&lt;dl&gt;&lt;br /&gt;&lt;dt&gt;konkretne &lt;span style="font-style:italic;"&gt;user stories&lt;/span&gt;&lt;/dt&gt;&lt;dd&gt;np.: &lt;span style="font-style:italic;"&gt;Jako U mogę zobaczyć listę swoich zamówień, aby wiedzieć co już otrzymałem, a czego jeszcze nie&lt;/span&gt;; do takich sformułowań zmierzamy podczas pracy z interesariuszami&lt;/dd&gt;&lt;br /&gt;&lt;dt&gt;niekonkretne &lt;span style="font-style:italic;"&gt;user stories&lt;/span&gt;&lt;/dt&gt;&lt;dd&gt;np.&lt;span style="font-style:italic;"&gt; Jako P mogę zarządzać dokumentami?&lt;/span&gt;; 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 &lt;a href="http://scrummethodology.com/scrum-epics"&gt;epic&lt;/a&gt;;&lt;/dd&gt;&lt;br /&gt;&lt;/dl&gt;&lt;br /&gt;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 &lt;span style="font-style:italic;"&gt;user stories&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Dodatkowe porady&lt;/b&gt;&lt;br /&gt;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ą.&lt;br /&gt;&lt;br /&gt;Tego typu spotkania wygodnie jest prowadzić w dwie osoby. Jedna aktywnie moderuje rozmowę, druga nieco mniej zaangażowana zachowuje &lt;span style="font-style:italic;"&gt;big picture&lt;/span&gt; i wkracza w razie kłopotów.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1759916214638009707-3120602869323553644?l=mbartyzel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mbartyzel.blogspot.com/feeds/3120602869323553644/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1759916214638009707&amp;postID=3120602869323553644' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/3120602869323553644'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/3120602869323553644'/><link rel='alternate' type='text/html' href='http://mbartyzel.blogspot.com/2011/06/pea3-wyodrebnianie-user-stories.html' title='PEA(3): Wyodrębnianie user stories'/><author><name>Michał Bartyzel</name><uri>http://www.blogger.com/profile/03968505875451301931</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/-oO8iidDn3p0/TgmZkaMa4ZI/AAAAAAAAA3g/F05vRp0V0EM/s72-c/aktorzy.PNG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1759916214638009707.post-243009024704785176</id><published>2011-06-16T23:44:00.005+02:00</published><updated>2011-06-17T23:00:31.685+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='wzorce'/><category scheme='http://www.blogger.com/atom/ns#' term='embedded'/><category scheme='http://www.blogger.com/atom/ns#' term='refaktoring'/><title type='text'>Obiektowość dla embedded?</title><content type='html'>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.&lt;br /&gt;&lt;br /&gt;Jakiś czas temu, konstruktywnie krytykując mój &lt;a href="http://mbartyzel.blogspot.com/2011/03/lean-architecture-for-agile-software.html"&gt;wpis, &lt;/a&gt; &lt;a href="http://art-of-software.blogspot.com/"&gt;Sławek&lt;/a&gt; powiedział mniej więcej coś takiego: "Kto w obecnych czasach podaje w książkach przykłady w C++? Od razu widać, że &lt;span style="font-style:italic;"&gt;old school&lt;/span&gt;"&lt;br /&gt;&lt;br /&gt;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 &lt;a href="http://www.tiobe.com/index.php/content/paperinfo/tpci/index.html"&gt;ten ranking&lt;/a&gt;. Jak widać Java i C# mają towarzystwo i to całkiem spore.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;RTS, Entertainment&lt;/span&gt;&lt;br /&gt;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 &lt;a href="http://www.oracle.com/technetwork/java/javacard/overview/index.html"&gt;Java Card&lt;/a&gt;)&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;C rządzi!&lt;/span&gt;&lt;br /&gt;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. &lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Brak kompilatorów&lt;/span&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Koszt wejścia&lt;/span&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Niedoskonałość sprzętu&lt;/span&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Trudności w poszukiwaniu błędów&lt;/span&gt;&lt;br /&gt;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++.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Koronny argument - wydajność&lt;/span&gt;&lt;br /&gt;Hmmm, trochę prawda, trochę mit. Tak myślę. Przeanalizujmy.&lt;br /&gt;&lt;br /&gt;Po pierwsze: &lt;br /&gt;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?&lt;br /&gt;&lt;br /&gt;Po drugie: &lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;Po trzecie:&lt;br /&gt;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: &lt;span style="font-weight:bold;"&gt;czytelność ponad wydajność&lt;/span&gt;. 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ć. &lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Co dalej?&lt;/span&gt;&lt;br /&gt;Jakie wyzwania stoją przed technikami refaktoryzacji i wzorcami, które w swoim najbardziej światowym wydaniu, utknęły gdzieś pomiędzy Javą a C#?&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Jak pracować z hybrydowym &lt;span style="font-style:italic;"&gt;legacy code&lt;/span&gt;, pisanym trochę w C trochę w C++?&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Jak bezpiecznie przepisywać kod proceduralny na obiektowy?&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Jakie standardy kodowania przyjąć dla C++, aby uniknąć pułapek wynikających z bogactwa języka&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Jak sensownie rozwinąć narzędzia wspierające refaktoryzację. Sorki, ale VC++ i wsparcie dla refaktoryzacji to porażka. &lt;a href="http://www.wholetomato.com/"&gt;Visual Assist X&lt;/a&gt; jest super, ale to jeszcze nie to. Eclipse C/C++ nie próbowałem, &lt;a href="http://www.windriver.com/products/workbench/"&gt;Wind River Workbench&lt;/a&gt; jest ponoć dobry, ale i kosztuje słono&lt;/li&gt;&lt;br /&gt;&lt;li&gt;i cała reszta bajerów, których się w okół Javy i C# dorobiliśmy&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;Za różnymi problemami oraz przekonaniami kryją się ludzie, którzy poszukują skutecznych rozwiązań swoich problemów. Na pewno coś da się zrobić.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1759916214638009707-243009024704785176?l=mbartyzel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mbartyzel.blogspot.com/feeds/243009024704785176/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1759916214638009707&amp;postID=243009024704785176' title='Komentarze (3)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/243009024704785176'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/243009024704785176'/><link rel='alternate' type='text/html' href='http://mbartyzel.blogspot.com/2011/06/obiektowosc-dla-embedded.html' title='Obiektowość dla embedded?'/><author><name>Michał Bartyzel</name><uri>http://www.blogger.com/profile/03968505875451301931</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1759916214638009707.post-2302751328075412949</id><published>2011-06-09T21:57:00.006+02:00</published><updated>2011-06-10T00:27:15.609+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><category scheme='http://www.blogger.com/atom/ns#' term='analiza'/><category scheme='http://www.blogger.com/atom/ns#' term='zarządzanie'/><title type='text'>Value Stream i zarządzanie wymaganiami w korporacji</title><content type='html'>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.&lt;br /&gt;&lt;br /&gt;Podczas warsztatów z zarządzania wymaganiami największy &lt;span style="font-style:italic;"&gt;challenge&lt;/span&gt; mam z pracownikami departamentów IT w korporacjach. Złożoność organizacyjna rodzi kilka dodatkowych problemów.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Hipertraceability&lt;/span&gt;&lt;br /&gt;Pisałem na ten temat &lt;a href="http://mbartyzel.blogspot.com/2011/04/zeby-tak-wszystko-ze-wszystkiego.html"&gt;tutaj&lt;/a&gt;. Nie dajmy się zwieść, że pragnienie hipertraceability jest potrzebą organizacji. Nie jest to potrzeba lecz &lt;span style="font-style:italic;"&gt;rozwiązanie&lt;/span&gt; problemu związanego z bałaganem w wymaganiach. Rozwiązanie to daje złudzenie, że wszystko jest pod kontrolą. Zazwyczaj nie jest.&lt;br /&gt;&lt;br /&gt;Wstrzymałbym się chwilowo ze skłanianiem się ku temu rozwiązaniu dopóki dokładnie nie zrozumiemy natury problemu. (tak tak wiem, &lt;span style="font-style:italic;"&gt;focus on solutions, not on problems&lt;/span&gt;; ale czy można zaproponować rozwiązania nie rozumiejąc problemu? - moim zdaniem nie). &lt;br /&gt;&lt;br /&gt;Niech nieco światła na problem zarządzania wymaganiami w korporacjach rzuci parę poniższych akapitów.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Time to market&lt;/span&gt;&lt;br /&gt;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ę!&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Harmonogram wdrożeń i rezerwacja mendejsów&lt;/span&gt;&lt;br /&gt;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). &lt;br /&gt;&lt;br /&gt;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 &lt;span style="font-style:italic;"&gt;Jakiś Bardzo Ważny Projekt&lt;/span&gt;. 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".&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Pigułka: Nowy System&lt;/span&gt;&lt;br /&gt;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 ??? &lt;br /&gt;&lt;br /&gt;Mimo szczegółowej procedury decyzyjnej oraz masy zebrań, komitetów, analiz i opinii, powstaje pięćset szósty system, który sprawia, że:&lt;br /&gt;&lt;ul style="line-height: 0.9em;"&gt;&lt;br /&gt;&lt;li&gt;potrzeba kolejnego etatu do jego utrzymania,&lt;/li&gt;&lt;br /&gt;&lt;li&gt;SOA staje się naprawdę jedynym sensownym rozwiązaniem,&lt;/li&gt;&lt;br /&gt;&lt;li&gt;skomplikowanie procedur organizacyjnych dąży do nieskończoności,&lt;/li&gt;&lt;br /&gt;&lt;li&gt;końcowi użytkownicy ze starymi przyzwyczajeniami próbują korzystać ze starego systemu na nowy sposób i klną na czym świat stoi.&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Paraliż decyzyjny&lt;/span&gt;&lt;br /&gt;Wyobraźmy sobie następującą, powiedzmy, że hipotetyczną, sytuację:&lt;br /&gt;&lt;ul style="line-height: 1.05em;"&gt;&lt;br /&gt;&lt;li&gt;Komitet sterujący projektu IT składa się z: Prezesa oraz członków Zarządu&lt;/li&gt; &lt;br /&gt;&lt;li&gt;Komitet spotyka się z Kierownikiem Projektu, aby podjąć decyzję o zmianie harmonogramu tworzenia projektu&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;Rozmowa przebiega następująco:&lt;br /&gt;&lt;ul style="line-height: 1.05em;"&gt;&lt;br /&gt;&lt;li&gt;Kierownik: C&lt;span style="font-style:italic;"&gt;zy zmieniamy harmonogram?&lt;/span&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Prezes: &lt;span style="font-style:italic;"&gt;Zmieniamy?&lt;/span&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Członkowie Zarządu&lt;span style="font-style:italic;"&gt;: hmm...&lt;/span&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Prezes: &lt;span style="font-style:italic;"&gt;Tak! Zmieniamy!&lt;/span&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Kierownik: &lt;span style="font-style:italic;"&gt;A zatem wpisuję w protokole: "Komitet sterujący podjął decyzję o zmianie harmonogramu"&lt;/span&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Prezes: &lt;span style="font-style:italic;"&gt;Zaraz, zaraz...Jaką decyzję? Proszę napisać: "Komitet sterujący &lt;span style="font-weight:bold;"&gt;rekomenduje&lt;/span&gt; zmianę harmonogramu". Niech zostanie to zatwierdzone na zebraniu Zarządu.&lt;/span&gt;&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;yyyyy????&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Obosieczny miecz standardów&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Buy, don't write&lt;/span&gt; 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.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Zmęczony Biznes znajduje drogę na skróty&lt;/span&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;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: &lt;span style="font-weight:bold;"&gt;ktoś tam siedział, słuchał biznesu i zrobił&lt;/span&gt;. 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.&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Value Stream&lt;/span&gt;&lt;br /&gt;Ktoś kiedyś napisał bądź powiedział: "Informatyzacja efektywnego procesu zwielokrotnia jego efektywność. Optymalizacja procesu nieefektywnego zwielokrotnia jego nieefektywność".&lt;br /&gt;&lt;br /&gt;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 &lt;a href="http://en.wikipedia.org/wiki/Value_stream_mapping"&gt;strumienia wartości biznesowej&lt;/a&gt;, czyli zoptymalizowanego procesu zarabiania pieniędzy.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Tajemniczy Dział Optymalizacji Procesów&lt;/span&gt; &lt;br /&gt;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 &lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;Jako zajawkę w pokrewnej tematyce polecam &lt;a target="_blank" href="http://www.mragowo.pti.org.pl/pti/mragowo.nsf/a99b238a44267d1b80256e54005c1944/307cee159b86696780256f83006715ee/$FILE/Mragowo%202004,%20H.%20Glaser.pdf"&gt;prezentację&lt;/a&gt;. (nie wiem ile powisi, więc kiedyś link może się zdezaktualizować)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1759916214638009707-2302751328075412949?l=mbartyzel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mbartyzel.blogspot.com/feeds/2302751328075412949/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1759916214638009707&amp;postID=2302751328075412949' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/2302751328075412949'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/2302751328075412949'/><link rel='alternate' type='text/html' href='http://mbartyzel.blogspot.com/2011/06/value-stream-i-zarzadzanie-wymaganiami.html' title='Value Stream i zarządzanie wymaganiami w korporacji'/><author><name>Michał Bartyzel</name><uri>http://www.blogger.com/profile/03968505875451301931</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1759916214638009707.post-5468317285242670717</id><published>2011-06-07T19:30:00.002+02:00</published><updated>2011-06-07T19:31:25.899+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='info'/><title type='text'>Jak wykorzystać swoje doświadczenie i jeszcze wiele się nauczyć?</title><content type='html'>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.&lt;br /&gt;Zatem jeśli masz doświadczenie praktyczne w pracy na projektami programistycznymi, jesteś kompetentny w PRZYNAJMNIEJ W JEDNYM z następujących obszarów:&lt;br /&gt;- wzorce projektowe&lt;br /&gt;- dobre praktyki pracy z kodem (refaktoryzacja, czysty kod, obiektowość (SOLID, GRASP, interfejsy))&lt;br /&gt;- test-driven development&lt;br /&gt;- domain-driven design&lt;br /&gt;- scrum (agile)&lt;br /&gt;- komunikacja w zespole (w kontekście projektów programistycznych),&lt;br /&gt;- zarządzanie czasem dla programistów,&lt;br /&gt;- zarządzanie projektami,&lt;br /&gt;- zarządzanie wymaganiami, analiza.&lt;br /&gt;&lt;br /&gt;Ważna jest wiedza i doświadczenie projektowe, co do warsztatu trenera, jesteśmy w stanie odpowiednio do tego przygotować.&lt;br /&gt;&lt;br /&gt;Jesteśmy głównie zainteresowani stałą współpracą. Aczkolwiek ewentualnie opcja współpracy od czasu do czasu też wchodzi w grę.&lt;br /&gt;&lt;br /&gt;Pisz śmiało: m [kroppka] bartyzel [mauppa] bnsit [kropkka] pl&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1759916214638009707-5468317285242670717?l=mbartyzel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mbartyzel.blogspot.com/feeds/5468317285242670717/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1759916214638009707&amp;postID=5468317285242670717' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/5468317285242670717'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/5468317285242670717'/><link rel='alternate' type='text/html' href='http://mbartyzel.blogspot.com/2011/06/jak-wykorzystac-swoje-doswiadczenie-i.html' title='Jak wykorzystać swoje doświadczenie i jeszcze wiele się nauczyć?'/><author><name>Michał Bartyzel</name><uri>http://www.blogger.com/profile/03968505875451301931</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1759916214638009707.post-675142660538922633</id><published>2011-06-03T14:45:00.005+02:00</published><updated>2011-06-03T18:14:00.159+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='antywzorce'/><title type='text'>Grunt, to prostota</title><content type='html'>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:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;czwartek&lt;/span&gt;: 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ć. &lt;br /&gt;Nie idzie. Zorientowałem się, że zmieniłem notebooka na mniejszego i nie mam CD.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;piątek 16.30&lt;/span&gt;: 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!&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;piątek 22.00:&lt;/span&gt; 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.&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;piątek 23.50:&lt;/span&gt; Obrazy gotowe idę spać.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;sobota 13.00:&lt;/span&gt; Obrazy mają ponad 4GB. Na mojego pendrive nie wejdą. Szlag! Spróbuję udostępnić pliki poprzez sieć.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;sobota 13.45:&lt;/span&gt; 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.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;sobota 14.15:&lt;/span&gt; Też lipa. Nagle mnie olśniło. Mam dysk zewnętrzny! Przekopiuję na dysk a potem do siebie.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;sobota 14:17&lt;/span&gt;: 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 &lt;span style="font-style:italic;"&gt;ofisa &lt;/span&gt;oraz guziki &lt;span style="font-style:italic;"&gt;power &lt;/span&gt;i &lt;span style="font-style:italic;"&gt;reset&lt;/span&gt;, to bym komuś za to zapłacił i miałbym z głowy, no trudno).&lt;br /&gt;Podjąłem męską decyzję: przekonwertuję dysk na NTFS i po kłopocie. Google mówi, że polecenie winda ma wbudowane polecenie &lt;i&gt;convert&lt;/i&gt; i po kłopocie.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;sobota 16.00&lt;/span&gt;: Polecenie &lt;i&gt;convert&lt;/i&gt; zgłasza błędne sektory dysku, co uniemożliwia konwersję. W eleganckim komunikacie zapewnia mnie, że po wykonaniu polecenia &lt;i&gt;chkdsk&lt;/i&gt; będzie ok.&lt;br /&gt;&lt;br /&gt;No więc wykonuję polecenie &lt;i&gt;chkdsk&lt;/i&gt;, które raportuje błędy i pyta czy naprawić? No, pytanie! Naprawiam. Znów odpalam &lt;i&gt;convert&lt;/i&gt;. 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)&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;sobota 16.30&lt;/span&gt;: Sciągam Partition Magic. Odpalam, wybieram partycję, konwertuj na NTFS, ok.....Partition Magic odpala program &lt;i&gt;convert&lt;/i&gt;! Efekt do przewidzenia. Grrr!!!!!&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;sobota 17.00:&lt;/span&gt; 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.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;sobota 21.13: &lt;/span&gt;Wciaż naprawia...&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;sobota 23.40:&lt;/span&gt; Dalej naprawia...&lt;br /&gt; &lt;br /&gt;&lt;span style="font-weight:bold;"&gt;niedziela 9.07:&lt;/span&gt; Naprawił. Odpalam &lt;i&gt;convert&lt;/i&gt;. AAAaaaaaaaaaa!!! Wciąż to samo. Googluję, googluję, googluję. Mam! mój dysk ma ustawiony &lt;i&gt;dirty bit&lt;/i&gt; i stąd te kłopoty. Znalazłem jakieś polecenie windozy, które sprawdza ten &lt;i&gt;dirty bit&lt;/i&gt;. Odpalam - brak praw do wykonania operacji. &lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;niedziela 11:30:&lt;/span&gt; Odpaliłem konsolę na prawach administratora i &lt;i&gt;chkdsk&lt;/i&gt; a potem  &lt;i&gt;convert&lt;/i&gt;. Robi się.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;niedziela 12.00: &lt;/span&gt;Taaak! Przekonwertowane. Przegrywam obrazy, montuję, instaluję, działa. Na wszelki wypadek sprawdzam rozmiar danych na płytce: 154 MB....!@#*&amp;Y#*! Dlaczego nie robiłem tego na początku?&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;&lt;h3&gt;Wnioski&lt;/h3&gt;&lt;/span&gt;&lt;br /&gt;Chwila refleksji nad moją przygodą, która do złudzenia przypomina mi sytuację, których doświadczam podczas prac programistycznych.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Błąd 1: Brak planu&lt;/span&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Błąd 2: Zosia Samosia&lt;/span&gt;&lt;br /&gt;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ę &lt;b&gt;buy, don't write&lt;/b&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Błąd 3: Brak feedbacku&lt;br /&gt;&lt;/span&gt;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ł.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Błąd 4: Ignorowanie intuicji&lt;/span&gt;&lt;br /&gt;Pierwsza myśl była dobra. Mogłem przynajmniej sprawdzić, czy to zadziała.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;color:red"&gt;KARDYNALNY Błąd 5: Brak koncentracji na wartości biznesowej&lt;/span&gt;&lt;br /&gt;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: &lt;i&gt;zagraniu w grę edukacyjną&lt;/i&gt;. Żadne z moich działań nie dodawała wartości biznesowej. To był &lt;a href="http://www.amazon.com/Death-March-2nd-Edward-Yourdon/dp/013143635X"&gt;marsz ku klęsce&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1759916214638009707-675142660538922633?l=mbartyzel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mbartyzel.blogspot.com/feeds/675142660538922633/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1759916214638009707&amp;postID=675142660538922633' title='Komentarze (5)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/675142660538922633'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/675142660538922633'/><link rel='alternate' type='text/html' href='http://mbartyzel.blogspot.com/2011/06/tak-prosto-jak-to-tylko-mozliwe.html' title='Grunt, to prostota'/><author><name>Michał Bartyzel</name><uri>http://www.blogger.com/profile/03968505875451301931</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1759916214638009707.post-8650386090090339323</id><published>2011-04-20T21:33:00.007+02:00</published><updated>2011-04-20T23:07:17.446+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='architektura'/><title type='text'>Gadżety Javy</title><content type='html'>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.&lt;br /&gt;&lt;br /&gt;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:&lt;br /&gt;&lt;br /&gt;&lt;table border="1"&gt;&lt;tr&gt;&lt;td&gt;&lt;span style="font-weight:bold;"&gt;SpringFramework&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span style="font-weight:bold;"&gt;EJB3.*&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;bierzesz, co chcesz; w razie potrzeb dokładasz kolejne moduły&lt;/td&gt;&lt;td&gt;bierzesz wszystko albo nic; klejony na siłę koncept &lt;a href="http://weblogs.java.net/blog/286/2008/02/22/profiles-java-ee-6-platform"&gt;profili&lt;/a&gt; moim zdaniem tak bezsensowny, że nawet nie warto się rozpisywać&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;częste wydania&lt;/td&gt;&lt;td&gt;w bólach i na drodze kompromisów rodząca się specyfikacja jest sporo w tyle za nowinkami ze świata OpenSource&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;nastawiony na bezinwazyjne &lt;span style="font-tyle:italic;"&gt;sklejanie&lt;/span&gt; fragmentów aplikacji oraz na integrowanie się z bibliotekami i frameworkami, które już istnieją i dobrze się sprawdzają&lt;/td&gt;&lt;td&gt;mityczna przenośność aplikacji pomiędzy serwerami&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;staje się coraz cięższy; może nie sam kontener ale włączając kolejne ficzery robi się coraz ciężej&lt;/td&gt;&lt;td&gt;zmierz w stronę odchudzania (JPA poza kontenerem, koncept profili)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Projekt &lt;a href="http://www.terracotta.org"&gt;OpenTerracotta&lt;/a&gt; spierający skalowanie aplikacji opartych o Springa&lt;/td&gt;&lt;td&gt;kontener EJB dostarcza możliwości skalowania aplikacji&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;można tworzyć aplikacje wielowątkowe&lt;/td&gt;&lt;td&gt;zakaz własnoręcznego korzystania z wątków; wątkami zarządza wyłącznie kontener&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;brak standardu dot. zarządzania aplikacją; istnieją projekty SpringSource dedykowane do tego celu&lt;/td&gt;&lt;td&gt;spójny sposób zarządzania aplikacją&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Kontynuując tyradę narzekania&lt;/b&gt;&lt;br /&gt;Kontynuując tę tyradę narzekanie trzeba wspomnieć jeszcze wiele genialnych frejmłorków i bibliotek, które świetnie wyglądają w &lt;span style="font-style:italic;"&gt;10 minutes tutorial&lt;/span&gt;, rozwiązują parę problemów i wprowadzają szereg nowych. &lt;br /&gt;Wymieniam parę wad: &lt;br /&gt;&lt;br /&gt;&lt;table widht="100%" border="1"&gt;&lt;tr width="35%"&gt;&lt;td&gt;&lt;a href="http://www.oracle.com/technetwork/java/javaee/javaserverfaces-139869.html"&gt;JSF&lt;/a&gt;&lt;/td&gt;&lt;td&gt;cięż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; &lt;a href="http://www.jboss.org/richfaces"&gt;RichFaces 4.0&lt;/a&gt; wspierajace JSF 2.0 już jest&lt;/td&gt;&lt;/tr&gt;&lt;tr width="35%"&gt;&lt;td&gt;&lt;a href="http://www.oracle.com/technetwork/articles/javaee/jpa-137156.html"&gt;JPA&lt;/a&gt;&lt;/td&gt;&lt;td&gt;wolno rozwijająca się specyfikacja, plus wszystkie &lt;a href="http://mbartyzel.blogspot.com/2011/03/po-co-orm.html"&gt;wady O/RMów&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr width="35%"&gt;&lt;td&gt;&lt;a href="http://code.google.com/intl/pl/webtoolkit/"&gt;GWT&lt;/a&gt;&lt;/td&gt;&lt;td&gt;dostawca monopolista, ciężki klient, brak standardu, po stronie widoku obsługiwana jest tylko część maszyny wirtualnej&lt;/td&gt;&lt;/tr&gt;&lt;tr width="35%"&gt;&lt;td&gt;&lt;a href="http://struts.apache.org/2.x/index.html"&gt;Struts2&lt;/a&gt;&lt;/td&gt;&lt;td&gt;"prawie" wsparcie dla Ajaxa, koszmarne adnotacji&lt;/td&gt;&lt;/tr&gt;&lt;tr width="35%"&gt;&lt;td&gt;&lt;a href="http://www.springsource.org/webflow"&gt;Spring WebFlow&lt;/a&gt;&lt;/td&gt;&lt;td&gt;fajny, gdy GUI ma charakter procesowo-kreatorowy, poza tym przerost formy nad treścią&lt;/td&gt;&lt;/tr&gt;&lt;tr width="35%"&gt;&lt;td&gt;&lt;a href="http://www.oracle.com/technetwork/developer-tools/adf/overview/index.html"&gt;Oracle ADF&lt;/a&gt;&lt;/td&gt;&lt;td&gt;w tutorialach genialny, w użyciu prowadzi do prawie takiego samego bałaganu w kodzie jak przy bezmyślnym klikaniu w Borland Delphi Buildera&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;&lt;b&gt;Co zamiast w/w?&lt;/b&gt;&lt;br /&gt;Jakie mamy zatem mamy alternatywy? Co można używać zamiast powyższych rozwiązań. Spotkałem się z następującymi konfiguracjami:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.stripesframework.org/display/stripes/Home"&gt;Stripes &lt;/a&gt;+ &lt;a href="http://dojotoolkit.org/"&gt;dojo&lt;/a&gt; + &lt;a href="http://www.hibernate.org/"&gt;Hibernate &lt;/a&gt;- 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ć&lt;/li&gt;&lt;li&gt;&lt;a href="http://freemarker.sourceforge.net/"&gt;Freemarker &lt;/a&gt;+ &lt;a href="http://static.springsource.org/spring/docs/2.0.7/reference/mvc.html"&gt;SpringMVC &lt;/a&gt;+ &lt;a href="http://www.mybatis.org/"&gt;myBatis&lt;/a&gt; - całkowita rezygnacja z JSP oraz pogodzenie się z faktem, że schemat bazy jest czasem tak prosty, że nie ma co przekombinowywać&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.oracle.com/technetwork/developer-tools/forms/overview/index.html"&gt;Oracle Forms&lt;/a&gt;, &lt;a href="http://www.sybase.com/products/modelingdevelopment/powerbuilder"&gt;PowerBuilder &lt;/a&gt;- w architekturze dwuwarstwowej&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.php.net/"&gt;PHP&lt;/a&gt; - tak po prostu... to o wiele bardziej dojrzała technologia, niż jawowcom może się wydawać, mają nawet swoje automagiczne frejmłorki&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Do czego właściwie nadaje się się JEE&lt;/b&gt;&lt;br /&gt;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).&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;P.S. Wpis wyraża prywatne myśli autora, a autor nie zarzeka się, że myśli tych kiedyś nie zmieni:)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1759916214638009707-8650386090090339323?l=mbartyzel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mbartyzel.blogspot.com/feeds/8650386090090339323/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1759916214638009707&amp;postID=8650386090090339323' title='Komentarze (5)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/8650386090090339323'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/8650386090090339323'/><link rel='alternate' type='text/html' href='http://mbartyzel.blogspot.com/2011/04/gadzety-javy.html' title='Gadżety Javy'/><author><name>Michał Bartyzel</name><uri>http://www.blogger.com/profile/03968505875451301931</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1759916214638009707.post-3711107133412075347</id><published>2011-04-08T22:14:00.004+02:00</published><updated>2011-04-12T09:57:59.153+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='wydarzenia'/><title type='text'>Po 33rd Degree</title><content type='html'>Przede wszystkim wielkie ukłony dla Grześka. Konferencja tej skali to z pewnością nie lada wyczyn. Dziękuję.&lt;br /&gt;&lt;br /&gt;Kilka słów, na temat prezentacji, które szczególnie utkwiły mi w pamięci.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://33degree.org/talks.html#CreateSoftware"&gt;Don't code - create software!&lt;/a&gt;. Zapamiętałem ze względu na świetny sposób prowadzenia. Bardzo energicznie i przyjemnie. &lt;br /&gt;&lt;br /&gt;&lt;a href="http://33degree.org/talks.html#FractalTDD"&gt;Fractal TDD: Using tests to drive system design&lt;/a&gt;. Ech...naprawdę fajne koncepcje, naprawdę ciekawego człowieka, podane w nieco zagmatwany sposób (dopiero na drugi dzień doszedłem do tego o, co chodzi z tym "Fractal"). Po prezentacji, gdy kilku uczestników rozmawiało z p. Freemanem, widać było wyraźnie, że prowadzący zdecydowanie lepiej odnajduje się w małych grupach. Mimo tych niedogodności podobało mi się. &lt;br /&gt;&lt;br /&gt;&lt;a href="http://33degree.org/talks.html#Git"&gt;Git Going with a Distributed Version Control System &lt;/a&gt;, &lt;a href="http://33degree.org/talks.html#Sonar"&gt;&lt;br /&gt;Monitoring 10 Critical Code Quality Metrics with Sonar&lt;/a&gt;. Merytorycznie raczej tutoriale do narzędzi, ale sposób prezentacji absolutnie rewelacyjny. Moim zdaniem najlepszy prelegent Konferencji.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://33degree.org/talks.html#NOSQL"&gt;Architecture and programming model for NOSQL web&lt;/a&gt;. Prezentację zapamiętałem, ze względu na to, że nic nie zapamiętałem:) Prowadzący założył pewną wiedzę u uczestników, ja jej nie miałem i się nie odnalazłem. Sąsiedzi twierdzili, że była ciekawa więc wierzę im na słowo. Przyszedł mi do głowy pewien pomysł. Być może na konferencjach powinno rozróżniać się prezentacje ogólne/przeglądowe od szczegółowych, na których zakłada się jakąś określoną wiedzę od uczestników. Prezentacja o NOSQL była raczej szczegółowa i jeśli ktoś przyszedł z konkretnym problemem, to pewnie znalazł rozwiązanie. Ja chciałem się zorientować o co chodzi i niestety nie skorzystałem.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://33degree.org/talks.html#BOFKompetencjeProgramisty"&gt;BOF: Dokąd zmierza Software Craftsmanship &lt;/a&gt; W zamierzeniu miała być dyskusja o profesjonalizmie w IT. Skończyło się na zabawie, że jeden uczestnik wymyślał metaforę: &lt;span style="font-style:italic;"&gt;programista jest jak: [szewc | budowniczy | architekt | lekarz]&lt;/span&gt;, a cała sala ripostowała przypadkami szczególnymi, dla których metafora kuleje. Było dużo śmiechu, ale moje rozumienie profesjonalizmu raczej się nie poszerzyło. Miałem wrażenie, że wylewaliśmy swoje żale, mówiliśmy o własnych nieprzyjemnych doświadczeniach, które następnie uogólnialiśmy do nowotworu trawiącego całą branżę. Pomysł na dyskusję na pewno cenny, temat warto eksplorować.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://33degree.org/talks.html#CqRS"&gt;Command-query Responsibility Segregation - nowe, bardziej racjonalne podejście do warstw&lt;/a&gt;. Obawiałem się konferencyjnej przeglądówki, ale było ok. Jasno konkretnie i po kolei wyłożone o co chodzi w temacie. Prezentacja a'la Matrix dodała kolorytu.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://33degree.org/talks.html#DivineCode"&gt;Lost Chapters of Divine Code: 7 Deadly Sins&lt;/a&gt;. Pierwsze wrażenie bardzo pozytywne. Świetny kontakt z publicznością, ważne rzeczy przedstawione w ciekawy i kreatywny sposób. Gdy wracałem do domu i myślałem o tej prezentacji, pojawiały mi się mieszane uczucia.&lt;br /&gt;&lt;br /&gt;Pierwsza rzecz, to odniosłem wrażenie (z powodu komentarzy kierowanych w stronę słuchaczy), że prowadzący zaczęli prezentację z założeniem, że mają przed sobą bandę troglodytów, którzy do programowania używają dłuta i maczugi, a których oni właśnie oświecają. O czym mówili? O ile dobrze zapamiętałem to: nie używać metod prywatnych, nie używać konstrukcji statycznych, nie używać metod i klas &lt;span style="font-style:italic;"&gt;final&lt;/span&gt;, preferować kompozycję ponad dziedziczenie. Nie są to więc sprawy, które nagle spłynęły z nieba, lecz tematy przewijające się w branży od czasów GoF i raczej większość programistów ma swoje zdanie na te tematy. &lt;br /&gt;&lt;br /&gt;Z wieloma argumentami prowadzących można się zgodzić, ale podawane bez kontekstu tracą swoje znaczenia, a dogmatyczne przestrzeganie tych zaleceń &lt;span style="font-style:italic;"&gt;zawsze&lt;/span&gt; i &lt;span style="font-style:italic;"&gt;wszędzie &lt;/span&gt;doprowadzi bajzlu w kodzie równie szybko, co ich ignorowanie. Będzie to bajzel innej jakości, ale zawsze bajzel. Sądzę, że porady prowadzących były ciekawe, ale jak wszystko mają zakres swojej stosowalności. Myślę, że tworzenie &lt;span style="font-style:italic;"&gt;boskiego kodu&lt;/span&gt;, to coś więcej niż mechaniczne przestrzeganie niskopoziomowych wytycznych. &lt;br /&gt;&lt;br /&gt;Moje całościowe wrażenie odnośnie przesłania tej prezentacji jest bardzo pozytywne, potrzebujemy tego rodzaju ewangelistów. Jedna rzecz mnie zniesmaczyła. Prowadzący kolejno wyśmiewali: K.Becka, E.Gamma, S.Freemana, R.Martina i kogoś jeszcze, za to jakie błędy popełnili i co powiedzieli w przeszłości. Przypomniało mi to wiersz Asnyka &lt;a href="http://literat.ug.edu.pl/asnyk/080.htm"&gt;Do młodych&lt;/a&gt;, którym napisał &lt;span style="font-style:italic;"&gt;ale nie depczcie przeszłości ołtarzy, choć macie sami doskonalsze wznieść&lt;/span&gt;. Myślę, że gdyby nie ci wszyscy "giganci" inżynierii oprogramowania, Autorzy prezentacji z pewnością nie robiliby tego, co teraz robią, nie prezentowaliby siebie na konferencji, a i konferencji z pewnością by nie było. Autorzy prawdopodobnie rzeźbiliby paznokciami w rzadkim...kodzie i nie przychodziłoby im do głowy, że można inaczej. Myślę, że choć Autorom nie brakuje świetnych pomysłów, to jednocześnie przydałoby im się nieco pokory i szacunku do Becka, Gamma, Freemana, Martina i innych, gdyż między innymi dzięki ich błędom (i sukcesom, oczywiście), Autorzy są tam, gdzie są i robią to, co robią.&lt;br /&gt;&lt;br /&gt;Podsumowując - niecierpliwie czekam na kolejną edycję Konferencji.&lt;br /&gt;&lt;br /&gt;Tyle ode mnie.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1759916214638009707-3711107133412075347?l=mbartyzel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mbartyzel.blogspot.com/feeds/3711107133412075347/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1759916214638009707&amp;postID=3711107133412075347' title='Komentarze (3)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/3711107133412075347'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/3711107133412075347'/><link rel='alternate' type='text/html' href='http://mbartyzel.blogspot.com/2011/04/po-33rd-degree.html' title='Po 33rd Degree'/><author><name>Michał Bartyzel</name><uri>http://www.blogger.com/profile/03968505875451301931</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1759916214638009707.post-1496245388356481984</id><published>2011-04-06T00:15:00.006+02:00</published><updated>2011-04-06T09:44:19.908+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><category scheme='http://www.blogger.com/atom/ns#' term='wizje'/><category scheme='http://www.blogger.com/atom/ns#' term='analiza'/><title type='text'>"żeby tak wszystko ze wszystkiego wynikało"</title><content type='html'>Problem dotyczy zarządzania zmianami w wymaganiach. Cytując rozmowę, oczekiwanie brzmi następująco &lt;span style="font-style:italic;"&gt;Proszę Pana, chciałbym tu mieć takie narzędzie do zarządzania wymaganiami, w którym będę mógł sobie je definiować, &lt;span style="font-weight:bold;"&gt;żeby tak wszystko ze wszystkiego wynikało&lt;/span&gt;. Na przykład jak przyjdzie jakaś zmiana, to żebym od razu wiedział gdzie, co i jak, w której klasie należy zmienić. Rozumie Pan?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;No, niby rozumiem...&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Zarządzanie? Dobre sobie!&lt;/b&gt;&lt;br /&gt;Weź pierwszą z brzegu mądrą książkę, która ma w tytule &lt;span style="font-style:italic;"&gt;Requirements Management&lt;/span&gt;. 99% tekstu jest o (w kolejności ilości stron): dokumentowaniu, zbieraniu (ale raczej skąd? niż jak?) i analizie wymagań. I gdzieś tam pod koniec parę akapitów o tym, że &lt;span style="font-style:italic;"&gt;change happens&lt;/span&gt;. A kluczową atrakcję wieczoru, czyli &lt;span style="font-style:italic;"&gt;management&lt;/span&gt; zbywa się truizmem w stylu &lt;span style="font-style:italic;"&gt;trzeba wdrożyć proces zarządzania zmianą&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Czyli co to jest to &lt;span style="font-style:italic;"&gt;zarządzanie&lt;/span&gt;? Sądzę, że:&lt;br /&gt;&lt;ul style="line-height: 1.05em;"&gt;&lt;br /&gt;&lt;li&gt;składowanie wymagań&lt;/li&gt;&lt;br /&gt;&lt;li&gt;dowiadywanie się jak nowe wymagania wpływają na istniejące&lt;/li&gt;&lt;br /&gt;&lt;li&gt;wykrywanie konfliktów w wymaganiach&lt;/li&gt;&lt;br /&gt;&lt;li&gt;dowiadywanie się jak zmiany (w skrócie: CR) wpływają na istniejące wymagania&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;b&gt;Hipertraceability&lt;/b&gt;&lt;br /&gt;Czy oczekiwanie wyrażone w początkowej historyjce ma sens. Jest w nim ukryta jakaś potrzeba, ale zastanawiam się czy ma sens. Można zaprzęgnąć EA albo coś droższego i wyklikać wszystkie możliwe powiązania tak, "żeby tak wszystko ze wszystkiego wynikało". A co w przypadku zmiany? Oprócz dowiedzenia się co z czym się wiąże, znów trzeba będzie poklikać. Sądzę, że utrzymywanie takiej macierzy powiązań to robota na kilka pełnych etatów. Wątpię, czy warta świeczki. Wątpię, czy jest nawet warta ogarka.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Gdzie leży problem z &lt;span style="font-style:italic;"&gt;traceablility&lt;/span&gt;&lt;/b&gt;?&lt;br /&gt;Duży system jest zazwyczaj podzielony na moduły, które są rozwijane przez osobne podzespoły, którym przewodzą dedykowani liderzy. Gdy przychodzi zmiana dotycząca jednego z modułów, może ona jakiś wpływ na inne. Jeśli dane lider na to wpadnie to świetnie. Jeśli nie, to sprawa wypłynie prędzej czy później.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/-mJXuAP_d-AI/TZuel2cHEjI/AAAAAAAAA28/LaOJHhSjgVw/s1600/tr.PNG"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 238px;" src="http://4.bp.blogspot.com/-mJXuAP_d-AI/TZuel2cHEjI/AAAAAAAAA28/LaOJHhSjgVw/s400/tr.PNG" border="0" alt=""id="BLOGGER_PHOTO_ID_5592237735416369714" /&gt;&lt;/a&gt;&lt;br /&gt;Niszczące działanie zmiany nie jest wynikiem braku hiepertraceability, braku jedynie poprawnego narzędzia czy wynikiem braku kompetencji. To przede wszystkim problem organizacyjny i komunikacyjny. Liderzy nie wiedzą co się dzieje w inny modułach, analizują zmianę lokalnie bez odniesienia do całości (której nie znają) i nie komunikują się ze sobą wystarczająco.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Product Manager&lt;/b&gt;&lt;br /&gt;Brakuje osoby (&lt;span style="font-style:italic;"&gt;Product Manager&lt;/span&gt;), która będzie spinać system całość. Od razu pada pytania: czy od strony technicznej, czy biznesowej? Nie chodzi to, żeby przez &lt;span style="font-style:italic;"&gt;Product Managera&lt;/span&gt; przechodziły wszystkie CR, a on będzie podejmował je analizował i podejmował decyzje. Nie może tak być, bo zaraz zrobi się z niego ktoś w stylu &lt;span style="font-style:italic;"&gt;Solution Architect&lt;/span&gt;, w którym będzie powoli skupiała się kluczowa wiedza o systemie i który będzie wąskim gardłem procesu zarządzania zmianą. (a niech tam, to zatrudnimy mu asystentów i już, czemu nie? :) )&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Product Manage&lt;/span&gt;r jest raczej kimś kto dba o to by komunikacja pomiędzy liderami i zespołami przebiegała płynnie. Oczywiście będą trafiać do niego wszystkie CR, będzie posiadał dużą wiedzę biznesową i będzie doskonale znał produkt. Jego główny zadaniem będzie troszczenie się o produkt jako całość i &lt;span style="font-weight:bold;"&gt;pomaganie&lt;/span&gt; poszczególnym zespołom w komunikowaniu się z innymi i dogrywaniu wszelkich zmian.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/-fRo-2M3-asc/TZuiOb08-FI/AAAAAAAAA3E/e5UF-vy8QNg/s1600/Przechwytywanie.PNG"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 215px;" src="http://3.bp.blogspot.com/-fRo-2M3-asc/TZuiOb08-FI/AAAAAAAAA3E/e5UF-vy8QNg/s400/Przechwytywanie.PNG" border="0" alt=""id="BLOGGER_PHOTO_ID_5592241731182327890" /&gt;&lt;/a&gt;&lt;br /&gt;Zauważmy, że nie jakaś konkretna osoba analizuje wymagania, wykrywa konflikty i wpływ nowych na istniejące. Rzeczy te &lt;span style="font-weight:bold;"&gt;wykrywane są w procesie komunikacji&lt;/span&gt; pomiędzy poszczególnymi zespołami i liderami.&lt;br /&gt;&lt;br /&gt;Czy &lt;span style="font-style:italic;"&gt;Product Manager&lt;/span&gt; będzie miał co robić? Jeżeli mówimy o produkcie, który ma wdrożenia dla poszczególnych klientów, to z pewnością tak. Odpowiedzialności &lt;span style="font-style:italic;"&gt;Product Manager&lt;/span&gt; to:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;dbanie o rozwój produktu jako całości&lt;/li&gt;&lt;br /&gt;&lt;li&gt;dbanie o &lt;span style="font-style:italic;"&gt;loose coupling&lt;/span&gt; między produktem a wdrożeniami dla poszczególnych klientów :)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;przyjmowanie CR&lt;/li&gt;&lt;br /&gt;&lt;li&gt;pomaganie liderom i zespołom w komunikowaniu się między sobą&lt;/li&gt;&lt;br /&gt;&lt;li&gt;uzgadnianie i mediowanie w przypadku wprowadzania zmian w produkcie&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1759916214638009707-1496245388356481984?l=mbartyzel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mbartyzel.blogspot.com/feeds/1496245388356481984/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1759916214638009707&amp;postID=1496245388356481984' title='Komentarze (2)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/1496245388356481984'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/1496245388356481984'/><link rel='alternate' type='text/html' href='http://mbartyzel.blogspot.com/2011/04/zeby-tak-wszystko-ze-wszystkiego.html' title='&quot;żeby tak wszystko ze wszystkiego wynikało&quot;'/><author><name>Michał Bartyzel</name><uri>http://www.blogger.com/profile/03968505875451301931</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-mJXuAP_d-AI/TZuel2cHEjI/AAAAAAAAA28/LaOJHhSjgVw/s72-c/tr.PNG' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1759916214638009707.post-4841690776318579411</id><published>2011-04-05T00:14:00.007+02:00</published><updated>2011-04-05T01:33:35.134+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><category scheme='http://www.blogger.com/atom/ns#' term='wizje'/><category scheme='http://www.blogger.com/atom/ns#' term='architektura'/><title type='text'>Strażnik architektury i ewangelista</title><content type='html'>Zauważyłem pewną cechę różnicującą projekty, w których kod woła o pomstę do nieba, od tych, które są bardzo przyzwoicie napisane. Różnicą, którą mam na myśli nie jest bynajmniej skala projektu, skomplikowanie domeny, język programowania, czy nawet wiek projektu. Zauważyłem, że w zespołach, w których kod jest dobrze utrzymany objawia się osoba, która nakręca cały ten pęd ku ciągłemu doskonaleniu. Nazwałem go &lt;span style="font-style:italic;"&gt;Strażnikiem architektury&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Nie posługuję się nomenklaturą &lt;a href="http://www.ambysoft.com/scottAmbler.html"&gt;Scotta Amblera&lt;/a&gt;, który mówi o &lt;a href="http://www.agilemodeling.com/essays/architectureOwner.htm"&gt;Właścicielu architektury&lt;/a&gt;, gdyż sądzę, że chodzi o nieco inną rolę. Mimo koncepcji Właściciela architektury, jako roli, a nie stanowiska (zapewne z inspiracji Product Ownerem) trudno uciec od skojarzeń, że &lt;span style="font-style:italic;"&gt;właściciel&lt;/span&gt; coś posiada. Tego typu rola, bardzo szybko przekształca się w klasyczne stanowisko architekta, który jest wyrocznią w sprawie architektury, od czego Scott Ambler chciał uciec.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Strażnik architektury&lt;/span&gt; jest jednym z członków zespołu, który ma "parcie" na ciągłe doskonalenie projektu oraz &lt;span style="font-weight:bold;"&gt;ewangelizuje&lt;/span&gt; zespół w zakresie jakości tworzonego kodu. Zaobserwowałem, że zazwyczaj &lt;span style="font-style:italic;"&gt;Strażnik architektury&lt;/span&gt; jest inicjatorem i koordynatorem następujących aktywności w zespole:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;wprowadzanie standardu kodowania&lt;/li&gt;&lt;br /&gt;&lt;li&gt;zmiana/wprowadzanie systemu kontroli wersji/zmian&lt;/li&gt;&lt;br /&gt;&lt;li&gt;wprowadzenie code review&lt;/li&gt;&lt;br /&gt;&lt;li&gt;wprowadzenie procesu continuous integration&lt;/li&gt;&lt;br /&gt;&lt;li&gt;wprowadzenie/zmiana podejścia tworzenia kodu np:. DDD&lt;/li&gt;&lt;br /&gt;&lt;li&gt;wprowadzenie/zmiana technologii/frameworka&lt;/li&gt;&lt;br /&gt;&lt;li&gt;tworzenie warstw abstrakcji na niektóre z używanych bibliotek, w celu uniezależnienia się od nich&lt;/li&gt;&lt;br /&gt;&lt;li&gt;zmiana architektury w celu poprawienia wydajności (i nie chodzi tylko do dopisanie paru SQLi i założenie paru indeksów)&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;Zazwyczaj &lt;span style="font-style:italic;"&gt;Strażnik architektury&lt;/span&gt; objawia się sam. Po prostu jest ktoś taki w zespole, od kto stopniowo staje się autorytetem dla innych. Uczy ich, prowokuje do wyjścia poza utarte schematy, stymuluje do rozwoju. Zazwyczaj pomaga rozstrzygnąć sporne kwestie dotyczące technicznej strony projektu. Doradza i nieformalnie akceptuje nowe pomysły albo je odrzuca (albo jak mawiają znajomi z pewnego sympatycznego zespołu "spsikuje" pomysły ;) )&lt;br /&gt;&lt;br /&gt;Kilka punktów nt. zaobserwowanej charakterystyki &lt;span style="font-style:italic;"&gt;Strażnika architektury&lt;/span&gt;.&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;jest pasjonatem&lt;/li&gt;&lt;br /&gt;&lt;li&gt;poświęca wolny czas na czytanie blogów, literatury, rozpoznawanie technologii&lt;/li&gt;&lt;br /&gt;&lt;li&gt;testuje nowe rozwiązania (często projekcie, w którym uczestniczy)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;często staje się liderem z nadania (poprzez stanowisko) i bywa, że to go "zabija" bo tonie w papierkach, budżetach i spotkaniach&lt;/li&gt;&lt;br /&gt;&lt;li&gt;mimo szeregowego stanowiska z jego zdaniem management się liczy i potrafi przelobbować praktycznie co tylko chce&lt;/li&gt;&lt;br /&gt;&lt;li&gt;szybko wyciąga wnioski z pomyłek, ale się nie zraża&lt;/li&gt;&lt;br /&gt;&lt;li&gt;jest motywowany głównie "na cel"&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;Pojawia się jednak pewne niebezpieczeństwo. Pęd &lt;span style="font-style:italic;"&gt;Strażnika architektury&lt;/span&gt; do doskonalenia projektu jest niemal niepohamowany. Niepohamowany do tego stopnia, że może łatwo przekroczyć dopuszczalną tolerancję biznesu oraz wytrzymałość zespołu. Istnieje duże prawdopodobieństwo, że za przyczyną niekontrolowanego&lt;span style="font-style:italic;"&gt; Strażnika architektury&lt;/span&gt; zespół będzie co miesiąc zmieniał frameworki, a co pół roku technologię.&lt;br /&gt;&lt;br /&gt;Kontrolowanie &lt;span style="font-style:italic;"&gt;Strażnika&lt;/span&gt; przez management bardzo szybko zachęci go do poszukania nowej pracy, gdzie będzie mógł realizować swoje pomysły. Rozwiązanie tej kwestii, podpowiedział mi układ personalny pojawiający się nieraz w zespołach. Otóż, w sprawnie funkcjonującym zespole, prócz&lt;span style="font-style:italic;"&gt; Strażnika architektury&lt;/span&gt; pojawia się jeszcze jego przeciwwaga. Nazwijmy go &lt;span style="font-style:italic;"&gt;Weryfikatorem&lt;/span&gt;. Charakterystyka &lt;span style="font-style:italic;"&gt;Weryfikatora &lt;/span&gt;to:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;jest równie kompetentny technicznie co &lt;span style="font-style:italic;"&gt;Strażnik architektury&lt;/span&gt; &lt;/li&gt;&lt;br /&gt;&lt;li&gt;bardziej niż nowinki technologicznie ceni sobie bezpieczeństwo&lt;/li&gt;&lt;br /&gt;&lt;li&gt;jest skrupulatny, metodyczny i niesamowicie cierpliwy&lt;/li&gt;&lt;br /&gt;&lt;li&gt;potrafi długo dyskutować ze &lt;span style="font-style:italic;"&gt;Strażnikiem architektury&lt;/span&gt; i obalać jego teorie jeśli uzna je za niewystarczająco dobrze uzasadnione&lt;/li&gt;&lt;br /&gt;&lt;li&gt;jest motywowany głównie "od problemu"&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/-XRJWIqpnoW0/TZpF9uuWlSI/AAAAAAAAA2w/HAGyFL-BLZ0/s1600/Przechwytywanie.PNG"&gt;&lt;img style="float:none; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 254px;" src="http://1.bp.blogspot.com/-XRJWIqpnoW0/TZpF9uuWlSI/AAAAAAAAA2w/HAGyFL-BLZ0/s400/Przechwytywanie.PNG" border="0" alt=""id="BLOGGER_PHOTO_ID_5591858814150677794" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Strażnik architektury&lt;/span&gt; oraz &lt;span style="font-style:italic;"&gt;Weryfikator&lt;/span&gt; stanowią główną oś zespołu dzięki, dzięki któremu projektu ewoluują w równomiernym tempie. Żaden z nich nie jest nadmiernie, czy sztucznie kontrolowany. Raczej wspólnie wypracowują rozwiązania, czerpiąc jednocześnie wiele satysfakcji z pracy.&lt;br /&gt;&lt;br /&gt;Podsumowując: jeśli chcesz mieć dobry zespół i dobrze napisany projekt, to proponuję następujący przepis:&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;Zatrudnij &lt;span style="font-style:italic;"&gt;Strażnika architektury&lt;/span&gt; oraz &lt;span style="font-style:italic;"&gt;Weryfikatora&lt;/span&gt; o wskazanych wyżej cechach - ci muszą być rewelacyjni&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Zatrudnij pozostałych członków zespołu - ci powinni być dobrzy&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Pozwól im działać&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;Mnóstwo pytań nasuwa się w związku z tym pomysłem, chociażby: jako to zrobić?, skąd wziąć ludzi?, jak to zrobić najtaniej?. TODO.... :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1759916214638009707-4841690776318579411?l=mbartyzel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mbartyzel.blogspot.com/feeds/4841690776318579411/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1759916214638009707&amp;postID=4841690776318579411' title='Komentarze (2)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/4841690776318579411'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/4841690776318579411'/><link rel='alternate' type='text/html' href='http://mbartyzel.blogspot.com/2011/04/straznik-architektury-i-ewangelista.html' title='Strażnik architektury i ewangelista'/><author><name>Michał Bartyzel</name><uri>http://www.blogger.com/profile/03968505875451301931</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-XRJWIqpnoW0/TZpF9uuWlSI/AAAAAAAAA2w/HAGyFL-BLZ0/s72-c/Przechwytywanie.PNG' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1759916214638009707.post-605553415692792159</id><published>2011-03-19T07:45:00.010+01:00</published><updated>2011-03-22T21:33:03.316+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='orm'/><category scheme='http://www.blogger.com/atom/ns#' term='architektura'/><title type='text'>Generowanie danych dla widoku</title><content type='html'>Spotkałem się niedawno z ciekawym rozwiązaniem dotyczącym sposobu generowania danych dla widoku. Warto je opisać.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;O co chodzi?&lt;/b&gt;&lt;br /&gt;W większości aplikacji musimy dostarczać do widoku różnego dane by je zaprezentować użytkownikowi. Mogą być to dane, na których użytkownik bieżąco pracuje i które widzi na stronie albo dane służące go produkowania raportów, z którymi użytkownik nie wchodzi w interakcję.&lt;br /&gt;&lt;br /&gt;Często wystarcza nam przesyłanie do widoku obiektów detached. Przy złożonych modelach domenowych przesyłanie fragmentów modelu domenowego nie jest wygodne. Chociażby z tego względu, że widok często wymaga danych przekrojowych, pochodzących z różnych miejsc modelu. Radzimy sobie wtedy za pomocą obiektów &lt;a href="http://java.sun.com/blueprints/corej2eepatterns/Patterns/TransferObject.html"&gt;DTO&lt;/a&gt; tworzonych na potrzeby konkretnych widoków (Rysunek 1).&lt;br /&gt;&lt;table&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/-0k0CeFzULnM/TYRpd8twe6I/AAAAAAAAA2A/SYYrb1Gif4w/s1600/rys1.PNG"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 137px;" src="http://2.bp.blogspot.com/-0k0CeFzULnM/TYRpd8twe6I/AAAAAAAAA2A/SYYrb1Gif4w/s400/rys1.PNG" border="0" alt=""id="BLOGGER_PHOTO_ID_5585705401081428898" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;&lt;br /&gt;Rysunek 1: Generowanie &lt;a href="http://java.sun.com/blueprints/corej2eepatterns/Patterns/TransferObject.html"&gt;DTO&lt;/a&gt; z modelu domenowego&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;/table&gt;&lt;br /&gt;W zależności od skomplikowania obiektów transferowych, generowanie ich można umieścić albo w samych obiektach domenowych albo scentralizować w usłudze &lt;a href="http://java.sun.com/blueprints/corej2eepatterns/Patterns/TransferObjectAssembler.html"&gt;Transfer Object Assembler&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Gdy ilość sposobów prezentowania danych dramatycznie wzrasta (raporty, ekrany), okazuje się, że kod związany z obiektami transferowymi zaśmieca projekt i coraz trudniej go utrzymywać.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Pierwsze rozwiązanie&lt;/b&gt;&lt;br /&gt;Pierwszy pomysł to przeniesienie odpowiedzialności generowania obiektów DTO na SQL np. z wykorzystaniem biblioteki &lt;a href="http://www.mybatis.org/"&gt;myBatis&lt;/a&gt;. Pamiętajmy, że chodzi o obiekty &lt;u&gt;tylko do odczytu&lt;/u&gt;.  &lt;br /&gt;&lt;table&gt;&lt;tr&gt;&lt;td&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/-DzqtG_iTsv8/TYRplD89_TI/AAAAAAAAA2I/mMILz0Fa1cM/s1600/rys2.PNG"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 351px;" src="http://4.bp.blogspot.com/-DzqtG_iTsv8/TYRplD89_TI/AAAAAAAAA2I/mMILz0Fa1cM/s400/rys2.PNG" border="0" alt=""id="BLOGGER_PHOTO_ID_5585705523283361074" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;&lt;br /&gt;Rysunek 2: ORM dla modelu domentowego myBatis dla &lt;a href="http://java.sun.com/blueprints/corej2eepatterns/Patterns/TransferObject.html"&gt;DTO&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;/table&gt;&lt;br /&gt;Powoduje to dwa problemy. Po pierwsze: znów w miarę rozrastania warstwy widoku a wraz z nią rożnych sposobów (przekrojów) prezentowania danych, zarządzanie zapytaniami SQL nawet umieszczonymi w plikach XML jest uciążliwe. Po drugie pojawia się dualizm: z jednej strony ORM zarządza modelem domenowym, z drugiej wcinamy się gdzieś z boku SQLem, aby pobrać dane dla widoku.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Mapowanie widoków bazodanowych&lt;/b&gt;&lt;br /&gt;Rozwiązanie, z którym się spotkałem, polega na zepchnięciu generowania danych przekrojowych bazę danych i reprezentowania ich w postaci widoków bazodanowych. Obiekt &lt;a href="http://java.sun.com/blueprints/corej2eepatterns/Patterns/TransferObject.html"&gt;DTO&lt;/a&gt; mapujemy jako encje na w zdefiniowane w bazie widoki.&lt;br /&gt;W usłudze, dzięki której pobieramy dane z bazy udostępniamy wyłącznie możliwość odczytu.&lt;br /&gt;&lt;br /&gt;Ciekawe jakby można nazwać obiekt taką usługę. &lt;span style="font-style:italic;"&gt;DAO, Repository&lt;/span&gt;? Jakoś kłóci się z tym, co zwyczajowo rozumiemy przez tego typu usługi. Wydaje mi się, że dobrą (na razie ogólną) nazwą będzie &lt;span style="font-style:italic;"&gt;PresentationDataService&lt;/span&gt;.&lt;br /&gt;&lt;table&gt;&lt;tr&gt;&lt;td&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/-JVtDSyAwKvs/TYRpsStgoMI/AAAAAAAAA2Q/lEoSXZRhQok/s1600/rys3.PNG"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 308px;" src="http://4.bp.blogspot.com/-JVtDSyAwKvs/TYRpsStgoMI/AAAAAAAAA2Q/lEoSXZRhQok/s400/rys3.PNG" border="0" alt=""id="BLOGGER_PHOTO_ID_5585705647504138434" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;&lt;br /&gt;Rysunek 3: ORM mapuje widoki bazodanowe&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;/table&gt;&lt;br /&gt;Urzekająca jest symetryczność tego rozwiązania: to co obiektowe jest po stronie obiektów, to co bazodanowe po stronie bazy danych, a ORM wykorzystany jako pomost pomiędzy tymi dwoma światami.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Tymczasowa niespójność danych&lt;/b&gt;&lt;br /&gt;W opisanym rozwiązaniu kluczowym aspektem jest wydajność. Po pierwsze: umieszczamy dane dla prezentacji w widoku zmaterializowanym. &lt;br /&gt;Wydajność można dramatycznie poprawić jeśli zgodzimy się na tymczasową niespójność danych. Na przykład: użytkownik dodaje nowego pracownika i otrzymuje komunikat: &lt;span style="font-style:italic;"&gt;"Twoje zmiany pojawią się w systemie w ciągu 10 minut."&lt;/span&gt;. Okresowe przeliczanie widoku zmaterializowanego jest zdecydowanie wydajniejszym rozwiązaniem niż robienie tego na każde żądanie użytkownika.&lt;br /&gt;Oczywiście jeśli baza danych nie wspiera widoków zmaterializowanych to używamy tabeli tymczasowej i sami klepiemy kod aktualizujący.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Przeszukiwanie dużych ilości danych&lt;/b&gt;&lt;br /&gt;Poniższe rozwiązanie dotyczy sytuacji, gdy mamy w bazie kilka milionów np.: klientów oraz złożone kryteria wyszukiwania. Mówiąc o złożonych kryteriach mam na myśli zmienną liczbę parametrów, po których będziemy wyszukiwać (w zależności od potrzeb wynikających z sytuacji biznesowych). Przy stałej liczbie parametrów można stworzyć odpowiednią ilość zapytań QL. Przy zmiennej liczbie parametrów najwygodniej posługiwać się obiektami &lt;span style="font-style:italic;"&gt;Cirteria&lt;/span&gt; udostępnianymi przez dany ORM. Znów kluczową sprawą jest wydajność przeszukiwania.&lt;br /&gt;&lt;!--&lt;br /&gt;Powiedzmy sobie jasno: trzeba się naklepać, żeby skorzystać z Criteria API. Dodatkowo samo budowanie różnego rodzaju obiektów Criteria, w zależności od kontekstu biznesowego może rozrosnąć się do rozmiarów osobnego podprojektu.&lt;br /&gt;--&gt;&lt;br /&gt;&lt;b&gt;Tabela pośrednia z kryteriami wyszukiwania&lt;/b&gt;&lt;br /&gt;Pomysł polega na utworzeniu w bazie danych pomocniczej tabeli (widoku zmaterializowanego), która z jednej strony zawiera iloczyn kartezjański wszystkich atrybutów wyszukiwanego obiektu, a z drugiej namiar na odpowiedni wiersz w tabeli związanej z właściwym obiektem, który spełnia kryteria wyszukiwania.&lt;br /&gt;&lt;table&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/-7evHK4rW630/TYRp1SG3V8I/AAAAAAAAA2Y/J0mAUXO2iqk/s1600/rys4.PNG"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 228px;" src="http://3.bp.blogspot.com/-7evHK4rW630/TYRp1SG3V8I/AAAAAAAAA2Y/J0mAUXO2iqk/s400/rys4.PNG" border="0" alt=""id="BLOGGER_PHOTO_ID_5585705801960871874" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;&lt;br /&gt;Rysunek 4: Pomocnicza tabela z kryteriami wyszukiwania&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;/table&gt;&lt;br /&gt;Pytanie otwarte: Czy pośrednia tabela kryteriów i odpowiednie jej poindeksowanie rzeczywiście przyśpieszy wyszukiwanie obiektów?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1759916214638009707-605553415692792159?l=mbartyzel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mbartyzel.blogspot.com/feeds/605553415692792159/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1759916214638009707&amp;postID=605553415692792159' title='Komentarze (5)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/605553415692792159'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/605553415692792159'/><link rel='alternate' type='text/html' href='http://mbartyzel.blogspot.com/2011/03/generowanie-danych-dla-widoku.html' title='Generowanie danych dla widoku'/><author><name>Michał Bartyzel</name><uri>http://www.blogger.com/profile/03968505875451301931</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/-0k0CeFzULnM/TYRpd8twe6I/AAAAAAAAA2A/SYYrb1Gif4w/s72-c/rys1.PNG' height='72' width='72'/><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1759916214638009707.post-6814027003799929499</id><published>2011-03-12T12:35:00.005+01:00</published><updated>2011-03-12T15:31:28.294+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='orm'/><category scheme='http://www.blogger.com/atom/ns#' term='architektura'/><title type='text'>Po co O/RM?</title><content type='html'>Oprócz tego, że JPA, Hibernate, TopLink i stado podobnych są fajne to jaki konkretnie jest z nich pożytek? Ale tak konkretnie: jaki?&lt;br /&gt;&lt;br /&gt;Wydaje mi się, że zakres stosowalności O/RM jest dużo węższy niż, po wstępnym zachłyśnięciu się technologią, mogłoby się wydawać. Poniżej zebrałem parę argumentów, za O/RM, które często mi się obijały o uszy plus moje wątpliwości, czy rzeczywiście to są wystarczająco mocne argumenty.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;1. Niezależność od konkretnej bazy danych&lt;/span&gt;&lt;br /&gt;Ok, ale jak często zmieniasz bazę danych? 2 czy 3 razy w tygodniu? Może, gdy tworzy się soft, którzy będzie miał różne wdrożenia i różnych klientów, w różnych środowiskach, to mooooże to być jakiś argument. Z drugiej strony, gdy tworzymy, takie oprogramowanie, to zazwyczaj mamy bazę, którą &lt;span style="font-style:italic;"&gt;rekomendujemy&lt;/span&gt;, a klient się na to godzi, bo nie ma innego wyjścia&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;2. Automagiczne generowanie schematu&lt;/span&gt;&lt;br /&gt;Fajne podczas prototypowania, ale soft produkcyjny oparty o automatycznie wygenerowany schemat z encji, które miały tylko @Entity, @Id i @OneToMany, to brzydactwo. Autogenerowanie uczy złego nawyku, że baza danych to pikuś i nie trzeba się nią przejmować. &lt;br /&gt;&lt;br /&gt;Otóż, trzeba. Jedyne słuszne spostrzeżenie entuzjastów O/RM jest takie, że baza danych i obiekty to dwie różne bajki. Model obiektowy powinien być tworzony przez ludzi, którzy się na tym znają, a model danych (schemat bazy) przez innych dedykowanych temu specjalistów. Natomiast O/RM jest po to, aby jedno z drugim ożenić.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;3. Programista obiektowy powinien zapomnieć o bazie danych&lt;/span&gt;&lt;br /&gt;Akurat baza danych da o sobie zapomnieć, dobre sobie! Kto zapomniał jak się pisze w SQL, ręka w górę...&lt;br /&gt;&lt;br /&gt;Po pierwsze: ewoluujący w trakcie rozwoju projektu model, często wymaga modyfikacji mapowań, co siłą rzeczy nie pozwala zapomnieć o bazie danych.&lt;br /&gt;&lt;br /&gt;Po drugie: mapowania, podobnie jak baza danych wymagają profilowania, np.: nie za dużo joinów w zapytaniach, czy występuje n+1 select problem, jakiego rodzaju zapytania są najczęstsze itd. Takie profilowanie, wymaga jednak analizy generowanych przez O/RM SQLi. I znów baza danych zagląda nam przez ramię.&lt;br /&gt;&lt;br /&gt;Po trzecie: w 8/10 projektach, których w ten czy w inny sposób uczestniczyłem programiści wspomagali się procedurami składowymi, trigerami itp,, w poważaniu mając idealistyczny koncept zapominania o bazie danych.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;4. Wygoda użytkowania&lt;/span&gt;&lt;br /&gt;No nie wiem... O/RM jedne problemy rozwiązuje, ale za to wprowadza szereg innych. Żeby dobrze korzystać ze zmapowanego modelu, trzeba mieć &lt;span style="font-weight:bold;"&gt;dogłębną&lt;/span&gt; świadomość relacji, trzeba wiedzieć jak są obiekty ze sobą powiązane, gdzie jest lazy, a gdzie eager, gdzie jest kaskadowość, a gdzie jej nie ma, kto jest właścicielem relacji itp. Inny jest sposób pracy z modelem z włączony filtrem OpenSessionInView, inny bez niego. &lt;br /&gt;&lt;br /&gt;Te ograniczenia są dla mnie sporym usztywnieniem. Staram się zapomnieć o bazie danych, ale muszę jednocześnie zawsze pamiętać o sposobie mapowania do bazy i mapowania pomiędzy obiektami.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;5. JPA pozwala używać różnych dostarczycieli presystencji&lt;/span&gt;&lt;br /&gt;Owszem pozwala, ale jaka z tego korzyść dodana? Używanie JPA w celu uniezależnienia się o konkretnego frameworka to mit. JPA, jak to standard, rozwija się dość powoli, a programiści chcąc poradzić sobie z bieżącymi problemami, używają rozwiązań (np.: adnotacji) specyficznych dla danego dostarczyciela i wspaniała idea niezależności bierze w łeb.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;6. Nie ma bałaganu z DTO dzięki obiektom &lt;span style="font-style:italic;"&gt;detached&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;Trochę racja trochę nie. Bardzo często na widoku potrzebujemy pokazać dane przekrojowe, pochodzące z wielu obiektów domenowych. Fragmenty modelu trzeba spłaszczyć oraz najczęściej przepakować do DTO.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Czy używanie O/RM na zatem sens?&lt;/span&gt;&lt;br /&gt;Sądzę, że ma. Widzę tu następujące kryterium &lt;span style="font-style:italic;"&gt;w modelu domenowym występują złożone relacje pomiędzy obiektami i chcemy z tych relacji korzystać&lt;/span&gt;. &lt;br /&gt;&lt;br /&gt;To &lt;span style="font-weight:bold;"&gt;relacje&lt;/span&gt; między obiektami są największą wartością dodaną O/RMów. Egzekwowanie kaskadowości, leniwości może w bogatych i złożonych modelach uprościć programowanie kodu biznesowego. Jeśli zaś mam prościutki (i często anemiczny) model zawierający jedynie @Entity @Id @OneToMany i koncentrujemy się na operacjach CRUD na encjach, to O/RM jest zdecydowanie na wyrost, stanowi niepotrzebną warstwę pośrednią&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Jeśli nie O/RM, to co?&lt;/span&gt;&lt;br /&gt;Czyste JDBC (a jakże!) plus biblioteki pomocnicze. Rozwiązania takie jak &lt;a href="http://www.mybatis.org"&gt;mybatis&lt;/a&gt; (dawniej iBatis) albo klasa narzędziowa &lt;a href="http://static.springsource.org/spring/docs/2.0.x/api/org/springframework/jdbc/core/JdbcTemplate.html"&gt;JdbcTemplate&lt;/a&gt; z stajni &lt;a href="http://www.springsource.org/documentation"&gt;Springa&lt;/a&gt; oraz sensowne przemyślenie architektury z udziałem &lt;a href="http://java.sun.com/blueprints/corej2eepatterns/Patterns/DataAccessObject.html"&gt;DAO&lt;/a&gt; w bardzo wielu przypadkach &lt;span style="font-weight:bold;"&gt;naprawdę &lt;/span&gt; wystarcza.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1759916214638009707-6814027003799929499?l=mbartyzel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mbartyzel.blogspot.com/feeds/6814027003799929499/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1759916214638009707&amp;postID=6814027003799929499' title='Komentarze (7)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/6814027003799929499'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/6814027003799929499'/><link rel='alternate' type='text/html' href='http://mbartyzel.blogspot.com/2011/03/po-co-orm.html' title='Po co O/RM?'/><author><name>Michał Bartyzel</name><uri>http://www.blogger.com/profile/03968505875451301931</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1759916214638009707.post-1194023669211540198</id><published>2011-03-10T19:07:00.006+01:00</published><updated>2011-06-28T11:33:14.884+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='pea'/><category scheme='http://www.blogger.com/atom/ns#' term='architektura'/><title type='text'>PEA(2): Kontekst środowiskowy systemu</title><content type='html'>&lt;span style="font-style:italic; font-size:80%"&gt;To jest artykuł z serii &lt;a href="http://mbartyzel.blogspot.com/search/label/pea" target="_blank"&gt;Proces ewolucji architektury&lt;/a&gt;&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/-WDXPHRBhAjU/TXkUjJp1kXI/AAAAAAAAA1w/vI7OTR_WIA8/s1600/kontekst.PNG"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 190px;" src="http://1.bp.blogspot.com/-WDXPHRBhAjU/TXkUjJp1kXI/AAAAAAAAA1w/vI7OTR_WIA8/s400/kontekst.PNG" border="0" alt=""id="BLOGGER_PHOTO_ID_5582515807221813618" /&gt;&lt;/a&gt;9 rano, siadasz z ludźmi, którzy chcą, żeby zaprojektować &lt;span style="font-weight:bold;"&gt;architekturę systemu&lt;/span&gt;. Twoja wiedza domenowa = null. &lt;br /&gt;&lt;br /&gt;Zaczynają zasypywać cię gradem szczegółów. &lt;br /&gt;&lt;br /&gt;10.30 mózg przestaje absorbować informacje. Czujesz się jak po całym dni w obcym kraju, gdzie musiałeś wytężać 100% uwagi, żeby zrozumieć choć trochę co do ciebie mówią. Naturalna reakcja obronna organizmu jest zabawna - chce ci się spać. O, żeby zdrzemnąć się choć na minutkę... Stop!&lt;br /&gt;&lt;br /&gt;Zbuduj sobie &lt;span style="font-weight:bold;"&gt;ogólne overview&lt;/span&gt; na sytuację. Określ kontekst środowiskowy systemu, z kim on współpracuje i jakie informacje wymienia z otoczeniem:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;trzymaj się na dość dużym poziomie ogólności; na tym etapie szczegół to twój wróg, uśpi cię szybciej niż myślisz&lt;/li&gt;&lt;br /&gt;&lt;li&gt;definiuj: nazwy systemów, odpowiedzialności systemów (jednym zdaniem), nazwy operacji wykonywanych pomiędzy systemami (czego chce jeden od drugiego?), nazwy protokołów (tylko nazwy)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;unikaj: formatów przesyłanych danych, sposobów nawiązywania połączeń itp; jeszcze nie jest na to czas&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Nie wstydź się bazgrać&lt;/span&gt;&lt;br /&gt;Celem tych działań jest zrozumienie z czym masz do czynienia, ani brylowanie znajomością UMLa. Na tym etapie diagram komponentów wcale nie jest bardziej profesjonalny niż prostokąty nabazgrane na kartce. Diagram to tylko umowa co do formatu rysunków, jeśli kredki odpowiadają ci bardziej dlaczego ich nie używać?&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/-Xkx3_wa0Ky8/TXkcdo85B-I/AAAAAAAAA14/xkR9rn9sfEk/s1600/Przechwytywanie.PNG"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 242px;" src="http://3.bp.blogspot.com/-Xkx3_wa0Ky8/TXkcdo85B-I/AAAAAAAAA14/xkR9rn9sfEk/s400/Przechwytywanie.PNG" border="0" alt=""id="BLOGGER_PHOTO_ID_5582524508637038562" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1759916214638009707-1194023669211540198?l=mbartyzel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mbartyzel.blogspot.com/feeds/1194023669211540198/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1759916214638009707&amp;postID=1194023669211540198' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/1194023669211540198'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/1194023669211540198'/><link rel='alternate' type='text/html' href='http://mbartyzel.blogspot.com/2011/03/pea2-kontekst-srodowiskowy-systemu.html' title='PEA(2): Kontekst środowiskowy systemu'/><author><name>Michał Bartyzel</name><uri>http://www.blogger.com/profile/03968505875451301931</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-WDXPHRBhAjU/TXkUjJp1kXI/AAAAAAAAA1w/vI7OTR_WIA8/s72-c/kontekst.PNG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1759916214638009707.post-9008911613474269800</id><published>2011-03-09T21:29:00.005+01:00</published><updated>2011-03-09T21:45:53.022+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='architektura'/><category scheme='http://www.blogger.com/atom/ns#' term='książki'/><title type='text'>Lean Architecture: for Agile Software Development</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/-qZOEDORJt48/TXfjqj2F1wI/AAAAAAAAA1o/vwirDfwxz8E/s1600/leanarchitecturefrontcover.jpg"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 324px; height: 400px;" src="http://1.bp.blogspot.com/-qZOEDORJt48/TXfjqj2F1wI/AAAAAAAAA1o/vwirDfwxz8E/s400/leanarchitecturefrontcover.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5582180583465146114" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://eu.wiley.com/WileyCDA/WileyTitle/productCd-0470684208.html" target="_blank"&gt;&lt;/a&gt;Nie, to nie jest recenzja książki, a raczej gorące jej polecenie. Lektura tak mnie zachwyciła, że aż musiałem wpisać to na blogu, co poskutkowało dorzuceniem nowej etykiety, a o ile pamiętam liczba etykiet na moim blogu nie zmieniła się od początku jego powstania. Słowem: WIELKIE wydarzenie.&lt;br /&gt;&lt;br /&gt;Nie znajdziesz w tej książce supertajnych wzorców w postaci UML, nie poczytasz o wyższości jednej technologii nad drugą. Jest ona o tym, o czym być powinna: o budowaniu zrozumienia dziedziny, o tworzeniu porządnego softu i o ludziach, którzy są w to wszystko zaangażowani. Wymagająca lektura nie-na-jeden-wieczór, ale warto!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1759916214638009707-9008911613474269800?l=mbartyzel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mbartyzel.blogspot.com/feeds/9008911613474269800/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1759916214638009707&amp;postID=9008911613474269800' title='Komentarze (3)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/9008911613474269800'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/9008911613474269800'/><link rel='alternate' type='text/html' href='http://mbartyzel.blogspot.com/2011/03/lean-architecture-for-agile-software.html' title='Lean Architecture: for Agile Software Development'/><author><name>Michał Bartyzel</name><uri>http://www.blogger.com/profile/03968505875451301931</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-qZOEDORJt48/TXfjqj2F1wI/AAAAAAAAA1o/vwirDfwxz8E/s72-c/leanarchitecturefrontcover.jpg' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1759916214638009707.post-5233474676454373189</id><published>2011-02-15T21:20:00.004+01:00</published><updated>2011-02-15T21:38:17.235+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='wizje'/><category scheme='http://www.blogger.com/atom/ns#' term='refaktoring'/><title type='text'>Myjcie swoje kubki!</title><content type='html'>Widziałem w kuchni jednej z firm taki napis:&lt;br /&gt;&lt;div style="text-align:center;font-style:italic"&gt;&lt;br /&gt;Umyj po sobie kubek. Tobie łatwiej umyć jeden kubek niż nam sto.&lt;br /&gt;&lt;br /&gt;Dziękujemy,&lt;br /&gt;Serwis Sprzątajacy&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Niniejszym ogłaszam ludzi z &lt;span style="font-style:italic;"&gt;Serwisu Sprzątającego&lt;/span&gt; mistrzami refaktoryzacji. Przecież o to właśnie tu chodzi.&lt;br /&gt;&lt;br /&gt;Łatwiej poradzić sobie z syfiastym kodem, gdy jest go jeszcze mało. Nawet jeśli jest i 200 kubków w zlewie, to dokładanie kolejnego z nadzieją, że może jeszcze dziś się nie rozleci, jest najgorszą rzeczą jaką można zrobić. Tak wiem: a bo czas, a bo pieniądze, a bo biznes, a bo babcia... &lt;br /&gt;&lt;br /&gt;Być może biznes nie chce dać kasy na porządny Serwis Sprzątający, ale o swój kubek można z pewnością zadbać bez większego uszczerbku na zdrowiu.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1759916214638009707-5233474676454373189?l=mbartyzel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mbartyzel.blogspot.com/feeds/5233474676454373189/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1759916214638009707&amp;postID=5233474676454373189' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/5233474676454373189'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/5233474676454373189'/><link rel='alternate' type='text/html' href='http://mbartyzel.blogspot.com/2011/02/myjcie-swoje-kubki.html' title='Myjcie swoje kubki!'/><author><name>Michał Bartyzel</name><uri>http://www.blogger.com/profile/03968505875451301931</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1759916214638009707.post-6852240266267857195</id><published>2011-02-15T20:53:00.003+01:00</published><updated>2011-02-15T21:19:39.234+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='wydarzenia'/><title type='text'>MiernotaFactory</title><content type='html'>Przez jakiś czas poszukiwaliśmy praktykanta :) Pomijając marnujących mój czas luzaków, którym zdarzało się nie wiedzieć, czym zajmuje się firma albo nawet na jakie stanowisko aplikują (serio! wysyłają cv do 20 firm, a potem wędrują od rozmowy do rozmowy), większość z nich ma oczekiwania finansowe, których nie powstydziłby się developer z dwuletnim stażem w łódzkiem. &lt;br /&gt;&lt;br /&gt;Trafiło mnie na miejscu, bo nie dość, że trzeba delikwenta wszystkiego nauczyć, to jeszcze trzeba go najpierw sporo oduczyć. Nie mówię wcale o supertajnej wiedzy merytorycznej lecz o punktualności, odpowiedzialności i doprowadzaniu spraw do końca. Merytoryka to osobna historia. &lt;br /&gt;&lt;br /&gt;Wyprostujcie mnie proszę, ale gdy ja starałem się dostać na praktyki (a było nie dalej jak 8 lat wstecz), to mało komu przychodziło do głowy, że może chcieć wynagrodzenie. Słowo! Szczęśliwców z roku, którzy załapali się na płatne praktyki do P&amp;G czy IBM można było policzyć na palcach jednej ręki.&lt;br /&gt;&lt;br /&gt;No nie mogę przeżyć, że ktoś chce poprzychodzić miesiąc albo dwa, nie robi nic co można by jasno przełożyć na zysk firmy, zazwyczaj kosztuje, bo trzeba mu poświęcać czas i chce tyle kasy, co regularny programista.&lt;br /&gt;&lt;br /&gt;Ktoś mnie jednak olśnił. Podobno za samo studiowanie kierunku technicznego można dostać stypendium z jakiegoś ministerstwa. No to sprawa jasna...&lt;br /&gt;&lt;br /&gt;Boję się tylko jednego, że tego typu rozleniwianie narodu skończy się produkcją defaultowych miernot z wyższym wykształceniem. Miernot bez pasji, pracowitości, wytrwałości, chęci nauki. Miernot ze sprzętowo wbudowaną roszczeniową postawą wobec świata. Gdybym wierzył w państwowe ubezpieczenia społeczne, to bym się zaczął bać.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1759916214638009707-6852240266267857195?l=mbartyzel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mbartyzel.blogspot.com/feeds/6852240266267857195/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1759916214638009707&amp;postID=6852240266267857195' title='Komentarze (4)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/6852240266267857195'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/6852240266267857195'/><link rel='alternate' type='text/html' href='http://mbartyzel.blogspot.com/2011/02/miernotafactory.html' title='MiernotaFactory'/><author><name>Michał Bartyzel</name><uri>http://www.blogger.com/profile/03968505875451301931</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1759916214638009707.post-4519815833616571230</id><published>2011-02-12T15:03:00.006+01:00</published><updated>2011-02-12T15:18:38.190+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='wizje'/><category scheme='http://www.blogger.com/atom/ns#' term='refaktoring'/><title type='text'>Pączkowanie kodu</title><content type='html'>Znalazłem analogię do &lt;a target="_blank" href="http://msieraczkiewicz.blogspot.com/2011/02/kilka-nowych-koncepcji-mantra.html"&gt;Naturalnego porządku refaktoryzacji&lt;/a&gt;, o którym pisze &lt;a target="_blank" href="http://msieraczkiewicz.blogspot.com/"&gt;Mariusz&lt;/a&gt;. Otóż kod pączkuje zupełnie jak drożdże.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://medycyna.linia.pl/drozdze1.gif"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 330px; height: 228px;" src="http://medycyna.linia.pl/drozdze1.gif" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Zaczynamy pisać od kawałka kodu, aby zadziałało, potem wyodrębnienie zmiennych, wyodrębnienie metod, przegląd odpowiedzialności, pojawiają się nowe klasy. Naturalny porządek refaktoryacji pozwala projektowy rosnąć i rozwijać się w odpowiednim tempie, z zachowaniem sensownej struktury.&lt;br /&gt;&lt;br /&gt;Kłopot pojawia się, gdy próbujmy przyśpieszyć wzrost drożdżowego kodu. Zostawiamy zahardkodowane rozwiązania, na w projekcie pojawiają się &lt;a href="http://mbartyzel.blogspot.com/2009/01/7-krokw-za-w-projektach-it_02.html"&gt;brzydkie rozwiązania&lt;/a&gt;. Tego typu rzeczy się zdarzają, kłopot w tym, że zostają na zawsze. Wtedy zamiast wypieczonego projektu, dostajemy zakalec albo spaleniznę.&lt;br /&gt;&lt;br /&gt;Każda idea ma swój czas inkubacji. Wydaje mi się, że nie ma dróg na skróty.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1759916214638009707-4519815833616571230?l=mbartyzel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mbartyzel.blogspot.com/feeds/4519815833616571230/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1759916214638009707&amp;postID=4519815833616571230' title='Komentarze (2)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/4519815833616571230'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/4519815833616571230'/><link rel='alternate' type='text/html' href='http://mbartyzel.blogspot.com/2011/02/paczkowanie-kodu.html' title='Pączkowanie kodu'/><author><name>Michał Bartyzel</name><uri>http://www.blogger.com/profile/03968505875451301931</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1759916214638009707.post-2197336668117515499</id><published>2010-10-12T21:49:00.003+02:00</published><updated>2010-10-13T00:08:09.998+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='wizje'/><category scheme='http://www.blogger.com/atom/ns#' term='refaktoring'/><title type='text'>Kto płaci za dobry kod?</title><content type='html'>Oświeciło mnie ostatnio...przynajmniej trochę.&lt;br /&gt;Gdy pracuję z innymi programistami nad tematami związanymi z jakością kodu bardzo często uderza mnie fakt, że pod względem technicznym żadnego z nich nie jestem w stanie nic, ale to nic nowego nauczyć!&lt;br /&gt;&lt;br /&gt;Programiści zazwyczaj wiedzą:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;jakie są słabe punkty ich kodu&lt;/li&gt;&lt;br /&gt;&lt;li&gt;jak powinien wyglądać ich kod&lt;/li&gt;&lt;br /&gt;&lt;li&gt;co dokładnie należy zrobić, aby ich kod wyglądał tak jak&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;Wiedzą to wszystko i...nic się nie dzieje! Nic się nie zmienia. Ciekawe jak to jest możliwe, że mimo tej ogromnej wiedzy, świadomości dobrych rozwiązań, znajomości wzorców projektowych, umiejętności tworzenia czytelnego kodu wciąż jest jak jest - czyli kod woła o pomstę do nieba, a my narzekamy.&lt;br /&gt;&lt;br /&gt;Przeprowadziłem małe śledztwo, polegające głownie na zadawaniu pytań i nakłanianiu ludzi do wypełniania ankiet. &lt;br /&gt;&lt;br /&gt;Podsumowując:&lt;span style="font-weight:bold;"&gt; nic się nie dzieje, ponieważ:&lt;/span&gt;&lt;br /&gt;&lt;ul style="font-style:italic;"&gt;&lt;br /&gt;&lt;li&gt;za działający kod płaci każdy, za dobry nikt&lt;/li&gt;&lt;br /&gt;&lt;li&gt;nacisk na jakość kodu powinien iść z góry, od menadżerów; programiści-idealiści w końcu zniechęcają&lt;/li&gt;&lt;br /&gt;&lt;li&gt;długotrwała praca ze kodem o złej jakości, skutkuje tendencją do dopasowywania się do otoczenia; równamy w dół i tworzymy kod, którego jakość jest nie lepsza niż jego otoczenie&lt;/li&gt;&lt;br /&gt;&lt;li&gt;obawiamy się, że radykalne decyzje projektowe okażą się niesłuszne w przyszłości&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1759916214638009707-2197336668117515499?l=mbartyzel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mbartyzel.blogspot.com/feeds/2197336668117515499/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1759916214638009707&amp;postID=2197336668117515499' title='Komentarze (6)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/2197336668117515499'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/2197336668117515499'/><link rel='alternate' type='text/html' href='http://mbartyzel.blogspot.com/2010/10/kto-paci-za-dobry-kod.html' title='Kto płaci za dobry kod?'/><author><name>Michał Bartyzel</name><uri>http://www.blogger.com/profile/03968505875451301931</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1759916214638009707.post-6209214663450510450</id><published>2010-10-02T17:24:00.002+02:00</published><updated>2010-10-02T20:04:40.495+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='wizje'/><category scheme='http://www.blogger.com/atom/ns#' term='rozwój'/><title type='text'>30 lat z życia programisty</title><content type='html'>Miałem ostatnio przyjemność pracować z programistami, które swoje pierwsze programy tworzyli korzystając z kart perforowanych lub kodu maszynowego procesora. Tak istnieją jeszcze tacy...&lt;br /&gt;&lt;br /&gt;Zastanawiałem się w jaki sposób Ci ludzie utrzymali się w tej branży tak długo, gdzie przecież co chwila jesteśmy świadkami skoków technologicznych, gdzie wciąż trzeba poszerzać swoje umiejętności albo przekwalifikowywać się. Pewnie pomyślicie, że Ci ludzie zachomikowali się gdzieś na wygodnych stanowiskach i dłubią swoje w COBOLu (nawiasem mówiąc stawka programisty COBOLa to $5000/m-c). Otóż nie, jest zupełnie inaczej.&lt;br /&gt;&lt;br /&gt;Najczęściej spotykam programistów w wieku do 30 lat z doświadczeniem od 0 do 8 lat. Większość z nich jest absolutnie przekonana, że OOP rulez! Bardzo wielu nie widzi świata poza Javą, .NETem albo C/C++ - w zależności od tego co piszą. Są absolutnymi fanami tego co robią. I dobrze! &lt;br /&gt;Czym zatem różnią się od programistów z 30 letnim stażem? Przede wszystkim tym, że Ci drudzy są absolutnymi fanami &lt;span style="font-weight:bold;"&gt;pragmatyzmu&lt;/span&gt;.Wciąż tworzą rozwiązania, które zaspokajają potrzeby klientów. Dla wielu z nich OOP albo Java to kolejna nowinka technologiczna. Z mojej perspektywy mają oni niemal ponadczasowe spojrzenie na branżę IT.&lt;br /&gt;&lt;br /&gt;Gdy tak roztrząsaliśmy wspólnie różne rozwiązania w systemach IT i próbowałem przekonywać ich do moich ulubionych wizji i ulubionych technologii, jeden z nich uśmiechnął się i powiedział &lt;span style="font-style:italic;"&gt;wiesz, z tego co obserwuję co 8-10 lat następuje jakiś gwałtowny zwrot w technologii, jakaś nowinka, która zupełnie odmienia sposób w jaki programiści myślą i tworzą; przeszedłem już przez kilka takich zmian, teraz kończy się mniej więcej 8 lat od dżawowego szału i jestem bardzo ciekaw co będzie dalej...&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Moi rozmówcy wieszczyli, że zbliża się era języków funkcyjnych, no zobaczymy czy mają rację.&lt;br /&gt;&lt;br /&gt;Życzę sobie, abym kiedyś również potrafił patrzyć na swoją pracę i pracę innych z takim dystansem i trzeźwością co programiści z trzydziestoletnim stażem.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1759916214638009707-6209214663450510450?l=mbartyzel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mbartyzel.blogspot.com/feeds/6209214663450510450/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1759916214638009707&amp;postID=6209214663450510450' title='Komentarze (1)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/6209214663450510450'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/6209214663450510450'/><link rel='alternate' type='text/html' href='http://mbartyzel.blogspot.com/2010/10/30-lat-z-zycia-programisty.html' title='30 lat z życia programisty'/><author><name>Michał Bartyzel</name><uri>http://www.blogger.com/profile/03968505875451301931</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1759916214638009707.post-7663652120941406495</id><published>2010-07-28T23:26:00.006+02:00</published><updated>2010-07-29T06:32:44.562+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='analiza'/><category scheme='http://www.blogger.com/atom/ns#' term='rozwój'/><category scheme='http://www.blogger.com/atom/ns#' term='praca z klientem'/><title type='text'>Kilka spraw, o których powinien wiedzieć analityk</title><content type='html'>Gdy wchodzisz do firmy jako zewnętrzny analityk, czasem dzieją się dziwne rzeczy...Zebrałem parę punktów, o których warto wiedzieć przed przystąpieniem do pracy. (to luźne, nieposegregowane notatki, więc bez pedantyzmu, pliz ;))&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;Rozpoznaj strukturę organizacyjną&lt;/b&gt; - przed spotkaniem warto wiedzieć kto jest kim i za co odpowiada; pozwoli to lepiej ułożyć grafik rozmów&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;Ustal wcześniej grafik spotkań&lt;/b&gt; - w większości firm nie można wyciągnać ludzi na rozmowę ot tak sobie, trzeba się najpierw umówić&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;Zawsze ustalaj, czego chcesz się dowiedzieć&lt;/b&gt; - bo może się zdarzyć, że po całym dniu spotkań, będziesz przeglądać notatki i zastanawiać się, czego się właściwie dowiedziałeś&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;Trudno wyciągnąć wymagania od osoby nastawionej na różnice&lt;/b&gt; - czasem zdarzy się klient, który wymagania formułuje poprzez wyjątki od reguł; baaaardzo trudno ustalić jak właściwie ma działać wspomagający go system, bo w sposobie myślenia klienta większość rzeczy, którymi zajmuje się w pracy nie ma ze sobą nic wspólnego (np.: nastawiony na różnice doradca bankowy "potrzebuje" oddzielnego systemu dla każdego klienta&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;System wciąga&lt;/b&gt; - gdy przebywasz więcej niż 1 dzień w firmie klienta, zaczynasz wciągać się w ich problemy; ludzie z którymi się spotykasz bezwiednie próbują umieścić w środowisku, w którym się znajdują, próbują cię zaklasyfikować, nadać jakąś etykietkę, jakąś rolę; np. zaczynają cię traktować jako podwładnego Dyrektora IT; jeśli dasz się wciągnąć w tę grę to po tobie, bo stracisz perspektywę "kogoś z boku"&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;Prowadź spotkanie&lt;/b&gt; - bo jeśli ty nie będziesz kierował jego przebiegiem, to na pewno zrobi to ktoś inny; nie osiągniesz wtedy swoich celów&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;Odróżniaj fakty od emocji&lt;/b&gt; - Niektórzy ludzie mówią o swoich odczuciach związanych z oprogramowaniem; pamiętaj, że opiniom nie przysługuje atrybut prawdy; jeśli będziesz wystarczająco długo zadawał pytanie &lt;i&gt;po czy konkretnie poznasz, że...?&lt;/i&gt; (np.: po czym konkretnie poznasz, że GUI jest ładne), to dojdziesz do użytecznych faktów&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;Bądź wyczulony na relacje międzyludzkie&lt;/b&gt; - w każdej grupie ludzi, ktoś kogoś lubi albo nie, ktoś z kimś trzyma albo wojuje, ktoś rządzi, a ktoś słucha; rozpoznając relacje w firmie skuteczniej zidentyfikujesz interesariuszy (osoby, które mają odnieść korzyść z powstania systemu), &lt;i&gt;mocnych&lt;/i&gt; interesariuszy (osoby, które mają rzeczywistą moc powiedzieć, że system ma wyglądać i działać tak, a nie inaczej) oraz oponentów (tych, którzy będą negować idę powstania systemu); czasem trafnie rozpoznając relacje międzyludzkie możesz odgadnąć, że właściwie nie masz nic do roboty w tej firmie zanim zapadnie taka decyzja&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;W miarę możliwości porozmawiaj z każdym&lt;/b&gt; - jeśli kogoś pominiesz, to mogą przychodzić mu do głowy różne myśli, np.: &lt;i&gt;a może chcą mnie zwolnić?&lt;/i&gt; &lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;Ludzie mają przyzwyczajenia&lt;/b&gt; - i prędzej wyjmą twoje serce łyżką niż z nich zrezygnują; jeśli nowy soft nie będzie podobny do czegoś, co już znają albo widzieli, to nie będą go używać&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;Podczas zbierania wymagań koncentruj się na...zbieraniu wymagań&lt;/b&gt; - choć chęć zastanawiania się nad tym jak to zrobić jest bardzo silna; to nie jest jeszcze ten moment&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;Wysyłaj podsumowania po spotkaniu&lt;/b&gt; - po pierwsze uporządkujesz wiedzę, po drugie sprawdzisz, czy dobrze zrozumiałeś, po trzecie dostaniesz dodatkowe informacje (a może ktoś coś sobie przypomni?), po czwarte podkreślisz wagę spotkania, po wtóre to jest odbierane jako oznaka profesjonalizmu&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;Rób notatki podsumowujące spotkanie&lt;/b&gt; - i to jak najszybciej po jego zakończeniu! wtedy masz spostrzeżenia na gorąco; rewelacyjnie sprawdza się w tym zakresie mind mapping &lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;Nie daj się uwieść narzędziom&lt;/b&gt; - narzędzia w stylu EA i podobne są pożyteczne jak już dokładnie wiesz czego potrzebuje klient i chcesz to zgrabnie zebrać do kupy; korzystanie z nich na wczesnym etapie (choć twórcy wbudowują zachęcające funkcjonalności) ogranicza i usztywnia kreatywność; zamiast zastanawiać się nad potrzebami klienta, zaczniesz rozgryzać narzędzie (a każde z narzędzi ma inaczej zaprojektowany proces pracy, a tenże proces pracy zupełnie nie pasuje to tego w jaki sposób działają nasz mózgi)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;Poznaj procesy biznesowe&lt;/b&gt; - przed spotkaniami bardzo korzystnie jest poznać specyfikę pracy i procesy biznesowe, które ma wspierać nowe oprogramowanie&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1759916214638009707-7663652120941406495?l=mbartyzel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mbartyzel.blogspot.com/feeds/7663652120941406495/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1759916214638009707&amp;postID=7663652120941406495' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/7663652120941406495'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/7663652120941406495'/><link rel='alternate' type='text/html' href='http://mbartyzel.blogspot.com/2010/07/kilka-spraw-o-ktorych-powinien-wiedziec.html' title='Kilka spraw, o których powinien wiedzieć analityk'/><author><name>Michał Bartyzel</name><uri>http://www.blogger.com/profile/03968505875451301931</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1759916214638009707.post-4210227238342763312</id><published>2010-03-11T00:34:00.003+01:00</published><updated>2010-03-11T00:42:29.319+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='info'/><title type='text'>http://www.roseindia.net</title><content type='html'>Bardzo krótki post, bo mam intensywny tydzień:)&lt;br /&gt;Polecam portal &lt;a href="http://www.roseindia.net"&gt;http://www.roseindia.net&lt;/a&gt; może nie wygląda najlepiej, ale dawno nie widziałem tylu przykładów w jednym miejscu!&lt;br /&gt;&lt;br /&gt;P.S. Lektura uzupełniająca &lt;a href="http://static.raibledesigns.com/repository/presentations/ComparingJavaWebFrameworks-ApacheConUS2007.pdf"&gt;Comparing web frameworks&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1759916214638009707-4210227238342763312?l=mbartyzel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mbartyzel.blogspot.com/feeds/4210227238342763312/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1759916214638009707&amp;postID=4210227238342763312' title='Komentarze (1)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/4210227238342763312'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/4210227238342763312'/><link rel='alternate' type='text/html' href='http://mbartyzel.blogspot.com/2010/03/httpwwwroseindianet.html' title='http://www.roseindia.net'/><author><name>Michał Bartyzel</name><uri>http://www.blogger.com/profile/03968505875451301931</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1759916214638009707.post-659970964795964013</id><published>2009-12-17T08:55:00.012+01:00</published><updated>2011-08-10T20:33:30.464+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='wzorce'/><category scheme='http://www.blogger.com/atom/ns#' term='architektura'/><title type='text'>Dziedziczenie i kompozycja</title><content type='html'>&lt;div&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.bnsit.pl/files/strategie_decouplingu.pdf"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://bp2.blogger.com/_wQFWfmLrUy4/SFq_8FmWi_I/AAAAAAAAAC4/hpwTTs8-hoU/s200/PDF-Icon.jpg" alt="" id="BLOGGER_PHOTO_ID_5213690557650865138" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a style="color: rgb(119, 54, 7); text-decoration: underline; font-weight: normal;" href="http://bnsit.pl/files/mbblog/Wzorce_projektowe-Dziedziczenie_i_kompozycja.pdf"&gt;Wersja PDF&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Ostatnio wygrzebałem w polskiej blogsferze namiar na &lt;a href="http://weblogs.java.net/blog/82/2003/09/02/aristotles-error-or-agile-smagile"&gt;Aristotle's Error or Agile Smile&lt;/a&gt;. Wynika z niego, że nasza wspaniała obiektowość jest dziełem przypadku (a co nie jest?), a ideologię o modelowaniu świata rzeczywistego dorobili spece od marketingu. Jak było w rzeczywistości nie dociekałem. Skoro już obiektowość, a wraz z nią sztandarowe dziedziczenie.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Dziedziczenie&lt;/h4&gt;&lt;br /&gt;Na Rysunek 1 jest fragment jakiegoś tam systemu. Pewnie każdy z nas widział podobne rzeczy choćby w Java API, które roi się od podobnych lub o wiele bardziej skomplikowanych konstrukcji. &lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_wQFWfmLrUy4/Synk-s4uKXI/AAAAAAAAAy8/mHbz6tKU-Ys/s1600-h/Main.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 262px;" src="http://4.bp.blogspot.com/_wQFWfmLrUy4/Synk-s4uKXI/AAAAAAAAAy8/mHbz6tKU-Ys/s400/Main.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5416111792741820786" /&gt;&lt;/a&gt;&lt;br /&gt;Choć programiście całkiem nieźle używa się klas zaprojektowanych w ten sposób, to gdy programista chciałby na bazie takich konstrukcji rozwijać swoją aplikację (czytaj: dalej nieograniczenie dziedziczyć),  to pojawia się kilka problemów:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Aby zrozumieć działanie metody &lt;code&gt;MultiUserRemoteBookStore.findBook()&lt;/code&gt; zapoznać się z całą hierarchią dziedziczenia,&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Faktycznie uruchamiany kod metody tej metody jest rozsiany pomiędzy wiele klas w hierarchii,&lt;li&gt;&lt;br /&gt;&lt;li&gt;Wymusza się na nas użycie konstruktorów (parametrowych) z nadklas, których wcale nie mieliśmy zamiaru używać,&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Dodatkowo nie wiadomo co robią te kostruktory; a nóż przy tworzeniu mojego obiektu coś wybuchnie…&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Trudno przetestować jednostkowo nową klasę. No, bo jak tu zamokować kod wywoływany w testowanej metodzie poprzez &lt;code&gt;super.findBook()&lt;/code&gt;?&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;h4&gt;Kompozycja&lt;/h4&gt;&lt;br /&gt;Większość problemów wynikających ze swobodnego dziedziczenia rozwiązuje kompozycja. Zamiast wyprowadzać nową klasę &lt;code&gt;AcmeBookStore&lt;/code&gt; z &lt;code&gt;MultiUserBookStore&lt;/code&gt; implementujemy główny interfejs &lt;code&gt;BookStoreService&lt;/code&gt; a do potrzebnych metod odwołujemy się poprzez delegację.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_wQFWfmLrUy4/Sys-L_rf7zI/AAAAAAAAAzE/Ys1n-8fBK-Y/s1600-h/Main.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 262px;" src="http://4.bp.blogspot.com/_wQFWfmLrUy4/Sys-L_rf7zI/AAAAAAAAAzE/Ys1n-8fBK-Y/s400/Main.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5416491352636518194" /&gt;&lt;/a&gt;&lt;br /&gt;I kawałek kodu:&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;public class AcmeBookStore implements BookStoreService {&lt;br /&gt; &lt;br /&gt; private MultiUserBookStore multiUserBookStore;&lt;br /&gt; &lt;br /&gt; public Book findBook( String title ) {&lt;br /&gt;  //...&lt;br /&gt;  multiUserBookStore.findBook( title );&lt;br /&gt;  //...&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;(Na marginesie warto zauważyć, że w ten sposób stworzyliśmy implementację Dekoratora.)&lt;br /&gt;To rozwiązanie jest zdecydowanie bardziej czytelne i unit-testing-friendly. Kłopot pojawia się gdy nie w architekturze, z którą pracujemy nie istnieje odpowiednik interfejsu &lt;code&gt;BookStoreService&lt;/code&gt;. Wtedy już, chcąc nie chcąc, zazwyczaj godzimy się godzimy się na dziedziczenie.&lt;br /&gt;&lt;h4&gt;Programowanie poprzez interfejsy&lt;/h4&gt;&lt;br /&gt;Mając na uwadze w/w mogę zastanawiać się: w jaki sposób mogę projektować architekturę mojego kodu tak, aby nie generował problemów z dziedziczeniem. Pierwszą rzeczą, która przychodzi mi na myśl jest programowanie poprzez interfejsy. Nie oznacza to bynajmniej, że każda nowa klasa &lt;code&gt;UserManager&lt;/code&gt; ma swój interfejs &lt;code&gt;UserManagerService&lt;/code&gt;, albo (w wersji hardcore) z każdą nową klasą pojawiają się trzy nowe byty w systemie (&lt;code&gt;UserManagerService&lt;/code&gt;, &lt;code&gt;UserManagerImpl&lt;/code&gt;, &lt;code&gt;AbstractUserManager&lt;/code&gt;). Zerknijmy na rysunek:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_wQFWfmLrUy4/Sys_4MkrGWI/AAAAAAAAAzM/P_7f3jFMCJU/s1600-h/Main.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 347px;" src="http://1.bp.blogspot.com/_wQFWfmLrUy4/Sys_4MkrGWI/AAAAAAAAAzM/P_7f3jFMCJU/s400/Main.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5416493211523422562" /&gt;&lt;/a&gt;&lt;br /&gt;W tej architekturze centralnym punktem systemu (podsystemu, biblioteki) jest interfejs – kontrakt, który mają realizować poszczególne implementacje. Specyfika implementacji np. &lt;code&gt;RemoteBookStore&lt;/code&gt; uzyskiwana jest nie poprzez odpowiednie klasy narzędziowe np. &lt;code&gt;RemotingUtilty&lt;/code&gt;. Dzięki temu można tworzyć kolejne implementacje specjalizujące się w coraz to nowych rzeczach, bez konieczności dziedziczenia.&lt;br /&gt;&lt;h4&gt;Podsumowując&lt;/h4&gt;&lt;br /&gt;Ujawniły nam się następujące rzeczy:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Preferowanie kompozycji ponad dziedziczenie,&lt;br /&gt;&lt;li&gt;Programowanie poprzez interfejsy.&lt;br /&gt;Są to jedne z kluczowych paradygmatów programowania obiektowego. Mamy z nich następujące korzyści:&lt;br /&gt;&lt;li&gt;Kod jest czytelny&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Kod jest otwarty na testowanie.&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;Ostatecznie pozostaje jedno pytanie: czy dziedziczenie jest złe? Nie, jest bardzo dobre... w pewnych kontekstach… Złe jest jego nadużywanie. Jak więc rozpoznawać, które konteksty są odpowiedni dla dziedziczenia? Pewnie można wykombinować jakieś obiektywne kryteria, ale ja proponuję znać się na intuicję: czy dziedziczenie uprościło czy zagmatwała architekturę? Czy łatwiej testować, czy trudniej? Czy przyjemniej się pisze, czy - przeciwnie - chce Ci się...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1759916214638009707-659970964795964013?l=mbartyzel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mbartyzel.blogspot.com/feeds/659970964795964013/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1759916214638009707&amp;postID=659970964795964013' title='Komentarze (3)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/659970964795964013'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/659970964795964013'/><link rel='alternate' type='text/html' href='http://mbartyzel.blogspot.com/2009/12/dziedziczenie-i-kompozycja.html' title='Dziedziczenie i kompozycja'/><author><name>Michał Bartyzel</name><uri>http://www.blogger.com/profile/03968505875451301931</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://bp2.blogger.com/_wQFWfmLrUy4/SFq_8FmWi_I/AAAAAAAAAC4/hpwTTs8-hoU/s72-c/PDF-Icon.jpg' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1759916214638009707.post-6279320424838625324</id><published>2009-12-16T13:40:00.002+01:00</published><updated>2009-12-16T13:48:18.390+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='antywzorce'/><title type='text'>Dziedziczenie zasobnikowe i inne idiotyzmy</title><content type='html'>Wrzucam przykłady fantazji w dziedziczeniu, które spotkałem (serio!) parę lat temu. Pierwsze można nazwać dziedziczeniem zasobnikowym. Od razu widać co zrobił kreatywny programista. Pisząc fragment systemu raportowego potrzebował  przeczytać dane z pliku &lt;code&gt;properties&lt;/code&gt;, a że pamiętał coś takiego ze Struts2, to beztrosko sobie odziedziczył.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_wQFWfmLrUy4/SyjXAxSWFrI/AAAAAAAAAy0/vHzAjCui7YY/s1600-h/Main.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 109px;" src="http://4.bp.blogspot.com/_wQFWfmLrUy4/SyjXAxSWFrI/AAAAAAAAAy0/vHzAjCui7YY/s400/Main.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5415814960143275698" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Drugi kwiatek jest nieco trudniejszy. Dlaczego okrąg dziedziczy z punktu? Otóż dlatego, jak wyjaśnił autor koncepcji, że punkt jest środkiem tego okręgu…&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1759916214638009707-6279320424838625324?l=mbartyzel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mbartyzel.blogspot.com/feeds/6279320424838625324/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1759916214638009707&amp;postID=6279320424838625324' title='Komentarze (6)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/6279320424838625324'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/6279320424838625324'/><link rel='alternate' type='text/html' href='http://mbartyzel.blogspot.com/2009/12/dziedziczenie-zasobnikowe-i-inne.html' title='Dziedziczenie zasobnikowe i inne idiotyzmy'/><author><name>Michał Bartyzel</name><uri>http://www.blogger.com/profile/03968505875451301931</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_wQFWfmLrUy4/SyjXAxSWFrI/AAAAAAAAAy0/vHzAjCui7YY/s72-c/Main.jpg' height='72' width='72'/><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1759916214638009707.post-1095376496484073516</id><published>2009-05-18T07:56:00.006+02:00</published><updated>2009-05-20T06:27:57.077+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='wizje'/><category scheme='http://www.blogger.com/atom/ns#' term='rozwój'/><title type='text'>Takie będą systemy jak ich programistów chowanie</title><content type='html'>Zerknąłem na chwilę na &lt;a href="http://jlaskowski.blogspot.com/2009/05/rozwiazywanie-niezgodnosci-binarnych-z.html"&gt;blog Jacka&lt;/a&gt;. I przeczytałem następujący akapit.&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Jest wiele podobnych &lt;span style="font-style: normal;"&gt;[mb: do asm/cglib]&lt;/span&gt; tematów, których znajomość pomaga, ale &lt;span style="font-weight: bold;"&gt;nie będąc warunkiem koniecznym&lt;/span&gt; odkłada się je na półkę na bliżej nieokreśloną przyszłość. Możnaby mnożyć takich perełek bez liku, chociażby programowanie w języku funkcyjnym, &lt;span style="font-weight: bold;"&gt;albo nawet tak podstawowe jak wzorce projektowe&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Zawrzałem. Jak, na wszystkie potwory Mordoru, ktoś kto pretenduje do poczytnego bloggera w obszarze Java EE, może pisać podobne rzeczy?!? (Dla sprawiedliwości dodam, że następne niecytowane zdania myśl rozwijają i nieco łagodzą). Po chwili zastanowienia zdałem sobie sprawę, że rzeczywiście nie trzeba znać wzorców, żeby programować, ale również:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;nie trzeba używać sztućców, żeby się najeść&lt;/li&gt;&lt;br /&gt;&lt;li&gt;nie trzeba znać języka, żeby się komunikować za granicą&lt;/li&gt;&lt;br /&gt;&lt;li&gt;nie trzeba myć zębów&lt;/li&gt;&lt;br /&gt;&lt;li&gt;nie trzeba nosić czapki w zimę, a przy -30 kalesonów&lt;/li&gt;&lt;br /&gt;&lt;li&gt;nie trzeba czytać książek &lt;/li&gt;&lt;br /&gt;&lt;li&gt;nie trzeba się rozwijać&lt;/li&gt;&lt;br /&gt;&lt;li&gt;nie trzeba..., nie trzeba..., nie trzeba...&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;Żadnej z tych rzeczy nie trzeba. I z pewnością widzimy ludzi, którzy ich nie robią. Od nie robienia tych rzeczy się nie umiera. Przynajmniej nie od razu. Żadna z nich nie jest, wspomnianym przez Jacka, &lt;span style="font-weight:bold;"&gt;warunkiem koniecznym&lt;/span&gt;. Pytanie tylko czy chcemy tak żyć?&lt;br /&gt;&lt;br /&gt;[mb: po dyskusji z komentatorami i przemyśleniu sprawy doszedłem do wniosku, że ten akapit to o 1 most za daleko...]&lt;strike&gt;Więc jeśli robisz coś, co jak mniemasz kształtuje świadomość programistów i tych, którzy dopiero zaczynają tę przygodę, to kieruj ich w jak najlepszą twoim zdaniem stronę. Nawet jeśli nie dotrą do ideałów, o których piszesz, to:&lt;/strike&gt;&lt;br /&gt;&lt;div style="text-align:center;font-style:italic;"&gt;&lt;br /&gt;&lt;strike&gt;zostanie ta siła fatalna,&lt;br /&gt;co tobie żywemu na nic, tylko czoło zdobi,&lt;br /&gt;a będzie ich gniotła niewidzialna,&lt;br /&gt;aż zjadaczy chleba w aniołów przerobi&lt;br /&gt;&lt;/div&gt;&lt;/strike&gt;&lt;br /&gt;&lt;br /&gt;Wpis kończę parafrazą myśli przypisywanej Zamoyskiemu, Modrzewskiemu albo Staszicowi: &lt;span style="font-weight:bold;"&gt;takie będą systemy, jak ich programistów chowanie!&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1759916214638009707-1095376496484073516?l=mbartyzel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mbartyzel.blogspot.com/feeds/1095376496484073516/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1759916214638009707&amp;postID=1095376496484073516' title='Komentarze (8)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/1095376496484073516'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/1095376496484073516'/><link rel='alternate' type='text/html' href='http://mbartyzel.blogspot.com/2009/05/takie-beda-systemy-jak-ich-programistow.html' title='Takie będą systemy jak ich programistów chowanie'/><author><name>Michał Bartyzel</name><uri>http://www.blogger.com/profile/03968505875451301931</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1759916214638009707.post-6556929929089660265</id><published>2009-04-21T13:35:00.017+02:00</published><updated>2009-11-09T20:47:45.002+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='architektura'/><category scheme='http://www.blogger.com/atom/ns#' term='dsl'/><title type='text'>Domain Specific Language - XML i Fluent Interface</title><content type='html'>&lt;div&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.bnsit.pl/files/strategie_decouplingu.pdf"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://bp2.blogger.com/_wQFWfmLrUy4/SFq_8FmWi_I/AAAAAAAAAC4/hpwTTs8-hoU/s200/PDF-Icon.jpg" alt="" id="BLOGGER_PHOTO_ID_5213690557650865138" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a style="color: rgb(119, 54, 7); text-decoration: underline; font-weight: normal;" href="http://bnsit.pl/files/Domain_Specific_Language-XML_i_Fluent_Interface.pdf"&gt;Wersja PDF&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Zamiast rozwodzić się nad definicjami i pojęciami zacznę od pewnego problemu, z którym się spotkałem. Jakiś czas temu do generowania raportów używaliśmy biblioteki JasperReports. To naprawdę rewelacyjna biblioteka, której ideę działania przedstawia Rysunek 1:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_wQFWfmLrUy4/Se24Sb10i_I/AAAAAAAAAG8/7jitMYiBOc0/s1600-h/1.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 252px;" src="http://1.bp.blogspot.com/_wQFWfmLrUy4/Se24Sb10i_I/AAAAAAAAAG8/7jitMYiBOc0/s400/1.png" alt="" id="BLOGGER_PHOTO_ID_5327116561099820018" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Przy całej swej wspaniałości korzystanie z tej (i pewnie z innych) biblioteki do generowania raportów ma następujące konsekwencje:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Szybko generuje się tylko płaskie raporty czyli takie, w których wynikowy raport można „pociąć” na części generowane z jednego szablonu np. spis treści, lista płac, podsumowanie. Jeśli chcielibyśmy zagnieżdżać raport w raporcie, to oczywiście JasperReports daje taką możliwość, ale o całe przygotowanie danych, odpowiednią konfigurację definicji wyglądu i dostarczanie silnikowi danych w odpowiednich porcjach należy zadbać własnoręcznie.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Jeżeli raport musi odwzorowywać wiedzę dziedzinową, np. raportowane są wyniki testu IQ i związana jest z tym złożona merytoryka, to albo bardzo skomplikowane jest przygotowywanie danych a konfiguracja definicji wyglądu w miarę prosta albo odwrotnie. Trudno znaleźć złoty środek.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Ubogacanie raportów wykresami jest możliwe, lecz bardzo pracochłonne.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Jeśli automatyzowane są raporty, które do tej pory były tworzone ręcznie, to...czeka nas baaaardzo dużo pracy.&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;h4&gt;Framework raportowy&lt;/h4&gt;&lt;br /&gt;Powstał pomysł, aby problemom zaradzić. Stworzone rozwiązanie powinno zapewniać następujące funkcjonalności:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Definiowanie fragmentów raportu (podraportów), które można ze sobą łączyć sekwencyjnie (jeden za drugim) lub poprzez agregację (jeden w drugim)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Raport można zasilać danymi z: zapytania SQL, zapytania MDX, wyrażenia XPath lub Expression Language&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Raport można wzbogacić wykresem z dostępnego zbioru wykresów.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;I najważniejsze – wszystko wyżej wymienione powinno odbywać się deklaratywnie.&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;Została stworzona nadbudówka (warstwa abstrakcji – uwielbiam to wyrażenie!) na JasperReports, która pozwoli deklaratywnie tworzyć raporty. Jak zatem opisywać (deklarować) raporty tak, aby sprostać wymaganiom? Wybór padł na XML. Rysunek 2 prezentuje szkic rozwiązania.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_wQFWfmLrUy4/Se25EIEjQ9I/AAAAAAAAAHE/fehVjU5a8FM/s1600-h/2.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 244px;" src="http://3.bp.blogspot.com/_wQFWfmLrUy4/Se25EIEjQ9I/AAAAAAAAAHE/fehVjU5a8FM/s400/2.png" alt="" id="BLOGGER_PHOTO_ID_5327117414786352082" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Pojawiły się nowe elementy całego rozwiązania: plik XML, w którym będzie deklarowany raport (a konkretnie podraporty oraz zależności pomiędzy nimi) oraz nadbudówka, która przejmuje kontrolę nad silnikiem JasperReports. Oczywiście pojawia się dodatkowa warstwa pośrednicząca pomiędzy klientem, który chce wygenerować raport, a biblioteką. Wszystko ma swoją cenę. W tym przypadku prostota tworzenia raportów kosztuje dodatkową pracę przy implementacji warstwy pośredniczącej.&lt;br /&gt;&lt;br /&gt;Spójrzmy na zamieszczony przykład pliku opisującego raport (na potrzeby artykułu nieco uproszczonego).&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;reportConfiguration&amp;gt;&lt;br /&gt;&amp;lt;datasources&amp;gt;&lt;br /&gt;&amp;lt;datasource name="hsql" default="true" type="sql"&amp;gt;&lt;br /&gt;&amp;lt;property name="driver" value="org.hsqldb.jdbcDriver" /&amp;gt;&lt;br /&gt;&amp;lt;property name="url" value="jdbc:hsqldb:hsql://localhost/mydb" /&amp;gt;&lt;br /&gt;&amp;lt;property name="username" value="sa" /&amp;gt;&lt;br /&gt;&amp;lt;property name="password" value="" /&amp;gt;&lt;br /&gt;&amp;lt;/datasource&amp;gt;&lt;br /&gt;&amp;lt;/datasources&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;tableOfContents enabled="true" position="begin" designFile="tableOfContents.jrxml" /&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;subreports&amp;gt;&lt;br /&gt;&amp;lt;subreport type="static" name="introduction" designFile="introduction.jrxml" /&amp;gt; &lt;br /&gt;&lt;br /&gt;&amp;lt;subreport type="sql" name="employeesList" designFilePath="employeesList.jrxml"&lt;br /&gt;   query="select * name,surname from emplyees" /&amp;gt;&lt;br /&gt;&amp;lt;/subreports&amp;gt;&lt;br /&gt;&amp;lt;/reportConfiguration&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Pojawiły się tu słowa (w postaci znaczników XML) jak reportConfiguration, tableOfContents, subreport, desigFilePath. Nie są to słowa związane z językiem programowania, lecz przeznaczone do opisu jednego konkretnego problemu – deklaratywnego tworzenia raportów. Przy użyciu XML zdefiniowaliśmy język opisu raportów, język opisu specyficznego problemu – Domain Specific Language (DSL).  &lt;br /&gt;&lt;br /&gt;&lt;h4&gt;DSL - implementacja oparta o XML&lt;/h4&gt;&lt;br /&gt;Z punktu widzenia użytkownika opisującego raport XML jest wygodnym rozwiązaniem.  W tym przypadku użytkownikami byli programiści, którzy dodawali funkcjonalność generowania raportów do systemów nad którymi pracowali. Ale czy takie rozwiązanie jest najlepsze z perspektywy całego zespołu, w tym grupy odpowiedzialnej za rozwijanie Framework raportowego? Aby odpowiedzieć na to pytanie należy przyjrzeć się sposobowi zaimplementowania tego rozwiązania.&lt;br /&gt;&lt;br /&gt;Pierwszym krokiem jest odczyt konfiguracji z pliku XML. Wygląda to na dość żmudne zadanie. Ale zauważmy, że składnia XML ma charakter obiektowy. Znacznik odpowiada obiektowi, a atrybuty znacznika, atrybutom obiektu. Powstaje pytanie: czy istnieje biblioteka pozwalająca automatycznie przekształcić plik XML do odpowiadającego mu modelu obiektowego? Istnieje – Apache Betwixt (być może są też inne).  Rozwiązanie przybiera następującą postać ja na Rysunek 3.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_wQFWfmLrUy4/Se29FxnnmUI/AAAAAAAAAHM/trmkeUJr36E/s1600-h/3.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 218px;" src="http://2.bp.blogspot.com/_wQFWfmLrUy4/Se29FxnnmUI/AAAAAAAAAHM/trmkeUJr36E/s400/3.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5327121841165670722" /&gt;&lt;/a&gt;&lt;br /&gt;Każdemu znacznikowi z pliku XML odpowiada klasa Java. Biblioteka Betwixt jest odpowiedzialna za przekształcenie struktury XML do analogicznej struktury klas. Aby wykonać to zadanie potrzebna jest dodatkowa konfiguracja. W przypadku tej biblioteki konfigurowanie polega na utworzeniu dla każdej klasy modelu obiektowego pliku .betwixt, w którym zawarte są informacje o mapowaniach znacznik XML – obiekt.  Rozwiązanie to przedstawia Rysunek 4.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_wQFWfmLrUy4/Se29TGjGP5I/AAAAAAAAAHU/1WClnadxJqQ/s1600-h/4.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 239px;" src="http://2.bp.blogspot.com/_wQFWfmLrUy4/Se29TGjGP5I/AAAAAAAAAHU/1WClnadxJqQ/s400/4.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5327122070122151826" /&gt;&lt;/a&gt;&lt;br /&gt;Zauważmy, że struktura obiektowa odpowiada strukturze pliku XML (Listing 1). DSL w postaci pliku XML ma następujące zalety:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Jest intuicyjny i jego utrzymywaniem mogą zajmować się nieprogramiści;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Opis raportu jest oddzielony od kodu aplikacji;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Można stworzyć elastyczne reguły walidacji składni w oparciu o plik XSD;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Oparcie na standardzie XML daje możliwość edytowania pliku w już istniejących narzędziach WYSIWYG lub stworzenia nowego narzędzia do graficznego opisywania raportu;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Konwersja do nowej wersji DSL jest łatwa do zaimplementowania, np. za pomocą transformat XSLT lub po stronie języka Java.&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;Jednocześnie to rozwiązanie ma następujące wady:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Występuje dodatkowa warstwa pośrednicząca w postaci biblioteki Betwixt;&lt;br /&gt;&lt;li&gt;Framework korzysta już z 3 rodzajów konfiguracji:&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;Pliki jrxml – wymagane przez bibliotekę JasperReports definiują wygląd graficzny podraportów;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Pliki betwixt – wymagane przez bibliotekę Betwixt mapują znaczniki XML na obiekty Java;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Plik konfiguracyjny tworzonego frameworka – opisuje zależności pomiędzy podrap ortami, jest to punkt centralny naszego rozwiązania;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Podczas dodawania nowych funkcjonalności najbardziej pracochłonne są modyfikacje związane z plikiem konfiguracyjnym: mapowania, konwersje danych, obsługa błędów;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Ze względu na narzut prac nad plikiem konfiguracyjnym czas oczekiwania na nową wersję biblioteki jest dość długi;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Refaktoryzacja kodu na styku kod Java plik XML jest żmudna i trudna do przeprowadzenia;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Testowanie konfiguracji XML jest niewygodne – bardzo szybko rozmnażają się testowe pliki konfiguracyjne zawierające różne wersje konfiguracji do przetestowania;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Refaktoryzacja testów jest bardzo pracochłonna ze względu na istnienia bardzo wielu plików konfiguracyjnych;&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;DSL - implementacja oparta o Fluent Interface&lt;/h4&gt;&lt;br /&gt;W poszukiwaniu alternatywy do implementacji DSL we frameworku raportowym przyjrzyjmy się koncepcji Fluent Interface. Fluent Interface to sposób projektowania API, który łatwo można zobrazować na przykładzie biblioteki JMock.&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;&lt;br /&gt;mock.expects(once()).method("method").withAnyArguments().isVoid();&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;Trudno o bardziej trafną nazwę niż Fluent Inteface. Wywołania metod można przeczytać jak zdanie w języku naturalnym. Sam koncept nie jest nowy, ja doszukiwałbym się korzeni w kaskadowym korzystaniu ze strumieni w C++ za pomocą operatorów &lt;&lt; i &gt;&gt;.&lt;br /&gt;&lt;br /&gt;Zaprojektujmy zatem Fluent API do konfiguracji raportu. Powinno ono spełniać następujące założenia:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Wywołania kaskady metod czyta się jak zdanie w języku naturalnym;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;API powinno sugerować właściwą kolejność wywoływania metod.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Nowe API nie powinno ingerować w istniejący model obiektowy.&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;Na początek zajmijmy się klasą DatasourceBean. Potrzebujemy udostępnić metody o odpowiednich nazwach, które będą konfigurowały obiekty tej klasy. Jednocześnie API nie powinno ingerować w już istniejące rozwiązanie.  Wymóg separacji API od modelu reprezentującego opis raportu wynika z tego, że nie ma potrzeby, aby obiekty wiedziały w jaki sposób są konfigurowane. W terminologii angielskiej używane jest przy tej okazji słowo &lt;span style="font-style:italic;"&gt;agnostic&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Rozwiązaniem spełniającym powyższe kryteria jest wzorzec budowniczego&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_wQFWfmLrUy4/Se2_nXKikeI/AAAAAAAAAHk/AnS11_zlRpE/s1600-h/5.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 106px;" src="http://3.bp.blogspot.com/_wQFWfmLrUy4/Se2_nXKikeI/AAAAAAAAAHk/AnS11_zlRpE/s400/5.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5327124617203192290" /&gt;&lt;/a&gt;&lt;br /&gt;Odpowiedzialnością klasy DatasourceBeanBuilder jest udostępnienie Fluent API do konfigurowania obiektu klasy DatasourceBean. Praca z API mogłaby wyglądać następująco:&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;builder.isSqlDatasource()&lt;br /&gt;.withDriver( "org.hsqldb.jdbcDriver" )&lt;br /&gt;.withUrl( "jdbc:hsqldb:hsql://localhost/mydb" )&lt;br /&gt;.withUsername( "sa" )&lt;br /&gt;.withPassword( "" )&lt;br /&gt;.isDefault();&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;Zapewne domyślasz się, że sztuczka pozwalająca na kaskadowe wywoływanie metod polega na zwracaniu referencji do budowniczego w każdej metodzie. Poniżej implementacja tego budowniczego.&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;&lt;br /&gt;public class DatasourceBuilder {&lt;br /&gt;&lt;br /&gt; private DatasourceBean bean = new DatasourceBean();&lt;br /&gt; &lt;br /&gt; &lt;br /&gt; public DatasourceBuilder withUsername(String username) {&lt;br /&gt;  bean.addProperty( new PropertyBean("username", username) );&lt;br /&gt;  return this;&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; public DatasourceBuilder withPassword(String password) {&lt;br /&gt;  bean.addProperty( new PropertyBean("password", password) );&lt;br /&gt;  return this;&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; public DatasourceBuilder withUrl(String url) {&lt;br /&gt;  bean.addProperty( new PropertyBean("url", url) );&lt;br /&gt;  return this;&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; public DatasourceBuilder withDriver(String driver) {&lt;br /&gt;  bean.addProperty( new PropertyBean("driver", driver) );&lt;br /&gt;  return this;&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; public DatasourceBuilder isSqlDatasource() {&lt;br /&gt;  bean.setType( "sql" );&lt;br /&gt;  return this;&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; public DatasourceBuilder isDefault() {&lt;br /&gt;  bean.setDefaultDatasource( true );  &lt;br /&gt;  return this;&lt;br /&gt; } &lt;br /&gt;}&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;Dla każdej klasy modelu obiektowego będzie istniał budowniczy odpowiedzialny za udostępnienie API do konfiguracji obiektu (Rysunek 6).&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_wQFWfmLrUy4/Se3A0eet7SI/AAAAAAAAAHs/G1HQQWNddMI/s1600-h/6.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 190px;" src="http://2.bp.blogspot.com/_wQFWfmLrUy4/Se3A0eet7SI/AAAAAAAAAHs/G1HQQWNddMI/s400/6.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5327125942016797986" /&gt;&lt;/a&gt;&lt;br /&gt;Jednym z założeń projektowanego interfejsu było, aby sugerował on programiście kolejność wywoływania metod. Osiągnęliśmy to poprzez wprowadzenie wielu budowniczych. W ten sposób użytkownik, w danym momencie pracuje tylko z jednym budowniczym i ma dostęp do metod, które mają sens w danym kontekście. &lt;br /&gt;&lt;br /&gt;Centralnym punktem API jest ReportConfigurationBeanBuilder, który udostępnia użytkownikowi bardziej szczegółowych budowniczych za pomocą swoich metod (Rysunek 7).&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_wQFWfmLrUy4/Se3BE3n6b2I/AAAAAAAAAH0/t-RTndY6pz4/s1600-h/7.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 254px;" src="http://1.bp.blogspot.com/_wQFWfmLrUy4/Se3BE3n6b2I/AAAAAAAAAH0/t-RTndY6pz4/s400/7.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5327126223644159842" /&gt;&lt;/a&gt;&lt;br /&gt;Przy obecnym rozwiązaniu użytkownik korzysta z API w następujący:&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;&lt;br /&gt;ReportBuilder report = new ReportBuilder();&lt;br /&gt; report.withMasterDesing( "master.jrxml" )&lt;br /&gt;&lt;br /&gt; report.newDataSource( "hsql" )&lt;br /&gt;  .isSqlDatasource()&lt;br /&gt;  .withDriver( "org.hsqldb.jdbcDriver" )&lt;br /&gt;  .withUrl( "jdbc:hsqldb:hsql://localhost/mydb" )&lt;br /&gt;  .withUsername( "sa" )&lt;br /&gt;  .withPassword( "" )&lt;br /&gt;  .isDefault();&lt;br /&gt;  &lt;br /&gt; report.withTableOfContents()&lt;br /&gt;  .designFrom( "tableOfContents.jrxml" )&lt;br /&gt;  .atTheBegining();&lt;br /&gt; &lt;br /&gt; report.addStaticSubreport( "introduction" )&lt;br /&gt;  .designFrom( "introduction.jrxml" )&lt;br /&gt;  &lt;br /&gt; report.addSqlSubreport( "employeeList" )&lt;br /&gt;  .designFrom( "employeeList.jrxml" )&lt;br /&gt;  .withQuery( "select * name,surname from emplyees" )&lt;br /&gt;  .getDataFrom( "hsql" );&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;Możemy połączyć konfigurację w jeden ciąg wywołań dodając do każdego budowniczego metodę &lt;code&gt;public ReportBuilder and()&lt;/code&gt;. W ten sposób możliwe jest korzystanie z API w następujący sposób:&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;&lt;br /&gt;ReportBuilder report = new ReportBuilder();&lt;br /&gt;report .withMasterDesing( "master.jrxml" )&lt;br /&gt;.newDataSource( "hsql" )&lt;br /&gt;.isSqlDatasource()&lt;br /&gt; .withDriver( "org.hsqldb.jdbcDriver" )&lt;br /&gt; .withUrl( "jdbc:hsqldb:hsql://localhost/mydb" )&lt;br /&gt; .withUsername( "sa" )&lt;br /&gt; .withPassword( "" )&lt;br /&gt; .isDefault()&lt;br /&gt; .and()&lt;br /&gt; .withTableOfContents()&lt;br /&gt; .designFrom( "tableOfContents.jrxml" )&lt;br /&gt; .atTheBegining()&lt;br /&gt; .and()&lt;br /&gt; .addStaticSubreport( "introduction" )&lt;br /&gt; .designFrom( "introduction.jrxml" )&lt;br /&gt; .and()&lt;br /&gt; .addSqlSubreport( "employeeList" )&lt;br /&gt; .designFrom( "employeeList.jrxml" )&lt;br /&gt; .withQuery( "select * name,surname from emplyees" )&lt;br /&gt; .getDataFrom( "hsql" );&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;Wydaje się jednak, że to rozwiązanie jest mniej czytelne niż poprzednie.&lt;br /&gt;&lt;br /&gt;DSL oparty o Fluent Interface ma następujące zalety:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Jest bardzo czytelny i wygodny w użyciu;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Łatwość tworzenia i utrzymania testów jednostkowych – ponieważ wszystko napisane jest w Javie (innym języku);&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Wsparcie dla refaktoryzacji kodu i testów jednostkowych;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Zdecydowanie szybsza implementacja poprawek i nowych funkcjonalności w porównaniu z rozwiązaniem opartym na XML.&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;Przy powyższych niewątpliwych zaletach należy mieć świadomość następujących konsekwencji tego rozwiązania:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Tylko programista może konfigurować raport;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Zaprojektowanie dobrego Fluent API wymaga sporo czasu i wysiłku;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Stworzenie narzędzia WYSIWYG do konfigurowania raportu wymaga znacznego nakładu prac.&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Krótkie podsumowanie&lt;/h4&gt;&lt;br /&gt;Zarówno XML jaki Fluent Interface mają swoje plusy dodatnie i ujemne. Można próbować określić zakresy przydatności każdego z rozwiązań. W omawianym przykładzie framework  raporty był biblioteką programistyczną. Jedynymi jej użytkownikami byli programiści. Gdybym jeszcze raz brał udział w tym projekcie z pewnością przychylałbym się ku Fluent Interface. Głównym moim argument są korzyści wynikające z łatwości testowania, refaktoryzacji i możliwości szybkiej rozbudowy narzędzia. Gdyby jednak framework miał być wykorzystywany przez zewnętrzne systemy np. narzędzia WYSIWYG to XML, mimo narzutów implementacyjnych, jest rozwiązaniem bezkonkurencyjnym.&lt;br /&gt;&lt;br /&gt;Przedstawione tu rozwiązania to nie jedyny sposób tworzenia DSL. Gdy tworzyliśmy framework raportowy pojawiały się pomysły napisania języka do opisu raportów przy użyciu Ruby. Wtedy jednak nie nazywaliśmy tego jeszcze DSL. Zainteresowanych tematem odsyłam do &lt;a href="http://www.martinfowler.com/bliki/dsl.html"&gt;bliki Martina Fowlera&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1759916214638009707-6556929929089660265?l=mbartyzel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mbartyzel.blogspot.com/feeds/6556929929089660265/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1759916214638009707&amp;postID=6556929929089660265' title='Komentarze (1)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/6556929929089660265'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/6556929929089660265'/><link rel='alternate' type='text/html' href='http://mbartyzel.blogspot.com/2009/04/domain-specific-language-xml-i-fluent.html' title='Domain Specific Language - XML i Fluent Interface'/><author><name>Michał Bartyzel</name><uri>http://www.blogger.com/profile/03968505875451301931</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://bp2.blogger.com/_wQFWfmLrUy4/SFq_8FmWi_I/AAAAAAAAAC4/hpwTTs8-hoU/s72-c/PDF-Icon.jpg' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1759916214638009707.post-4928906975885069800</id><published>2009-04-07T12:41:00.002+02:00</published><updated>2009-04-07T12:56:38.082+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='wzorce'/><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><category scheme='http://www.blogger.com/atom/ns#' term='rozwój'/><title type='text'>Nawyki programisty</title><content type='html'>&lt;span style="font-size:70%"&gt;Artykuł ukazał się w kwietniowym numerze &lt;a href="http://www.sdjournal.org/prt/view/aktualnosci/issue/997.html"&gt;Software Developer's Journal&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Jak myślisz, co ma wpływ na Twoją skuteczność, kiedy programujesz? Wśród wielu czynników z pewnością wymienisz: wiedzę, umiejętności techniczne, doświadczenie, motywację, zaangażowanie, współpracę, chęć uczenia się i wiele, wiele innych. Na ogólnym poziomie wymienione rzeczy dzielą się na dwie grupy: czynniki techniczne oraz czynniki nietechniczne. Zakładamy, że skoro jesteś programistą, to doskonale wiesz, czego potrzebujesz w obszarze umiejętności technicznych. Dlatego proponujemy Ci przyjrzenie się umiejętnościom z drugiej grupy – umiejętnościom nietechnicznym.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Rzucamy wyzwanie&lt;/h4&gt;&lt;br /&gt;Zaprezentujemy kilka prostych czynności, które konsekwentnie stosowane każdego dnia mogą wprowadzić ogromną jakościową zmianę w Twojej pracy. &lt;br /&gt;Nie próbujemy Cię przekonywać, nie prosimy, abyś uwierzył na słowo. Sprawdź&lt;br /&gt;i przekonaj się sam. &lt;br /&gt;&lt;br /&gt;Zawrzyjmy kontrakt, że przez najbliższe trzydzieści dni będziesz stosować opisywane nawyki, a potem ocenisz efekty. W tym względzie wymagamy sumienności. Trzydzieści dni to trzydzieści dni i ani jednego mniej. To bardzo niewielkie wymaganie, biorąc pod uwagę fakt, że jakość Twojej pracy znacząco wzrośnie. Jeśli zrobisz przerwę w trakcie eksperymentu, to zacznij odliczanie od nowa. Mamy umowę?&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Nawyk 1. – Rozpoczynaj pracę o stałej porze&lt;/h4&gt;&lt;br /&gt;Nie bez powodu metodyki z nurtu Agile zalecają trzymanie się ustalonej długości iteracji. Gdy wykonujesz rzeczy regularnie, w określonym porządku – nabierasz rytmu. W ten sposób skupiasz się na rzeczach najistotniejszych i nie zaprzątasz sobie głowy nieustannym organizowaniem swojego dnia pracy, ponieważ masz pewien nawykowy schemat postępowania.&lt;br /&gt;&lt;br /&gt;Wielu programistów ma elastyczny czas pracy. Muszą być być na swoim stanowisku, np.: od 10 do 16, a pozostałe godziny mogą odpracować w domu. To bardzo wygodne rozwiązanie, ale powoduje, że dużo energii poświęcają na zorganizowanie każdego dnia, ponieważ każdy dzień jest inny. Stosowanie stałego rozkładu dnia pozwoli Ci skoncentrować się na rzeczach najważniejszych. Na początek rozpoczynaj dzień pracy o stałej porze.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Nawyk 2. – Planuj  swój dzień&lt;/h4&gt;&lt;br /&gt;Jak często zdarza Ci się mówić: Nie mam czasu? To zdanie to bardzo dobry pretekst lub wymówka. Masz czas. Masz dokładnie tyle samo czasu, co każdy inny programista na Ziemi – 24 godziny w ciągu doby (życie na innych planetach pomijamy). Najważniejsze pytanie brzmi – co robisz z czasem, który masz do dyspozycji?&lt;br /&gt;&lt;br /&gt;Przeprowadź eksperyment. Przeznacz jeden dzień na przyglądanie się wszystkiemu, co robisz w trakcie pracy. Zanim cokolwiek zrobisz – zapisz to. Przykładowe czynności, które możesz zanotować: napisanie testu metody, napisanie implementacji metody, wdrożenie aplikacji na serwer testowy, wyszukanie informacji w Internecie, rozmowa telefoniczna, sprawdzanie poczty, rozmowa, problemy z oprogramowaniem lub sprzętem. &lt;br /&gt;&lt;br /&gt;Zapisanie zajmie najwyżej kilka sekund, zatem koszt naszego eksperymentu jest znikomy. Na koniec dnia powinieneś mieć spis rzeczy, które robiłeś w ciągu dnia. Następnie oblicz, jaki procent czasu przeznaczyłeś na programowanie. Jak bardzo zdziwił cię wynik?&lt;br /&gt;Niech planowanie dnia stanie się Twoim codziennym rytuałem. Zanim zaczniesz pracę zaplanuj, co będziesz robić danego dnia i ustal, co jest dziś najważniejsze. Przeanalizuj jak wiele zrobiłeś i zaznacz wykonane zadania w swoim planie. Być może właśnie postanowiłeś, że najpierw przeczytasz jakąś supermądrą książkę na temat zarządzania czasem, zainstalujesz odpowiednie oprogramowanie i dopiero wtedy będziesz gotowy do działania zgodnie z planem. Nic z tych rzeczy, absolutnie tego nie rób. Jesteśmy bardzo dumni z Twojej kreatywności, ale książki i oprogramowanie nie są Ci w tej chwili potrzebne. Wystarczy kartka papieru i długopis. Zachowuj te kartki, niech to będzie Twój Osobisty Dziennik Sukcesów.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Nawyk 3. – Opracuj rozwiązanie przed implementacją&lt;/h4&gt;&lt;br /&gt;Słynny fizyk John Wheeler powiedział kiedyś: Nigdy nie zabieraj się do obliczeń, dopóki nie znasz odpowiedzi. Możemy sparafrazować tę myśl: nigdy nie zbieraj się do programowania, dopóki nie znasz rozwiązania. Dość często programiści rzucają się do implementowania, nie zadając sobie sobie podstawowego pytania: Czy to ma sens?. Gdy programujesz pod wpływem impulsu, napotykasz szereg problemów, na które nie jesteś przygotowany. Poświęcasz na ich rozwiązanie wiele energii i jednocześnie odczuwasz frustrację, że to zajmuje aż tyle czasu. Po kilku godzinach lub co gorsza po kilku dniach okazuje się, że  funkcjonalność najlepiej zaimplementować w zupełnie inny sposób. Dochodzisz wtedy do wniosku, że wykonałeś kawał wspaniałej, lecz niepotrzebnej roboty.&lt;br /&gt;&lt;br /&gt;Nigdy nie zabieraj się do programowania, dopóki nie znasz rozwiązania. Najpierw przemyśl swój pomysł, naszkicuj kilka diagramów, zbadaj konsekwencje rozwiązania, zastanów się nad alternatywami. Czasem kilkanaście minut prac koncepcyjnych oszczędza wiele godzin programowania.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Nawyk 4. – Szacuj zadania&lt;/h4&gt;&lt;br /&gt;Wykonanie zadania zajmie przeważnie co najmniej tyle czasu, ile na nie przeznaczysz. Jeśli na zaimplementowanie jakiejś funkcjonalności przeznaczysz 16 godzin, a uda Ci się zakończyć zadanie w 10, to kolejne 6 spędzisz na udoskonalaniu i poprawianiu rozwiązania albo nawet na sześciogodzinnej refaktoryzacji. Co więcej, znajdziesz bardzo wiele racjonalnych powodów, dla których było to absolutnie konieczne. &lt;br /&gt;&lt;br /&gt;Zanim przystąpisz do programowania, oszacuj czas potrzebny na to zadanie. Prawdopodobnie miałeś już do czynienia z podobnymi zadaniami, a nawet jeśli nie, to znasz kogoś, kto robił coś podobnego. Będziesz mieć punkt odniesienia dla szacowania. W skrajnym przypadku oszacuj intuicyjnie. Od razu uprzedzamy, że często będziesz się mylić – to nieuniknione. Wszelkie informacje dotyczące odchylenia od przewidywanego czasu zapisuj w swojej bazie szacowań. Zaglądaj do niej często i koryguj przewidywania według zapisanych obserwacji. Bardzo szybko staniesz się ekspertem w tym obszarze.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Nawyk 5. – Odłącz się od internetu&lt;/h4&gt;&lt;br /&gt;Internet jest niecenioną pomocą w naszej pracy, lecz potrafi przykuć uwagę na długie godziny. Zastanów się jak często poszukujesz informacji w sieci i jak często kończysz surfowanie, gdy znajdziesz potrzebne rzeczy. Czy  odsyłacze do innych stron nie kuszą Cię? Czy podczas zapoznawania się z API danej metody, nabierasz chęci zapoznania się z całą dostępną dokumentacją   biblioteki lub frameworka? Jeśli tak,to odłącz się od internetu na czas pracy. Być może przychodzą Ci teraz do głowy myśli, że nie możesz dobrze pracować bez internetu, że będziesz potrzebował absolutnie niezbędnych informacji. Jeśli tak właśnie myślisz, to zajrzyj do notatek, które zrobiłeś w trakcie ćwiczenia dotyczącego planowania dnia (lub zrób je jeszcze raz na bardziej szczegółowym poziomie). Ile czasu poświęcasz poszukiwanie informacji potrzebnych do pracy, a ile na czytanie ciekawych artykułów nie związanych z tym co aktualnie robisz, na sprawdzanie poczty co pięć minut, na korzystanie z komunikatorów internetowych? Porównaj wyniki z czasem, który przeznaczasz na odnajdywanie informacji związanych z Twoim bieżącym zadaniem.&lt;br /&gt;&lt;br /&gt;Aby pożytecznie korzystać z internetu, najlepiej podporządkować to aktualnemu zadaniu. Proponujemy następując schemat postępowania:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Zaplanuj swój dzień (patrz: Nawyk 2.);&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Opracuj rozwiązanie przed implementacją (patrz: Nawyk 3.);&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Zdobądź informacje potrzebne do wykonania zadania;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Odłącz internet i programuj przez dwie godziny;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Zrób przerwę, przeanalizuj to, co udało się wykonać i przejdź do kolejnej części zadania.&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;Musimy wyjaśnić jeszcze jedną rzecz. Przyczyną naszej propozycji odłączenia się od sieci nie jest internet sam w sobie, a celem wskazanego sposobu postępowania nie jest odcięcie Cię od źródła informacji. Naszym zamierzeniem jest zapanowanie na nawykowym i częstym, niż to potrzebne, korzystaniem z internetu, które rozprasza programistę i negatywnie wpływa na jego efektywność.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Nawyk 6. – W pierwszej kolejności poszukuj błędów w swoim kodzie&lt;/h4&gt;&lt;br /&gt;Za chwilę przeczytasz bardzo kontrowersyjny akapit, zatem zrób krótką przerwę. Przerwij na chwilę czytanie, popatrz na drzewa, zanuć ulubioną piosenkę.&lt;br /&gt;&lt;br /&gt;Uwaga! Z naszego doświadczenia i z doświadczenia liderów, z którymi współpracujemy wynika, że większość przyczyn błędów w oprogramowaniu leży po stronie programisty, natomiast ten poszukuje ich na zewnątrz: w technologiach, w bibliotekach, w niedociągnięciach innych programistów, w złośliwości rzeczy martwych.&lt;br /&gt;&lt;br /&gt;Przed Tobą ostatnie i najtrudniejsze ćwiczenie. Najtrudniejsze, ponieważ dotyka Twoich przekonań. Wiemy, że to niełatwe zdanie. Odwagi, uda Ci się!&lt;br /&gt;Za każdym razem, gdy napotkasz irytujący błąd w kodzie, nad którym pracujesz, załóż, że to Ty zrobiłeś coś, co go spowodowało. Poszukuj przyczyny przez założony czas i dopiero, gdy to nie przyniesie efektu, przyjmij, że możesz szukać na zewnątrz.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Nie ma drogi na skróty&lt;/h4&gt;&lt;br /&gt;Być może zadajesz sobie pytanie: Ile czasu mam poświęcić, aby stać się wysoce efektywnym programistą?. Odpowiedź brzmi: Tyle, ile trzeba. Nie ma drogi na skróty. Nabywanie nowych umiejętności i rozwijanie ich wymaga czasu, pracy, cierpliwości i sumienności. Jeśli zaakceptujesz ten fakt, nauka stanie się łatwiejsza i przyjemniejsza. Nawyki, które opisaliśmy, mogą pomóc Ci skoncentrować działanie na ważnych rzeczach i zorganizować sposób pracy, lecz odpowiedzialność za ich wprowadzenie w życie leży po Twojej stronie – Ty decydujesz.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;&lt;/h4&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1759916214638009707-4928906975885069800?l=mbartyzel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mbartyzel.blogspot.com/feeds/4928906975885069800/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1759916214638009707&amp;postID=4928906975885069800' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/4928906975885069800'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/4928906975885069800'/><link rel='alternate' type='text/html' href='http://mbartyzel.blogspot.com/2009/04/nawyki-programisty.html' title='Nawyki programisty'/><author><name>Michał Bartyzel</name><uri>http://www.blogger.com/profile/03968505875451301931</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1759916214638009707.post-1986292400775186196</id><published>2009-01-14T13:56:00.003+01:00</published><updated>2009-01-21T16:29:46.885+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='wydarzenia'/><title type='text'>mistrzprogramowania.pl</title><content type='html'>Z przyjemnością informuję, że BNS IT wydało swoją pierwszą książkę!&lt;br /&gt;Nosi piękny tytuł &lt;span style="font-style:italic;"&gt;Jak całkowicie odmienić sposób programowania używając REFAKTORYZACJI&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Autorem książki jest &lt;a href="http://msieraczkiewicz.blogspot.com"&gt;Mariusz Sieraczkiewicz&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:normal;font-size:150%;text-align:center"&gt;Szczegóły na &lt;a href="http://mistrzprogramowania.pl" target="_blank"&gt;mistrzprogramowania.pl&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Możesz pobrać wersję bezpłatną (jest to ok. połowa książki i zawiera trochę reklam BNS IT).&lt;br /&gt;&lt;br /&gt;Miłej lektury!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1759916214638009707-1986292400775186196?l=mbartyzel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mbartyzel.blogspot.com/feeds/1986292400775186196/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1759916214638009707&amp;postID=1986292400775186196' title='Komentarze (1)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/1986292400775186196'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/1986292400775186196'/><link rel='alternate' type='text/html' href='http://mbartyzel.blogspot.com/2009/01/mistrzprogramowaniapl.html' title='mistrzprogramowania.pl'/><author><name>Michał Bartyzel</name><uri>http://www.blogger.com/profile/03968505875451301931</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1759916214638009707.post-2226620286438255657</id><published>2009-01-02T08:02:00.012+01:00</published><updated>2009-01-02T12:35:18.203+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='antywzorce'/><category scheme='http://www.blogger.com/atom/ns#' term='wizje'/><category scheme='http://www.blogger.com/atom/ns#' term='rozwój'/><title type='text'>7 Kroków Zła w Projektach IT</title><content type='html'>&lt;div&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.bnsit.pl/files/strategie_decouplingu.pdf"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;" src="http://bp2.blogger.com/_wQFWfmLrUy4/SFq_8FmWi_I/AAAAAAAAAC4/hpwTTs8-hoU/s200/PDF-Icon.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5213690557650865138" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a style="color:#773607; text-decoration:underline; font-weight:normal" href="http://bnsit.pl/files/7_krokow_zla_w_projektach_it.pdf"&gt;Wersja PDF&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br/&gt;&lt;br /&gt;&lt;br /&gt;Czy zastanawiałeś się już jak to się dzieje, że na początku projektu jesteś maksymalnie zmotywowany, piszesz wspaniałe testy (wszystkie są oczywiście green-bar), używasz swojego najpiękniejszego stylu kodowania, klasy, interfejsy metody, ba! nawet pola mają swoją własną, niepowtarzalną odpowiedzialność. Rysujesz piękne diagramy, używasz wzorców projektowych w rozsądnej ilości, a Twój kod czyta się jak najbardziej przejrzystego ebooka. A potem...potem pojawia się niewielki, ledwo zauważalny zgrzyt, mała rysa na wspaniałym krysztale projektu. Ignorujesz to, bo przecież nic się nie stało. Rysa rośnie, a przez nią wsączają się kolejne niedociągnięcia i niedoróbki, aż po jakimś czasie nie poznajesz już tego wspaniałego projektu, siadasz do niego z największym obrzydzeniem i myślisz tylko &lt;span style="font-style:italic;"&gt;kiedy to się skończy?&lt;/span&gt; Lecz projekt się nie kończy, wciąż są nowe wymagania, wciąż trzeba go utrzymywać. I to, mój przyjacielu, jest Programistyczne Piekło!&lt;br /&gt;&lt;br /&gt;Jako przestrogę podam Ci kilka prostych wskazówek jak się tam znaleźć. Ścieżka prowadząca wprost do Programistycznego Piekła jest szeroka, gładka i bardzo prosta. Wystarczy siedem kroków.&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;Bądź obojętny&lt;/b&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Czy to ja powinienem zająć się tym //FIXME? Nieee, to nie ja pisałem, niech ktoś inny to zrobi.&lt;/span&gt; &lt;br /&gt;Czy często zdarza ci się rozumować w ten sposób? Jeśli tak, to gratuluję! Osiągnąłeś pierwszy poziom wtajemniczenia. Obojętność wobec niewielkich rys na projekcie to początek drogi w dół. Być może pomyślisz: oj, jeśli w jednej klasie będzie niewielki bałagan, to przecież nic się nie stanie. Pamiętaj, że małe rzeczy się kumulują. Nie zauważysz od razu różnicy pomiędzy metodą nazwaną &lt;span style="font-style:italic;"&gt;divideByTwo()&lt;/span&gt;, a &lt;span style="font-style:italic;"&gt;div2()&lt;/span&gt;&lt;br /&gt;, bo łatwo umyka wśród reszty kodu. Lecz z pewnością dostrzeżesz różnicę za pół roku, gdy tego typu nazewnictwo będzie obecne w całym projekcie. &lt;span style="font-style:italic;"&gt;Ziarnko do ziarnka...&lt;/span&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;Bądź w miarę wierny swoim ideałom&lt;/b&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Cóż, w zasadzie stosuję wzorce projektowe...to znaczy w niektórych projektach. Tych w domu. Piszę też testy...prawie wszystkie przechodzą. Piszę zgodnie ze standardem kodowania...właściwe to w 30%, bo reszta jest niepotrzebna. Odpowiedzialność? Taa, fajny koncept, ale moim zdaniem....&lt;/span&gt; &lt;br /&gt;Znasz to? Czy uważasz, że techniki programowania obiektowego teoretycznie są bardzo dobre ale faktycznie się nie sprawdzają? Jak wyrobiłeś sobie takie zdanie? Acha, przetestowałeś to, rozumiem. Wiesz, to że nie działają, to tylko jedna możliwość. Druga to taka, że używasz ich niewłaściwie. Co wybierasz?&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;Postępuj zgodnie z procedurami&lt;/b&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Pokrycie kodu ma być co najmniej 90% więc w tym tygodniu już nie muszę pisać żadnego testu! Ta metoda jest nieczytelna...no, ale CheckStyle się nie czepia. Diagramy muszą być tylko do istotnych elementów systemu...moja jest chyba nieistotna?&lt;/span&gt;&lt;br /&gt;Procedury, reguły, zasady są dobre. Precyzują sposób pracy i optymalizują sposób wytwórczy. Często jednak, niemal automatycznie, uważa się, że stosowanie procedur w zupełności wystarczy, zatem można zwolnić się z myślenia. Kłopot w tym, że nawet najbardziej wyrafinowane zasady nie przewidują wszystkich sytuacji, które mogą wystąpić w życiu. Bardzo wiele problemów, z którymi się spotkasz, nie da się rozwiązać za pomocą &lt;span style="font-style:italic;"&gt;Księgi Procedur&lt;/span&gt; używanej w twoim zespole. Jednak z każdym z nich można sobie poradzić przy użyciu zdrowego rozsądku.&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;Graj dla zespołu&lt;/b&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Nie wychylaj się. Bezkrytycznie akceptuj opinie bardziej doświadczonych kolegów. Postaw cele zespołu nad swoimi własnymi&lt;/span&gt;&lt;br /&gt;Przede wszystkim: dlaczego pracujesz w tym zespole? Wymień dziesięć przyczyn. Zrób to teraz!&lt;br /&gt;Jeśli praca, która wykonujesz nie jest zgodna z twoimi osobistymi celami, nie prowadzi cię do jakiegoś wyżej postawionego celu, to prędzej czy później, zaczniesz sabotować to, co robisz. Krok po kroku, niepostrzeżenie, zaczniesz wprowadzać w życie misterny plan obniżania jakości swojej pracy. Być może już teraz warto wybrać się na rozmowę z samym sobą.&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;Dziel się odpowiedzialnością&lt;/b&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Jest błąd w mojej części kodu? ...ale Paweł kazał mi tak napisać...powiedział, że będzie działać...&lt;/span&gt;&lt;br /&gt;Zadziwiające, że jeśli chodzi o sukces, to chętnie podpisujemy się pod nim sami. Jeśli chodzi o wzięcie odpowiedzialności za błąd i niepowodzenie chętnie dzielimy się odpowiedzialnością z innymi.&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;Ceń ludzi takich jak ty&lt;/b&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;MY programiści i ONI analitycy. MY javowcy i ONI .NETowcy. MY od kluczowego projektu i ONI od maintenance. MY starzy pracownicy i ONI nowi...&lt;/span&gt;&lt;br /&gt;Dzieląc &lt;span style="font-style:italic;"&gt;swoich&lt;/span&gt; i &lt;span style="font-style:italic;"&gt;innych&lt;/span&gt; sprawia, że nadajemy grupie osób wspólne cechy odróżniające ich od nas samych, czyniących w jakimś stopniu gorszymi. Etykietowanie zapewnia poczucie bezpieczeństwa i porządkuje świat. Daje złudzenie, że nie zginiemy w zespole jako indywidualność. Jak na ironię, takie postępowanie likwiduje indywidualność członków zespołu i blokuje efekt synergii, obejmującą ludzi nic nie znaczącą etykietą &lt;span style="font-style:italic;"&gt;oni&lt;/span&gt;.&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;Wierz w najlepsze rozwiązanie&lt;/b&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Ok, pracujemy w Agile, teraz już będzie dobrze. JEE rozwiąże wszystkie problemy. Nowy framework sprawi, że praktycznie kod będzie pisał się sam.&lt;/span&gt;&lt;br /&gt;Gdyby istniało rozwiązanie/technologia/framework rozwiązująca wszystkie problemy to już dawno by zostało wymyślone i żylibyśmy w świecie, w którym nie byłoby wojen, nikt nie przekraczałby  prędkości, a programy by się nie zawieszały. Nie istnieje najlepsze rozwiązanie (w ogóle). Co najwyżej może istnieć rozwiązanie najlepsze, w sensie: najbardziej odpowiednie i optymalne, w danej chwili, dla danego problemu, w danym zespole. Jedyne co może zrobić nowa technologia, framework, biblioteka, czy język to przenieść ciężar problemu w inne miejsce. To coś jak dźwignia pozwalająca zużyć mniej energii do uzyskania tego samego efektu. Pamiętaj jednak, że zawsze istnieją dwie strony medalu. Coś co rozwiązuje jedne problemy zazwyczaj generuje nowe.&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;span style="font-size:70%;"&gt;Tekst powstał z inspiracji artykułem Philipa Zimbardio &lt;span style="font-style: italic;"&gt;Evil's Seven Step Seduction Scenario&lt;/span&gt; opublikowanym w &lt;span style="font-style: italic;"&gt;Charaktery&lt;/span&gt; 9/2008&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1759916214638009707-2226620286438255657?l=mbartyzel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mbartyzel.blogspot.com/feeds/2226620286438255657/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1759916214638009707&amp;postID=2226620286438255657' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/2226620286438255657'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/2226620286438255657'/><link rel='alternate' type='text/html' href='http://mbartyzel.blogspot.com/2009/01/7-krokw-za-w-projektach-it_02.html' title='7 Kroków Zła w Projektach IT'/><author><name>Michał Bartyzel</name><uri>http://www.blogger.com/profile/03968505875451301931</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://bp2.blogger.com/_wQFWfmLrUy4/SFq_8FmWi_I/AAAAAAAAAC4/hpwTTs8-hoU/s72-c/PDF-Icon.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1759916214638009707.post-4231457886536980139</id><published>2008-12-29T21:23:00.002+01:00</published><updated>2008-12-29T21:26:49.435+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='wydarzenia'/><title type='text'>"Coaching dla programisty". Ruszł program pilotażowy</title><content type='html'>O postępach w rozwijaniu rozwijaniu umiejętności dowiesz się z bloga jednego z uczestników programu: &lt;span style="font-weight:bold;"&gt;&lt;a href="http://bnsitrafal.blogspot.com" target="_blank"&gt;Rafała 0.&lt;/a&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1759916214638009707-4231457886536980139?l=mbartyzel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mbartyzel.blogspot.com/feeds/4231457886536980139/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1759916214638009707&amp;postID=4231457886536980139' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/4231457886536980139'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/4231457886536980139'/><link rel='alternate' type='text/html' href='http://mbartyzel.blogspot.com/2008/12/coaching-dla-programisty-rusz-program.html' title='&quot;Coaching dla programisty&quot;. Ruszł program pilotażowy'/><author><name>Michał Bartyzel</name><uri>http://www.blogger.com/profile/03968505875451301931</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1759916214638009707.post-4038567980955933420</id><published>2008-12-22T18:24:00.005+01:00</published><updated>2009-01-02T09:35:37.240+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='wzorce'/><title type='text'>Wzorce projektowe - Fabryki. Rysunkowy tutorial</title><content type='html'>&lt;div&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.bnsit.pl/files/strategie_decouplingu.pdf"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;" src="http://bp2.blogger.com/_wQFWfmLrUy4/SFq_8FmWi_I/AAAAAAAAAC4/hpwTTs8-hoU/s200/PDF-Icon.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5213690557650865138" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a style="color:#773607; text-decoration:underline; font-weight:normal" href="http://bnsit.pl/files/wzorce_fabryki/Fabryki_rysunkowy_tutorial.pdf"&gt;Wersja PDF&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br/&gt;&lt;br /&gt;Kreacyjne wzorce projektowe dostarczają programistą szeregu metod pozwalających na sprawne zarządzanie tworzeniem obiektów w systemie. W tutorialu omawiam kilka z nich, prezentując strukturę w postaci diagramów UML, implementację oraz obszary zastosowań.&lt;br /&gt;&lt;br /&gt;Jeśli chcesz przypomnieć sobie jak czytać diagramy UML w odniesieniu do kodu Java przeczytaj najpierw wcześniejsze tutoriale:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;&lt;a href="http://jdn.pl/node/1608"&gt;Java i UML - Diagram klas&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href="http://mbartyzel.blogspot.com/2008/12/java-i-uml-diagram-sekwencji-rysunkowy.html"&gt;Java i UML - Diagram sekwencji&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;img src="http://bnsit.pl/files/wzorce_fabryki/sl1.jpg"/&gt;&lt;br /&gt;&lt;img src="http://bnsit.pl/files/wzorce_fabryki/sl2.jpg"/&gt;&lt;br /&gt;&lt;img src="http://bnsit.pl/files/wzorce_fabryki/sl3.jpg"/&gt;&lt;br /&gt;&lt;img src="http://bnsit.pl/files/wzorce_fabryki/sl4.jpg"/&gt;&lt;br /&gt;&lt;img src="http://bnsit.pl/files/wzorce_fabryki/sl5.jpg"/&gt;&lt;br /&gt;&lt;img src="http://bnsit.pl/files/wzorce_fabryki/sl6.jpg"/&gt;&lt;br /&gt;&lt;img src="http://bnsit.pl/files/wzorce_fabryki/sl7.jpg"/&gt;&lt;br /&gt;&lt;img src="http://bnsit.pl/files/wzorce_fabryki/sl8.jpg"/&gt;&lt;br /&gt;&lt;img src="http://bnsit.pl/files/wzorce_fabryki/sl9.jpg"/&gt;&lt;br /&gt;&lt;img src="http://bnsit.pl/files/wzorce_fabryki/sl10.jpg"/&gt;&lt;br /&gt;&lt;img src="http://bnsit.pl/files/wzorce_fabryki/sl11.jpg"/&gt;&lt;br /&gt;&lt;img src="http://bnsit.pl/files/wzorce_fabryki/sl12.jpg"/&gt;&lt;br /&gt;&lt;img src="http://bnsit.pl/files/wzorce_fabryki/sl13.jpg"/&gt;&lt;br /&gt;&lt;img src="http://bnsit.pl/files/wzorce_fabryki/sl14.jpg"/&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1759916214638009707-4038567980955933420?l=mbartyzel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mbartyzel.blogspot.com/feeds/4038567980955933420/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1759916214638009707&amp;postID=4038567980955933420' title='Komentarze (5)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/4038567980955933420'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/4038567980955933420'/><link rel='alternate' type='text/html' href='http://mbartyzel.blogspot.com/2008/12/wzorce-projektowe-fabryki-rysunkowy.html' title='Wzorce projektowe - Fabryki. Rysunkowy tutorial'/><author><name>Michał Bartyzel</name><uri>http://www.blogger.com/profile/03968505875451301931</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://bp2.blogger.com/_wQFWfmLrUy4/SFq_8FmWi_I/AAAAAAAAAC4/hpwTTs8-hoU/s72-c/PDF-Icon.jpg' height='72' width='72'/><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1759916214638009707.post-8580228231017041890</id><published>2008-12-12T22:18:00.005+01:00</published><updated>2008-12-12T23:15:00.545+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='wizje'/><category scheme='http://www.blogger.com/atom/ns#' term='wydarzenia'/><title type='text'>Light? heavy?</title><content type='html'>Sporo już powiedziano o relacji pomiędzy Spring a EJB. Jedni twierdzili, że to konkurencyjne rozwiązania, inni zgodzili się, że wzajemnie się uzupełniają. Moje prywatne zdanie jest takie, że Spring wyrósł na obrzydzeniu do EJB2.x i jego podstawowymi zaletami były: nieinwazyjność, lekkość, elastyczność i coś co nazywam sobie lepkością czyli umiejętność integracji i "przylepiania się" do istniejących rozwiązań. Pojawienie się EJB3 trochę rozmyło granice. Oto bowiem dostaliśmy eleganckie rozwiązanie korporacyjne z niezależną od kontenera częścią do trwałego przechowywania danych i innymi bajerami. Co prawda całość była nieco w tyle, za rozwiązaniami z community, ale aura standardu słodziła niedogodności. W takiej sytuacji moim zdaniem pomiędzy Spring a EJB istniały 2 zasadnicze:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;EJB wymaga osobnego kontenera, Spring nie&lt;/li&gt;&lt;br /&gt;&lt;li&gt;jeśli używasz EJB to bierzesz całą technologię, cało wielgachną maszynerię którą oferuje, w Springu bierzesz tyle ile potrzebujesz&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;Ostatecznie każde z nich znalazło swoją niszę i dobrze się tam miało. Szczególnie punkt nr 2 stanowił o przewadze Spring w systemach działających na jednej maszynie, nie wymagających rozproszonych transakcji, asynchroniczności, itd., itd.&lt;br /&gt;&lt;br /&gt;Bardzo podoba mi się w Sunie to, że uczy konsekwentnie się uczy. Uczy się diabelnie dużo od społeczności OpenSource, czego efektem było właśnie rzeczone EJB3.&lt;br /&gt;Wydarzyły się też dwie ważne rzeczy, które rzucają nowe światło na relację Spring - EJB. &lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Po pierwsze&lt;/span&gt; Interface21 vel SpringFramework vel. SpringSource dostało kupę forsy od inwestora (słyszałem o $10mln). Sprawiło to, że chcąc używać Springa za darmo będziemy korzystać tylko z głównych wydań bez późniejszych poprawek, aż do kolejnego wydania głównego...chyba, że opłacimy subskrypcję:) Trochę głupio, ale trudno mieć im za złe, że chcą zarobić pieniądze na swojej pracy. Sęk w tym, że będąc najpierw projektem OO naruszyli pewną barierę psychologiczną. Bardzo Springowi pomagało bycie darmową "alternatywą" dla EJB, do tego użyteczną i świetnie napisaną. To było coś w stylu Robin Hooda - w tej roli bezinteresowny Spring Framework, a z przeciwnej strony Szeryf z Nottingham - czyli EJB Samo Zło. I w całej sytuacji najlepsze jest to, że Robin wybudował sobie własny zamek i ściąga jeszcze większą daninę niż Szeryf, walcząc zażarcie o każdą piędź Lasu Sherwood.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Po drugie:&lt;/span&gt; Przeglądając nowości w JEE6 i EJB3.1 jeszcze bardziej podoba mi się kierunek, w którym Sun zmierza. Moją uwagę zwróciła koncepcja &lt;a href="http://weblogs.java.net/blog/robc/archive/2008/02/profiles_in_the_1.html"&gt;profili&lt;/a&gt;, której ideą jest, aby można było użyć tylko taką cześć platformy, która jest akurat potrzebna. Czyli można będzie odchudzić sobie korporacyjną Javę np. z asynchroniczności i rozproszonych transakcji jeśli zajdzie taka potrzeba. Ja tu widzę światełko w tunelu do zapewnienia tej użytecznej możliwości, którą posiada Spring czyli: bierzesz tyle ile potrzebujesz. &lt;br /&gt;Jest więcej ciekawych (bardzo ciekawych: żeby zwrócić uwagę na adnotację @Singleton i specyfikację WebBeans) rzeczy w EJB3.1, ażeby się nie powtarzać  zamieszczam na końcu linki do artykułów.&lt;br /&gt;&lt;br /&gt;Jak to dalej będzie ze EJB i Springiem? Może JEE6 albo JEE7 da nam wszystko czego potrzebujemy? A może jakiś nowy pomysł SprigSource okaże się tak rewolucyjny, że zdeklasuje alternatywy na długie lata? A może jeszcze inaczej? Któż to może wiedzieć w czasach kryzysu:)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Literatura&lt;/b&gt;&lt;br /&gt;&lt;a href="http://blog.dywicki.pl/2008/09/28/spring-commercial-source-replaces-open-source/"&gt;http://blog.dywicki.pl/2008/09/28/spring-commercial-source-replaces-open-source/&lt;/a&gt;&lt;br /&gt;&lt;a href="http://springinpractice.wordpress.com/2008/12/02/new-stuff-in-spring-30/"&gt;http://springinpractice.wordpress.com/2008/12/02/new-stuff-in-spring-30/&lt;/a&gt;&lt;br /&gt;&lt;a href="http://springinpractice.wordpress.com/2008/12/03/new-stuff-in-spring-30-part-2/"&gt;http://springinpractice.wordpress.com/2008/12/03/new-stuff-in-spring-30-part-2/&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.theserverside.com/tt/articles/article.tss?l=NewFeaturesinEJB3-1"&gt;http://www.theserverside.com/tt/articles/article.tss?l=NewFeaturesinEJB3-1&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.theserverside.com/tt/articles/article.tss?l=NewFeaturesEJB31"&gt;http://www.theserverside.com/tt/articles/article.tss?l=NewFeaturesEJB31&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.theserverside.com/tt/articles/article.tss?l=NewFeaturesEJB31-3"&gt;http://www.theserverside.com/tt/articles/article.tss?l=NewFeaturesEJB31-3&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.theserverside.com/tt/articles/article.tss?l=NewFeaturesinEJB3-Part4"&gt;http://www.theserverside.com/tt/articles/article.tss?l=NewFeaturesinEJB3-Part4&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1759916214638009707-8580228231017041890?l=mbartyzel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mbartyzel.blogspot.com/feeds/8580228231017041890/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1759916214638009707&amp;postID=8580228231017041890' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/8580228231017041890'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/8580228231017041890'/><link rel='alternate' type='text/html' href='http://mbartyzel.blogspot.com/2008/12/light-heavy.html' title='Light? heavy?'/><author><name>Michał Bartyzel</name><uri>http://www.blogger.com/profile/03968505875451301931</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1759916214638009707.post-730095002919323174</id><published>2008-12-09T14:51:00.000+01:00</published><updated>2008-12-09T14:52:44.384+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='wydarzenia'/><title type='text'>Weekendowe Warsztaty: Wzorce Projektowe w Paraktyce</title><content type='html'>Zapraszam na „Weekendowe Warsztaty: Wzorce Projektowe w&lt;br /&gt;Paraktyce".&lt;br /&gt;&lt;br /&gt;Każdy uczestnik ma swój komputer (notebook), aby realizować ćwiczenia.&lt;br /&gt;Osią warsztatów jest projekt, który jest sukcesywnie rozwijany -&lt;br /&gt;dodawane są nowe funkcjonalności. Rozbudowa systemu jest pretekstem do&lt;br /&gt;wprowadzania kolejnych wzorców.&lt;br /&gt;&lt;br /&gt;Warsztaty mają charakter praktyczny i ostatecznie prowadzą do stworzenia&lt;br /&gt;systemu opartego o wzorce, zachowując pragmatyzm przy ich użyciu. Przede&lt;br /&gt;wszystkim stawiamy na podkreślenie aspektu współpracy między wzorcami,&lt;br /&gt;gdyż największa ich siła ujawnia się dopiero wtedy.&lt;br /&gt;&lt;br /&gt;ZOBACZ PROGRAM&lt;br /&gt;http://www.bnsit.pl/files/Wzorce_projektowe_java_i_refaktoring.pdf&lt;br /&gt;&lt;br /&gt;KIEDY?: 13, 14 grudnia br.&lt;br /&gt;&lt;br /&gt;CZAS TRWANIA: 2 x 8 godzin (sobota, niedziela), od 9 do 17&lt;br /&gt;&lt;br /&gt;GDZIE?: W centrum Łodzi; wybór konkretnej sali zależy od ilości uczestników&lt;br /&gt;&lt;br /&gt;CZEGO POTRZEBUJESZ?:&lt;br /&gt;    * Notebook z kartą Wi-Fi&lt;br /&gt;    * Zapału i chęci do poznania czegoś nowego&lt;br /&gt;&lt;br /&gt;JAK SIĘ ZGŁOSIĆ?:&lt;br /&gt;    * przesłać mail na adres bnsit@bnsit.pl z tematem WARSZTATY&lt;br /&gt;    * wpłacić zaliczkę (do piątku 12 grudnia br.) w wysokości 100zł na&lt;br /&gt;konto mBank 12 1140 2004 0000 3902 5596 2724, w tytule przelewu proszę&lt;br /&gt;wpisać swoje imię i nazwisko; dane adresowe firmy znajdziesz w stopce maila&lt;br /&gt;    * pozostała część opłaty wnoszona jest przed rozpoczęciem zajęć w sobotę&lt;br /&gt;    * w przypadku, gdy nie zgłosi się wystarczająca ilość uczestników, aby&lt;br /&gt;uruchomić szkolenie, otrzymasz zwrot zaliczki w ciągu 3 dni roboczych&lt;br /&gt;&lt;br /&gt;TWOJA INWESTYCJA: 800 zł&lt;br /&gt;&lt;br /&gt;Na dodatkowe pytania odpowie Michał Bartyzel m.bartyzel{{{orangutan}}}bnsit.pl&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1759916214638009707-730095002919323174?l=mbartyzel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mbartyzel.blogspot.com/feeds/730095002919323174/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1759916214638009707&amp;postID=730095002919323174' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/730095002919323174'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/730095002919323174'/><link rel='alternate' type='text/html' href='http://mbartyzel.blogspot.com/2008/12/weekendowe-warsztaty-wzorce-projektowe.html' title='Weekendowe Warsztaty: Wzorce Projektowe w Paraktyce'/><author><name>Michał Bartyzel</name><uri>http://www.blogger.com/profile/03968505875451301931</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1759916214638009707.post-4974915145099096398</id><published>2008-12-09T14:44:00.005+01:00</published><updated>2009-01-02T09:36:50.933+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='architektura'/><title type='text'>Java i UML - Diagram sekwencji. Rysunkowy tutorial</title><content type='html'>&lt;div&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.bnsit.pl/files/strategie_decouplingu.pdf"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;" src="http://bp2.blogger.com/_wQFWfmLrUy4/SFq_8FmWi_I/AAAAAAAAAC4/hpwTTs8-hoU/s200/PDF-Icon.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5213690557650865138" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a style="color:#773607; text-decoration:underline; font-weight:normal" href="http://bnsit.pl/files/uml_sequences/java_uml_diagram_sekwencji.pdf"&gt;Wersja PDF&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br/&gt;&lt;br /&gt;Diagram sekwencji jest, obok diagramu klas, najczęściej używanym diagramem UML. Pozwala ma modelowanie dynamicznych aspektów systemu.&lt;br /&gt;W artykule zamieszczam bardzo zwięzły rysunkowy tutorial, obrazujący sposób korzystania z diagramu sekwencji. Dodatkowo dodałem przykłady pokazujące relację pomiędzy diagramem, a kodem w języku Java.&lt;br /&gt;&lt;br /&gt;&lt;img src="http://bnsit.pl/files/uml_sequences/sl01.jpg"/&gt;&lt;br /&gt;&lt;img src="http://bnsit.pl/files/uml_sequences/sl02.jpg"/&gt;&lt;br /&gt;&lt;img src="http://bnsit.pl/files/uml_sequences/sl03.jpg"/&gt;&lt;br /&gt;&lt;img src="http://bnsit.pl/files/uml_sequences/sl04.jpg"/&gt;&lt;br /&gt;&lt;img src="http://bnsit.pl/files/uml_sequences/sl05.jpg"/&gt;&lt;br /&gt;&lt;img src="http://bnsit.pl/files/uml_sequences/sl06.jpg"/&gt;&lt;br /&gt;&lt;img src="http://bnsit.pl/files/uml_sequences/sl07.jpg"/&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1759916214638009707-4974915145099096398?l=mbartyzel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mbartyzel.blogspot.com/feeds/4974915145099096398/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1759916214638009707&amp;postID=4974915145099096398' title='Komentarze (4)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/4974915145099096398'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/4974915145099096398'/><link rel='alternate' type='text/html' href='http://mbartyzel.blogspot.com/2008/12/java-i-uml-diagram-sekwencji-rysunkowy.html' title='Java i UML - Diagram sekwencji. Rysunkowy tutorial'/><author><name>Michał Bartyzel</name><uri>http://www.blogger.com/profile/03968505875451301931</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://bp2.blogger.com/_wQFWfmLrUy4/SFq_8FmWi_I/AAAAAAAAAC4/hpwTTs8-hoU/s72-c/PDF-Icon.jpg' height='72' width='72'/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1759916214638009707.post-4372750197343836668</id><published>2008-12-02T12:53:00.003+01:00</published><updated>2008-12-02T12:57:07.394+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='wydarzenia'/><category scheme='http://www.blogger.com/atom/ns#' term='rozwój'/><title type='text'>Ad.pilotażowego programu "Coaching dla programisty"</title><content type='html'>W związku z pytaniami zamieszczam więcej szczegółowych informacji nt. programu.&lt;br /&gt;&lt;br /&gt;CEL: Praktyczne zweryfikowanie hipotezy: "Każdy może stać się dobrym programistą"&lt;br /&gt;&lt;br /&gt;ADRESACI: Osoby, które:&lt;br /&gt;    * znają język Java&lt;br /&gt;    * posiadają niewielkie doświadczenie w pracy w tym języku (np.: język Java poznany na studiach, certyfikat SCJP, samodzielna nauka języka, pisanie programów na zaliczenia albo jako hobby)&lt;br /&gt;    * chcą pracować jako programiści Java/JEE&lt;br /&gt;    * potrafią prezcyzyjnie określić swój cel zawodowy w perspektywnie najbliższych 2 lat&lt;br /&gt;&lt;br /&gt;KOSZT: bns it nie pobiera opłaty od uczestników programu&lt;br /&gt;&lt;br /&gt;ZOBOWIĄZNIA UCZESTNIKA:&lt;br /&gt;    * ukończenie programu&lt;br /&gt;    * systematyczna praca&lt;br /&gt;    * prowadzenie bloga programistycznego, na którym uczestnik będzie regularnie opisywał swoje doświadczenia, spostrzeżenia, porady dla innych, itp.&lt;br /&gt;&lt;br /&gt;ZOBOWIĄZANIA BNS IT:&lt;br /&gt;    * zapewnienie wykwalifikowanego trenera&lt;br /&gt;    * prowadzenie zajęć i ocenianie postępów&lt;br /&gt;&lt;br /&gt;JAK APLIKOWAĆ:&lt;br /&gt;    * przysłać zgłoszenie na adres m.bartyzel {maupeczka} bnsit.pl&lt;br /&gt;    * w treści maila proszę umieścić frazę [COACHING]&lt;br /&gt;    * do zgłoszenia proszę dołączyć kod źródłowy programu napisanego w języku Java (np. program, z którego jesteś najbardziej dumny/a albo taki, który napiszesz specjalnie dla mnie:))&lt;br /&gt;    * do zgłoszenia proszę dołączyć linki do 3 ofert pracy, którymi jesteś zainteresowany&lt;br /&gt;    * do zgłoszenia proszę dołączyć informację: w jakich miastach rozważasz pracę jako programista, kiedy orientacyjnie planujesz zacząć pracę&lt;br /&gt;    * na każde zgłoszenie odpowiemy do 20 grudnia&lt;br /&gt;    * zastrzegamy sobie prawo do przyjęcia tylko wybranych kandydatów/kandydatek&lt;br /&gt;&lt;br /&gt;FORMA ZAJĘĆ:&lt;br /&gt;    * zajęcia odbywają się zdalnie za pośrdednictwem komunikatora&lt;br /&gt;    * sesje odbywają się 1 lub 2 razy w tygodniu w odzinach&lt;br /&gt;ustalonych indywidualnie z trenerem&lt;br /&gt;    * ogólny plan zajęć można przedstawić następująco:   &lt;br /&gt;        - sformułowanie celu do osiągniecia&lt;br /&gt;        - stworzenie harmonogramu prac&lt;br /&gt;        - systematyczna praca nad przygotowaniem się do osiągnięcia postawionego celu&lt;br /&gt;        - osiągnięcie celu&lt;br /&gt;        - koniec uczestnictwa w programie&lt;br /&gt;&lt;br /&gt;CZAS TRWANIA:&lt;br /&gt;    * zależy od czestnika oraz postawionego celu&lt;br /&gt;    * szacunkowo można zakładać od 3 miesięcy w górę&lt;br /&gt;&lt;br /&gt;DALSZE PERSPEKTYWY:&lt;br /&gt;    * Po pozytywnym ukończeniu programu "Coaching dla programisty":&lt;br /&gt;        - osiągniesz postawiony przez siebie cel&lt;br /&gt;&lt;br /&gt;    * Do poniższych rzeczy się nie zobowiązujemy, ale też nie wykluczamy, że:&lt;br /&gt;        - być może przygotujemy Cię do rozmowy kwalifikacyjnej&lt;br /&gt;        - być może polecimy Ci firmę rekruterską&lt;br /&gt;        - być może być może zorganizujemy Ci spoktanie z potencjalnym pracodawcą&lt;br /&gt;        - być może zaproponujemy Ci pracę w jednym z projektów projektów prowadzonych przez nas&lt;br /&gt;        - być może...:) &lt;br /&gt;&lt;br /&gt;i jeszcze krótka notatka dot. przykładowego kodu, o który proszę:&lt;br /&gt;1. To nie musi być ukończony i działający program. Chciałbym się zorientować co do sposobu pisania&lt;br /&gt;2. Interfejs użytkownika jest dla mnie na chwilę obecną najmniej ważny&lt;br /&gt;3. Przykładowe aplikacje:&lt;br /&gt;    * System ankietujący - ma umożliwiać przygotowanie, wysłanie i zebranie odpowiedzi na pytania zawarte w ankiecie&lt;br /&gt;    * System aukcyjny - ma umożliwiać przeprowadzanie aukcji internetowych&lt;br /&gt;&lt;br /&gt;A TERAZ UWAGA! Ponieważ wiem, że programiści mają tendencję do perfekcjonizmu i wykonanie zadanie mogło by kogoś pochłonąć na kilka najbliższych lat:) proszę ustawić sobie czasomierz i przesłać mi tyle ile da się napisać W CIĄGU 36 GODZIN(oczywiście nie trzeba siedzieć przed komputerem 3 dni z rzędu:) można rozłożyć pracę na tydzień albo 2)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1759916214638009707-4372750197343836668?l=mbartyzel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mbartyzel.blogspot.com/feeds/4372750197343836668/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1759916214638009707&amp;postID=4372750197343836668' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/4372750197343836668'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/4372750197343836668'/><link rel='alternate' type='text/html' href='http://mbartyzel.blogspot.com/2008/12/adpilotaowego-programu-coaching-dla.html' title='Ad.pilotażowego programu &quot;Coaching dla programisty&quot;'/><author><name>Michał Bartyzel</name><uri>http://www.blogger.com/profile/03968505875451301931</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1759916214638009707.post-3004819366222075935</id><published>2008-11-28T09:39:00.004+01:00</published><updated>2008-11-28T10:19:39.844+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='wydarzenia'/><category scheme='http://www.blogger.com/atom/ns#' term='rozwój'/><title type='text'>Zdobądź wymarzoną pracę jako programista/projektant Java/JEE!</title><content type='html'>Jeśli marzysz o programowaniu,&lt;br /&gt;&lt;br /&gt;Jeśli chcesz stać się ekspertem,&lt;br /&gt;&lt;br /&gt;Jeśli stale przeglądasz oferty pracy dla programistów&lt;br /&gt;&lt;br /&gt;ale&lt;br /&gt;&lt;br /&gt;Twoje doświadczenie nie jest wystarczające,&lt;br /&gt;&lt;br /&gt;Nie wiesz od czego zacząć,&lt;br /&gt;&lt;br /&gt;Przytłacza cię mnogość wymagań w ofertach pracy.&lt;br /&gt;&lt;br /&gt;Weź udział w pilotażowym programie &lt;span style="font-style:italic;"&gt;Coachig dla programisty&lt;/span&gt;. Jeśli dołączysz do programu, zostanie ci przydzielony trener, który podczas &lt;span style="font-weight:bold;"&gt;indywidualnej pracy z tobą&lt;/span&gt; wprowadzi cię w tajniki programowania.&lt;br /&gt;W ciągu kilku miesięcy możesz zostać świetnym programistą i dostać wymarzoną pracę. Przy pomocy trenera sformułujesz cel, który osiągniesz. Czy masz odwagę marzyć...?&lt;br /&gt;&lt;br /&gt;U podstaw programu leży przekonanie, że każdy może stać się świetnym programistą. &lt;br /&gt;Stawiamy tylko dwa wymagania:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt; &lt;li&gt;znajomość języka Java (np. wyniesione ze studiów)&lt;/li&gt;&lt;br /&gt; &lt;li&gt;umiejętność systematycznej pracy&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Ile to kosztuje? 0 zł (słownie: zero zł)&lt;br /&gt;&lt;br /&gt;Twój kontakt dot. pilotażowego programu &lt;span style="font-style:italic;"&gt;Coaching dla programisty&lt;/span&gt;:&lt;br /&gt;Michał Bartyzel&lt;br /&gt;m.bartyzel {{{maupeczka}}} bnsit.pl&lt;br /&gt;+48 503 062 421&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1759916214638009707-3004819366222075935?l=mbartyzel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mbartyzel.blogspot.com/feeds/3004819366222075935/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1759916214638009707&amp;postID=3004819366222075935' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/3004819366222075935'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/3004819366222075935'/><link rel='alternate' type='text/html' href='http://mbartyzel.blogspot.com/2008/11/zdobd-wymarzon-prac-jako.html' title='Zdobądź wymarzoną pracę jako programista/projektant Java/JEE!'/><author><name>Michał Bartyzel</name><uri>http://www.blogger.com/profile/03968505875451301931</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1759916214638009707.post-4324289380660787085</id><published>2008-11-06T09:14:00.008+01:00</published><updated>2009-01-02T10:10:43.566+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='wzorce'/><category scheme='http://www.blogger.com/atom/ns#' term='wizje'/><category scheme='http://www.blogger.com/atom/ns#' term='architektura'/><title type='text'>Język wzorców</title><content type='html'>&lt;div&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.bnsit.pl/files/strategie_decouplingu.pdf"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;" src="http://bp2.blogger.com/_wQFWfmLrUy4/SFq_8FmWi_I/AAAAAAAAAC4/hpwTTs8-hoU/s200/PDF-Icon.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5213690557650865138" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a style="color:#773607; text-decoration:underline; font-weight:normal" href="http://bnsit.pl/files/jezyk_wzorcow.pdf"&gt;Wersja PDF&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br/&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Przewrotnie nadałem temu wpisowi tytuł nawiązujący do książki &lt;a href="http://en.wikipedia.org/wiki/Christopher_Alexander"&gt;Christophera Alexandra&lt;/a&gt;, gdyż od niego zaczęła się ta cała zabawa i chyba już nigdy się nie skończy. &lt;br /&gt;Trudno powiedzieć czy Alexander odkrył naturę powtarzalności czy też tylko uświadomił ludziom to, co czynili od zawsze.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Architektura oprogramowania&lt;/h4&gt;&lt;br /&gt;Jak na złość koncept powtarzalnych wzorców zyskał największy posłuch wśród inżynierów oprogramowania. Gdy się zastanowić, to są ku temu ważkie powody. Po pierwsze znakomita większość projektów programistycznych przekracza budżet i/lub założone ramy czasowe. Po drugie tworząc milion razy ten sam system można to zrobić na milion różnych sposobów. Naturalnie powstaje pytanie: który ze sposobów jest najlepszy? Bez wahania można odpowiedzieć, że ten który najlepiej spełnia założone kryteria będące w tym przypadku funkcją oceny produktu. Utożsamienie wspomnianej funkcji oceny oprogramowania z, tylko i wyłącznie, wymaganiami użytkowników jest poważanym uproszczeniem. Rzeczona funkcja ma wiele składowych: wymagania użytkowników, założony koszt, ramy czasowe, oczekiwania każdego z członków zespołu, itd. Jedne z nich są specyfikowane jawnie, inne manifestowane zupełnie nieświadomie. Mamy zatem pewne kryterium ewaluacji sposobu programowania: końcowy produkt ma być optymalny ze względu na przyjętą funkcję oceny.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Wzorce projektowe&lt;/h4&gt;&lt;br /&gt;Szansę na optymalizację funkcji oceny oprogramowania dostrzeżono właśnie w konceptach Christophera Alexandra. Założenia były proste: wiele systemów jest do siebie podobnych, podobieństwo dotyczy różnych poziomów abstrakcji i różnych części systemu. Dodatkowo systemy tworzone są za pomocą języka programowania. Stąd pytanie: czy istnieją takie konstrukcje językowe, które w optymalny sposób rozwiązują problemy związane z programowaniem?  &lt;br /&gt;&lt;br /&gt;Wspomniane problemy dotyczą sposobu w jaki współpracują obiekty w systemie w celu realizacji określonego zdania. (Część zagadnień opisałem w artykule &lt;a href="http://mbartyzel.blogspot.com/2008/10/organizowanie-logiki-biznesowej.html"&gt;Organizowanie logiki biznesowej&lt;/a&gt;.) W 1995 światło dzienne ujrzała książka &lt;a href="http://www.amazon.com/Design-Patterns-Object-Oriented-Addison-Wesley-Professional/dp/0201633612"&gt;Design Patterns&lt;/a&gt; katalogująca 23 wzorce projektowe dotyczących inżynierii oprogramowania. Niezwykle ważną rzeczą, prócz samych wzorców, którą wniosła wspomniana publikacja, był aparat pojęciowy umożliwiający rozpoznawanie oraz klasyfikowanie nowych pojawiających się wzorców projektowych. Od tego momentu nastąpiła gwałtowna eksploracja tego tematu przez różnych autorów.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.amazon.com/Design-Patterns-Object-Oriented-Addison-Wesley-Professional/dp/0201633612"&gt;Design Patterns&lt;/a&gt; została napisana przez czterech autorów i przyjęło się określać ich jako &lt;em&gt;Gang of Four (GoF)&lt;/em&gt;, natomiast wzorce przez nich skatalogowane jako &lt;em&gt;Wzorce GoF&lt;/em&gt;. &lt;br /&gt;Ich charakterystyczną cechą jest, że dotyczą konstrukcji programistycznych używanych do poprawy jakość tworzonego kodu. Wzorce te dotyczą współpracy obiektów w obrębie jednego systemu.&lt;br /&gt;Umiejętne posługiwanie się tymi wzorcami jest absolutnym minimum kompetencji programisty i bazą dzięki której może on efektywnie korzystać z kolejnych technologii. Wzorce GoF są podstawą piramidy, na której opiera się praca i rozwój programisty. Istnieje możliwość wzięcia udziału w &lt;a href="http://mbartyzel.blogspot.com/2008/11/weekendowe-warsztaty-wzorce-projektowe.html"&gt;Weekendowych Warsztatach z Wzorców GoF&lt;/a&gt;, o których wspominałem w poprzednim wpisie.&lt;br /&gt;&lt;br /&gt;Klienci stawiali przed programistami coraz większe wymagania. Systemy informatyczne musiały mieć coraz większą funkcjonalność, stawały się coraz większe. Dało to impuls do rozwoju technologii takich jak J2EE czy .NET. Technologie dostarczają wiele możliwości, czasem zbyt wiele,...technologie bywają niedoskonałe. W przypadku J2EE te niedoskonałości i problemy z użytkowaniem spowodowały powstawanie wzorców projektowych w odniesieniu do tej konkretnej technologii, czego egzemplifikacją stała się przełomowa publikacja &lt;a href="http://java.sun.com/blueprints/corej2eepatterns/Patterns/"&gt;Core J2EE Patterns&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Z drugiej strony skala systemów informatycznych, niezależnie od użytej technologii rodziła problemy, których nie rozwiązywały klasyczne Wzorce GoF (GoF, jak pamiętamy, dotyczyły przede wszystkim efektywnej współpracy obiektów pomiędzy sobą w obrębie systemu). Zastosowanie Wzorców GoF w dużym systemie, rzeczywiście ułatwiało pracę i czyniło go bardziej elastycznym, lecz już sama jego rozległość wymagała dodatkowego podejścia - podejścia globalnego, podejścia od strony architektury całego systemu. System miał wykonywać pewne zadania, prezentować dane użytkownikowi i trwale przechowywać wyniki swoich działań. Rozwinęły się: koncepcja warstw w systemie informatycznym oraz pomysły na udostępnianie danych klientom oraz na ich trwałe przechowywanie. Klasyką w tym obszarze jest publikacja Martina Fowlera &lt;a href="http://martinfowler.com/books.html#eaa"&gt;Patterns of Enterprise Application Architecture&lt;/a&gt;, w której autor opisuje wzorce projektowe w aplikacjach klasy enterprise. Pozycja ta daje globalny pogląd na architekturę systemów informatycznych. Wzorce tam opisywane, na własny użytek i dla odróżnienia od GoF, nazywam Wzorcami Architektonicznymi. Warto nadmienić, że Martin Fowler przy gotowuje kolejną publikację na temat Wzorców Architektonicznych. Nie wiadomo kiedy się ona ukaże, jednak z postępem prac można zapoznać się na &lt;a href="http://martinfowler.com/eaaDev/"&gt;blogu Fowlera&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Problemy związane z architekturą aplikacji, z użytkowaniem technologii J2EE sprowokowały co najmniej trzy bardzo wartościowe następstwa. Po pierwsze: "stworzyły" środowisko sprzyjające rozwojowi wzorców projektowych. Po drugie: jako implementacja konkretnych Wzorców Architektonicznych powstały frameworki takie jak: Struts, Hibernate, JDO, Spring Framework, WebWork, iBatis i wiele innych. Po trzecie: w konsekwencji popularności frameworków rozpoczął się proces standaryzacyjny JCP, który zaowocował specyfikacją JEE5.&lt;br /&gt;&lt;br /&gt;Dalszy rozwój systemów informatycznych uświadomił wszystkim zaangażowanym, że żadna z istniejących technologii jest w jakiś szczególny sposób uprzywilejowana. Jakkolwiek by nie argumentować każda będzie miała swoich zwolenników i przeciwników. Można się z tym poglądem nie zgadzać, ale nie sposób zaprzeczyć, że istnieje jego namacalna konsekwencja: w strukturze informatycznej przedsiębiorstwa działają systemy różnego typu stworzone w różnych technologiach. I choć najbardziej popularne rozwiązania dostarczają sposobów na obsługę całego infrastruktury informatycznej, to jednak każde przedsiębiorstwo ma swoją historię i nikt przy zdrowych zmysłach nie będzie zmieniał sprawnie działającego systemu tylko dlatego, że został napisany w Fortranie a nie w Javie.&lt;br /&gt;&lt;br /&gt;Zatem każdy nowy system musi sprawnie komunikować się z istniejącą infrastrukturą. Wymaganie to spowodowało odkrywanie wzorców dotyczących integracji systemów informatycznych. Tę gałąź wzorców projektowych nazywam Wzorcami Integracyjnymi, a jako programową publikację można podać &lt;a href="http://www.enterpriseintegrationpatterns.com"&gt;Enterprise Integration Patterns&lt;/a&gt; napisaną przez Gregora Hohpe'a i Bobbyego Woolfa.&lt;br /&gt;&lt;br /&gt;Poszukiwanie pewnej powtarzalności w tworzeniu systemów informatycznych, mające na celu optymalizowanie określonej wcześniej funkcji oceny, pojawia się na każdym etapie złożoności nie zależnie od tego, czy jest to oprogramowanie desktopowe czy system obsługujący wielką korporację.&lt;br /&gt;&lt;br /&gt;Okazuje się, że stosowanie konstrukcji architektonicznych to jedna część układanki. Pracując w różnych projektach programiści wypracowali swego rodzaju wiedzę plemienną, która pomaga im w pracy. Zaznaczam, że nie chodzi tutaj o wzorce projektowe, które rozwiązują konkretne problemy, chodzi raczej o &lt;em&gt;sposób posługiwania się wzorcami&lt;/em&gt; w możliwie efektywny sposób.&lt;br /&gt;Odkrycie strategii postępowania programistów wiąże się ze spostrzeżeniem, iż kod źródłowy jest częściej czytany niż pisany. Zatem sposób pisania kodu, konwencje, standardy, w tym sposób używania wzorców projektowych jest kolejnym obszarem, w którym można poszukiwać powtarzalności. &lt;br /&gt;Doświadczony programista przechodząc z projektu do projektu będzie przenosił pewne pomocne nawyki mające ułatwić mu tworzenie oprogramowania. Dalej, doświadczony lider będzie dbał o to, aby uspójniać te nawyki wśród zespołu. Po co? Celem jest tu efektywna komunikacja. Jeden programista sprawniej pracuje posługując się sposobem kodowania który zna, zespół sprawnie pracuje posługując się tym samym stylem kodowania, nowa osoba w projekcie łatwiej wdroży się do zadań jeśli będzie mogła czytać kod wg pewnych, z góry określonych, zasad.&lt;br /&gt;Wzorce wyodrębnione na tym poziomie zostały zaprezentowane przez Kenta Becka w książce&lt;br /&gt;&lt;a href="http://www.amazon.com/Implementation-Patterns-Addison-Wesley-Signature-Kent/dp/0321413091"&gt;Implementation Patterns&lt;/a&gt;. &lt;br /&gt;&lt;br /&gt;Wzorce Implementacyjne to kolejny kamień milowy w poszukiwaniu powtarzalnych schematów podczas wytwarzania oprogramowania. Dotyczą one sposobów posługiwania się językiem oraz wzorcami projektowymi, a nie konkretnej architektury oprogramowania. Używając porównania do budownictwa: Wzorce Projektowe mówią jakich cegieł należy używać, Wzorce Implementacyjne wskazują jak najlepiej pchać taczkę.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Dalsza dekompozycja&lt;/h4&gt;&lt;br /&gt;Richard Dawkins w swojej książce &lt;a href="http://pl.wikipedia.org/wiki/Samolubny_gen"&gt;Samolubny gen&lt;/a&gt; stawia hipotezę, że rozwój nie jest progresywny lecz ekspansywny. Nie przebiega zgodnie z odgórnie ustalonym planem lecz odbywa się poprzez najlepsze dopasowanie do sytuacji bieżącej. Jednostką rozwoju nie jest istota wysokiego rzędu np. człowiek, lecz najbardziej elementarna jednostka - gen. Gen maksymalizuje swoje korzyści w danej chwili, a rozwój osobników wyższego rzędu jest jedynie skutkiem "samolubnych" zachowań genu.&lt;br /&gt;&lt;br /&gt;Zastanawia mnie czy ta sama zasada obowiązuje, jawnie bądź w ukrytej postaci, podczas wytwarzania oprogramowania? Bytem wyższego rzędu jest system informatyczny, lecz kto jest samolubnym genem? Obiekt, czy może...programista? Kto dąży to maksymalizowania swoich korzyści w danej chwili? Dawkinsowy gen zachowuje się samolubnie, gdyż pragnie przetrwać, przekazać swój materiał genetyczny. Rozważając programowanie obiektowe musimy zrezygnować z przypisywania obiektom cech genów, gdyż jest obiekt jest ze swej strony bierny w obszarze replikacji. A zatem programista? Czy programista jest samolubnym genem? Zaznaczam, że nie chodzi to celowe działanie na szkodę, lecz o nieświadomy mechanizm funkcjonowania. Jeśli programista spełnia funkcję genu, to materiałem genetycznym musi być kod, który jest przez niego pisany!&lt;br /&gt;&lt;br /&gt;Końcowy produkt jest zatem wypadkową: wymagań klienta, budżetu, ram czasowych oraz samolubności programisty. O ile z zewnątrz, w działaniach objawiających się bezpośrednio użytkownikowi, pierwsze cztery czynniki mają znaczącą rolę, o tyle wewnątrz systemu największe znaczenie ma samolubność programisty. Na czym miałaby ona polegać? Na przekazaniu jak największej ilości swoich koncepcji, rozwiązań, pomysłów do kodu systemu. Z kolei koncepcje te zależą od indywidualnych predyspozycji, umiejętności stosowania Wzorców Projektowych i Implementacyjncych,...humoru, itd. Stąd najkorzystniej dla projektu jest dbać o jakość przekazywanych koncepcji dbając o rozwój programistów.&lt;br /&gt;&lt;br /&gt;Wspomniany Chirstopher Alexander w książce &lt;a href="http://en.wikipedia.org/wiki/The_Timeless_Way_of_Building"&gt;Timeless Way of Building&lt;/a&gt; przedstawia, podobny w idei, koncept, który nazywa &lt;em&gt;porządkiem naturalnym&lt;/em&gt;. &lt;br /&gt;(Przykład za &lt;a href="http://www.projekt-hio.info/dwn/alexander_doskonalosc.html"&gt;Christopher Alexander czyli w poszukiwaniu doskonałości&lt;/a&gt;) Wyobraźmy salę wypełnioną krzesłami w uporządkowany sposób. Chcąc umieścić na sali jak najwięcej osób, można identyczne krzesła ustawić równo w rzędach optymalnie wypełniając salę. Na sali zmieści się wiele osób, ale nie wszystkim będzie wygodnie.&lt;br /&gt;Z drugiej strony można poprosić osoby aby przyszły z własnymi krzesłami i usiadły możliwie najbliżej siebie. W tej sytuacji na sali będą krzesła różnego typu: duże i małe, odległości między nimi będą różne - w zależności od potrzeb siedzących, lecz wszyscy będą się starali, aby na sali zmieściło się najwięcej osób. Takie uporządkowanie Alexander nazywa &lt;em&gt;porządkiem naturalnym&lt;/em&gt;. Charakteryzuje się on tym, każda osób ma tyle miejsca ile potrzebuje oraz występuje sprzężenie zwrotne z całością systemu (chęć zmieszczenia jak największej ilości osób). Charakterystyczną cechą porządku naturalnego jest to, że za każdym razem będzie przebiegał według tych samych reguł i za każdym razem efekt końcowy będzie nieco inny od poprzedniego.&lt;br /&gt;&lt;br /&gt;W obu przedstawionych koncepcjach kształt ostatecznego systemu jest sterowany przez działania programisty. Alexander dokłada jednak jedną drobną, acz kluczową rzecz: &lt;em&gt;sprzężenie zwrotne&lt;/em&gt;. &lt;br /&gt;Można zatem wnioskować, że jeżeli każdy programista ma dokładną świadomość ostatecznego celu, ostatecznego kształtu systemu i dbając przekazywanie własnych koncepcji w kodzie, weźmie pod uwagę to sprzężenie zwrotne, to jakość wytworzonego oprogramowania wzrośnie.&lt;br /&gt;&lt;br /&gt;Koncept sprzężenia zwrotnego uwidacznia się w programowaniu między innymi w takich podejściach jak &lt;a href="http://martinfowler.com/articles/continuousIntegration.html"&gt;Continuous Integration&lt;/a&gt;, Continuous Testing, czy &lt;a href="http://mbartyzel.blogspot.com/2008/07/tdd-o-co-waciwie-chodzi.html"&gt;Test-Driven Development&lt;/a&gt;. Całość podejścia do wytwarzania oprogramowania wywiedzionego z porządku naturalnego uwidacznia się w metodykach &lt;a href="http://pl.wikipedia.org/wiki/Agile"&gt;Agile&lt;/a&gt;.&lt;br /&gt;Należy podkreślić jednak niezwykle istotną rzecz. We wspomnianym przykładzie nt. porządku naturalnego, to ludzie przynosili własne krzesła i ustawiali je optymalnie do własnych potrzeb, biorąc pod uwagę całość systemu. Również w podejściu Agile ciężar odpowiedzialności przeniesiony został na programistę. Już nie procedury sterują projektem, lecz ludzie. Wymaga to od programisty wiele uwagi, dojrzałości, a przede wszystkim odpowiedzialności. Wymaga również kompetencji innego rodzaju niż biegłość techniczna w stosowaniu określonych technologii, Wzorców Projektowych, czy Implementacyjnych.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Poza kodem źródłowym&lt;/h4&gt;&lt;br /&gt;W poszukiwaniu powtarzalności podczas wytwarzania oprogramowania przeszliśmy ścieżkę od Wzorców GoF, poprzez Wzorce Architektoniczne, Implementacyjne, aż do powtarzalnych procesów Agile, gdzie programista tworząc kod nieustannie bierze pod uwagę końcowy kształt systemu.&lt;br /&gt;Każdy programista wie, że nauka wymienionych rzeczy zabiera wiele czasu. Moim zdaniem minimum 2 lata, a to i tak w odpowiednich warunkach. Jednym zabiera to wspomniane 2 lata, innym dłużej, a może i krócej, wielu zniechęca się po drodze. Lecz ci, którym się udało zaczęli programować w inny sposób. Jaka jest zatem różnica pomiędzy stanem początkowym, a końcowym w ścieżce rozwoju programisty i gdzie tej różnicy poszukiwać?&lt;br /&gt;Z pewnością różnica nie polega na znajomości wzorców, bo wiedza teoretyczna może nie zmienić się przez ten czas. Ale przecież różnica istniej! Widać ją w sposobie kodowania, w sposobie podejścia do problemu, w jakości wytwarzanego oprogramowania.&lt;br /&gt;Być może chodzi o to, że taki programista &lt;em&gt;czuje&lt;/em&gt; programowanie, myśli poprzez wzorce, widzi je i potrafi zastosować w praktyce. Następuje zatem zmiana w sposobie myślenia (o pewnych jej aspektach pisałem w artykule &lt;a href="http://mbartyzel.blogspot.com/2008/06/wersja-pdf-jeli-jeste-programist-albo-w.html"&gt;Metaprogramy w tworzeniu oprogramowania&lt;/a&gt;). &lt;br /&gt;&lt;br /&gt;Skoro programista &lt;em&gt;czujący programowanie&lt;/em&gt; ma pewien nowy sposób myślenia, a jest wielu takich programistów, to można wnioskować, że istnieje pewien zbiór sposobów postępowania czy myślenia, charakterystyczny dla tych ludzi. Z pewnością każdy robi to w nieco inny sposób, ale skoro potrafią otrzymywać identyczne wyniki w postaci fantastycznie napisanego kodu, to jest jakaś część wspólna tych strategii. Zatem istnieją pewne &lt;em&gt;powtarzalne wzorce&lt;/em&gt;, coś jak najlepsze praktyki skutecznych programistów, które charakteryzują ludzie osiągających sukcesy w naszej branży.&lt;br /&gt;Odkrycie tych wzorców jest moim zdaniem kolejnym wyzwaniem przed inżynierią oprogramowania, kolejnym etapem odkrywania i stosowania optymalnych metod pracy. &lt;br /&gt;Kolejne kroki usprawniania pracy wiodą od udoskonalania narzędzi i metod do rozwoju programisty. Tak już jest, że jakkolwiek skomplikowany by system nie był, w centralnym punkcje i tak znajduje się człowiek.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1759916214638009707-4324289380660787085?l=mbartyzel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mbartyzel.blogspot.com/feeds/4324289380660787085/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1759916214638009707&amp;postID=4324289380660787085' title='Komentarze (1)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/4324289380660787085'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/4324289380660787085'/><link rel='alternate' type='text/html' href='http://mbartyzel.blogspot.com/2008/11/jzyk-wzorcw.html' title='Język wzorców'/><author><name>Michał Bartyzel</name><uri>http://www.blogger.com/profile/03968505875451301931</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://bp2.blogger.com/_wQFWfmLrUy4/SFq_8FmWi_I/AAAAAAAAAC4/hpwTTs8-hoU/s72-c/PDF-Icon.jpg' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1759916214638009707.post-588044783122769139</id><published>2008-11-05T22:42:00.004+01:00</published><updated>2008-11-05T22:47:01.978+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='wzorce'/><category scheme='http://www.blogger.com/atom/ns#' term='wydarzenia'/><title type='text'>Weekendowe Warsztaty Wzorce Projektowe</title><content type='html'>Serdecznie zapraszamy na „Warsztaty weekendowe poświęcone wzorcom projektowym”. Jest to oferta specjalna dla użytkowników portalu Goldenline.pl i czytelników mojego bloga i &lt;a href="http://msieraczkiewicz.blogspot.com/"&gt;bloga Mariusza&lt;/a&gt;. Tej oferty nie znajdziesz na stronie BNS IT!&lt;br /&gt;&lt;br /&gt;Warsztaty umożliwiają nabycie praktycznych umiejętności tworzenia aplikacji z użyciem wzorców projektowych w języku Java.&lt;br /&gt;&lt;br /&gt;Zobacz &lt;a href="http://www.bnsit.pl/files/Wzorce_projektowe_java_i_refaktoring.pdf"&gt;program warsztatów&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Czego potrzebujesz?&lt;br /&gt;• Notebook z kartą wi-fi&lt;br /&gt;• Zapału, chęci i otwartego umysłu&lt;br /&gt;&lt;br /&gt;Twoja inwestycja to jedyne: 800 zł.&lt;br /&gt;&lt;br /&gt;Nigdzie nie znajdziesz szkolenia ani warsztatów w takiej cenie i jakości.&lt;br /&gt;&lt;br /&gt;Powiedz znajomym.&lt;br /&gt;&lt;br /&gt;Gdzie?&lt;br /&gt;Warszawa, 13-14.12.2008&lt;br /&gt;Wrocław, 13-14.12.2008&lt;br /&gt;Kraków, 13-14.12.2008&lt;br /&gt;&lt;br /&gt;Kontakt:&lt;br /&gt;m.sieraczkiewicz [[[[[ MAUPA ]]]]]] bnsit.pl&lt;br /&gt;+48 500 189 752&lt;br /&gt;&lt;a href="http://www.bnsit.pl"&gt;http://www.bnsit.pl&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1759916214638009707-588044783122769139?l=mbartyzel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mbartyzel.blogspot.com/feeds/588044783122769139/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1759916214638009707&amp;postID=588044783122769139' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/588044783122769139'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/588044783122769139'/><link rel='alternate' type='text/html' href='http://mbartyzel.blogspot.com/2008/11/weekendowe-warsztaty-wzorce-projektowe.html' title='Weekendowe Warsztaty Wzorce Projektowe'/><author><name>Michał Bartyzel</name><uri>http://www.blogger.com/profile/03968505875451301931</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1759916214638009707.post-7786089430829072714</id><published>2008-10-31T15:21:00.011+01:00</published><updated>2008-10-31T16:02:28.945+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='wzorce'/><category scheme='http://www.blogger.com/atom/ns#' term='architektura'/><title type='text'>Wzorce projektowe: Temporal Object</title><content type='html'>&lt;div&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.bnsit.pl/files/strategie_decouplingu.pdf"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;" src="http://bp2.blogger.com/_wQFWfmLrUy4/SFq_8FmWi_I/AAAAAAAAAC4/hpwTTs8-hoU/s200/PDF-Icon.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5213690557650865138" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a style="color:#773607; text-decoration:underline; font-weight:normal" href="http://www.bnsit.pl/files/temporal_object.pdf"&gt;Wersja PDF&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;a href="http://www.bnsit.pl/files/temporal_object-src.zip"&gt;Kod źródłowy&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br/&gt;&lt;br /&gt;Gdy zaczynałem poznawać wzorce projektowe punktem wyjścia dla mnie były książki w stylu GoF, blogi, fora, itd. Znajdowałem tam przede wszystkim diagramy UML, oraz banalne przykłady kodu w stylu: fabryka pizzy, szablon algorytmu, budowniczy okienka. Mój kłopot polegał na tym, że chociaż rozumiałem o czym się do mnie pisze, to nie wiedziałem jak zastosować te koncepcje w moim kodzie. Moje projekty związane były np. ze sklepem internetowym lub systemem ankietowym i nijak to się miało do pizzy, algorytmów czy okienek. Brakowało mi przede wszystkim sensownej implementacji wzorca oraz konkretnych wskazówek jak i gdzie go użyć.&lt;br /&gt;&lt;br /&gt;Po jakimś czasie zacząłem analizować źródła programów OpenSource takie jak Spring i apache-commons. Sęk w tym, że aby zrozumieć dobrze te projekty trzeba było wzorce projektowe wcześniej znać, a ja dopiero chciałem się ich nauczyć. Sporo mnie kosztowało rozgryzanie tego tematu.&lt;br /&gt;&lt;br /&gt;W tej serii artykułów odpowiem choć na część w/w pytań. Będę: omawiał różne wzorce, podawał przykładowe implementacje i podpowiadał gdzie można ich użyć. Jeśli chodzi o sam sposób użycia czyli wprowadzanie wzorca do projektu i wykrywanie potencjalnych miejsc jego zastosowania w projekcie, to ten temat zostanie poruszony w wątku o refaktoringu (w najbliższej przyszłości).&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Obiekty z historią&lt;/h4&gt;&lt;br /&gt;Wyobraźmy sobie, że należy stworzyć model obiektowy, który posłuży do zrealizowania funkcjonalności sklepu (taaa...wiem, że przykład mocno wyświechtany, lecz jakże użyteczny i skoro skojarzenia takie jak Hello world!, foo bar i Team-Member mocno zapadły w umysły rzesz programistów, więc i ja nie będę odstawał i posłużę się dobrze znanym przykładem rzeczonego sklepu).&lt;br /&gt;&lt;br /&gt;Centralną klasą modelu będzie obiekt Order. Zakładając, że klient użytkujący sklep może zapisać stan swojego zamówienia, a następnie do niego wrócić, okazuje się, że warto śledzić historię jego...hmmm...niezdecydowania? W przypadku sklepu może być to pomocne np. podczas analizy aktywności klienta, na podstawie której można będzie mu w przyszłości zaproponować nowe produkty i usługi. &lt;br /&gt;&lt;br /&gt;Postawiony problem można uogólnić następująco: stan danego obiektu może zmieniać się w czasie i należy zapewnić możliwość śledzenia historii zmian.&lt;br /&gt;W tym miejscu zrób krótką przerwę, weź kartkę i długopis oraz zaproponuj przykładowe rozwiązanie omówionej kwestii. &lt;br /&gt;&lt;br /&gt;Już masz? Świetnie, zatem porównaj je z dalszą częścią artykułu.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Temporal Object&lt;/h4&gt;&lt;br /&gt;Twoje rozwiązanie jest z pewnością wystarczające, lecz posłuchaj o innym, które jest na tyle często eksploatowane przez programistów, zostało określone mianem wzorca projektowego. &lt;br /&gt;&lt;br /&gt;Intencją wzorca &lt;span style="font-style:italic;"&gt;Temporal Object&lt;/span&gt; jest śledzenie zmian w obiekcie i udostępnianie ich na życzenie. Wzorzec ten jest również znany pod nazwami &lt;span style="font-style:italic;"&gt;History on Self&lt;/span&gt; oraz &lt;span style="font-style:italic;"&gt;Version History&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;W przykładzie mamy do czynienia obiektem reprezentującym zamówienie. Sformułujmy wymagania co do funkcjonalności:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;usługa pracuje z obiektem zamówienia Order&lt;/li&gt;&lt;br /&gt;&lt;li&gt;zamówienie można dowolnie zmieniać&lt;/li&gt;&lt;br /&gt;&lt;li&gt;historia zmiana ma być śledzona i udostępniana na życzenie&lt;/li&gt;&lt;br /&gt;&lt;li&gt;dla celów raportowych, oprócz bieżących, należy zapamiętywać godzinowe milestones&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;Spójrzmy na projekt rozwiązania:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_wQFWfmLrUy4/SQsVrrRcAdI/AAAAAAAAADo/y51hwJQcZKc/s1600-h/temporal_object_uml.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 270px;" src="http://4.bp.blogspot.com/_wQFWfmLrUy4/SQsVrrRcAdI/AAAAAAAAADo/y51hwJQcZKc/s400/temporal_object_uml.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5263324429606978002" /&gt;&lt;/a&gt;&lt;br /&gt;Głównym konceptem jest wprowadzenie obiektu &lt;span style="font-style:italic;"&gt;OrderVersion&lt;/span&gt;, który śledzi zmiany w zamówieni, tzn. dla każdej zmiany tworzony jest nowy obiekt &lt;span style="font-style:italic;"&gt;OrderVersion&lt;/span&gt;. Sam obiekt klasy &lt;span style="font-style:italic;"&gt;Order&lt;/span&gt;, z które będą korzystały usługi jest niejako proxy bieżącej wersji zamówienia. Dodatkowo wprowadzona została klasa &lt;span style="font-style:italic;"&gt;VersionHistory&lt;/span&gt;, której odpowiedzialnością jest zarządzanie historią zamówienia.&lt;br /&gt;&lt;br /&gt;Całe piękno tego rozwiązania polega na tym, że usłudze udostępniony będzie obiekt Order, który powinien proksować API OrderVersion tyle, że pracuje zawsze na wersji bieżącej. Reszta przetwarzania jest ukryta przed klientem.&lt;br /&gt;&lt;br /&gt;Zgodnie z założeniem tej serii artykułów przedstawiam również implementację wzorca.&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;&lt;br /&gt;public class Order implements Serializable {&lt;br /&gt; private Long id;&lt;br /&gt; private VersionHistory versioningHistory = new VersionHistory();&lt;br /&gt; private OrderVersion currentVersion;&lt;br /&gt; public void createNewVersion( String productId, &lt;br /&gt;            String productName, Double price ) {&lt;br /&gt;  OrderVersion orderVersion = new OrderVersion();&lt;br /&gt;  orderVersion.setCustomId( productId );&lt;br /&gt;  orderVersion.setName( productName );&lt;br /&gt;  orderVersion.setPrice( price );&lt;br /&gt;  versioningHistory&lt;br /&gt;                    .addOrderVersion( orderVersion.getDate(),   &lt;br /&gt;                       orderVersion );&lt;br /&gt;  currentVersion = orderVersion;&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; public void setCurrentVersionTo( Date when ) {&lt;br /&gt;  currentVersion = versioningHistory.findVersion( when );&lt;br /&gt; }&lt;br /&gt; protected OrderVersion getCurrentVersion() {&lt;br /&gt;  return currentVersion;&lt;br /&gt; }&lt;br /&gt; public String getCustomId() {&lt;br /&gt;  return getCurrentVersion().getCustomId();&lt;br /&gt; }&lt;br /&gt; public void setCustomId( String customId ) {&lt;br /&gt;  getCurrentVersion().setCustomId( customId );&lt;br /&gt; }&lt;br /&gt; //delegacje reszty getterów i setterów&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;&lt;br /&gt;public class VersionHistory implements Serializable {&lt;br /&gt; private Map&lt;Date, OrderVersion&gt; orderVersions&lt;br /&gt;            = new HashMap&lt;Date, OrderVersion&gt;();&lt;br /&gt; private List&lt;OrderVersion&gt; orderHourMilestones&lt;br /&gt;            = new ArrayList&lt;OrderVersion&gt;();&lt;br /&gt; public OrderVersion findVersion( Date date ) {&lt;br /&gt;  return orderVersions.get( date );&lt;br /&gt; }&lt;br /&gt; public void addOrderVersion( Date date, OrderVersion version ) {&lt;br /&gt;  orderVersions.put( date , version );&lt;br /&gt; }&lt;br /&gt; public void createHourMilestone() {&lt;br /&gt;  //...&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;&lt;br /&gt;public class OrderVersion implements Serializable {&lt;br /&gt; private Long id;&lt;br /&gt; private String customId;&lt;br /&gt; private String name;&lt;br /&gt; private Double price;&lt;br /&gt; private Date date;&lt;br /&gt; public OrderVersion() {&lt;br /&gt;     this.date = Utils.getNow();&lt;br /&gt; } &lt;br /&gt;}&lt;br /&gt; //gettery i settery&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;A co z persystencją?&lt;/h4&gt;&lt;br /&gt;Kolejny problem, o który można potknąć się podczas nauki wzorców to kwestia związana z trwałym przechowywaniem danych. O ile w języku obiektowym można napisać niemal wszystko, również w bazie danych można stworzyć dowolnie złożone rozwiązanie to jednak sklejenie tego razem czasem nastręcza kłopotów. Dlatego, aby opis wzorca był kompletny zajmijmy się teraz trwałym przechowywaniem danych w relacyjnej bazie danych.&lt;br /&gt;&lt;br /&gt;Domyślnie, używając dostarczycieli persystencji dla JPA, przyjmowana jest zasada, że jeden obiekt jest mapowany do jednej tabeli w bazie danych. Moim zdaniem przyjęcie takiej arbitralnej zasady prowadzi do bałaganu w bazie danych oraz do jej „niewyważenia”. Niewyważenie rozumiem jako sytuację, gdzie poszczególne tabele przechowują nieproporcjonalnie dużą ilość danych, np. jedna tabela ma 2 kolumny oraz 10 wierszy, natomiast inna 20 kolumn i 10000 wierszy. Taka sytuacja w moim mniemaniu daje przesłanki do zastanowienia się, czy ta mała tabela jest potrzebna. Być może można znajdujące się w niej dane umieścić jako dodatkową kolumnę i innej tabeli i w ten sposób uprość zapytania SQL pracujące na bazie. Zaznaczam, że to moje prywatne zdanie.&lt;br /&gt;&lt;br /&gt;Wykorzystując mapowania JPA umieścimy strukturę obiektową w dwóch tabelach: &lt;span style="font-style:italic;"&gt;orders &lt;/span&gt;– przechowującej zamówienia oraz &lt;span style="font-style:italic;"&gt;orders_versions&lt;/span&gt; – przechowującą wersje poszczególnych zamówień.&lt;br /&gt;&lt;br /&gt;Schemat bazy danych będzie wyglądał następująco:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_wQFWfmLrUy4/SQsX2nzniFI/AAAAAAAAADw/PxQM9vebiOs/s1600-h/temporal_object_db.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 159px;" src="http://3.bp.blogspot.com/_wQFWfmLrUy4/SQsX2nzniFI/AAAAAAAAADw/PxQM9vebiOs/s400/temporal_object_db.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5263326816678414418" /&gt;&lt;/a&gt;&lt;br /&gt;Wiersze z &lt;span style="font-style:italic;"&gt;orders &lt;/span&gt;identyfikują poszczególne zamówienia oraz wskazują na jego bieżącą wersję. Natomiast wiersze z &lt;span style="font-style:italic;"&gt;orders_versions&lt;/span&gt; przechowują dane na temat danej wersji.&lt;br /&gt;&lt;br /&gt;Dodatkowo każda wersja wskazuje na zamówienie do którego należy oraz, jeśli jest godzinowym milestonem, to wskazuje na właściciela. Na poziomie obiektowym pomiędzy obiektami &lt;span style="font-style:italic;"&gt;Order&lt;/span&gt; oraz &lt;span style="font-style:italic;"&gt;VersionHistory &lt;/span&gt;występuje relacja 1:1, zatem wiersze z orders identyfikują również obiekt &lt;span style="font-style:italic;"&gt;VersionHistory&lt;/span&gt;. Z tego względu &lt;span style="font-style:italic;"&gt;orders_versions&lt;/span&gt; posiada dodatkowe wskazanie na orders w postaci klucza &lt;span style="font-style:italic;"&gt;ref_order_hour_milestone&lt;/span&gt;, określające, że dana wersja należy do historii wersji danego zamówienia.&lt;br /&gt;&lt;br /&gt;Odpowiednie mapowania JPA wyglądają następująco:&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;&lt;br /&gt;@Entity @Table( name = "orders" )&lt;br /&gt;@NamedQuery( name="Order.findAll", query="from Order" )&lt;br /&gt;public class Order implements Serializable {&lt;br /&gt; @Id&lt;br /&gt; @GeneratedValue( strategy=GenerationType.AUTO )&lt;br /&gt; private Long id;&lt;br /&gt;&lt;br /&gt; @Embedded&lt;br /&gt; private VersionHistory versioningHistory = new VersionHistory();&lt;br /&gt;&lt;br /&gt; @OneToOne&lt;br /&gt; @JoinColumn(name="ref_current_version")&lt;br /&gt; private OrderVersion currentVersion;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;&lt;br /&gt;@Embeddable&lt;br /&gt;public class VersionHistory implements Serializable {&lt;br /&gt; &lt;br /&gt; @OneToMany(cascade=CascadeType.ALL)&lt;br /&gt; @MapKey( name="date" )&lt;br /&gt;&lt;br /&gt;     @JoinColumn( name="ref_order_history" )   &lt;br /&gt; private Map&lt;Date, OrderVersion&gt; orderVersions&lt;br /&gt;  = new HashMap&lt;Date, OrderVersion&gt;();&lt;br /&gt; &lt;br /&gt; @OneToMany&lt;br /&gt; @JoinColumn( name="ref_order_hour_milestone" )&lt;br /&gt; private List&lt;OrderVersion&gt; orderHourMilestones&lt;br /&gt;            = new ArrayList&lt;OrderVersion&gt;();&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;&lt;br /&gt;@Entity @Table( name = "orders_versions" )&lt;br /&gt;public class OrderVersion implements Serializable {&lt;br /&gt; @Id&lt;br /&gt; @GeneratedValue( strategy=GenerationType.AUTO )&lt;br /&gt; private Long id;&lt;br /&gt; @Column( name="custom_id" )&lt;br /&gt; private String customId;&lt;br /&gt; private String name;&lt;br /&gt; private Double price;&lt;br /&gt; private Date date; &lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Jak można zauważyć pomiędzy tabelami &lt;span style="font-style:italic;"&gt;orders&lt;/span&gt;a &lt;span style="font-style:italic;"&gt;orders_versions&lt;/span&gt; występuje powiązanie dwukierunkowe.  &lt;br /&gt;Na wstępie tego rozdziału wspominałem o dbaniu o optymalność zapytań. Przeprowadziłem test i zapis jednego zamówienia z trzema wersjami powoduje wykonanie na bazie następujących zapytań SQL:&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;&lt;br /&gt;Hibernate: insert into orders (ref_current_version) values (?)&lt;br /&gt;Hibernate: insert into orders_versions (custom_id, date, name, price) values (?, ?, ?, ?)&lt;br /&gt;Hibernate: insert into orders_versions (custom_id, date, name, price) values (?, ?, ?, ?)&lt;br /&gt;Hibernate: insert into orders_versions (custom_id, date, name, price) values (?, ?, ?, ?)&lt;br /&gt;Hibernate: update orders set ref_current_version=? where id=?&lt;br /&gt;Hibernate: update orders_versions set ref_order_hour_milestone=? where id=?&lt;br /&gt;Hibernate: update orders_versions set ref_order_history=? where id=?&lt;br /&gt;Hibernate: update orders_versions set ref_order_history=? where id=?&lt;br /&gt;Hibernate: update orders_versions set ref_order_history=? where id=?&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Zmieńmy jedna nieco schemat bazy danych przenosząc powiązanie zamówienia z jego bieżącą wersją do tabeli &lt;span style="font-style:italic;"&gt;orders_versions&lt;/span&gt;. Rysunek poniżej:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_wQFWfmLrUy4/SQsZYvUUQqI/AAAAAAAAAD4/nZS_8jbZ3l0/s1600-h/temporal_object_db_refactored.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 163px;" src="http://4.bp.blogspot.com/_wQFWfmLrUy4/SQsZYvUUQqI/AAAAAAAAAD4/nZS_8jbZ3l0/s400/temporal_object_db_refactored.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5263328502321791650" /&gt;&lt;/a&gt;&lt;br /&gt;Zmiana na w mapowaniach jest bardzo niewielka:&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;&lt;br /&gt; //...&lt;br /&gt;public class Order implements Serializable {&lt;br /&gt; //...&lt;br /&gt; @OneToOne(mappedBy="parentOrder")&lt;br /&gt; private OrderVersion currentVersion;&lt;br /&gt; //...&lt;br /&gt; public void createNewVersion( String productId, String productName, &lt;br /&gt;  Double price ) {&lt;br /&gt;  //..&lt;br /&gt;  orderVersion.setParentOrder( this );&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;&lt;br /&gt;//..&lt;br /&gt;public class OrderVersion implements Serializable {&lt;br /&gt; //..&lt;br /&gt; @OneToOne&lt;br /&gt; @JoinColumn(name="ref_order")&lt;br /&gt; private Order parentOrder;&lt;br /&gt; //..&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Zestaw zapytań tym razem wygenerowany przez Hibernate wygląda następująco:&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;&lt;br /&gt;Hibernate: insert into orders values ( )&lt;br /&gt;Hibernate: insert into orders_versions (custom_id, date, name, ref_order, price) values (?, ?, ?, ?, ?)&lt;br /&gt;Hibernate: insert into orders_versions (custom_id, date, name, ref_order, price) values (?, ?, ?, ?, ?)&lt;br /&gt;Hibernate: insert into orders_versions (custom_id, date, name, ref_order, price) values (?, ?, ?, ?, ?)&lt;br /&gt;Hibernate: update orders_versions set ref_order_hour_milestone=? where id=?&lt;br /&gt;Hibernate: update orders_versions set ref_order_history=? where id=?&lt;br /&gt;Hibernate: update orders_versions set ref_order_history=? where id=?&lt;br /&gt;Hibernate: update orders_versions set ref_order_history=? where id=?&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Zatem mamy o jedno zapytanie mniej. Czy to dużo? Trudno powiedzieć, aczkolwiek na każde tysiąc zapisów zamówienia do bazy danych mamy tysiąc zapytań mniej...&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Podsumowując&lt;/h4&gt;&lt;br /&gt;Wzorca Temporal Object można użyć jeśli występuje potrzeba śledzenia i zapamiętywania zmian w modelu obiektowym. Używając narzędzi O\RM o trwałego zapisu danych, nie dajmy się zwieść iluzji, że programista może zapomnieć o bazie danych. Jeśli mamy na uwadze wydajność należy o tym pamiętać, zwłaszcza wtedy, gdy większość narzędzi ukrywa przed programistą złożoność swoich działań.&lt;br /&gt;&lt;br /&gt;Kompletny kod źródłowy omawianego rozwiązania znajdziesz na blogu, którego adres widoczny jest na stronie tytułowej artykułu. W projekcie zostały użyte mapowania JPA, Hibernate jako dostarczyciel persystencji oraz baza danych MySQL&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1759916214638009707-7786089430829072714?l=mbartyzel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mbartyzel.blogspot.com/feeds/7786089430829072714/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1759916214638009707&amp;postID=7786089430829072714' title='Komentarze (1)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/7786089430829072714'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/7786089430829072714'/><link rel='alternate' type='text/html' href='http://mbartyzel.blogspot.com/2008/10/wzorce-projektowe-temporal-object.html' title='Wzorce projektowe: Temporal Object'/><author><name>Michał Bartyzel</name><uri>http://www.blogger.com/profile/03968505875451301931</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://bp2.blogger.com/_wQFWfmLrUy4/SFq_8FmWi_I/AAAAAAAAAC4/hpwTTs8-hoU/s72-c/PDF-Icon.jpg' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1759916214638009707.post-8088628879839939021</id><published>2008-10-29T19:46:00.007+01:00</published><updated>2008-10-29T19:56:39.479+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='wzorce'/><category scheme='http://www.blogger.com/atom/ns#' term='architektura'/><category scheme='http://www.blogger.com/atom/ns#' term='refaktoring'/><title type='text'>Uwaga na Immutable + JPA</title><content type='html'>Ostatnio użyłem wzorca &lt;span style="font-style:italic;"&gt;Immutable&lt;/span&gt; w tradycyjnej implementacji&lt;br /&gt;&lt;code style="background:grey"&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;public class Team {&lt;br /&gt;  &lt;br /&gt;   public Member getMember() {&lt;br /&gt;     return new Member( this.member );&lt;br /&gt;   }&lt;br /&gt;  &lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;Po zmapowaniu klasy adnotacjami JPA sporo głowiłem się dlaczego dostaję albo zbyt wiele wierszy w bazie albo wyjątek z informacją, że nastąpiła próba zapisu obiektu transient...rzut oka na powyższy kod wyjaśnia sprawę ;) ech...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1759916214638009707-8088628879839939021?l=mbartyzel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mbartyzel.blogspot.com/feeds/8088628879839939021/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1759916214638009707&amp;postID=8088628879839939021' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/8088628879839939021'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/8088628879839939021'/><link rel='alternate' type='text/html' href='http://mbartyzel.blogspot.com/2008/10/uwaga-na-immutable-jpa.html' title='Uwaga na Immutable + JPA'/><author><name>Michał Bartyzel</name><uri>http://www.blogger.com/profile/03968505875451301931</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1759916214638009707.post-7267435936446722761</id><published>2008-10-28T17:53:00.006+01:00</published><updated>2008-10-28T18:49:53.437+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='wizje'/><category scheme='http://www.blogger.com/atom/ns#' term='rozwój'/><title type='text'>Strzeż się ludzi, którzy są pewni tego, że mają rację!</title><content type='html'>Programista, architekt, bazodanowiec, temaleader...cokolwiek człowiek by nie robił, z biegiem czasu się specjalizuje, z biegiem czasu staje się ekspertem. I to chyba jest bardzo niebezpieczne... &lt;br /&gt;&lt;br /&gt;Zbyt łatwo zdarza się nam powiedzieć do siebie samego: "Ok, już wszystko umiem". Kiedy przyjdzie Ci do głowy takie zdanie wiedz, że już po tobie! Twoja kariera, kimkolwiek byś nie był, właśnie rozpoczęła powolny lecz konsekwentny ruch w dół, czy raczej w tył.&lt;br /&gt;&lt;br /&gt;Powyższe, wypowiedziane na głos lub choć wewnętrznie zadeklarowane, stwierdzenie automatycznie zamyka na dalszy rozwój, gdyż zakłada, że on się zakończył. Świat się rozwija, technologia się rozwija i zatrzymanie się w miejscu faktycznie oznacza cofanie się.&lt;br /&gt;&lt;br /&gt;Profesjonalizm można poznać po tym, że osoba pozostaje otwarta. Otwarta na to, że każdego dnia może nauczyć się czegoś nowego, że może nauczyć się czegoś od młodszego kolegi właśnie przyjętego do pracy, od podwładnego, od kogoś kogo uważa za mniej kompetentnego od siebie, że może nauczyć się czegoś od swojego ucznia. Tylko ta postawa gwarantuje możliwość ciągłego doskonalenia się. Oto jest sens słynnego &lt;span style="font-style:italic;"&gt;Wiem, że nic nie wiem&lt;/span&gt;!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1759916214638009707-7267435936446722761?l=mbartyzel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mbartyzel.blogspot.com/feeds/7267435936446722761/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1759916214638009707&amp;postID=7267435936446722761' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/7267435936446722761'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/7267435936446722761'/><link rel='alternate' type='text/html' href='http://mbartyzel.blogspot.com/2008/10/strze-si-ludzi-ktrzy-s-pewni-tego-e-maj.html' title='Strzeż się ludzi, którzy są pewni tego, że mają rację!'/><author><name>Michał Bartyzel</name><uri>http://www.blogger.com/profile/03968505875451301931</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1759916214638009707.post-7643914625437144184</id><published>2008-10-02T20:27:00.005+02:00</published><updated>2008-10-02T21:47:04.148+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='wzorce'/><category scheme='http://www.blogger.com/atom/ns#' term='architektura'/><title type='text'>Organizowanie logiki biznesowej</title><content type='html'>Chris Richardson, w książce &lt;span style="font-style: italic;"&gt;Pojo in Action&lt;/span&gt; podaje kilka decyzji, które musi podjąć projektant systemu enterprise w Jawie. Jednym z wyborów przed którym rzeczony projektant stoi dotyczy sposobu w jaki zorganizowana jest logika biznesowa. Autor nazywa to wyborem pomiędzy podejściem proceduralnym a obiektowym. Rzecz w tym, by wybrać jeden z trzech &lt;a href="http://martinfowler.com/eaaCatalog"&gt;opisanych&lt;/a&gt; przez Martina Fowlera wzorców. Choć Richardson podaje pewne kryteria, to jednak operuje na pojęciach wybitnie nieostrych typu: duże projekty, małe projekty, skomplikowana logika, niewiele logiki. W artykule chciałbym przyjrzeć się problemowi i podać bardziej namacalne kryteria wyboru.&lt;br /&gt;(Czytelnik niezaznajomiony z wzorcami enterprise znajdzie zwięzłe charakterystyki na końcu artykułu; po szczegóły odsyłam do &lt;a href="http://martinfowler.com/eaaCatalog"&gt;bliki&lt;/a&gt; Martina Fowlera, rozdział &lt;span style="font-style: italic;"&gt;Domain Logic Patterns&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Proceduralnie czy obiektowo?&lt;/h4&gt;&lt;br /&gt;Bez obawy! Nikt nie zmusza Cię do cofnięcia się w świat języków proceduralnych, nie w tym rzecz...Istotę problemu można sformułować następująco: Powstało wymaganie biznesowe, aby napisać system robiący COŚ TAM. Jak się do tego zabrać, aby uczynić zadość oczekiwaniom klienta i jednocześnie włożyć to wysiłek odpowiedni do natury rzeczy. Wiadomo, że klient chciałby jak najwyższą jakość za jak najniższą ceną, natomiast dostawca chce dostarczyć &lt;span style="font-style: italic;"&gt;najniższą dopuszczalną&lt;/span&gt; jakość za jak najwyższą cenę. Słowem, kwestia jest poważna.&lt;br /&gt;&lt;br /&gt;Klasyczne podejście obiektowe każe nam zbudować obiektowy model dziedziny problemu charakteryzujący się współpracującymi pomiędzy sobą obiektami, z których każdy charakteryzuje się swoim stanem oraz zachowaniem. Obiekty będą współpracować ze sobą odzwierciedlając swój stan w bazie danych oraz w interfejsie użytkownika w taki sposób, aby zrealizować zdefiniowane przez niego wymagania.&lt;br /&gt;&lt;br /&gt;W podejściu proceduralnym nie będziemy modelować rzeczywistości, nie będziemy modelować dziedziny problemu. W tym podejściu każemy bazie danych krok po kroku zapamiętać pewne dane, każemy interfejsowi użytkownika wprost wypisać pewne dane tak, aby w konsekwencji użytkownik dostał to, co chciał. Skąd wiemy co chciał? Chciał to, co definiują &lt;span style="font-style: italic;"&gt;use cases&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Jak przełożą się powyższe decyzje na prace programisty? Np. tak, że w pierwszym przypadku zaprzęgniemy do działania Spring Framework, JSF i Hibernate albo EJB i resztę a drugim zdecydujemy się na PHP. Albo jeśli lubimy Jawę, to w drugim przypadku weźmiemy Tomcata, Struts2 i  nie zważając na to co nam mówią o warstwach i odpowiedzialnościach, zaimplementujemy całą logikę w akcjach (tu właśnie mogą być pomocne &lt;span style="font-style: italic;"&gt;Transaction Script&lt;/span&gt; lub &lt;span style="font-style: italic;"&gt;Table Module&lt;/span&gt;, sprawdź w jaki sposób:))&lt;br /&gt;&lt;br /&gt;Zauważmy, że działania użytkownika w każdym, nawet najbardziej skomplikowanym systemie, w ostatecznym rozrachunku sprowadzają się odpowiedniej sekwencji operacji &lt;span style="font-style: italic;"&gt;CRUD&lt;/span&gt;. Tak, końcowym rezultatem interakcji pomiędzy obiektami jest zmiana stanu bazy danych. Można zatem twierdzić, że każdą usługę systemu zdefiniowaną poprzez &lt;span style="font-style: italic;"&gt;use case&lt;/span&gt; można zastąpić skończoną ilością operacji elementarnych &lt;span style="font-style: italic;"&gt;CRUD&lt;/span&gt;. Ot i istota całego problemu.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Kwestia wyboru pomiędzy podejściem obiektowym a proceduralnym sprowadza się do rozstrzygnięcia jaka jest relacja pomiędzy usługą systemu a operacjami elementarnymi.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Jeśli jest to przełożenie 1:1 np. sklep internetowy, katalog książek, itp, gdzie działania użytkowników sprowadzają się właściwie do operacji &lt;span style="font-style:italic;"&gt;CRUD&lt;/span&gt; to opłaca się użyć podejścia proceduralnego.&lt;br /&gt;&lt;br /&gt;Jeśli mamy do czynienia np. z aplikacją kadr i płac, bankiem czy obsługą giełdy to usługa systemu może mieć przełożenie na setki albo tysiące operacji elementarnych. W takim przypadku stworzenie rzetelnego modelu dziedziny ułatwi panowanie nad rozwojem projektu. Skorzystamy też z dobrodziejstwa wielu frameworków, które ułatwiają pracę. Pamiętajmy, że w konsekwencji i tak ostatecznym rezultatem będzie zestaw &lt;span style="font-style:italic;"&gt;CRUDów&lt;/span&gt; z tą różnicą, że nie będziemy zmuszeni tworzyć go samodzielnie, dzięki modelowi obiektowemu oraz frameworkom zatrzymamy się na wysokim poziomie abstrakcji.&lt;br /&gt;&lt;br /&gt;Wiem, że pominąłem kilka istotnych aspektów takich jak bezpieczeństwo, transakcyjnośc itd. Koncentrowałem się tylko na organizowaniu logiki biznesowej.&lt;br /&gt;&lt;br /&gt;&lt;hr /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Transaction Script&lt;/span&gt; - w podejściu proceduralnym pozwala na ujecie w całość wielu operacji, które muszą być wykonane w jednej transakcji&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Domain Model&lt;/span&gt; - podejście obiektowe charakteryzuje się tworzenie modelu obiektowego dziedziny problemu&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Table Module&lt;/span&gt; - w podejściu proceduralnym jest czymś pośrednim pomiedzy &lt;span style="font-style:italic;"&gt;Transaction Script&lt;/span&gt; a &lt;span style="font-style:italic;"&gt;Domain Model&lt;/span&gt;, pozwala na skupienie logiki biznesowej w okół danych, na których logika pracuje&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1759916214638009707-7643914625437144184?l=mbartyzel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mbartyzel.blogspot.com/feeds/7643914625437144184/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1759916214638009707&amp;postID=7643914625437144184' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/7643914625437144184'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/7643914625437144184'/><link rel='alternate' type='text/html' href='http://mbartyzel.blogspot.com/2008/10/organizowanie-logiki-biznesowej.html' title='Organizowanie logiki biznesowej'/><author><name>Michał Bartyzel</name><uri>http://www.blogger.com/profile/03968505875451301931</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1759916214638009707.post-1403518920833525093</id><published>2008-07-22T19:59:00.011+02:00</published><updated>2008-07-26T22:42:11.656+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='wizje'/><title type='text'>Jakieś to takie skomplikowane...</title><content type='html'>Ostatnio miałem trochę do czynienia z narzędziem PowerDesigner. Ogólnie rzecz ujmując jest to narzędzie do modelowania... &lt;br /&gt;Próbując określić odpowiedzialność tego narzędzia doszedłem do wniosku, że jest to narzędzie, które wychodząc od procesu biznesowego, pozwala w zrozumiały dla wszystkich (od dołu aż do góry korporacyjnej hierarchii) sposób opisać to, co dzieje się w biznesie, wspomóc analizę tegoż oraz, jeśli zajdzie taka potrzeba, doprowadzić do zaprojektowania stosownych narzędzi informatycznych, począwszy od wstępnych wymagań, na szkielecie systemu z wykorzystaniem konkretnych technologii skończywszy, uff!&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Po pierwsze: zgubiłem się w strukturze&lt;/h4&gt;&lt;br /&gt;Rzeczą, która od razu rzuciła mi się w oczy, to ogrom możliwości tego narzędzia. Użytkownik może stworzyć różnego rodzaju modele, diagramy i zależności między nimi. Jako (zaznaczam: początkującemu) użytkownikowi brakowało mi procesu, który wskazywałby kierunek prac. PowerDesigner nie wspiera żadnej metodyki, więc w zasadzie nie wiadomo co należy robić. I mimo, że można wszystko, to i tak nie wiadomo co...&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Po drugie: "Na przekór czasom i ludziom wbrew..."&lt;/h4&gt;&lt;br /&gt;Projektanci narzędzia z pewnością mieli pomysł na jego używanie. Przynajmniej ja gorąco w to wierzę. Aczkolwiek odniosłem wrażenie, że Sybase próbuje forsować jakieś własne podejście do modelowania, za nic sobie mając przyzwyczajenia analityków. Owszem, PowerDesigner wspiera co tylko może wspierać, ale odpowiedzialności poszczególnych składowych nachodzą na siebie. Tego właśnie mi brakowało! - dokładnie zdefiniowanych odpowiedzialności poszczególnych modelów.&lt;br /&gt;&lt;br /&gt;Skoro 95% tego, co można zrobić w PowerDesigner, da się zrealizować za pomocą UML, to po co mi narzędzie za $7000?&lt;br /&gt;&lt;br /&gt;Trzeba uczciwie przyznać, że po głębszym przyjrzeniu się narzędzie szokuje możliwościami, lecz nie wychodzenie na przeciw przyzwyczajeniom użytkowników sprawia, że próbują oni używać programu na swój własnny sposób, niezgodny z pomysłem projektantów. Oczywiście powoduje to frustrację, a interfejs użytkownika czyni nieergonomicznym do granic możliwości.&lt;br /&gt;&lt;br /&gt;Wiele narzędzi przekonało mnie, że próby generowania kodu "z automatu" kończą się źle. Nie inaczej i w tym przypadku. Totalna kaszana, choć wierzę, że intencje były dobre.&lt;br /&gt;&lt;br /&gt;PowerDesigner sprawia wrażenia programu rozwijanego przez grupę fantastycznych, ale kompletnie oderwanych od rzeczywistości, programistów.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Po trzecie: Narzędzie do wszystkiego&lt;/h4&gt;&lt;br /&gt;Mówią, że "jeśli coś jest do wszystkiego, to jest do niczego". Odkryłem, że to bzdura i daleko idące uogólnienie. Takie, na przykład, koło, dźwignia albo&lt;br /&gt;klin. Używane są wszędzie i do wszystkiego, ale nikt im nie zarzuca, że są nieprzydatne.&lt;br /&gt;&lt;br /&gt;Otóż i esencja mojego odkrycia: &lt;b&gt;jeśli coś jest wystarczająco proste, może być "do wszystkiego"&lt;/b&gt; albo inaczej &lt;b&gt;złożoność narzędzia/koncepcji/rozwiązania jest odwrotnie proporcjonalna do zakresu jego stosowalności&lt;/b&gt;.&lt;br /&gt;&lt;br /&gt;Gdyby zatem Sybase, zamiast gigantycznego all-in-one, wypuścił zestaw narzędzi o określonej specjalizacji, które dodatkowo świetnie ze sobą współpracują, to miałby u mnie lepsze noty:)&lt;br /&gt;Dobrym przykładem jest pakiet MS Office. Pomiając indywidualne upodobania, mamy klarowną sytuację: Word - piszemy, Excel - liczmy, PowerPoint - prezentujemy, Outlook - organizujemy, Binder - i to jest genialne, spinamy wszystko razem ale tak, że narzędzie nie zatracają własnej indywidualności. Dla użytkownika jest w miarę jasne co ma zrobić, aby uzyskać określony efekt.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;A teraz objadę sobie UMLa&lt;/h4&gt;&lt;br /&gt;Ilu diagramów UML najczęściej używasz? Ja 2 - klas i sekwencji. A ilu elementów z tych diagramów najczęściej korzystasz? Ja z co najwyżej 10. Duch Pareto nie śpi, co? UML, z początku fajny, ale w miarę rozrastania się i usztywniania zrobił się beee. To musi pęknąć, już pęka. Powstają mutacje w stylu Robustness Diagrams, które wybierają z UML tylko to, co jest naprawdę niezbędne do określonego celu.&lt;br /&gt;&lt;br /&gt;Osobiście traktuję UML jako zbiór sugestii odnośnie modelowania Używam piktogramów, ale konkretne zasady traktuje raczej luźno. Jestem zdania, że jeśli zespół jednoznacznie rozumie notację, to jest to ok. Nawet jeśli jest to notacja nieformalna.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Więc czego bym tak naprawdę chciał?&lt;/h4&gt;&lt;br /&gt;Myślę, że jeśli chodzi o projekty (nie tylko IT) będziemy świadkami następujących przemian:&lt;br /&gt;&lt;dl&gt;&lt;br /&gt;&lt;dt&gt;&lt;em&gt;centralizacja&lt;/em&gt; na rzecz &lt;em&gt;decentralizacji i współpracy&lt;/em&gt;&lt;/dt&gt;&lt;br /&gt;&lt;dd&gt;szansą na ogarnięcie coraz to bardziej złożonych projektów jest podzielenie ich na mniejsze kawałki; brzmi trywialnie...coraz trudniej centralnie sterować ogromnymi przedsięwzięciami programistycznymi, zatem należy zrezygnować (pozornego) kontrolowania sytuacji i bardziej polegać na współpracy niewielkich, wyspecjalizowanych zespołów programistycznych; zamiast na dokładne modele, należy postawić na zaufanie i na kompetentnych ludzi&lt;/dd&gt;&lt;br /&gt;&lt;dt&gt;&lt;em&gt;ustrukturyzowanie&lt;/em&gt; na rzecz &lt;em&gt;procesów, elementów składowych oraz płaskich relacji&lt;/em&gt;&lt;/dt&gt;&lt;/li&gt;&lt;br /&gt;&lt;dd&gt;w miarę rozrostu projektu, utrzymywanie odpowiedniej struktury staje się coraz bardziej pracochłonne; po pewnym czasie nadchodzi moment, w którym dbanie, aby wszystko odbywało się wg wytycznych jest kosztowniejsze niż dodawanie wartości biznesowej do produktu; strukturę mogą zastąpić procesy - łatwiejsze w modyfikacji i bardziej elastyczne oraz elementy składowe wraz z płaskimi relacjami pomiędzy nimi; &lt;/dd&gt;&lt;br /&gt;&lt;/dl&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1759916214638009707-1403518920833525093?l=mbartyzel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mbartyzel.blogspot.com/feeds/1403518920833525093/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1759916214638009707&amp;postID=1403518920833525093' title='Komentarze (1)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/1403518920833525093'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/1403518920833525093'/><link rel='alternate' type='text/html' href='http://mbartyzel.blogspot.com/2008/07/jakie-to-takie-skomplikowane.html' title='Jakieś to takie skomplikowane...'/><author><name>Michał Bartyzel</name><uri>http://www.blogger.com/profile/03968505875451301931</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1759916214638009707.post-1488494735726829548</id><published>2008-07-21T07:21:00.001+02:00</published><updated>2008-07-21T20:11:57.220+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><category scheme='http://www.blogger.com/atom/ns#' term='tdd'/><category scheme='http://www.blogger.com/atom/ns#' term='refaktoring'/><title type='text'>TDD: O co właściwie chodzi?</title><content type='html'>&lt;div&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.bnsit.pl/files/strategie_decouplingu.pdf"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;" src="http://bp2.blogger.com/_wQFWfmLrUy4/SFq_8FmWi_I/AAAAAAAAAC4/hpwTTs8-hoU/s200/PDF-Icon.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5213690557650865138" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a style="color:#773607; text-decoration:underline; font-weight:normal" href="http://www.bnsit.pl/files/tdd_o_co_wlasciwie_chodzi.pdf"&gt;Wersja PDF&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br/&gt;&lt;br /&gt;Szczerze mówiąc nie wiem jak jest w polskich firmach z TDD. Wiem, że testy się pisze, pokrycie się bada, ale jak z samym TDD sprawy się mają – pojęcie mam bliskie zeru. Wszak pisanie testów i TDD to nie to samo.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Testy jednostkowe&lt;/h4&gt;&lt;br /&gt;Wiadomo co to są testy jednostkowe i jak działają – w gruncie rzeczy, chodzi o to, aby rozpocząć testowanie możliwie wcześnie na najbardziej elementarnym poziomie – na poziomie obiektów i ich metod. Co i jak testować – na tym skupię się innym razem. Teraz chodzi mi raczej o wyszczególnienie sytuacji z jakimi można zetknąć się podczas pisania testów jednostkowych.&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;Testy dopisywane są po zakończeniu implementacji – cóż, jeśli w projekcie do tej pory testów nie praktykowano, to nie ma innej rady. Trzeba pamiętać tylko o jednej rzeczy: jeśli istniejąca metoda zawiera buga, który jeszcze się nie objawił, to napisany do niej test traktuje go jako poprawne działanie metody.   Jest tak właśnie dlatego, że test pisany jest do istniejącej metody, przy założeniu że działa ona poprawnie. Trzeba się więc przygotować na niespodzianki.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Najpierw pisany jest cały test, a następnie cała implementacja – jest to kłopotliwe ponieważ: trudno jest od razu zaplanować kompletny test dla metody, po implementacji często okazuje się, że nawet jeśli jest ona poprawna i tak otrzymujemy green bar. Często z tego powodu, że pomyłka była w teście. I co wtedy, o zgrozo, się dzieje? Zmieniany jest test, a to przecież to on miał być naszą ostoją i gwarantem poprawności implementacji. Jak się za chwilę przekonamy, testy i implementację piszemy przyrostowo – po kawałku.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Pisane są zbędne testy w celu podniesienia współczynnika pokrycia – to taki przejaw instynktu samozachowawczego. Narzędzia do badania pokrycia po części wykrywają takie sytuacje. Ocenę tych praktyk pozostawiam Czytelnikowi.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Wykrycie błędów nie powoduje dodania nowego przypadku testowego – jeśli testy nie ewoluują wraz z kodem, to osłabiana jest tkwiąca w nich siła. Każdy błąd wykryty w kodzie powinien spowodować, że: zostanie dodane nowy przypadek testowy wykrywający dany błąd, a następnie implementacja zostanie poprawiona. Dodanie nowego testu zabezpiecza przed ponownym wystąpieniem danego błędu.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Test odpowiada klasie tylko z nazwy – czasami, w magiczny sposób, implementacja znacznie oddala się od testów. Dzieje się to zwłaszcza wtedy, gdy programiści nie mają nawyku rozpoczynania programowania od testu, pozornie brak czasu na testowanie, a jednocześnie w projekcie nie istnieje kontrola kodu.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Zapomina się, że testy również podlegają refaktoringowi oraz wypracowano dla nich stosowne wzorce projektowe – wiadomo, że entropia wzrasta z upływem czasu. Nic dziwnego zatem, jeśli w pewnym momencie kod klasy testującej jest tak obrzydliwy i ciężki, że wcale nie chce się go czytać. Wzorce i refaktoring testów to temat na osobny artykuł.&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Filozofia TDD&lt;/h4&gt;&lt;br /&gt;Całe TDD można zamknąć w powiedzeniu: „Kapitanowi, który nie wie dokąd płynie, każdy wiatr jest na rękę”. TDD stwierdza wprost: najpierw postaw cel, a potem do niego zmierzaj – najpierw test, potem implementacja. Ma to dawać następujące korzyści: tworzony jest tylko niezbędny kod – ten który jest istotny dla osiągnięcia celu, rozwiązanie jest przemyślane, ze względu na konieczność rozpoczynania od testu, TDD wymusza dobry projekt obiektowy, gdyż testowanie kodu luźno traktującego inżynierię oprogramowania, to droga przez mękę. Dodatkowo posiadanie zestawu dobrych testów to rzecz absolutnie konieczna jeśli chce się myśleć o bezpiecznym refaktoringu kodu.&lt;br /&gt;Zatem jeśli najpierw należy napisać test, to jak ma wyglądać cały proces? &lt;br /&gt;Wspomniałem wcześniej, że pisanie kompletnego testu, a następnie kompletnej implementacji nie jest dobrą praktyką. Zatem jak? Otóż, przyrostowo, spiralnie – kawałek testu, kawałek implementacji. &lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;Napisz fragment testu&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Napisz najprostszy możliwy kod, który spełnia test&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Zrefaktoruj implementację do pożądanego stanu&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Czy implementacja wciąż spełnia test?&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;Tak: Jeśli implementacja nie zakończona idź do 1&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Nie: Idź do 3&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;Powyżej znajduje się ramowy algorytm tworzenia oprogramowanie poprzez TDD. Warto podkreślić istotność punktu 2. Dlaczego piszemy najprostszą możliwą implementację spełniającą test? Aby przekonać się czy test jest poprawny. Dlatego właśnie pisanie kompletnego testu od razu jest niewskazane – trudno jest zweryfikować jego poprawność. &lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Red-Green-Refactor: przykład Eclipse'a wzięty&lt;/h4&gt;&lt;br /&gt;Załóżmy, że tworzony jest sklep internetowy. Pierwszą funkcjonalnością, którą warto się zająć jest koszyk, z którego będzie korzystał użytkownik. Zaczniemy od odnajdywania produktów w koszyku.&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;Tworzę szkielet klas:&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;public class CartManager {&lt;br /&gt;    public Product findProduct( String name ) {&lt;br /&gt;        return null;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public class Product {&lt;br /&gt;    private String name;&lt;br /&gt;    //...&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Tworzę fragment testu jednostkowego jednostkowego:&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;public class CartManagerTest extends TestCase {&lt;br /&gt;    public void testFindProduct() {&lt;br /&gt;        CartManager cartManager = new CartManager();&lt;br /&gt;&lt;br /&gt;        Product product = cartManager&lt;br /&gt;            .findProduct( &amp;quot;myProduct&amp;quot; );&lt;br /&gt;&lt;br /&gt;        assertNotNull( product );&lt;br /&gt;    }    &lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Uruchamiam test:  Red Bar &lt;/li&gt;&lt;br /&gt;&lt;li&gt;Refaktoruję implementację metody (&lt;span style="font-weight:bold;"&gt;najprostsza możliwa implmentacja!&lt;/span&gt;):&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;public Product findProduct( String name ) {&lt;br /&gt;    return new Product();&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Uruchamiam test:  Green Bar &lt;/li&gt;&lt;br /&gt;&lt;li&gt;Rozbudowuję test:&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;public void testFindProduct() {&lt;br /&gt;    CartManager cartManager = new CartManager();&lt;br /&gt;    Product product = cartManager.findProduct( &amp;quot;myProduct&amp;quot; );&lt;br /&gt;        &lt;br /&gt;    assertNotNull( product );&lt;br /&gt;    assertEquals( &amp;quot;myProduct&amp;quot; , product.getName() );&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Uruchamiam test:  Red Bar &lt;/li&gt;&lt;br /&gt;&lt;li&gt;Refaktoruję implementację metody (&lt;span style="font-weight:bold;"&gt;najprostsza możliwa implmentacja!&lt;/span&gt;):&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;public Product findProduct( String name ) {&lt;br /&gt;    Product product = new Product();&lt;br /&gt;    product.setName( &amp;quot;myProduct&amp;quot; );&lt;br /&gt;    return product;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Uruchamiam test:  Green Bar &lt;/li&gt;&lt;br /&gt;&lt;li&gt;Refaktoruję implementację klasy:&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;public class CartManager {&lt;br /&gt;    private Map&amp;lt;String, Product&amp;gt; cartMap&lt;br /&gt;         = new HashMap&amp;lt;String, Product&amp;gt;();&lt;br /&gt;&lt;br /&gt;    public Product findProduct( String name ) {&lt;br /&gt;        Product product = new Product();&lt;br /&gt;        product.setName( &amp;quot;myProduct&amp;quot; );&lt;br /&gt;        &lt;br /&gt;        cartMap.put( &amp;quot;myProduct&amp;quot; , product );&lt;br /&gt;        return cartMap.get( &amp;quot;myProduct&amp;quot; );&lt;br /&gt;    }    &lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Uruchamiam test: wciąż  Green Bar &lt;/li&gt;&lt;br /&gt;&lt;li&gt;1.Refaktoruję test:&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;public void testFindProduct() {&lt;br /&gt;    CartManager cartManager = new CartManager();&lt;br /&gt;    final String PRODUCT_NAME = &amp;quot;myProduct&amp;quot;; &lt;br /&gt;        &lt;br /&gt;    Product putProduct = new Product();&lt;br /&gt;    putProduct.setName( PRODUCT_NAME );&lt;br /&gt;        &lt;br /&gt;    Map&amp;lt;String, Product&amp;gt; cartMap&lt;br /&gt;         = new HashMap&amp;lt;String, Product&amp;gt;();&lt;br /&gt;    cartMap.put( PRODUCT_NAME , putProduct );&lt;br /&gt;        &lt;br /&gt;    cartManager.setCartMap( cartMap );&lt;br /&gt;        &lt;br /&gt;    Product product = cartManager.findProduct( PRODUCT_NAME );&lt;br /&gt;        &lt;br /&gt;    assertNotNull( product );&lt;br /&gt;    assertEquals( PRODUCT_NAME , product.getName() );&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Uruchamiam test: wciąż  Green Bar &lt;/li&gt;&lt;br /&gt;&lt;li&gt;Dodaję do testu nową asercję:&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;public void testFindProduct() {    &lt;br /&gt;    //...    &lt;br /&gt;    assertNotNull( product );&lt;br /&gt;    assertEquals( PRODUCT_NAME , product.getName() );&lt;br /&gt;    assertSame( putProduct , product );&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Uruchamiam test:  Red Bar &lt;/li&gt;&lt;br /&gt;&lt;li&gt;Refaktoruję implementację metody:&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;public Product findProduct( String name ) {&lt;br /&gt;    return cartMap.get( &amp;quot;myProduct&amp;quot; );&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Uruchamiam test:  Green Bar &lt;/li&gt;&lt;br /&gt;&lt;li&gt;1.Refaktoruję implementację metody:&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;public Product findProduct( String name ) {&lt;br /&gt;    return cartMap.get( name );&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Uruchamiam test:  Green Bar &lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;To wszystko jeśli chodzi o zasadniczą funkcjonalność wyszukiwania w koszyku. Zadanie domowe brzmi następująco: jeśli w koszuku nie ma produktu o danej nazwie metoda findProduct powinna rzucić wyjątek. Dodaj tę funcjonalność pracując zgodnie z TDD. Podpowiedź: aby wymusić red bar użyj metody &lt;span style="font-style:italic;"&gt;fail()&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Czyli...&lt;/h4&gt;&lt;br /&gt;Gdybym chciał wybrać jedną rzecz do zapamiętania z tego artykułu to powiedziałbym: kawałek testu, kawałek implementacji...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1759916214638009707-1488494735726829548?l=mbartyzel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mbartyzel.blogspot.com/feeds/1488494735726829548/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1759916214638009707&amp;postID=1488494735726829548' title='Komentarze (2)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/1488494735726829548'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/1488494735726829548'/><link rel='alternate' type='text/html' href='http://mbartyzel.blogspot.com/2008/07/tdd-o-co-waciwie-chodzi.html' title='TDD: O co właściwie chodzi?'/><author><name>Michał Bartyzel</name><uri>http://www.blogger.com/profile/03968505875451301931</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://bp2.blogger.com/_wQFWfmLrUy4/SFq_8FmWi_I/AAAAAAAAAC4/hpwTTs8-hoU/s72-c/PDF-Icon.jpg' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1759916214638009707.post-5143731863535257270</id><published>2008-07-18T09:45:00.002+02:00</published><updated>2008-07-21T16:15:53.514+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='antywzorce'/><category scheme='http://www.blogger.com/atom/ns#' term='rozwój'/><title type='text'>Antywzorce w pracy programistów: Wymyślanie koła na nowo</title><content type='html'>Zastanawiam się czy wymyślanie koła na nowo ma sens. Ktoś napisał, że jeśli ma być ono bardziej okrągłe niż dotychczasowe to tak. Trudno odmówić sensu temu stwierdzeniu. Ja rozumiem je jako udoskonalanie istniejących rzeczy. Proces udoskonalania jest oczywiście dobry i potrzebny. Jednak podczas programowania „wymyślanie koła na nowo” nabiera czasem nowego, złowieszczego charakteru.&lt;br /&gt;&lt;br /&gt;Większość problemów, z którymi się spotkałeś została już rozwiązana. Większość bibliotek, które opracowujesz po nocach została już napisana. Większość algorytmów, które wymyślasz w przypływie twórczego geniuszu już została opublikowana. Dlaczego więc nie korzystasz z tego bogactwa wiedzy?Napisałem „większość”, uwzględniając fakt, że „są na niebie i ziemi rzeczy, o których nie śniło się filozofom".&lt;br /&gt;&lt;br /&gt;Jeśli Twoje, z pasją tworzone, autorskie rozwiązania mają charakter edukacyjny albo zwyczajnie robisz to dla własnej satysfakcji – tym lepiej dla Ciebie. Nauczysz się czegoś ciekawego i będziesz dobrze się bawić. Lecz jeśli pracujesz i zależy Ci na wydajności – korzystaj z dorobku innych. Pamiętaj, że ludzie po prostu kochają dzielić się swoją wiedzą i doświadczeniem. Gdyby było inaczej, nie mielibyśmy w internecie żadnej grupy dyskusyjnej.&lt;br /&gt;&lt;br /&gt;Kłopot w tym, że większość uczelni kształcących programistów zniechęca do korzystania zewnętrznych bibliotek. No, bo po co używać JGAP w programie skoro można napisać algorytm genetyczny samemu? W ciągu pięciu lat takiej metodyki nauczania studenci nabierają dziwnych nawyków nieoptymalnej pracy, a potem przyjmując studentów do pracy musimy ich tego oduczać...ech...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1759916214638009707-5143731863535257270?l=mbartyzel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mbartyzel.blogspot.com/feeds/5143731863535257270/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1759916214638009707&amp;postID=5143731863535257270' title='Komentarze (4)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/5143731863535257270'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/5143731863535257270'/><link rel='alternate' type='text/html' href='http://mbartyzel.blogspot.com/2008/07/antywzorce-w-pracy-programistw.html' title='Antywzorce w pracy programistów: Wymyślanie koła na nowo'/><author><name>Michał Bartyzel</name><uri>http://www.blogger.com/profile/03968505875451301931</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1759916214638009707.post-3415689566921987947</id><published>2008-07-11T09:03:00.004+02:00</published><updated>2008-07-11T19:40:37.042+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='antywzorce'/><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><category scheme='http://www.blogger.com/atom/ns#' term='rozwój'/><title type='text'>Antywzorce w pracy programistów: The error is out there</title><content type='html'>&lt;div&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.bnsit.pl/files/strategie_decouplingu.pdf"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;" src="http://bp2.blogger.com/_wQFWfmLrUy4/SFq_8FmWi_I/AAAAAAAAAC4/hpwTTs8-hoU/s200/PDF-Icon.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5213690557650865138" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a style="color:#773607; text-decoration:underline; font-weight:normal" href="http://www.bnsit.pl/files/the_error_is_out_there.pdf"&gt;Wersja PDF&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br/&gt;&lt;br /&gt;Coraz częściej dochodzę do wniosku, że sposób pracy programistów nie został jeszcze całkowicie zbadany. Lawina, którą zapoczątkowali Gang of Four zbiera coraz większe żniwo. Zaczęliśmy od wzorców projektowych w tworzeniu kodu, dalej już popłynęło wzorce w projektowaniu stron www, wzorce J2EE (w innych technologiach pewnie też), wzorce integracyjne, wzorce, wzorce, wzorce...&lt;br /&gt;&lt;br /&gt;Nie sposób zauważyć, że choć odkrywanie wzorców projektowych przebiega bardzo ekspansywnie, to jednak ogranicza się on tylko do jednej płaszczyzny: umiejętności technicznych. Nietrudno odgadnąć przyczynę tego stanu rzeczy, wszak pracujemy w konkretnej technologii, za pomocą konkretnych narzędzi i biegłość w praktyce jest gwarantem naszej atrakcyjności jako profesjonalisty w zawodzie.&lt;br /&gt;&lt;br /&gt;Pracując z programistami w trakcie szkoleń, jako zewnętrzny konsultant, czy też jako członek zespołu, zauważam, że doskonalenie naszych umiejętności i poszukiwanie wzorców powinno odbywać się w co najmniej dwóch płaszczyznach. Pierwsza – wspomniane wcześniej umiejętności techniczne – rozwija się bardzo ekspansywnie. Druga – umiejętności nietechniczne (mniejsza teraz o nazwę) – trzeba przyznać, że trochę kuleje. Nie tak dawno pisałem o tego rodzaju umiejętnościach w artykule &lt;a href=”http://mbartyzel.blogspot.com/2008/06/wersja-pdf-jeli-jeste-programist-albo-w.html”&gt;Metaprogramy w tworzeniu oprogramowania&lt;/a&gt;. Od tamtej chwili rosła we mnie chęć poszukiwania dobrych praktyk programistycznych na nietechnicznym poziomie. Owa chęć nabiera kształtu w niniejszym artykule. Postanowiłem sobie tropić wzorce w pracy programistów. Ponieważ łatwiej mi najpierw zdefiniować antywzorzec, to od nich właśnie zacznę. Będę wyróżniał postawy i schematy działania, które w moim odczuciu negatywnie wpływają na pracę programisty i jeśli to możliwe będę poszukiwał remedium.&lt;br /&gt;&lt;br /&gt;Kilka postów wcześniej pisałem o postawie roboczo nazwanej &lt;a href=”http://mbartyzel.blogspot.com/2008/06/wzorzec-job-security.html”&gt;Job Security&lt;/a&gt;, którą z cała pewnością można można nazwać antywzorcem. Teraz czas na drugi, który pozwoliłem sobie nazwać: &lt;span style="font-weight:bold;"&gt;The error is out there&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Niełatwo zapanować na tym schematem postępowania. Gdy poszukujemy przyczyny wadliwego działania kodu, niemal zawsze przyjmowane jest milczące założenie, że przyczyną błędu jest wadliwie działający framework, lub błąd w bibliotece, lub błąd w systemie, lub błąd współpracownika, lub działanie sił wyższych. Po kilku godzinach poszukiwań okazuje się jednak, że przyczyną zamieszania była literówka. Oczywiście wszystkie z uprzednio wymienionych błędów mogą się zdarzyć, lecz najczęściej wina leży po naszej stronie. Z jakiś powodów programiści odczuwają opór przed zaakceptowaniem faktu, że to oni mogą być przyczyną swoich niepowodzeń. A spróbuj takiemu programiście powiedzieć, że to on jest przyczyną błędu! Zdarzyło mi się parę razy narobić sobie w ten sposób wrogów, więc teraz jestem ostrożny w tego typu komentarzach.&lt;br /&gt;Jak zatem sobie radzić w tego typu sytuacjach? Pytanie trzeba rozbić na dwie części. Po pierwsze, jak radzić sobie jeśli komuś pomagam oraz jak radzić sobie jeśli problem dotyczy mnie samego.&lt;br /&gt;&lt;br /&gt;W pierwszym przypadku jest dużo prościej. Tak to już jest, że szybciej dostrzegamy czyjeś błędy niż nasze własne. Jeśli chcę komuś pomóc to unikam mówienia wprost o jego błędach – to zwyczajnie nie działa. Sprawdzają się za to niedyrektywne metafory, np. „Mój kolega też miał podobny problem i...”. Buduję krótką historyjkę o „moim koledze”, w której przekazuję wskazówki odnośnie możliwych rozwiązań. Metoda sprawdza się w 90% przypadków. Pozostałe 10% albo wymaga bardziej wyrafinowanych metod albo trafiliśmy na nieuleczalny przypadek.&lt;br /&gt;&lt;br /&gt;Sprawy stają się bardziej skomplikowane, gdy chodzi o nas samych. Kluczem do sukcesu w tej materii jest rozwijanie umiejętności introspekcji. Wyjściowym ćwiczeniem może być tu przyjęcie założenia, że „przyczyna wadliwego działania aplikacji leży po mojej stronie”. Zdaję sobie sprawę, że reguła nie sprawdza się w 100% przypadków, ale w większości tak. Przyjęcie tego wstępnego założenia znacząco oszczędza czas. Dopiero po upewnieniu się, za pomocą możliwie obiektywnych kryteriów (warto poprosić kogoś o przeanalizowanie problemu) można przystąpić do oskarżania bibliotek i  frameworków o spowodowanie kłopotów.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1759916214638009707-3415689566921987947?l=mbartyzel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mbartyzel.blogspot.com/feeds/3415689566921987947/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1759916214638009707&amp;postID=3415689566921987947' title='Komentarze (2)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/3415689566921987947'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/3415689566921987947'/><link rel='alternate' type='text/html' href='http://mbartyzel.blogspot.com/2008/07/antywzorce-w-pracy-programistw-error-is.html' title='Antywzorce w pracy programistów: The error is out there'/><author><name>Michał Bartyzel</name><uri>http://www.blogger.com/profile/03968505875451301931</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://bp2.blogger.com/_wQFWfmLrUy4/SFq_8FmWi_I/AAAAAAAAAC4/hpwTTs8-hoU/s72-c/PDF-Icon.jpg' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1759916214638009707.post-7980513422898503796</id><published>2008-07-04T16:18:00.005+02:00</published><updated>2008-07-11T19:40:02.395+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='wzorce'/><category scheme='http://www.blogger.com/atom/ns#' term='architektura'/><title type='text'>Iluzja O/RM</title><content type='html'>Gdy po raz pierwszy dałem się uwieść wspaniałemu konceptowi O/RM, Hibernate był w wersji 2 z kawałkiem, a o JPA nawet nie słyszałem.&lt;br /&gt;Idea jest naprawdę wspaniała: raz mapujesz pomiędzy tabelami a obiektami, ba (!) nawet framework stworzy schemat bazy danych za ciebie, a potem już tylko pracujesz z obiektami - programista obiektowy swoją drogą, bazodanowiec swoją. Prawdziwy raj!&lt;br /&gt;&lt;br /&gt;We wspomnianej wersji Hibernate'a pałętało się sporo plików xml, ale wspomagając się xdocletem można było jakoś przeżyć. Weszły anotacje i miało być jeszcze prościej, wspanialej - no, słowem obiektowa orgia.&lt;br /&gt;&lt;br /&gt;Moim zdaniem wcale nie jest tak kolorowo. Po pierwsze dlatego, że nie możliwe jest zmapowanie O/R raz na zawsze. Baza danych wciąż o sobie przypomina. A to wyskoczy jakiś constraint i trzeba pogrzebać w bazie w poszukiwaniu przyczyn (a potem okazuje się, że to jakiś błąd mapowania:]), a to model obiektowy ulega refaktoringowi albo rozbudowie i znów należy wracać do bazy danych - wciąż wracamy do bazy danych stojąc okrakiem pomiędzy obiektami i relacjami.&lt;br /&gt;&lt;br /&gt;Kolejną kwestią jest to, że cała idea O/RM skłania do zaniedbywania bazy danych (myślimy - nie jest moją rzeczą zajmować się bazą danych, jestem programistą obiektowym...). W związku z czym baza jest projektowana niechlujne lub (o zgrozo!) pozwala się frameworkom na zarządzanie schematem. Prowadzi to tak wielkiej kaszany w bazie danych, jak wielka kaszana tylko może być: każdy obiekt ma swoją tabele, istnieje wiele tabel zawierających po kilka wierszy ("a, bo mnie tak wyszło z mapowania..."), tabele z jedną kolumną są na porządku dziennym.&lt;br /&gt;&lt;br /&gt;Do czego to prowadzi? Ano, bywa, że O/RM mają problem z wydajnością i czasem korzystnie jest wspomóc się jakimiś procedurami składowanymi i widokami. W takim momencie okazuje się, że praca ze schematem zarządzanym przez O/R M to gorzej niż czyściec dla duszy programisty.&lt;br /&gt;&lt;br /&gt;W pewnym momencie rozwoju J(2)EE było paru ludzi (żeby nie wymieniać nazwisk), którzy pchnęli dalszy rozwój technologii w określonym kierunku. A społeczność za tym poszła, bo wizja była fajna. Aktualnie mam na myśli idę O/RM i całą resztę kryjąca się za wzorcem &lt;i&gt;Domain Store&lt;/i&gt;. A przecież istnieją rozwiązania, które społeczności Javy zostały zignorowane, a które świetnie się sprawdzają w innych technologiach. Mówię rozwiązaniach, które warstwę danych organizują w okół bazy danych, a nie w okół modelu obiektowego, np: Oracle BC4J albo implementacja Active Record w Ruby on Rails&lt;br /&gt;&lt;br /&gt;O faworyzowaniu pewnych rozwiązań świadczy choćby fakt, że do tej pory nie doczekaliśmy się popularnej i w pełni funkcjonalnej implementacji Active Record dla Javy. Myślę, że mogło by to wnieść wiele dobrego do aplikacji, które rozwijamy.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1759916214638009707-7980513422898503796?l=mbartyzel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mbartyzel.blogspot.com/feeds/7980513422898503796/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1759916214638009707&amp;postID=7980513422898503796' title='Komentarze (11)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/7980513422898503796'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/7980513422898503796'/><link rel='alternate' type='text/html' href='http://mbartyzel.blogspot.com/2008/07/iluzja-orm.html' title='Iluzja O/RM'/><author><name>Michał Bartyzel</name><uri>http://www.blogger.com/profile/03968505875451301931</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>11</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1759916214638009707.post-5064992097127647476</id><published>2008-06-25T20:48:00.004+02:00</published><updated>2008-07-11T19:39:24.878+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='antywzorce'/><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><title type='text'>Wzorzec Job Security</title><content type='html'>Prowadząc szkolenia z refaktoringu, coraz częściej natykam się na pewien specyficzny schemat zachowania. Schemat, który napawa mnie przerażeniem i kładzie cień na moich programistycznych ideałach. A było to tak...&lt;br /&gt;&lt;br /&gt;Wykładałem pracowicie cel refaktoringu, konkretne techniki właściwe dla poszczególnych warstw i technologii i...nic jak grochem o ścianę - wszyscy uparcie twierdzili, że ich manager w życiu nie zgodzi się na poświęcenie choćby chwili na refaktoring. Przeszedłem więc do broni masowego rażenia - korzyści płynące ze stosowania refaktoringu:&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;Kod jest łatwiejszy w czytaniu&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Łatwiej jest dokładać nowe funkcjonalności&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Wdrożenie nowej osoby do projektu zajmuje mniej czasu&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Testowanie kodu jest łatwiejsze&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Odnajdywanie błędów trwa krócej&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Rozbudowywanie projektu zajmuje mniej czasu&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;A zatem, argumentowałem, potencjalnie zyskujemy najcenniejszy zasób: czas. A czas to, jak wiadomo, pieniądz! Zatem manager musi zgodzić się na rozprzestrzenianie praktyki refaktoringu...&lt;br /&gt;&lt;br /&gt;Słuchaj, Michał - powiedział jeden z uczestników szkolenia - jeśli napiszę w czasie krótszym niż mój manager to oszacował to dostanę kolejny projekt. Dodatkowo na projekt zostanie przydzielone mniej czasu, bo już pokazałem, że potrafię pracować efektywniej. I tak z każdym kolejnym projektem mój manager wyciśnie ze mnie wszystkie soki. Jeśli dostanę 10 dni na skończenie projektu, to choćbym wyrobił się w 3, nigdy się do tego nie przyznam. Nie opłaca mi się. Poza tym, mam płacone za każdą nadgodzinę. Im dłużej pracuję, tym więcej zarabiam.&lt;br /&gt;Powiedziałeś, że łatwiej jest wdrażać nowe osoby do projektu. Też mi korzyść! A jeśli nowy będzie lepszy ode mnie? Wtedy ja wylecę z roboty. Piszę mój kod tak, żebym tylko ja mógł go zrozumieć. Być może praca z JSP liczącym 2000 wierszy nie jest zbyt wygodna, ale przynajmniej wiem, że będę potrzebny. Wiem, że będę miał pracę. Refaktoring jest mi zbędny.&lt;br /&gt;&lt;br /&gt;Szczerze mówiąc nie wiedziałem co odpowiedzieć na takie dictum...Myślałem, że gdy podzielę się tą historią, to będzie mi lepiej. Nie jest ;/&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1759916214638009707-5064992097127647476?l=mbartyzel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mbartyzel.blogspot.com/feeds/5064992097127647476/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1759916214638009707&amp;postID=5064992097127647476' title='Komentarze (3)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/5064992097127647476'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/5064992097127647476'/><link rel='alternate' type='text/html' href='http://mbartyzel.blogspot.com/2008/06/wzorzec-job-security.html' title='Wzorzec Job Security'/><author><name>Michał Bartyzel</name><uri>http://www.blogger.com/profile/03968505875451301931</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1759916214638009707.post-8720144078749405469</id><published>2008-06-24T19:52:00.010+02:00</published><updated>2008-07-11T19:38:49.692+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='rozwój'/><category scheme='http://www.blogger.com/atom/ns#' term='zarządzanie'/><category scheme='http://www.blogger.com/atom/ns#' term='praca z klientem'/><title type='text'>Metaprogramy w tworzeniu oprogramowania</title><content type='html'>&lt;div&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.bnsit.pl/files/strategie_decouplingu.pdf"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;" src="http://bp2.blogger.com/_wQFWfmLrUy4/SFq_8FmWi_I/AAAAAAAAAC4/hpwTTs8-hoU/s200/PDF-Icon.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5213690557650865138" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a style="color:#773607; text-decoration:underline; font-weight:normal" href="http://www.bnsit.pl/files/metaprogramy_w_tworzeniu_oprogramowania.pdf"&gt;Wersja PDF&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br/&gt;&lt;br /&gt;Jeśli jesteś programistą albo w jakikolwiek inny sposób związany z branżą IT, to najprawdopodobniej po przeczytaniu tytułu, spodziewałeś się  porcji informacji technicznych. Muszę Cię zaskoczyć, artykuł będzie o innych programach i o innym programowaniu niż sobie wyobrażasz. &lt;br /&gt;&lt;br /&gt; Ludzie posługują się swoimi myślami w zorganizowany sposób. Dzieje się to często na poziomie nieświadomym. Gdy o czymś myślimy, w umyśle pojawiają się różnego rodzaju obrazy, odczucia czy dźwięki. Choć nie zawsze zdajemy sobie z tego sprawę, w ten właśnie sposób przetwarzamy informacje docierające z zewnątrz (i z wewnątrz). &lt;br /&gt;&lt;br /&gt; Psycholingwistyce zawdzięczamy badania nad tą wewnętrzną organizacją codziennych doświadczeń. Okazuje się, że można wyróżnić pewne schematy, że ludzie posługują się pewnymi wzorcami zachowań, które nazwano metaprogramami. Metaprogramy zostały pogrupowane w przeciwstawne, uzupełniające się pary scenariuszy w następujący sposób:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Unikanie – Dążenie&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Autorytet wewnętrzny – Autorytet zewnętrzny&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Podobieństwa – Różnice&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Ja – Inni&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Informacje szczegółowe – Informacje globalne&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Proaktywne – Reaktywne&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Opcje – Procedury&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;Dla osoby skoncentrowanej na unikaniu, bodźcem do działania będzie chęć uniknięcia niepożądanych sytuacji. Przeciwnie, dla osoby posługującej się metaprogramem Dążenie, ważniejsze będzie osiągnięcie wyznaczonego celu. Czytelników zainteresowanych dokładnym poznaniem metaprogramów odsyłam do literatury.&lt;br /&gt;&lt;h4&gt;Preferowane metaprogramy&lt;/h4&gt;&lt;br /&gt; W praktyce nigdy nie jest tak, aby dany scenariusz np. Unikanie występował w czystej formie. Jest tak przede wszystkim dlatego, że procesy myślowe są w swej naturze zbyt skomplikowane (i jeszcze wiele jest do odkrycia), by opisać je za pomocą tak prostego modelu jakim są metaprogramy. Koncept metaprogramów należy traktować zatem jako pewne przybliżenie rzeczywistości o ograniczonym zakresie stosowalności.&lt;br /&gt;&lt;br /&gt; Używanie metaprogramu jest zależne od kontekstu (kontekstualizm), środowiska w którym znajduje się człowiek. Ktoś na co dzień skoncentrowany na Dążeniu może radykalnie zmienić sposób myślenia, gdy ucieka przed goniącym go psem – wtedy najprawdopodobniej skupi się na uniknięciu niebezpieczeństwa, bez znaczenia w jaki sposób.&lt;br /&gt;&lt;br /&gt; Bardzo istotne jest to, że metaprogramy nie podlegają ewaluacji. Żaden z nich nie jest lepszy lub gorszy – są inne. Jedyne co można powiedzieć to, że dany scenariusz może być mniej lub bardziej użyteczny w określonej sytuacji. Zadaniem artykułu jest, przede wszystkim, pobudzenie do refleksji nad własnym stylem pracy.&lt;br /&gt;&lt;br /&gt; Choć obserwując zachowania ludzi, można wskazać pewne przejawy każdego z metaprogramów to jednak poszczególne osoby mają osobiste preferencje. Najczęściej 1 do 3 metaprogramów dominuje, pozostałe pojawiają się sporadycznie. W dalszej części zastanowimy się, które z metaprogramów są najistotniejsze w pracy programisty.&lt;br /&gt;&lt;h4&gt;Zbieranie wymagań&lt;/h4&gt;&lt;br /&gt; Zbieranie wymagań oraz modelowanie systemu są czynnościami o tyle ważnymi, że kierunkują dalsze prace zespołu. Prace nad projektem rozpoczynają się (powinny się rozpoczynać) od stworzenia jego wizji. Wizja, w postaci metafory, jest metacelem, do którego zmierzać będzie projekt w kolejnych fazach rozwoju. Dalej wyłania się zbiór wymagań, zestaw procesów, w których może brać udział użytkownik. Pojawia luźny koncept rozwiązania i będzie uszczegóławiany w dalszych krokach. &lt;br /&gt;&lt;br /&gt; W opisanym wyżej procesie projektowania zauważamy, że prace odbywają się na poziomie ogólnym. Programiści/projektanci wykazują w tym miejscu tendencję do skupiania się na konkretnym rozwiązaniu. Podczas rozmowy z potencjalnym użytkownikiem, od którego należy zebrać wymagania, deweloper stara się podążać za tokiem myślowym rozmówcy. Jednocześnie zastanawia się, czy i jak konkretne wymaganie zostanie zrealizowane. Myślenie o rozwiązaniu jest jak najbardziej w porządku tyle, że nie na to jest miejsce podczas zbierania wymagań, gdy należy się skoncentrować na zrozumieniu wyobrażeń użytkownika o sposobie pracy z przyszłym narzędziem. Z tego względu zbieranie wymagań warto przeprowadzać w sesjach, np.: godzinę rozmowy z użytkownikiem, a następnie pół godziny na analizę wymagań i formułowanie dodatkowych pytań. &lt;br /&gt;&lt;br /&gt; W artykule &lt;a href="http://mbartyzel.blogspot.com/2008/05/klient-ktry-wie-czego-chce.html"&gt;Klient, który wie, czego chce&lt;/a&gt; rozważałem różnice w sposobie myślenia analityka i klienta. Głównym wnioskiem było to, że klienci jednak wiedzą, czego chcą. Opisują to jednak w postaci procesów, natomiast analityk widzi system jako strukturę. Podążając za procesem łatwiej dokonywać w nim zmian. Z kolei zmiany wprowadzane w strukturze wymagają przeanalizowania całej koncepcji od nowa. Podczas zbierania wymagań klient często zastanawia się nad pożądanym sposobem pracy. Próbuje różnych alternatywnych przebiegów tego samego procesu i oczekuje od analityka pomocy w wyborze najlepszego rozwiązania. Jeśli analityk nie podąża w procesie za klientem, lecz percypuje system jako strukturę, to ma nie lada kłopot. Alternatywne ścieżki procesu klienta zazwyczaj mają istotny wpływ na domniemaną strukturę systemu i/lub implementację. &lt;br /&gt;&lt;br /&gt; Dochodzimy do kolejnego, istotnego w pracy programisty, metaprogramu: Opcje – Procedury. Najczęściej klient chce próbować różnych możliwości – jest nastawiony na opcje. Analityk powinien wyjść naprzeciw tym oczekiwaniom. Należy przypomnieć fakt, że nastawienie na opcje może nie być głównym metaprogramem klienta. Jednak w kontekście zbierania wymagań, gdy zastanawia się on nad sposobem pracy z narzędziem i analizuje różne procesy, najczęściej chce mieć możliwość wybrania najlepszego rozwiązania spośród dostępnych.&lt;br /&gt;&lt;br /&gt; Podsumowując część o zbieraniu wymagań stwierdzamy, że w tym kontekście pracy programisty ważne jest nastawienie na Ogół oraz na Opcje. Te sposoby myślenia pozwalają pozostać na odpowiednim poziomie abstrakcji i skupić się na wizji i celu istnienia systemu zamiast brnąć w konkretne technologie i rozwiązania tylko po to, aby w następstwie późniejszych decyzji w pośpiechu się z nich wycofywać.&lt;br /&gt;&lt;h4&gt;Programowanie&lt;/h4&gt;&lt;br /&gt; Po zebraniu wymagań i zaplanowaniu prac przychodzi czas na implementację. W chwili obecnej role projektanta oraz programisty przenikają w projekcie. Myślę, że to dobrze, gdyż można w pełni wykorzystać potencjał tkwiący w programistach. W tej sytuacji deweloperzy dostają pewne wytyczne z projektem systemu i mają dość dużą dowolność w implementowaniu poszczególnych klas oraz metod.&lt;br /&gt;&lt;br /&gt; Implementacja złożonego systemu informatycznego, gdzie współpracuje ze sobą wiele niezależnych bytów, jest skomplikowanym zadaniem. Na tym etapie programujemy już konkretne zachowania i procesy. Od programisty oczekujemy, że będzie potrafił uzasadnić wybór tego, a nie innego rozwiązania. Dodatkowo należy przestrzegać obowiązujących w zespole konwencji kodowania, zasad projektowania, wytycznych pisania testów, itp. Nie ma tu miejsca na swobodną twórczość albo raczej ma ona miejsce drugorzędne. Ważniejsze jest przestrzeganie określonych zasad – procedur. Ujawnia się nam  kolejny scenariusz pomocny programiście: Procedury. Osoba, sprawnie posługująca się procedurami, rozważa rzeczywistość jako ciąg logicznych następstw, gdzie każde zdarzenie ma swoją przyczynę oraz konsekwencje. Intuicyjnie czujemy, że Procedury to jeden największych sprzymierzeńców programistów. Możemy być dumni z faktu, że wykorzystujemy metaprogram do tworzenia wspaniałego oprogramowania.&lt;br /&gt;&lt;br /&gt; Warto jeszcze poruszyć jeszcze jeden aspekt programowania, istotny w kontekście rozważania metaprogramów. Mowa o abstrahowaniu. Języki obiektowe dają sposobność budowania złożonych zależności pomiędzy klasami dzięki np. dziedziczeniu, polimorfizmowi, interfejsom. Możliwości te, aż same zachęcają do ich korzystania. Istota kwestii leży w sposobie korzystania z tych udogodnień. Gdy programista implementuje daną funkcjonalność ma tendencję do tworzenia całej gamy abstrakcyjnych bytów „na wyrost”. Efekt jest taki, że w projekcie każda klasa implementuje specyficzny interfejs (nie używany nigdzie indziej) oraz posiada, do niczego nie potrzebną, klasę abstrakcyjną. Z kolei podczas używania danych klas i tak wszędzie następuje rzutowanie na obiekty konkretne. Przyczyną takiego tworzenia kodu jest „zachłyśnięcie się” paradygmatem reużywalności i elastyczności komponentów. Oczywiście paradygmat ten jest jak najbardziej słuszny, lecz sposób jego egzekwowania już nie. Błąd programisty polega na próbie zaprojektowanie stworzenia maksymalnie rozszerzalnego kodu i „zapomina” że każde rozwiązanie ma ściśle określone granice stosowalności. Programista próbuje stworzyć komponenty możliwe do zastosowania wszędzie (Golden Hammer). Popatrzmy na poniższy kod:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;public interface Problem {&lt;br /&gt; //...&lt;br /&gt;}&lt;br /&gt;public interface Solution {&lt;br /&gt; //...&lt;br /&gt;}&lt;br /&gt;public interface UniversalProblemSolver {&lt;br /&gt; public Solution solve( Problem problem );&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;Właściwie każda klasa mogłaby implementować interfejs UniversalProblemSolver, prawda? Gdy tworzymy kod, który ma dostarczać określoną funkcjonalność i koncentrujemy się przede wszystkim na jego uniwersalności, zamiast na konkretnym zadaniu które ma wykonać, popadamy w opisaną wyżej pułapkę. W takiej sytuacji myślimy poprzez Ogół i tworząc abstrakcyjne byty, zmierzamy do celu wyjątkowo krętą ścieżką.&lt;br /&gt;&lt;br /&gt; Optymalne programowanie wymaga podejścia od strony Szczegółu. Najpierw tworzymy konkretne rozwiązanie implementujące żądaną funkcjonalność. Jeśli w trakcie tworzenia kodu zajdzie potrzeba abstrahowania: wydzielenia hierarchii dziedziczenia, interfejsów – refaktorujemy kod. Praca odbywa się zatem od Szczegółu do Ogółu – w odwrotnym kierunku niż w przypadku zbierania wymagań i modelowania systemu. Ten styl programowania wymaga od deweloperów wewnętrznej samodyscypliny. Warto skorzystać z technik programowania np. Test-Driven Development, które wspomagają ten styl pracy. TDD, dzięki filozofii pisania testu funkcjonalności przed jej implementacją, zabezpiecza przed nadmiarowym „rozdmuchiwaniem” klas i dokładaniem kodu, być może użytecznego, lecz zbędnego z punktu widzenia tworzonego systemu.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Przenoszenie metaprogramów&lt;/h4&gt;&lt;br /&gt; Powyżej wyróżniłem dwa konteksty pracy programisty, w których pożądane jest posługiwanie się odmiennymi scenariuszami metaprogramów Ogół – Szczegół oraz Opcje – Procedury. Ta właśnie potrzeba przełączania się pomiędzy różnymi scenariuszami rodzi wiele kłopotów i frustracji. Jest tak przeważnie dla tego, że „uruchamianie” odpowiedniego metaprogramu odbywa się w sposób nieświadomy. Drugą przyczyną, jak na ironię, jest zdolność do uczenia się. Przypuśćmy, że ktoś uczy się programowania. Po jakimś czasie wykształca sobie pewien sposób myślenia i sprawnie posługuje się scenariuszami Procedury oraz Szczegół. W umyśle człowieka rodzi się skrót myślowy: &lt;em&gt;jeśli TO zadziałało w TYM przypadku, z pewnością zadziała również w TAMTYM&lt;/em&gt;. Ów człowiek, za pomocą metaprogramu, dobrze działającego w jednym kontekście (praca) próbuje wykonywać działanie w zupełnie innym kontekście (np. relacje międzyludzkie). To zjawisko może prowadzić do niepożądanych skutków. Praca nad własnymi metaprogramami uwrażliwia nas na podobne sytuacje i uczy efektywnego funkcjonowania w różnych kontekstach.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Korzyści&lt;/h4&gt;&lt;br /&gt; Najważniejszą, moim zdaniem, korzyścią ze znajomości i rozwijania określonych metaprogramów jest rozszerzenie spektrum możliwych reakcji na sytuacje pojawiające się podczas prac nad projektem. Umiejętność posługiwania sposobami myślenia innymi niż nasze własne sprawia, że efektywniej współpracujemy z klientami, użytkownikami oraz z innymi członkami zespołu. Poniżej wymieniam dodatkowe korzyści:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;pomoc w formowaniu zespołu projektowego&lt;/li&gt;&lt;br /&gt;&lt;li&gt;wyznacznik dla osób rekrutujących programistów&lt;/li&gt;&lt;br /&gt;&lt;li&gt;skrócenie czasu zbierania wymagań&lt;/li&gt;&lt;br /&gt;&lt;li&gt;poprawa komunikacji w zespole&lt;/li&gt;&lt;br /&gt;&lt;li&gt;pomoc podczas projektowania ścieżki rozwoju dla programistów&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Podsumowanie&lt;/h4&gt;&lt;br /&gt; W artykule wyróżniłem metaprogramy Ogół – Szczegół oraz Opcje – Procedury jako bardzo istotne w pracy programisty. Zdaję sobie sprawę, że istnieje wiele punktów w procesie rozwoju oprogramowania, które nie zostały tu wspomniane. W obszarach tych również korzystamy ze specyficznych metaprogramów i wiedza o nich będzie nieocenioną pomocą. Dalszą eksplorację tego zagadnienia rezerwuję sobie na najbliższą przyszłość. Warto wskazać czego potrzeba opracowaniu tego typu, aby stanowiło rzetelną pomoc w pracy dewelopera:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;kompletny opis procesu wytwarzania oprogramowania z punktu widzenia wykorzystywanych metaprogramów,&lt;/li&gt;&lt;br /&gt;&lt;li&gt;opis efektywnych technik pracy na każdym z etapów,&lt;/li&gt;&lt;br /&gt;&lt;li&gt;zestaw ćwiczeń pozwalających rozwijać pożądane metaprogramy.&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt; Każdy krok w kierunku rozwoju własnego warsztatu pracy uświadamia, że istnieje coś poza technologią, coś co porządkuje poszczególne umiejętności i pozwala korzystać z ich jeszcze efektywniej. Odkrywanie tych zasobów jest fascynującą podróżą ku doskonałości.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1759916214638009707-8720144078749405469?l=mbartyzel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mbartyzel.blogspot.com/feeds/8720144078749405469/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1759916214638009707&amp;postID=8720144078749405469' title='Komentarze (6)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/8720144078749405469'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/8720144078749405469'/><link rel='alternate' type='text/html' href='http://mbartyzel.blogspot.com/2008/06/wersja-pdf-jeli-jeste-programist-albo-w.html' title='Metaprogramy w tworzeniu oprogramowania'/><author><name>Michał Bartyzel</name><uri>http://www.blogger.com/profile/03968505875451301931</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://bp2.blogger.com/_wQFWfmLrUy4/SFq_8FmWi_I/AAAAAAAAAC4/hpwTTs8-hoU/s72-c/PDF-Icon.jpg' height='72' width='72'/><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1759916214638009707.post-7971452213396199744</id><published>2008-06-13T01:39:00.012+02:00</published><updated>2008-07-11T19:37:38.825+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='wzorce'/><category scheme='http://www.blogger.com/atom/ns#' term='architektura'/><category scheme='http://www.blogger.com/atom/ns#' term='refaktoring'/><title type='text'>Strategie decouplingu</title><content type='html'>&lt;div&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.bnsit.pl/files/strategie_decouplingu.pdf"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;" src="http://bp2.blogger.com/_wQFWfmLrUy4/SFq_8FmWi_I/AAAAAAAAAC4/hpwTTs8-hoU/s200/PDF-Icon.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5213690557650865138" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a style="color:#773607; text-decoration:underline; font-weight:normal" href="http://www.bnsit.pl/files/strategie_decouplingu.pdf"&gt;Wersja PDF&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br/&gt;&lt;br /&gt; W inżynierii oprogramowania występuje masowe dążenie do tworzenia systemów informatycznych z komponentów wielokrotnego użytku. Komponenty te mogą występować na różnym poziomie abstrakcji oraz złożoność. Artykuł poświęcony jest komponentom najniższego poziomu jakimi są klasy oraz ich obiekty.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Swobodna twórczość&lt;/h4&gt;&lt;br /&gt;O co właściwie chodzi z tym całym decouplingiem1? W gruncie rzeczy o przejrzystość, elastyczność i elegancję kodu. Wyobraźmy sobie następującą sytuację:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp0.blogger.com/_wQFWfmLrUy4/SFG0Y6mi_AI/AAAAAAAAACg/9VAItALuqxU/s1600-h/security_manager_idea.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://bp0.blogger.com/_wQFWfmLrUy4/SFG0Y6mi_AI/AAAAAAAAACg/9VAItALuqxU/s320/security_manager_idea.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5211144583985167362" /&gt;&lt;/a&gt;&lt;br /&gt;Pewien interfejs, &lt;em&gt;SecurityManager&lt;/em&gt;, jest odpowiedzialny za zrealizowanie operacji autentykacji oraz autoryzacji. Po krótkiej analizie stwierdzamy, że chociaż przeprowadzenie operacji autentykacji należy do interfejsu &lt;em&gt;SecurityManager&lt;/em&gt;, to już sama czynność sięgnięcia do bazy danych w celu pobrania potrzebnych informacji leży poza tą odpowiedzialnością. Na diagramie widać, że działania na bazie danych delegowane są do pomocniczego interfejsu &lt;em&gt;UserCredentialsDAO&lt;/em&gt;.&lt;br /&gt;Pojęcie decouplingu dotyczy powiązań pomiędzy poszczególnymi klasami/interfejsami w systemie, np.: powiązania pomiędzy implementacjami interfejsów &lt;em&gt;SecurityManager&lt;/em&gt; i &lt;em&gt;UserCredentialsDAO&lt;/em&gt;. Jak zatem zapewnić to powiązanie? Najprostszym możliwym sposobem – w konstruktorze.&lt;br /&gt;&lt;code style="background:grey"&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;public class JdbcSecurityManager implements SecurityManager {&lt;br /&gt;&lt;br /&gt;  public UserCredentialsDAO userCredentialsDAO;&lt;br /&gt;&lt;br /&gt;  public JdbcSecurityManager() {&lt;br /&gt;&lt;br /&gt;      userCredentialsDAO = new JdbcUserCredentialsDAO();&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;Szybko jednak okazuje się, że dana klasa wymaga więcej zależności, aby wykonać swoje zadanie. Dodatkowo chcemy mieć możliwość decydowania, które konkretne implementacje klas zależnych zostaną dostarczone do obiektu. W takim przypadku można zastosować parametryzowane konstruktory.&lt;br /&gt;&lt;code&gt;&lt;pre&gt;&lt;br /&gt;public class JdbcSecurityManager implements SecurityManager {&lt;br /&gt;&lt;br /&gt;  public UserCredentialsDAO userCredentialsDAO;&lt;br /&gt; &lt;br /&gt;  public SecurityHolder securityHolder;&lt;br /&gt; &lt;br /&gt;  public JdbcSecurityManager( UserCredentialsDAO credentialsDAO, &lt;br /&gt;    SecurityHolder securityHolder ) {&lt;br /&gt;&lt;br /&gt;    this.userCredentialsDAO = credentialsDAO;&lt;br /&gt;    this.securityHolder = securityHolder;&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Rozwiązanie to sprawia kłopot, gdy pisane są testy jednostkowe wykorzystujące klasę &lt;em&gt;JdbcSecurityManager&lt;/em&gt; lub jej mocka. Niedogodność polega na tym, że czasem , teście jednostkowym chcemy mieć możliwość podmiany  implementacji interfejsów &lt;em&gt;UserCredentialsDAO&lt;/em&gt; oraz &lt;em&gt;SecurityHolder&lt;/em&gt;. Z tego względu warto do tworzonej klasy , prócz parametryzowan/ch konstruktorów dodać również konstruktor domyślny oraz setery i getery do odpowiednich pól. W klasie wykorzystującej interfejs &lt;em&gt;SecurityManager&lt;/em&gt; można wstawić następujący kod:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;pre&gt;&lt;br /&gt;UserCredentialsDAO credentialsDAO = new JdbcUserCredentialsDAO();&lt;br /&gt;SecurityHolder securityHolder = new SecurityHolder();&lt;br /&gt;&lt;br /&gt;JdbcSecurityManager securityManager = new JdbcSecurityManager();&lt;br /&gt;securityManager.setUserCredentialsDAO( credentialsDAO );&lt;br /&gt;securityManager.setSecurityHolder( securityHolder );&lt;/pre&gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Stosując opisaną powyżej strategię zapewniamy utworzenie powiązań pomiędzy obiektami w systemie. Jednocześnie sprawiamy, że obiekty są silnie uzależnione od siebie. Jest tak dlatego, że instancje poszczególnych klas są tworzone w kodzie – klasa nadrzędna tworzy instancje klas z nią współpracujących. O klasach, w których powiązania między nimi są realizowane w ten sposób mówimy, że są &lt;em&gt;coupled&lt;/em&gt;. Konsekwencją takiego podejścia jest to, że jakakolwiek podmiana poszczególnych implementacji wiąże się z ingerencją w kod źródłowy. Taki kod jest nieelastyczny oraz trudny w utrzymaniu i rozwoju.&lt;br /&gt;&lt;br /&gt;Przeciwwagą kodu, w którym klasy są &lt;em&gt;coupled&lt;/em&gt;, jest kod w którym są one &lt;em&gt;decoupled&lt;/em&gt;, to znaczy w maksymalnym stopniu od siebie niezależne. Współpracują ze sobą, ale można w łatwy sposób wymieniać poszczególne implementacje, a ingerencja w projekt jest ograniczona do minimum. Czynność zapewniania takiego stanu rzeczy nazywa się &lt;em&gt;decoupling&lt;/em&gt; (lub po lekkim spolszczeniu decouplingiem) i jest przedmiotem niniejszego artykułu.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Fabryka&lt;/h4&gt;&lt;br /&gt;Ponownie odwołując się do pojęcia odpowiedzialności obiektów można zapytać, czy tworzenie nowych obiektów należy do odpowiedzialności klasy &lt;em&gt;JdbcSecurityManager&lt;/em&gt;? Nie, gdyż jej zadaniem jest przeprowadzać operacje związane z bezpieczeństwem. Obiekt tej klasy nie może wykonywać swoich działań gdy nie ma obiektów pomocniczych, do których deleguje odpowiednie operacje. Remedium przychodzi w postaci scentralizowanego miejsca, w którym tworzone będą obiekty używane w systemie. Można zaimplementować  to rozwiązanie w postaci wzorca &lt;em&gt;SimpleFactory&lt;/em&gt;.&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;pre&gt;&lt;br /&gt;public final class ObjectFactory {&lt;br /&gt;  public static SecurityManager createSecurityManager( &lt;br /&gt;    String type ) {&lt;br /&gt;&lt;br /&gt;    SecurityManager securityManager = //...  &lt;br /&gt;    return securityManager;&lt;br /&gt;  }&lt;br /&gt;  public static UserCredentialsDAO createUserCredentialsDAO( &lt;br /&gt;    String type ) {&lt;br /&gt;  //... &lt;br /&gt;  }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Metody fabryki muszą zdecydować, w jaki sposób należy zbudować dany obiekt, np. którą implementację należy utworzyć. Decyzja zostanie podjęta na podstawie parametru &lt;em&gt;type&lt;/em&gt; metod fabryki.&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;pre&gt;&lt;br /&gt;public class BankTransferManager {&lt;br /&gt;  private SecurityManager securityManager;&lt;br /&gt;&lt;br /&gt;  public BankTransferManager() {&lt;br /&gt;    securityManager = ObjectFactory.createSecurityManager(                                                             &lt;br /&gt;      "securityManager" );&lt;br /&gt;  } &lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;W powyższym rozwiązaniu tworzenie klas i powiązań pomiędzy nimi zostało oddelegowane do osobnego obiektu  fabryki. Dzięki temu nie klasa decyduje o użytych implementacjach lecz fabryka. Rozwiązanie zapewnia decoupling kodu, gdyż konkretne klasy nie są ze sobą trwale związane (np. poprzez tworzenie zależności w konstruktorach), zatem można w dowolnym momencie podmieniać implementacje modyfikując odpowiednio działanie klasy &lt;em&gt;ObjectFactory&lt;/em&gt;. Oczywiście ingerencja w kod jest nieodzowna, lecz dotyczy tylko jednego obiektu, nie wszystkich.&lt;br /&gt;&lt;br /&gt;&lt;h5&gt;Singleton&lt;/h5&gt;&lt;br /&gt;Czasem zachodzi konieczność, aby dany obiekt występował tylko raz w systemie, np. &lt;em&gt;SecurityManager&lt;/em&gt; jeśli nie chcemy, próba autentykacji użytkownika była podejmowana przez dwa byty. &lt;br /&gt;Może być też tak, że nie ma sensu tworzyć wielu bezstanowych obiektów zajmujących się tylko logiką, np. &lt;em&gt;UserCredentialsDAO&lt;/em&gt;, gdyż w zupełności wystarczy tylko jeden. &lt;br /&gt;W powyższych wypadkach stosuje się wzorzec Singleton, aby zapewnić, że dany obiekt zostanie utworzony tylko raz. Poniżej znajduje się przykładowa implementacja Singletonu.&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;pre&gt;&lt;br /&gt;public class LdapSecurityManager implements SecurityManager {&lt;br /&gt;&lt;br /&gt;  private static LdapSecurityManager instance;&lt;br /&gt; &lt;br /&gt;  private static LdapSecurityManager getInstance() {&lt;br /&gt;    if ( instance == null ) {&lt;br /&gt;      instance = new LdapSecurityManager();&lt;br /&gt;    }&lt;br /&gt;      return instance;&lt;br /&gt;    }&lt;br /&gt;} &lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Klasa &lt;em&gt;ObjectFactory&lt;/em&gt; musi skorzystać z metod &lt;em&gt;getInstance()&lt;/em&gt; do pobrania obiektu. Jeśli singleton ma być używany w aplikacji wielowątkowej musi być &lt;em&gt;thread-safe&lt;/em&gt;. Za Williamem Pughem podaję taką implementację:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;pre&gt;&lt;br /&gt;public class LdapSecurityManager implements SecurityManager {&lt;br /&gt; &lt;br /&gt;  private static class SingletonHolder {&lt;br /&gt;    private final static LdapSecurityManager instance&lt;br /&gt;      = new LdapSecurityManager();&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  private static LdapSecurityManager getInstance() {&lt;br /&gt;    return SingletonHolder.instance;&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Należy pamiętać, że jeśli system działa na wielu maszynach wirtualnych, to klasa singletonu będzie ładowana na każdej z nich. Z tego względu zaleca się unikać tego rozwiązania w systemach rozproszonych.&lt;br /&gt;&lt;br /&gt;&lt;h5&gt;Service Locator&lt;/h5&gt;&lt;br /&gt;Uogólnieniem &lt;em&gt;ObjectFactory&lt;/em&gt; jest wzorzec &lt;em&gt;Service Locator&lt;/em&gt;, którego zadaniem jest dostarczenie klientowi żądanej klasy usługowej, z tą różnicą, że klient nie wie skąd pochodzi dana usługa – czy jest lokalna, czy też zdalna.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Kontekst aplikacji&lt;/h4&gt;&lt;br /&gt;Alternatywą dla &lt;em&gt;ObjectFactory&lt;/em&gt; jest zastosowanie obiektu, w którym przechowywany jest tzw. kontekst aplikacji. Kontekst zawiera w sobie wszystko to, czego system potrzebuje do poprawnego działania, np. obiekty realizujące konkretne usługi.&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;pre&gt;&lt;br /&gt;public class LdapSecurityManager implements SecurityManager {&lt;br /&gt;&lt;br /&gt;  public void authenticate( UserCredentials credentials,&lt;br /&gt;    AppContext context ) {&lt;br /&gt;&lt;br /&gt;    UserCredentialsDAO credentialsDAO&lt;br /&gt;      = context.get( "userCredentialsDAO" );&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Każda metoda, w której potrzeba użyć usługi przechowywanej w kontekście będzie przyjmować dodatkowy parametr – &lt;em&gt;AppContext&lt;/em&gt;, który umożliwia pobranie potrzebnego obiektu. Oczywiście podczas startu aplikacji należy najpierw zbudować odpowiedni kontekst.&lt;br /&gt;&lt;br /&gt;Kiedy zatem używać obiektu kontekstu, a kiedy fabryki? Obiekt kontekstu umożliwia przechowywanie aktualnego stanu aplikacji do którego powinny mieć dostęp wszystkie obiekty (przechowywanie stanu w zewnętrznym obiekcie dostępnym poprzez metody statyczne jest mało eleganckie i nieintuicyjne). Fabryka skupia się tylko na tworzeniu obiektów. Konkretny wybór zależy o bieżących potrzeb. Kontekst, podobnie jak fabryka, zapewnia decoupling obiektów.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Dependency Injection&lt;/h4&gt;&lt;br /&gt;Konsekwencją stosowania zarówno fabryki jak i kontekstu aplikacji jest sytuacja, w której dana klasa musi zażądać obiektów pomocniczych, których chce użyć, od fabryki lub pobrać je z kontekstu aplikacji. Zatem dany obiekt dba o to, aby odnaleźć potrzebne mu obiekty współpracujące za pomocą fabryki, lokatora lub konktestu. Obiekt dba o swoje zależności. &lt;br /&gt;&lt;br /&gt;Przeformułujmy problem w następujący sposób: żądamy takiej architektury aplikacji, w której dostarczony zostanie nam obiekt gotowy do użycia z już rozwiązanymi zależnościami. Takie podejście nosi nazwę Dependency Injection. Obiekty są zarządzane przez tzw. kontener. Przed użyciem należy zdefiniować obiekty oraz powiązania pomiędzy nimi, a następnie pobierać obiekty z kontenera i używać ich w systemie.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_wQFWfmLrUy4/SFG41Qc-3rI/AAAAAAAAACo/-cRLalO4o0c/s1600-h/ioc.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://bp2.blogger.com/_wQFWfmLrUy4/SFG41Qc-3rI/AAAAAAAAACo/-cRLalO4o0c/s320/ioc.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5211149468933480114" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Na rysunku widać schemat Dependency Injection. Wszystkie obiekty oraz ich wzajemne relacje zdefiniowane są w zewnętrznym pliku XML, np:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;pre&gt;&lt;br /&gt;&amp;lt;bean id="userCredentialsDAO" &lt;br /&gt;  class="mbartyzel.decoupling.JdbcUserCredentialsDAO" /&amp;gt;&lt;br /&gt;&amp;lt;bean id="securityManager" &lt;br /&gt;  class="mbartyzel.decoupling.JdbcSecurityManager"&amp;gt;&lt;br /&gt; &amp;lt;property name="credentialsDAO" ref="userCredentialsDAO" /&amp;gt;&lt;br /&gt;&amp;lt;/bean&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;Natomiast w systemie pobierane są obiekty z kontenera:&lt;br /&gt;&lt;code&gt;&lt;pre&gt;&lt;br /&gt;SecurityManager securitManager = BeanFactoryHolder&lt;br /&gt;  .getBean( "securityManager" );&lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Przykłady frameworków dostarczających kontenera DI to np.: SpringFramework, PicoContainer, Google-Guice.&lt;br /&gt;&lt;br /&gt;Aby kod aplikacji był decoupled od frameworka oczekujemy, aby nie narzucał zarządzanym przez siebie obiektom implementowania specyficznych interfejsów. Gdyby tak było, kod stałby się zbyt zależny od samego framewokra. Niemożliwa byłaby wtedy sprawna zamiana jednego kontenera na inny, a testowanie utrudnione.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Podsumowanie&lt;/h4&gt;&lt;br /&gt;W artykule omówione zostały strategie decouplingu w systemach informatycznych takie jak: fabryka, &lt;em&gt;Service Locator&lt;/em&gt;, kontekst aplikacji, kontener Dependency Injection. Autor ma nadzieje, że podane przykłady implementacji pozwolą Czytelnikom poprawić jakość tworzonego kodu. Nadrzędnym celem było wskazanie kilku możliwości osiągnięcia tego samego efektu. Mając wybór możemy, w danej sytuacji,  świadomie decydować o przewadze jednego rozwiązania nad innym. Pamiętajmy, że jeśli jednym dostępnym narzędziem jest młotek, wszystko zaczyna wyglądać jak gwóźdź...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1759916214638009707-7971452213396199744?l=mbartyzel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mbartyzel.blogspot.com/feeds/7971452213396199744/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1759916214638009707&amp;postID=7971452213396199744' title='Komentarze (2)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/7971452213396199744'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/7971452213396199744'/><link rel='alternate' type='text/html' href='http://mbartyzel.blogspot.com/2008/06/strategie-decouplingu_12.html' title='Strategie decouplingu'/><author><name>Michał Bartyzel</name><uri>http://www.blogger.com/profile/03968505875451301931</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://bp2.blogger.com/_wQFWfmLrUy4/SFq_8FmWi_I/AAAAAAAAAC4/hpwTTs8-hoU/s72-c/PDF-Icon.jpg' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1759916214638009707.post-4225513269828552797</id><published>2008-06-11T15:18:00.001+02:00</published><updated>2008-07-11T19:37:03.703+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='wydarzenia'/><title type='text'>Historia jednego JUGa</title><content type='html'>&lt;p&gt;Czasem tworzysz coś planowo, czasem coś zwyczajnie się dzieje, lub też planujesz a i tak rzeczy biegną swoim torem. Nie inaczej był z JUGiem łódzkim.&lt;/p&gt; &lt;p&gt;Ubolewaliśmy z Mariuszem, że wcześniejsze plany nie pozwolą nam zjawić się ja Javarsovi. W pewnym momencie zaczęła się dyskusja o starych pomysłach utworzenia w Łodzi jakiejś javowej społeczności. No, więc szukamy w necie, szukamy i nic. Wyobrażacie sobie?!? Łódź - ponad milion ludzi, centra akademickie, kilka poważnych firmy developerskich, a lokalnej społeczności Java ani widu ani słychu. &lt;/p&gt; &lt;p&gt;Nieśmiało założyłem grupę na gmail, wysławszy następnie info na JDN. Następnego dołączył Tomek i wrzucił pierwsze logo, porozmawialiśmy trochę pogratulowaliśmy sobie powstania JUGa i tyle. Potem pojawił Bartek ze swoim zapasem niekończącej się energii:). Długo rozmawialiśmy na GG, Bartek jednocześnie spamował :) do JackaL z WawaJUG z prośbą o podzielenie się doświadczeniami. Na koniec dnia mieliśmy dość mglistą wizję: Co, gdzie, kiedy i jak...&lt;/p&gt; &lt;p&gt;Szczerze mówiąc potem już straciłem nad tym, kto kiedy dołączył i co powiedział. Jakoś tak z niczego pojawiły się logo, zjawili się studenci z PŁ z propozycją udostępnienia sal, koledzy z innych JUGów aktywnie właczyli się do dyskusji...mój Thunderbird pracował jak oszalały.&lt;/p&gt; &lt;p&gt;Spotkaliśmy się w sobotę 7 czerwca by proklamować powstanie łódzkiego JUGa. Doszliśmy do wniosku, że przez wakacje będziemy testować działanie społeczności, aby pełną parą ruszyć we wrześniu/październiku.&lt;br /&gt;Pierwsze spotkanie odbędzie się już za miesiąc 5 lipca i poruszać się będziemy wokół EJB3.&lt;/p&gt; &lt;p&gt;Mam nadzieję, że entuzjazm i energia zostaną utrzymane na długo, a rodząca się społeczność jest zaczątkiem czegoś wielkiego.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1759916214638009707-4225513269828552797?l=mbartyzel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mbartyzel.blogspot.com/feeds/4225513269828552797/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1759916214638009707&amp;postID=4225513269828552797' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/4225513269828552797'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/4225513269828552797'/><link rel='alternate' type='text/html' href='http://mbartyzel.blogspot.com/2008/06/historia-jednego-juga.html' title='Historia jednego JUGa'/><author><name>Michał Bartyzel</name><uri>http://www.blogger.com/profile/03968505875451301931</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1759916214638009707.post-8875994645498964651</id><published>2008-05-27T00:44:00.003+02:00</published><updated>2008-07-11T19:42:26.672+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><category scheme='http://www.blogger.com/atom/ns#' term='praca z klientem'/><title type='text'>Klient, który wie, czego chce</title><content type='html'>&lt;div&gt;&lt;br /&gt;&lt;a href="http://www.bnsit.pl/files/klient_ktory_wie_czego_chce.pdf"&gt;Wersja PDF&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;p style="margin-bottom: 0cm;"&gt; Powszechnie przyjętym dogmatem wśród analityków, projektantów, architektów, deweloperów i innych osób biorących udział w cyklu wytwarzania oprogramowania jest, że &lt;i&gt;Klient nie wie czego chce. &lt;/i&gt;&lt;span style="font-style: normal;"&gt;Sytuację rodem z głuchego telefonu przedstawia rysunek (&lt;a href="http://philhord.com/phord/wp-content/development.jpg"&gt;http://philhord.com/phord/wp-content/development.jpg&lt;/a&gt;), w którym klient opisuje swoje oczekiwania. Następnie trafiają one do poszczególnych osób zajmujących się tworzeniem systemu i w efekcie biedny klient dostaje coś, co drastycznie mija się z jego potrzebami. &lt;/span&gt; &lt;/p&gt; &lt;p style="margin-bottom: 0cm;"&gt;&lt;span style="font-style: normal;"&gt; Jak to zatem jest z owym klientem? Czy rzeczywiście nie ma on bladego pojęcia czego naprawdę chce? Jak wiadomo: punkt widzenia zależy od punktu siedzenia. Programiści wiedzą, że klient nie ma bladego pojęcia o swoich potrzebach, natomiast klienci są absolutnie przekonani, że deweloperzy dają im coś innego niż zostało to uzgodnione. Jaka jest więc prawda? Hmmm, żyję na świecie wystarczająco długo, by wiedzieć że każdy ma swoją własną prawdę. Jednakże twierdzę, że klient &lt;/span&gt;&lt;span style="font-style: normal;"&gt;&lt;b&gt;dokładnie wie, czego chce&lt;/b&gt;&lt;/span&gt;&lt;span style="font-style: normal;"&gt;&lt;span style=""&gt;. Z doświadczenia wiem, że:&lt;/span&gt;&lt;/span&gt;&lt;/p&gt; &lt;ol&gt;&lt;li&gt;&lt;p style="margin-bottom: 0cm;"&gt;&lt;span style="font-style: normal;"&gt;&lt;b&gt;Klient  wie, czego chce&lt;/b&gt;&lt;/span&gt;&lt;span style="font-style: normal;"&gt;&lt;span style=""&gt;  – aktualne oczekiwania wobec systemu wyniknęły z problemów,  które doskwierają klientowi w pracy, zatem chce on je  rozwiązać i ma na to konkretny pomysł. Klient (metaforycznie  rzecz ujmując) jest ekspertem z dziedziny problemu, więc tym  bardziej wie, czego chce.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;  &lt;/li&gt;&lt;li&gt;&lt;p style="margin-bottom: 0cm;"&gt;&lt;b&gt;&lt;span style="font-style: normal;"&gt;Klient  nie zawsze wie, czego potrzebuje&lt;/span&gt;&lt;/b&gt;&lt;span style="font-style: normal;"&gt;&lt;span style=""&gt;  – wynika to z jego niewielkiej wiedzy o możliwych technologiach.  Często klient sugeruje rozwiązanie (na miarę swojej wiedzy), gdy  tym czasem powinien zatrzymać się na sformułowaniu problemu i  oczekiwanych rezultatów.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;  &lt;/li&gt;&lt;li&gt;&lt;p style="margin-bottom: 0cm;"&gt;&lt;b&gt;&lt;span style="font-style: normal;"&gt;Klient  często nie uświadamia sobie konsekwencji własnych oczekiwań&lt;/span&gt;&lt;/b&gt;&lt;span style="font-style: normal;"&gt;&lt;span style=""&gt;  – jest to bolesne zwłaszcza, gdy prosi się nas o dodatkową  funkcjonalność w systemie. &lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;span style="font-style: normal;"&gt;&lt;span style=""&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt; &lt;p style="margin-bottom: 0cm;"&gt;&lt;/p&gt;&lt;p style="margin-bottom: 0cm;"&gt;&lt;span style="font-style: normal;"&gt;Przyczyna rozmijania się oczekiwań klient z rezultatem prac programistów koncentruje się wokół następujących faktów:&lt;/span&gt;&lt;/p&gt; &lt;ol&gt;&lt;li&gt;&lt;p style="margin-bottom: 0cm;"&gt;&lt;b&gt;&lt;span style="font-style: normal;"&gt;Klient  myśli procesowo&lt;/span&gt;&lt;/b&gt;&lt;span style="font-style: normal;"&gt;&lt;span style=""&gt;  – ma bardzo konkretne pomysły na sposób pracy z systemem.  Potrafi określić warunki początkowe dla danego procesu oraz  określić jego rezultat.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;  &lt;/li&gt;&lt;li&gt;&lt;p style="margin-bottom: 0cm;"&gt;&lt;b&gt;&lt;span style="font-style: normal;"&gt;Projektant  myśli strukturalnie&lt;/span&gt;&lt;/b&gt;&lt;span style="font-style: normal;"&gt;&lt;span style=""&gt;  – porusza się w przestrzeni baz danych, tabel, klas, obiektów.  Niejednokrotnie już podczas rozmowy z klientem myśli o  implementacji. Z tego względu częste zmiany w wymaganiach oraz  modyfikacje sposobów pracy z systemem, które klientowi  przychodzą niezwykle łatwo, u projektanta powodują frustrację.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt; &lt;/li&gt;&lt;/ol&gt; &lt;p style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/p&gt; &lt;p style="margin-bottom: 0cm;"&gt;&lt;span style="font-style: normal;"&gt;Mit o niewiedzy klienta nt. własnych oczekiwań bierze się powyższych różnić w myśleniu i analizowaniu informacji.&lt;/span&gt;&lt;/p&gt; &lt;p style="margin-bottom: 0cm;"&gt;&lt;span style="font-style: normal;"&gt;W swojej pracy wykorzystuję następujące praktyki pomagające w ustaleniu potrzeb klienta:&lt;/span&gt;&lt;/p&gt; &lt;ol&gt;&lt;li&gt;&lt;p style="margin-bottom: 0cm;"&gt;&lt;i&gt;Opisywanie  cyklu pracy z systemem&lt;/i&gt;&lt;span style="font-style: normal;"&gt; –  tworzę zestaw procesów, które opisują co użytkownik  może zrobić w systemie. Jeden proces to jedna konkretna rzecz,  np.: wykonanie przelewu, zalogowanie, wygenerowanie raportu&lt;/span&gt;&lt;/p&gt;  &lt;/li&gt;&lt;li&gt;&lt;p style="margin-bottom: 0cm;"&gt;&lt;i&gt;Rysowanie  z klientem ekrany systemu i zaznaczanie przepływu sterowania pomiędzy  nimi&lt;/i&gt;&lt;span style="font-style: normal;"&gt; – puryści mówią,  że tym powinien zajmować się projektant UI, natomiast do  definiowania wymagań służą &lt;/span&gt;&lt;i&gt;&lt;span style="text-decoration: none;"&gt;UML  use cases&lt;/span&gt;&lt;/i&gt;&lt;span style="font-style: normal;"&gt;. Cóż , nie spotkałem jeszcze klienta, który miałby ochotę uczyć  się nowych symboli (nawet jeśli jest ich kilka), aby definiować  swoje wymagania. Klient doświadcza systemu poprzez to co widzi –  ekrany. &lt;/span&gt;  &lt;/p&gt;  &lt;/li&gt;&lt;li&gt;&lt;p style="margin-bottom: 0cm;"&gt;&lt;i&gt;Pilnowanie,  aby klient precyzował jaki efekt chce uzyskać&lt;/i&gt;&lt;span style="font-style: normal;"&gt;  – klient jest od tego, aby wskazać problem i określić  oczekiwane rezultaty. Od rozwiązywania zadania jestem ja. Dobrze  jeśli klient może udzielić rad odnośnie implementacji, jednak  niekontrolowane mieszanie się tych odpowiedzialności nie raz  zapędziło mnie w kozi róg.&lt;/span&gt;&lt;/p&gt;  &lt;/li&gt;&lt;li&gt;&lt;p style="margin-bottom: 0cm;"&gt;&lt;i&gt;Skłanianie  klienta do przewidywania konsekwencji swoich oczekiwań&lt;b&gt; – &lt;/b&gt;&lt;/i&gt;&lt;span style="font-style: normal;"&gt;duże  korzyści przynosi to przy rozbudowanych systemach. Niestety klient  patrzy lokalnie na system – skupia się na aktualnym problemie i  nie ma wizji całości. Prowadzi to łatania dziur, dodawania  funkcyjnie zależnych od siebie usług do systemu i ogólnego  bałaganu. Prowokowanie klienta do globalnego spojrzenia na system i  przewidywania globalnych konsekwencji swoich oczekiwań ma  następujące zalety:&lt;/span&gt;&lt;/p&gt; &lt;/li&gt;&lt;/ol&gt; &lt;ul&gt;&lt;ul&gt;&lt;li&gt;&lt;p style="margin-bottom: 0cm; font-style: normal;"&gt;   ulepszany system jest traktowany jako całość&lt;/p&gt;   &lt;/li&gt;&lt;li&gt;&lt;p style="margin-bottom: 0cm; font-style: normal;"&gt;   unika się dublowania funkcjonalności&lt;/p&gt;   &lt;/li&gt;&lt;li&gt;&lt;p style="margin-bottom: 0cm; font-style: normal;"&gt;   czasem okazuje się, że poprawa komfortu pracy o 5% nie jest   warta wysiłku programistów&lt;/p&gt;  &lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt; &lt;p style="margin-bottom: 0cm; font-style: normal;"&gt;&lt;br /&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1759916214638009707-8875994645498964651?l=mbartyzel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mbartyzel.blogspot.com/feeds/8875994645498964651/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1759916214638009707&amp;postID=8875994645498964651' title='Komentarze (4)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/8875994645498964651'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/8875994645498964651'/><link rel='alternate' type='text/html' href='http://mbartyzel.blogspot.com/2008/05/klient-ktry-wie-czego-chce.html' title='Klient, który wie, czego chce'/><author><name>Michał Bartyzel</name><uri>http://www.blogger.com/profile/03968505875451301931</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1759916214638009707.post-7455676523234433892</id><published>2008-05-19T10:00:00.003+02:00</published><updated>2008-07-11T19:42:09.112+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><category scheme='http://www.blogger.com/atom/ns#' term='zarządzanie'/><title type='text'>Ewolucja Agile</title><content type='html'>&lt;div&gt;&lt;br /&gt;&lt;a href="http://ddinformatyku.pl/pdf/04-2008/12.pdf"&gt;Wersja PDF&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;p  style="font-family:verdana;"&gt;&lt;span style="font-size:100%;"&gt; Metodyki z nurtu Agile nazywane są ostatnio nowoczesnym podejściem do programowania. Zdobywają one coraz większą popularność dzięki swojej skuteczności i przestępności dla klienta. W tym artykule chciałbym zastanowić się, czy podejście Agile jest tym oczekiwanym, „prawie idealnym”, sposobem na wytwarzanie oprogramowania.&lt;/span&gt;&lt;/p&gt; &lt;h3 class="western"  style="font-family:verdana;"&gt;&lt;span style="font-size:100%;"&gt;Lekkie podejście do programowania&lt;/span&gt;&lt;/h3&gt; &lt;p  style="font-family:verdana;"&gt;&lt;span style="font-size:100%;"&gt; W odległej historii branży IT, projektanci oprogramowania zmęczeni wymogami popularnych wówczas metodyk prowadzenia projektów programistycznych, postanowili pozbyć się ciążącego balastu przeszłości. Doszli do wniosku, że wytwarzanie oprogramowania powinno przebiegać szybciej, płynniej, efektywniej, że powinno być bardziej otwarte na klienta i, co za tym idzie,  na zmianę jego oczekiwań. Słowem: nowa metodyka powinna w optymalny sposób zmierzać do usatysfakcjonowania sponsora projektu, użytkownika i programistów. Efektem tych przemyśleć był Manifest Agile.&lt;/span&gt;&lt;/p&gt; &lt;p  style="font-family:verdana;"&gt;&lt;span style="font-size:100%;"&gt; W metodykach z nurtu Agile (np.: eXtreme Programming, Scrum) oprogramowanie tworzy się przyrostowo. W krótkich iteracjach implementuje się kolejne funkcjonalności systemu. Użytkownik, przynajmniej w założeniu, jest cały czas dostępny i może podjąć wiążące decyzje dotyczące kierunku rozwoju projektu.&lt;/span&gt;&lt;/p&gt; &lt;p  style="font-family:verdana;"&gt;&lt;span style="font-size:100%;"&gt; Lekkie metodyki są ściśle zorientowane na jak najlepszą komunikację w zespole (przypominam, że zespół stanowią programiści wraz z klientem).   Poleganie na relacja pociąga za sobą rezygnację z formalizmu. Ogranicza się tworzenie produktów ubocznych tak bardzo jak jest to możliwe bez szkody dla projektu. Mówiąc o produktach ubocznych mam na myśli: dokumentację projektu, podręczniki użytkownika, biblioteki programistyczne, itp. &lt;/span&gt;&lt;/p&gt; &lt;h3 class="western"  style="font-family:verdana;"&gt;&lt;span style="font-size:100%;"&gt;Granice Agile&lt;/span&gt;&lt;/h3&gt; &lt;p  style="font-family:verdana;"&gt;&lt;span style="font-size:100%;"&gt; Na podstawie tego, co zostało już wyżej napisane rodzi się pytanie: czy Agile jest ukoronowaniem ewolucji inżynierii oprogramowania? Moim zdaniem jest etapem pośrednim. Zniechęcenie tradycyjnymi metodykami spowodowało „huraoptymistyczny” odwrót w stronę metodyk lekkich. Mniej dokumentacji, mniej wymagań formalnych, mniej pracy – być może myśleli programiści. Takie rozumowanie nie jest zgodne z prawdą. Programowanie w Agile jest równie (jeśli nie bardziej) wymagające co programowanie w metodykach tradycyjnych. Narzuca ono na członków zespołu dość dużą dyscyplinę. Dzięki krótkim iteracjom, które absolutnie muszą zakończyć się konkretnym (czytaj: widocznym dla użytkownika) efektem nie ma miejsca na zajmowanie się mało istotnymi, lecz interesującymi, miejscami w systemie. Postępy pracy monitorowane są z dokładnością do jednego osobodnia.&lt;/span&gt;&lt;/p&gt; &lt;p  style="font-family:verdana;"&gt;&lt;span style="font-size:100%;"&gt; Wyobraźmy sobie system zarządzania siecią elektrowni stworzony przez zespół pracujący według wytycznych Agile. System taki można nazwać dużym systemem informatycznym. Z pewnością będzie on rozwijany i modyfikowany przez lata. Co najważniejsze, ze względu na problematykę, wymaga dokładnej specyfikacji. Tego typu systemy są poza zasięgiem zainteresowania lekkich metodyk. Przedsięwzięcia informatyczne wspomnianego kalibru wymagają takiej metodyki prowadzenia projektu, która precyzyjnie definiuje każdy element procesu wytwarzania oprogramowania (np. metodyka RUP). Stosowanie twardej metodyki jest konieczne ze względu na skalę i potencjalny czas trwania projektu. Ma ona za zadanie zapewnić bezpieczeństwo przedsięwzięcia oraz osiągnięcie postawionych celów.&lt;/span&gt;&lt;/p&gt; &lt;p  style="font-family:verdana;"&gt;&lt;span style="font-size:100%;"&gt; Podsumowując zakres stosowalności metodyk Agile można powiedzieć, że świetnie nadają się do realizowania małych i średnich projektów programistycznych o relatywnie krótkim czasie wykonania, np.: serwisy internetowe lub oprogramowanie dedykowane specyficznym potrzebom klientów. Nie bez znaczenia dla skuteczności metodyki jest ilość osób biorących udział w pracach. Powyżej 12 osób Agile przestaje być lekką metodyką, a staje się metodyką chaotyczną.&lt;/span&gt;&lt;/p&gt; &lt;h3 class="western"  style="font-family:verdana;"&gt;&lt;span style="font-size:100%;"&gt;Metodyka „&lt;span lang="en-US"&gt;Adaptable&lt;/span&gt; &lt;span lang="en-US"&gt;Process&lt;/span&gt;”&lt;/span&gt;&lt;/h3&gt; &lt;p  lang="pl-PL" style="font-family:verdana;"&gt;&lt;span style="font-size:100%;"&gt; Obszar dużych i długotrwałych projektów programistycznych jeszcze nie został zdominowany przez nurt Agile. Sądzę, że nie stanie się to aż do chwili, gdy zwinna metodyka zapewni wysoki poziom kontroli prac nad projektem w każdym momencie jego trwania, przy jednoczesnym zachowaniu lekkości. Taką metodykę można by oprzeć z jednej strony na jednej z implementacji Agile, z drugiej na twardej metodyce o ściśle zdefiniowanym procesie realizowania projektu. Na własny użytek nazwałem taką metodykę &lt;i&gt;Adaptable &lt;/i&gt;&lt;span lang="en-US"&gt;&lt;i&gt;Process.&lt;/i&gt;&lt;/span&gt;&lt;i&gt;&lt;span style="text-decoration: none;"&gt; &lt;/span&gt;&lt;/i&gt;&lt;span style="font-style: normal;"&gt;&lt;span style="text-decoration: none;"&gt;Wyobrażam ją sobie jako proces, który może być dopasowywany do zmieniających się wymagań klienta. Można pokusić się o wskazanie kryteriów, które powinna spełniać metodyka &lt;/span&gt;&lt;/span&gt;&lt;i&gt;&lt;span style="text-decoration: none;"&gt;Adaptable Process&lt;/span&gt;&lt;/i&gt;&lt;span style="font-style: normal;"&gt;&lt;span style="text-decoration: none;"&gt;, np.:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt; &lt;ol  style="font-family:verdana;"&gt;&lt;li&gt;&lt;p&gt;&lt;span style="font-size:100%;"&gt;Posiada zdefiniowany proces wytwarzania oprogramowania. Każdy  element procesu ma określone kryteria wejścia i wyjścia.&lt;/span&gt;&lt;/p&gt;  &lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span style="font-size:100%;"&gt;Umożliwia szybką reakcję na zmianę oczekiwań klienta.&lt;/span&gt;&lt;/p&gt;  &lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span style="font-size:100%;"&gt;Pozwala utrzymać wysoki poziom kontroli prac nad projektem –  w każdym momencie (nawet po zakończeniu projektu) wiadomo z  jakiego powodu podjęte zostały określone decyzje w projekcie.&lt;/span&gt;&lt;/p&gt;  &lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span style="font-size:100%;"&gt;Angażuje do pracy klienta/użytkownika.&lt;/span&gt;&lt;/p&gt;  &lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span style="font-size:100%;"&gt;Angażuje programistę do prac projektowych – nie wydziela  osobnych ról: projektanta i programisty.&lt;/span&gt;&lt;/p&gt;  &lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span style="font-size:100%;"&gt;Definiuje standardy pracy programisty np. jakość kodu,  pokrycie kodu testami, technika programowania.&lt;/span&gt;&lt;/p&gt;  &lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span style="font-size:100%;"&gt;Umożliwia zespołowi pracę w rozsądnym tempie i przez  rozsądną ilość godzin w tygodniu...&lt;/span&gt;&lt;/p&gt; &lt;/li&gt;&lt;/ol&gt; &lt;p  style="font-family:verdana;"&gt;&lt;span style="font-size:100%;"&gt; Jeśli chodzi o inżynierię oprogramowania, z pewnością jeszcze długo nie zostanie wypowiedziane ostatnie słowo. Nowe wyzwania, które przed nią staną, sprowokują specjalistów do stworzenia nowych kreatywnych podejść. Dzięki temu następuje rozwój i możliwe coraz lepsze spełnianie oczekiwań klientów.&lt;/span&gt;&lt;/p&gt;&lt;p  style="font-family:verdana;"&gt;&lt;span style="font-size:100%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p  style="font-family:verdana;"&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-style: italic;"&gt;Artykuł ukazał się w kwietniowym numerze czasopisma DDI, http://ddinformatyku.pl&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p  style="font-family:verdana;"&gt;&lt;span style="font-size:100%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1759916214638009707-7455676523234433892?l=mbartyzel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mbartyzel.blogspot.com/feeds/7455676523234433892/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1759916214638009707&amp;postID=7455676523234433892' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/7455676523234433892'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1759916214638009707/posts/default/7455676523234433892'/><link rel='alternate' type='text/html' href='http://mbartyzel.blogspot.com/2008/05/ewolucja-agile.html' title='Ewolucja Agile'/><author><name>Michał Bartyzel</name><uri>http://www.blogger.com/profile/03968505875451301931</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>
