<?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-2338976640977990159</id><updated>2011-11-25T13:33:29.200+01:00</updated><category term='wydajność'/><category term='lean'/><category term='zespół'/><category term='tdd'/><category term='zwinność'/><category term='agile'/><category term='java'/><category term='konferencja'/><category term='architektura'/><category term='szkolenie tdd'/><title type='text'>Sprawna Inżynieria Oprogramowania</title><subtitle type='html'>czyli Agile Software Engineering po Polsku</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://sprawnainzynieriaoprogramowania.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://sprawnainzynieriaoprogramowania.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Paweł Lipiński</name><uri>http://www.blogger.com/profile/02772675014904905654</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>52</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-2338976640977990159.post-3754046902792330517</id><published>2011-02-03T10:55:00.000+01:00</published><updated>2011-02-03T10:55:56.706+01:00</updated><title type='text'>Dysleksja</title><content type='html'>&lt;blockquote&gt;&lt;span class="Apple-style-span" style="font-family: verdana; font-size: 12px; line-height: 16px;"&gt;40% of the 300 millionaires who participated in the more comprehensive study had been diagnosed with dyslexia. Adrian Atkinson, a business psychologist who worked with the research group, noted that "Most people who make a million have difficult childhoods or have been frustrated in a major way. Dyslexia is one of the driving forces behind that." (The Sunday Times, October 5, 2003)&lt;/span&gt;&lt;/blockquote&gt;Wiedziałem, że dysleksja jest nie tylko do tego, żeby nie liczyli błędów na egzaminach do liceum ;-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2338976640977990159-3754046902792330517?l=sprawnainzynieriaoprogramowania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2338976640977990159&amp;postID=3754046902792330517' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/3754046902792330517'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/3754046902792330517'/><link rel='alternate' type='text/html' href='http://sprawnainzynieriaoprogramowania.blogspot.com/2011/02/dysleksja.html' title='Dysleksja'/><author><name>Paweł Lipiński</name><uri>http://www.blogger.com/profile/02772675014904905654</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-2338976640977990159.post-5533562501956489570</id><published>2010-05-12T13:53:00.000+02:00</published><updated>2010-05-12T13:53:58.466+02:00</updated><title type='text'>Najlepszy Polski Prelegent</title><content type='html'>DWorld zorganizował ostatnio &lt;a href="http://spreadsheets.google.com/viewform?formkey=dGZuTW9DTHgtYk5HN3U0T3V2elU4Tnc6MQ"&gt;konkurs na najlepszego polskiego prelegenta&lt;/a&gt;. Jako, że zostałem zgłoszony, polecam się nieskromnie pamięci prosząc o klik we właściwym miejscu ;-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2338976640977990159-5533562501956489570?l=sprawnainzynieriaoprogramowania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2338976640977990159&amp;postID=5533562501956489570' title='Komentarze (2)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/5533562501956489570'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/5533562501956489570'/><link rel='alternate' type='text/html' href='http://sprawnainzynieriaoprogramowania.blogspot.com/2010/05/najlepszy-polski-prelegent.html' title='Najlepszy Polski Prelegent'/><author><name>Paweł Lipiński</name><uri>http://www.blogger.com/profile/02772675014904905654</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-2338976640977990159.post-1830760683183774717</id><published>2010-03-31T17:04:00.000+02:00</published><updated>2010-03-31T17:04:13.395+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tdd'/><title type='text'>Extremalne testowanie w SQLite</title><content type='html'>&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;To może nie koniecznie o TDD, ale związane z testowaniem. Przeczytałem ostatnio, że kod SQLite ma:&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;67.2 tyś linii kodu produkcyjnego&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;45678.3 tyś linii testów&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;Tak tak, nie pomyliłem się. To jest 679 razy więcej kodu testów niż kodu aplikacji.&amp;nbsp;Aplikacja jest w C. Pokrycie jest 100%.&amp;nbsp;Z resztą&amp;nbsp;&lt;a href="http://www.sqlite.org/testing.html"&gt;zobaczcie sami&lt;/a&gt;.&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;Nie wiem czy wszystkie mają sens. Nie wiem czy są rozłączne. Nie wiem czy kod powstaje test-first czy test-last.&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;Wiem jedno - przy tak silnej siatce bezpieczeństwa jest jasne czemu wszyscy producenci przeglądarek wybrali ją do implementacji HTML5 Database API...&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2338976640977990159-1830760683183774717?l=sprawnainzynieriaoprogramowania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2338976640977990159&amp;postID=1830760683183774717' title='Komentarze (1)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/1830760683183774717'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/1830760683183774717'/><link rel='alternate' type='text/html' href='http://sprawnainzynieriaoprogramowania.blogspot.com/2010/03/extremalne-testowanie-w-sqlite.html' title='Extremalne testowanie w SQLite'/><author><name>Paweł Lipiński</name><uri>http://www.blogger.com/profile/02772675014904905654</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-2338976640977990159.post-2946449027663473227</id><published>2010-03-30T13:28:00.000+02:00</published><updated>2010-03-30T13:28:20.691+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><category scheme='http://www.blogger.com/atom/ns#' term='tdd'/><title type='text'>Skrzynia biegów</title><content type='html'>Miałem wczoraj z klientem dość długą rozmowę m.in. na temat praktyk programistycznych i powołałem się w niej na metaforę, którą usłyszałem z ust niejakiego Nigel'a Baker'a w czasie zimowego agiletuning'u. Myślę, że jest ona dość fajna, więc podzielę się nią i tu (mam nadzieję, że nie złamię tymsamym żadnego copyrightu...)&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;- Co robisz jeśli chcesz jechać naprawdę szybko samochodem?&amp;nbsp;&lt;/blockquote&gt;&lt;blockquote&gt;- Dodaję gazu.&lt;/blockquote&gt;&lt;blockquote&gt;- Dokładnie, a po stu metrach twój silnik wyje i cała praca 100 koni mechanicznych idzie "w gwizdek"&lt;/blockquote&gt;&lt;blockquote&gt;- No tak, bo jeszcze zmieniam biegi.&lt;/blockquote&gt;&lt;blockquote&gt;- Właśnie, bo moc to nie wszystko - musi mieć jeszcze właściwe przełożenie. Tak też jest z zespołem programistycznym. Dodając do niego ludzi wciskasz gaz. Jeśli nie dostosujesz biegu, łatwo zarżnąć silnik. Jeśli chcesz jechać szybko, nie wystarczy pedał w ziemi, musisz zmieniać przełożenie mocy - to są własnie praktyki. I programistyczne i organizacyjne.&amp;nbsp;&lt;/blockquote&gt;Ciekawe porównanie. TDD byłoby tu pewnie dobrym olejem. Zapewnia długą pracę silnika ;-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2338976640977990159-2946449027663473227?l=sprawnainzynieriaoprogramowania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2338976640977990159&amp;postID=2946449027663473227' title='Komentarze (4)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/2946449027663473227'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/2946449027663473227'/><link rel='alternate' type='text/html' href='http://sprawnainzynieriaoprogramowania.blogspot.com/2010/03/skrzynia-biegow.html' title='Skrzynia biegów'/><author><name>Paweł Lipiński</name><uri>http://www.blogger.com/profile/02772675014904905654</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-2338976640977990159.post-2525140594261763246</id><published>2010-03-29T14:19:00.001+02:00</published><updated>2010-03-29T21:30:07.152+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tdd'/><title type='text'>Test-Drive'owanie GUI'a</title><content type='html'>Na&amp;nbsp;&lt;a href="http://blog.pragmatists.pl/2010/03/tdd-interfejsu-uzytkownika.html"&gt;http://blog.pragmatists.pl/2010/03/tdd-interfejsu-uzytkownika.html&lt;/a&gt;&amp;nbsp;zamieściłem post o TDD GUI'a.&lt;br /&gt;Przyjemnego czytania.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2338976640977990159-2525140594261763246?l=sprawnainzynieriaoprogramowania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2338976640977990159&amp;postID=2525140594261763246' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/2525140594261763246'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/2525140594261763246'/><link rel='alternate' type='text/html' href='http://sprawnainzynieriaoprogramowania.blogspot.com/2010/03/test-driveowanie-guia.html' title='Test-Drive&apos;owanie GUI&apos;a'/><author><name>Paweł Lipiński</name><uri>http://www.blogger.com/profile/02772675014904905654</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-2338976640977990159.post-337962847201622936</id><published>2010-03-23T08:53:00.002+01:00</published><updated>2010-03-29T21:30:35.110+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tdd'/><title type='text'>W TDD nie chodzi o testy</title><content type='html'>Napisałem wczoraj dość obszerny post na ten temat na&amp;nbsp;&lt;a href="http://blog.pragmatists.pl/2010/03/w-tdd-nie-chodzi-o-testy.html"&gt;http://blog.pragmatists.pl/2010/03/w-tdd-nie-chodzi-o-testy.html&lt;/a&gt;&lt;br /&gt;Miłego czytania ;-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2338976640977990159-337962847201622936?l=sprawnainzynieriaoprogramowania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2338976640977990159&amp;postID=337962847201622936' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/337962847201622936'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/337962847201622936'/><link rel='alternate' type='text/html' href='http://sprawnainzynieriaoprogramowania.blogspot.com/2010/03/w-tdd-nie-chodzi-o-testy.html' title='W TDD nie chodzi o testy'/><author><name>Paweł Lipiński</name><uri>http://www.blogger.com/profile/02772675014904905654</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-2338976640977990159.post-6194891002677516250</id><published>2010-03-19T18:17:00.001+01:00</published><updated>2010-03-29T21:31:43.509+02:00</updated><title type='text'>Seria postów o TDD</title><content type='html'>W ramach przygotowań do prowadzonego przez &lt;a href="http://www.pragmatists.pl/"&gt;nas&lt;/a&gt;&amp;nbsp;&lt;a href="http://www.pragmatists.pl/pl/szkolenia/tdd/szkolenie.gsp"&gt;szkolenia&lt;/a&gt; rozpoczęliśmy serię postów o TDD. &lt;a href="http://blog.pragmatists.pl/2010/03/testy-end-to-end-w-tdd.html"&gt;Pierwszy&lt;/a&gt;&amp;nbsp;o testach end-to-end napisał Krzysiek Jelski. Następne wktóce.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2338976640977990159-6194891002677516250?l=sprawnainzynieriaoprogramowania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2338976640977990159&amp;postID=6194891002677516250' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/6194891002677516250'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/6194891002677516250'/><link rel='alternate' type='text/html' href='http://sprawnainzynieriaoprogramowania.blogspot.com/2010/03/seria-postow-o-tdd.html' title='Seria postów o TDD'/><author><name>Paweł Lipiński</name><uri>http://www.blogger.com/profile/02772675014904905654</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-2338976640977990159.post-447316561059248478</id><published>2010-03-17T15:07:00.000+01:00</published><updated>2010-03-17T15:07:40.406+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><title type='text'>Czas i Data w Javie</title><content type='html'>Na infoQ pojawił się &lt;a href="http://www.infoq.com/news/2010/03/jsr-310"&gt;wywiad&lt;/a&gt; dot. zapowiadanego już dawno wprowadzenia jakiejś &lt;b&gt;NORMALNEJ&lt;/b&gt;&amp;nbsp;obsługi czasu i dat w Javie. Sam wywiad może nie jest jakiś pasjonujący, ale podobał mi się jeden fragment:&lt;br /&gt;&lt;blockquote&gt;&lt;span class="Apple-style-span" style="font-family: Lucida, 'Lucida Grande', Tahoma, sans-serif; font-size: 13px; line-height: 16px;"&gt;&lt;b&gt;InfoQ&lt;/b&gt;: Some of these concepts have already been explored in&amp;nbsp;&lt;a href="http://joda-time.sourceforge.net/" style="color: #0b59b2; text-decoration: underline;"&gt;JodaTime&lt;/a&gt;. What's the relationship between that and JSR 310?&lt;br /&gt;&lt;b&gt;Stephen&lt;/b&gt;: JodaTime has been used by a lot of developers already, but it's time that the base Java case is improved for everyone. The most obvious change is the package name (from&amp;nbsp;&lt;code style="font: normal normal normal 90%/130% 'Courier New', Courier;"&gt;org.joda.time&lt;/code&gt;&amp;nbsp;to&amp;nbsp;&lt;code style="font: normal normal normal 90%/130% 'Courier New', Courier;"&gt;javax.time&lt;/code&gt;), but in practice there are a few subtle differences as well.&lt;/span&gt;&lt;/blockquote&gt;Piękne :-) Ciekawe tylko dlaczego trzeba było czekać tak długo na tak oczywisty ruch...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2338976640977990159-447316561059248478?l=sprawnainzynieriaoprogramowania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2338976640977990159&amp;postID=447316561059248478' title='Komentarze (9)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/447316561059248478'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/447316561059248478'/><link rel='alternate' type='text/html' href='http://sprawnainzynieriaoprogramowania.blogspot.com/2010/03/czas-i-data-w-javie.html' title='Czas i Data w Javie'/><author><name>Paweł Lipiński</name><uri>http://www.blogger.com/profile/02772675014904905654</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>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2338976640977990159.post-1723246489813848370</id><published>2010-03-15T01:01:00.003+01:00</published><updated>2010-03-15T09:47:33.441+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='szkolenie tdd'/><title type='text'>Szczegóły szkolenia TDD</title><content type='html'>Powoli dopinamy kwestie organizacyjne związane ze szkoleniem Test-Driven Development. Zainteresowanych szczegółami odsyłam do oficjalnej&amp;nbsp;&lt;a href="http://www.pragmatists.pl/pl/szkolenia/tdd/szkolenie.gsp"&gt;strony szkolenia&lt;/a&gt;.&lt;br /&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;Polecam szybkie rejestrowanie się, ponieważ ze względu na to, że szkolenie będzie w formie warsztatów, liczba miejsc jest ograniczona!&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2338976640977990159-1723246489813848370?l=sprawnainzynieriaoprogramowania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2338976640977990159&amp;postID=1723246489813848370' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/1723246489813848370'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/1723246489813848370'/><link rel='alternate' type='text/html' href='http://sprawnainzynieriaoprogramowania.blogspot.com/2010/03/szczegoy-szkolenia-tdd.html' title='Szczegóły szkolenia TDD'/><author><name>Paweł Lipiński</name><uri>http://www.blogger.com/profile/02772675014904905654</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-2338976640977990159.post-4775753611931310024</id><published>2010-03-12T11:47:00.001+01:00</published><updated>2010-03-12T14:14:54.624+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='lean'/><title type='text'>Spotkanie z Mary Poppendieck</title><content type='html'>Miałem przedwczoraj okazję wziąć udział w spotkaniu z Mary Poppendieck zorganizowanym w Kopenhadze. Pani Mary opowiadała (delikatnie promując swoją &lt;a href="http://www.amazon.com/exec/obidos/ASIN/0321620704/poppendieckco-20"&gt;nową książkę&lt;/a&gt;) o prowadzeniu projektów w "szczupły" sposób. Prezentacja wyglądała tak, że prelegentka przeszła przez główne rozdziały książki streszczając je&amp;nbsp;w skrócie. Może nie brzmi to zbyt pasjonująco, ale tak naprawdę było to bardzo ciekawe.&lt;br /&gt;Mary dawała przykłady projektów nieprogramistycznych, których prowadzenie w stylu podobnym do lean (skupienie na przepływie, praca zlecona ekspertom, eliminowanie strat, itp.) dało niesamowite efekty. Najbardziej przemawiającym przykładem była historia budowy Empire State Building (a potem budynku Chrysler'a i jeszcze jednego, którego nie pamiętam) - cała budowa od podpisania umowy do oddania budynku trwała... 16 miesięcy (czy coś podobnego, mogę mylić się o jakieś 2). Pani Poppendieck opowiedziała w skrócie jak udało się to zespołowi, który budował te budynki przyrównując to do metod i praktyk tworzenia oprogramowania. Mary to do tego całkiem dobry mówca, więc słucha się jej przyjemnie i dużo wynosi z wykładu. Tym bardziej cieszę się na jej wizytę w Polsce (o ile uda mi się wybrać na dalekie południe ojczyzny...) i wszystkim polecam wybranie się na spotkania z nią.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2338976640977990159-4775753611931310024?l=sprawnainzynieriaoprogramowania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2338976640977990159&amp;postID=4775753611931310024' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/4775753611931310024'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/4775753611931310024'/><link rel='alternate' type='text/html' href='http://sprawnainzynieriaoprogramowania.blogspot.com/2010/03/spotkanie-z-mary-poppendieck.html' title='Spotkanie z Mary Poppendieck'/><author><name>Paweł Lipiński</name><uri>http://www.blogger.com/profile/02772675014904905654</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-2338976640977990159.post-435304947409595891</id><published>2010-03-08T22:12:00.000+01:00</published><updated>2010-03-08T22:12:10.956+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><title type='text'>Konferencje</title><content type='html'>To kolejny małotechniczny wpis, ale może być dla kogoś ważny. W najbliższym czasie będzie w Polsce przynajmniej parę ciekawych wydarzeń agile'owych, więc chciałem je tu wylistować.&lt;br /&gt;&lt;br /&gt;Najbliżej jest&amp;nbsp;&lt;a href="http://zimowy.agiletuning.pl/"&gt;Zimowy AgileTuning&lt;/a&gt;&amp;nbsp;bo już 20 marca. Nie byłem na poprzednim (i żałuję) - tym razem nie odpuszczę :-) Spotkań zwinnego światka jest w Polsce mało, więc trzeba delektować się tym co jest. Z resztą program przekonuje, że warto się wybrać.&lt;br /&gt;&lt;br /&gt;Następnie są spotkania z Mary Poppendieck (kiedyś sprawdzałem co oznacza po niemiecku 'poppen' i odwróciłem oczy; a ten dieck do tego to już w ogóle...) - jedno we Wrocławiu (23 marca) a następne w Krakowie (24 marca). &amp;nbsp;Ciekawe czy się będą od siebie czymś różnić...&lt;br /&gt;&lt;br /&gt;Później (8-9 kwietnia) jest &lt;a href="http://agilece.com/"&gt;AgileCE&lt;/a&gt;. Do tego zachęcam szczególnie - nie tylko będzie masa zagranicznych prelegentów, &amp;nbsp;ale również trochę naszych. Ja opowiem coś o naszych doświadczeniach bycia nearshore'owym zespołem naszego klienta.&lt;br /&gt;&lt;br /&gt;No a potem (19-21 kwietnia) jest nasze szkolenie TDD, do zgłaszania się na które serdecznie zachęcam. Kwestie ceny i miejsca są aktualnie ustalane, do końca tygodnia powinny być już ogłoszone.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2338976640977990159-435304947409595891?l=sprawnainzynieriaoprogramowania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2338976640977990159&amp;postID=435304947409595891' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/435304947409595891'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/435304947409595891'/><link rel='alternate' type='text/html' href='http://sprawnainzynieriaoprogramowania.blogspot.com/2010/03/konferencje.html' title='Konferencje'/><author><name>Paweł Lipiński</name><uri>http://www.blogger.com/profile/02772675014904905654</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-2338976640977990159.post-3408573282316875007</id><published>2010-03-05T23:27:00.000+01:00</published><updated>2010-03-05T23:27:07.731+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='szkolenie tdd'/><title type='text'>Szkolenie TDD</title><content type='html'>Tak, wiem - dość długo nic się tu nie działo. Postaram się niedługo wrócić do częstrzego pisania.&lt;br /&gt;Tymczasem ten wpis też nie ma za wiele treści, ale przynajmniej kieruje do takiego, który ma :-)&lt;br /&gt;&lt;br /&gt;Po sukcesie szkolenia dotyczącego zwinnych metodyk planowaliśmy przeprowadzenie szkolenia z TDD. Niestety (albo stety) ostatnie miesiące były pełne pracy przeplatanej z urlopami, więc nie bardzo było kiedy. Ale nadszedł czas, żeby wreszcie to zrobić.&lt;br /&gt;&lt;br /&gt;Tak więc niniejszym zapowiadam szkolenie z TDD - 3 dni pełne kodowania w parach, emergent design'u, dobrych praktyk, JUnit'a i Mockito, tricków klawiszowych w Eclipse i wiele wiele innych... A przede wszystkim doświadczeni prowadzący: Krzysiek Jelski (aka Uncle Cris) oraz Michał Margiel (aka Ciacho, a konkretnie Pączek*). Ja będę doglądał szkolenie głównie pod kątem donoszenia ciastek i kawy, i może czasem coś wtrącę ;-)&lt;br /&gt;&lt;br /&gt;Szczegóły na &lt;a href="http://blog.pragmatists.pl/"&gt;naszym blogu firmowym&lt;/a&gt; (http://blog.pragmatists.pl)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;*Nieaktualne gdzieś od września. Teraz to bardziej Faworek...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2338976640977990159-3408573282316875007?l=sprawnainzynieriaoprogramowania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2338976640977990159&amp;postID=3408573282316875007' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/3408573282316875007'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/3408573282316875007'/><link rel='alternate' type='text/html' href='http://sprawnainzynieriaoprogramowania.blogspot.com/2010/03/szkolenie-tdd.html' title='Szkolenie TDD'/><author><name>Paweł Lipiński</name><uri>http://www.blogger.com/profile/02772675014904905654</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-2338976640977990159.post-8688531313977211663</id><published>2009-12-09T19:14:00.000+01:00</published><updated>2009-12-09T19:14:08.778+01:00</updated><title type='text'>Po Zwinnym Szkoleniu</title><content type='html'>Reklamowane przeze mnie jakiś czas temu szkolenie Zwinne Rozwijanie Oprogramowania odbyło się w ostatni piątek / sobotę. Zainteresowanych co dokładnie się działo i jak poszło odsyłam do&lt;a href="http://blog.pragmatists.pl/"&gt; naszego firmowego bloga - Studio Pragmatists&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2338976640977990159-8688531313977211663?l=sprawnainzynieriaoprogramowania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2338976640977990159&amp;postID=8688531313977211663' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/8688531313977211663'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/8688531313977211663'/><link rel='alternate' type='text/html' href='http://sprawnainzynieriaoprogramowania.blogspot.com/2009/12/po-zwinnym-szkoleniu_09.html' title='Po Zwinnym Szkoleniu'/><author><name>Paweł Lipiński</name><uri>http://www.blogger.com/profile/02772675014904905654</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-2338976640977990159.post-8822785075800813569</id><published>2009-11-16T15:30:00.000+01:00</published><updated>2009-11-16T15:30:37.844+01:00</updated><title type='text'>Rekrutacja</title><content type='html'>Rozpoczynamy w &lt;a href="http://pragmatists.pl/"&gt;Pragmatists&lt;/a&gt; oficjalną rekrutację. Szczegóły tu: &lt;br /&gt;&lt;a href="http://blog.pragmatists.pl/2009/11/rekrutacja.html"&gt;http://blog.pragmatists.pl/2009/11/rekrutacja.html&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2338976640977990159-8822785075800813569?l=sprawnainzynieriaoprogramowania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2338976640977990159&amp;postID=8822785075800813569' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/8822785075800813569'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/8822785075800813569'/><link rel='alternate' type='text/html' href='http://sprawnainzynieriaoprogramowania.blogspot.com/2009/11/rekrutacja.html' title='Rekrutacja'/><author><name>Paweł Lipiński</name><uri>http://www.blogger.com/profile/02772675014904905654</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-2338976640977990159.post-3482947005303866927</id><published>2009-11-14T01:34:00.001+01:00</published><updated>2009-11-14T14:47:09.469+01:00</updated><title type='text'>TDD a czysty kod</title><content type='html'>W miarę ostatnio na blogu &lt;a href="http://art-of-software.blogspot.com/2009/11/czysty-kod-to-przetestowany-kod.html"&gt;Holistycznie o inżynierii oprogramowania&lt;/a&gt; pojawił się post o TDD i czystym kodzie. Podstawowym założeniem było, że TDD nie ma wiele wspólnego z czystym kodem, że łączenie tych dwóch rzeczy przez Roberta C. Martina zwanego czasem Wujem Bobem jest manipulacją i próbą wylansowania się. I choć Wuj faktycznie jest medialny i ma parcie na LCD, to myślę, że autor jednak trochę się tu zagalopował. Pod koniec autor zamieścił co prawda wytłumaczenie o co mu chodziło w poście, ale cyniczne żarty w jego treści spowodowały, że czyta się go jak tyradę przeciw testom jednostkowym. Co więcej wskazującą na brak praktycznego doświadczenia w takim tworzeniu oprogramowania przez jej autora, więc niestety dla praktyki tej krzywdzącą.&lt;br /&gt;&lt;br /&gt;A że internet to wolne medium, zdecydowałem się zamieścić własny pogląd na TDD i jego rolę w zapewnianiu czystości kodu, tyle, że bazującą na paroletnim doświadczeniu tworzenia w ten sposób oprogramowania.&lt;br /&gt;&lt;br /&gt;Czysty kod to kod czytelny. Wprowadzony przez Donalda Knuth'a termin/idea/paradygmat&lt;a href="http://en.wikipedia.org/wiki/Literate_programming"&gt; &lt;i&gt;Literate Programming&lt;/i&gt;&lt;/a&gt; oznacza prawie to samo. Kod powinien dać się czytać jak literaturę (na tyle na ile to możliwe), powinien być jak najbardziej przejrzysty dla programisty pracującego z nim. Tylko wtedy będzie można zapewnić niski poziom błędów (wiemy co robi i rozumiemy jak to robi) i wysoką utrzymywalność (kod zrozumiały dla każdego kto go czyta). To oczywiście platoński ideał kodu, ale właśnie czysty kod, tak jak opisuje go Uncle Bob w książce &lt;i&gt;Clean Code&lt;/i&gt; zdaje się być temu ideałowi najbliższy (przynajmniej w javie). To kod, który mówi dokładnie co robi. W metodach wyższego poziomu (zwykle o szerszym dostępie) jest kod bardziej odpowiadający na pytanie "co?" a czym niżej, tym bardziej idzie w kierunku "jak?". &lt;br /&gt;&lt;br /&gt;Czytelny kod rzadko powstaje przy pierwszym podejściu. To naturalne, że mamy jakiś pomysł - nasze przemyślenia i doświadczenie podpowiadają nam rozwiązanie i jest ono zwykle w mało czytelnej formie. Czasem jest to paręnaście/parędziesiąt linii odzwierciedlających nasz pomysł na rozwiązanie w formie jakiegoś algorytmu. I to jest nasze pole prób i błędów. Niestety bardzo często kod pozostaje na tym etapie. Tzn. działa, realizuje to o czym akurat myślał jego autor, ale nie komunikuje jasno do czego służy. Potem dodajemy kolejne metody i klasy współpracujące z tą pierwszą i tak powstaje nieczytelna aplikacja o rozmytych odpowiedzialnościach klas i metod.&lt;br /&gt;&lt;br /&gt;Gdyby jednak nie pozostać na poziomie poligonu, tylko spojrzeć na działający kod pod kątem jego czytelności i nadać mu zrozumiałą formę, byłby on nie tylko poprawny, ale też utrzymywalny. Gdy metody mają 2-3 linijki (czasem może 5-7) dużo łatwiej o lepsze ich rozmieszczenie, o przydzielenie odpowiednim klasom, o naturalne wyłanianie się wzorców projektowych (np. strategia, dekorator czy mediator to wzorce, które same wyłaniają się przy poprawnym rozłożeniu odpowiedzialności). Nie mówię, że pojawią się nawet jak ich nie znamy (w końcu to nie czary), ale dostrzeżenie miejsca dla nich jest dużo prostsze. Stąd też refaktoryzacja jest zupełnie nieodzowną praktyką programistyczną. Uważam, że niemożliwe jest napisanie kodu (o realnej złożoności, nie akademickie przykłady) od razu"na czysto". Najpierw realizujemy więc wymaganie, a potem za pomocą refaktoryzacji (i niskopoziomowej i do wzorców projektowych) dochodzimy do czystego kodu.&lt;br /&gt;&lt;br /&gt;Ale zaraz, kod który piszemy realizując jakąś funkcjonalność rzadko żyje sam sobie. Prawie zawsze wchodzi w interakcję z innymi komponentami. Metody nowych klas będą wołane z zewnątrz, same obiekty tworzone w różnych miejscach i na różne potrzeby. Jak więc stworzyć strukturę klasy tak, by była łatwa w użyciu? Jak osiągnąć jednoznaczność wywołań? Jak zapewnić, że nasz kod będzie wygodny w wykorzystaniu z zewnątrz? Hm. Najprościej zasymulować wykorzystanie. Wiemy czego chcemy od obiektów jakiejś klasy, więc to po prostu napiszmy. W ten sposób powstają przykłady.&lt;br /&gt;Piszemy więc np.&lt;br /&gt;&lt;blockquote&gt;email&lt;br /&gt;&amp;nbsp; .withTitle(someTitle)&lt;br /&gt;&amp;nbsp; .withBody(someTextInTheBody)&lt;br /&gt;&amp;nbsp; .shouldBeSentTo(recipient)&lt;br /&gt;&amp;nbsp; .withReplyToAddress(replyTo);&lt;br /&gt;email.send();&lt;br /&gt;&lt;/blockquote&gt;Jakie są szanse utworzenia takiego API za pierwszym razem, bez tworzenia takiego przykładu? Oczywiście można pozostać przy setterach i getterach, ale o ile łatwiej taki kod czytać i zrozumieć o co autorowi chodziło!&lt;br /&gt;A skoro już piszemy takie przykłady, to dlaczego nie napisać tego najpierw. Najlepiej rozpocząć myślenie o klasie właśnie przez pryzmat jej wykorzystania. Każde środowisko programistyczne pozwala automatycznie wygenerować puste definicje metod, więc kod kompiluje się od razu. A jak będziemy mieli gotowy szkielet klasy, wypełniamy ją kodem. W ten właśnie sposób prowadzimy projektowanie przykładami. Dzięki temu nasze klasy mają większe szanse na właściwe rozmieszczenie odpowiedzialności między nimi (bo przykłady definiują właśnie odpowiedzialności) a do tego metody publiczne od razu mają zrozumiałe nazwy. A po zakodowaniu ich "wnętrzności" jeszcze trochę refaktorowania i również wewnętrzna struktura klas będzie przejrzysta.&lt;br /&gt;&lt;br /&gt;Teraz mamy już kod, który powstał dzięki przykładom. No to przykłady można wywalić i pisać nowe... Zaraz! A może za miesiąc będzie trzeba trochę to przerobić... Może będzie trzeba do emaila dodać pole BCC albo formatowanie HTML. To lepiej te przykłady zostawmy - przydadzą się za miesiąc. Dodamy nowe wywołania, zmienimy nazwy tych, które zmienią znaczenie (tak, to też refaktoryzacja). Takie przykłady będące na bieżąco są do tego dość dobrą dokumentacją tego co kod potrafi i jak to osiągnąć. Może za miesiąc do zespołu dojdzie nowy programista i z satysfakcją powiemy mu RTFE ;)&lt;br /&gt;&lt;br /&gt;To jak już mamy te przykłady i utrzymujemy je na bieżąco, jak już definiują nam one wywołania, to dlaczego nie sprawdzać przy okazji czy te wywołania poprawnie działają? Wtedy gdy tylko ktoś zmieni implementację bez modyfikacji przykładu, ten przestanie odzwierciedlać rzeczywistość i automatycznie zgłosi to programiście. Co więcej pozwolą nam one weryfikować świadome zmiany w kodzie w przyszłości. W końcu gdy tylko będzie trzeba zmienić istniejącą funkcjonalność - powiedzmy wszystkich odbiorców maila z tej samej domeny umieścić w CC a z poza w BCC - przykłady nie spełniające tego wymagania zgłoszą nam błędy. Wystarczy je wtedy zaktualizować i kod dalej jest spójny. Albo lepiej - najpierw napisać przykład, który weźmie pod uwagę nowe zmiany, zweryfikuje poprawność ich implementacji, a potem już pewni poprawności uaktualnimy niedziałające przykłady.&lt;br /&gt;&lt;br /&gt;I tak nasze przykłady stają się automatycznymi testami. W większości jednostkowymi, częściowo akceptacyjnymi, gdzieniegdzie integracyjnymi. W połączeniu ze środowiskiem ciągłej integracji dają z niczym nie porównaną pewność poprawności oprogramowania. Przez cały czas. &lt;br /&gt;&lt;br /&gt;W ten sposób od kodu spisanego jak notatka, draft zawierający co prawda meritum, ale w niezrozumiałej dla nikogo oprócz autora formie, dochodzimy do programistycznego dzieła literackiego. Od cowboy-coding do metodycznego rozwijania oprogramowania. Od amatorskiego "żeby działało" do profesjonalnej pewności poprawności. To jest właśnie &lt;i&gt;clean code.&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;Mówiąc krótko: czysty kod jest wynikiem poprawnego stosowania TDD - definicji przykładu, potem implementacji a na koniec refaktoryzacji.&amp;nbsp; TDD pewnie nie jest jedynym sposobem uzyskania tego efektu, ale nie spotkałem się przykładami dużych projektów o czystym kodzie tworzonych bez TDD.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2338976640977990159-3482947005303866927?l=sprawnainzynieriaoprogramowania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2338976640977990159&amp;postID=3482947005303866927' title='Komentarze (22)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/3482947005303866927'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/3482947005303866927'/><link rel='alternate' type='text/html' href='http://sprawnainzynieriaoprogramowania.blogspot.com/2009/11/tdd-czysty-kod.html' title='TDD a czysty kod'/><author><name>Paweł Lipiński</name><uri>http://www.blogger.com/profile/02772675014904905654</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>22</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2338976640977990159.post-6357134120525192627</id><published>2009-11-13T22:46:00.000+01:00</published><updated>2009-11-13T22:46:29.385+01:00</updated><title type='text'>Studio Pragmatists</title><content type='html'>Ostatnio dość mało tu treści, a dużo reklam :) Postaram się, żeby był to ostatni raz.&lt;br /&gt;&lt;br /&gt;Jako Pragmatists postanowiliśmy (wzorem najlepszych) zrobić firmowy blog, na którym będziemy umieszczać aktualności dotyczące naszej działalności, ale co ważniejsze również techniczne artykuły i refleksje dotyczące naszej pracy. Blog nazywa się &lt;a href="http://blog.pragmatists.pl/"&gt;Studio Pragmatists (http://blog.pragmatists.pl)&lt;/a&gt;. &lt;br /&gt;&lt;br /&gt;Pierwszy wpis dotyczy organizowanego przez nas szkolenia, a dokładniej tego, że przed nami ostatni tydzień rejestracji.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2338976640977990159-6357134120525192627?l=sprawnainzynieriaoprogramowania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2338976640977990159&amp;postID=6357134120525192627' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/6357134120525192627'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/6357134120525192627'/><link rel='alternate' type='text/html' href='http://sprawnainzynieriaoprogramowania.blogspot.com/2009/11/studio-pragmatists.html' title='Studio Pragmatists'/><author><name>Paweł Lipiński</name><uri>http://www.blogger.com/profile/02772675014904905654</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-2338976640977990159.post-3159658763215212842</id><published>2009-11-05T15:37:00.000+01:00</published><updated>2009-11-05T15:37:12.457+01:00</updated><title type='text'>Zwinne szkolenie taniej :)</title><content type='html'>Właśnie się zorientowaliśmy, że szkolenia nie podlegają opodatkowaniu VAT, więc szkolenie nagle stało się tańsze i kosztuje okrągłe 2^10zł :)&lt;br /&gt;&lt;br /&gt;Mamy już zarezerwowaną prawie połowę miejsc, więc wszystkim chętnym polecam się pospieszyć!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2338976640977990159-3159658763215212842?l=sprawnainzynieriaoprogramowania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2338976640977990159&amp;postID=3159658763215212842' title='Komentarze (1)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/3159658763215212842'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/3159658763215212842'/><link rel='alternate' type='text/html' href='http://sprawnainzynieriaoprogramowania.blogspot.com/2009/11/zwinne-szkolenie-taniej.html' title='Zwinne szkolenie taniej :)'/><author><name>Paweł Lipiński</name><uri>http://www.blogger.com/profile/02772675014904905654</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-2338976640977990159.post-954949248839094196</id><published>2009-11-01T13:19:00.000+01:00</published><updated>2009-11-01T13:19:21.483+01:00</updated><title type='text'>Ci, którzy odeszli</title><content type='html'>Te święta to dobra okazja nie tylko na refleksję nad sobą, swoim życiem i jego celowością, nad własną rodziną i innym, którym zawdzięczamy to kim jesteśmy, gdzie żyjemy, czy jakie mamy warunki życia. Dla nas - ludzi zajmujących się oprogramowaniem - to może też być czas na refleksję nad tymi, dzięki którym jesteśmy tu gdzie jesteśmy - czas na chwilę wspomnienia wielkich matematyków i informatyków, którzy swoje zawodowe życie (a często i prywatne) oddali temu, co dziś jest naszym zawodem i naszymi narzędziami. By to co kiedyś nieosiągalne i skrajnie trudne mogło dla nas być codziennością.&lt;br/&gt;&lt;br /&gt;Kiedyś już polecałem poniższy film, tym razem polecam przerzucić dokładnie do 74 minuty i oddać dziś tym właśnie ludziom chwilę.&lt;br /&gt;&lt;br /&gt;&lt;embed allowfullscreen="true" allowscriptaccess="always" height="470" src="http://blip.tv/play/6VbaqWQA" type="application/x-shockwave-flash" width="600"&gt;&lt;/embed&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2338976640977990159-954949248839094196?l=sprawnainzynieriaoprogramowania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2338976640977990159&amp;postID=954949248839094196' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/954949248839094196'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/954949248839094196'/><link rel='alternate' type='text/html' href='http://sprawnainzynieriaoprogramowania.blogspot.com/2009/11/ci-ktorzy-odeszli.html' title='Ci, którzy odeszli'/><author><name>Paweł Lipiński</name><uri>http://www.blogger.com/profile/02772675014904905654</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-2338976640977990159.post-2325664455266742383</id><published>2009-10-31T23:03:00.000+01:00</published><updated>2009-10-31T23:03:19.753+01:00</updated><title type='text'>Zwinne szkolenie</title><content type='html'>Zeszłoweekendowa warsjava była chyba pierwszym większym Warszawskim spotkaniem ludzi zainteresowanych zwinnymi metodykami. Jej sukces (ponad 100 osób z tego co wiem i z tego co widziałem) pokazuje, że zwinne tematy są nie tylko ciekawe, ale przede wszystkim ważne. Idąc za ciosem zdecydowaliśmy się jako &lt;a href="http://www.pragmatists.pl/"&gt;Pragmatists&lt;/a&gt; podzielić się naszą wiedzą i doświadczeniami dojścia do tego co osiągnęliśmy w większych szczegółach. A osiągnęliśmy myślę, że dość niezwykłą rzecz. Jesteśmy zespołem, który realizuje to o czym mówi: krótkie iteracje, TDD, programowanie w parach, prawdziwy &lt;i&gt;shippable product&lt;/i&gt; na koniec każdej iteracji,&amp;nbsp; i wiele innych zwinnych praktyk wcielonych w życie. Ale przede wszystkim jesteśmy ukierunkowani na przynoszenie wartości, na pokonywanie barier i problemów, na dawanie swojego czasu, wiedzy, doświadczenia i zaangażowania naszym klientom. Staramy się skupiać na poprawianiu swojej efektywności i jakości.&lt;br /&gt;Zdecydowaliśmy się więc zorganizować otwarte dwudniowe szkolenie ze Zwinnego Rozwijania Oprogramowania. Szkolenie planowane jest dla 15~20 osób zainteresowanych pogłębieniem swojej wiedzy w tym zakresie i zdobyciem nowych doświadczeń. Szkolenie prowadzić będę ja wraz z Krzyśkiem Jelskim, który na warsjavie i ostatniej javarsovii zajmował się tematem TDD oraz ma za sobą dobre parę lat doświadczenia pracy w zwinnych zespołach. Obiecujemy nie tylko masę wartościowej, konkretnej wiedzy, ale również dobrą zabawę pomagającą utrwalić i zweryfikować nowe umiejętności.&lt;br /&gt;&lt;br /&gt;Szczegóły dotyczące szkolenia są tu: &lt;a href="http://pragmatists.pl/szkolenie"&gt;http://pragmatists.pl/szkolenie&lt;/a&gt;. W razie wątpliwości / pytań piszcie.&lt;br /&gt;Zapraszam!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2338976640977990159-2325664455266742383?l=sprawnainzynieriaoprogramowania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2338976640977990159&amp;postID=2325664455266742383' title='Komentarze (3)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/2325664455266742383'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/2325664455266742383'/><link rel='alternate' type='text/html' href='http://sprawnainzynieriaoprogramowania.blogspot.com/2009/10/zwinne-szkolenie.html' title='Zwinne szkolenie'/><author><name>Paweł Lipiński</name><uri>http://www.blogger.com/profile/02772675014904905654</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-2338976640977990159.post-6419090671019387078</id><published>2009-10-26T09:17:00.001+01:00</published><updated>2009-10-26T13:41:55.271+01:00</updated><title type='text'>Po WarsJawie</title><content type='html'>W ten weekend była warsjawa. Kto nie był niech (raczej) żałuje. To chyba było pierwsze większe spotkanie w Warszawie dotyczące zwinnych metodyk. I na pierwszy rzut oka widać było, że brakuje takich spotkań. Po pierwsze - było chyba ponad 100 osób, co od razu wskazuje na to, że temat jest ciekawy. Po drugie - to, że trzeba takie spotkania organizowa widać po pytaniach. Masa dotyczących estymacji (o co w ogóle chodzi), długości i zawartości spotkań, itp. Czyli dość podstawowe.&lt;br /&gt;Oczywiście świetnie, że ludzie chcą się uczyć i poznawać, z drugiej szkoda, że jest jeszcze tak mało doświadczeń.&lt;br /&gt;Tak czy siak, Łukasz (wraz z resztą organizatorów): wielkie dzięki za zorganizowanie tego spotkania!&lt;br /&gt;&lt;br /&gt;Jeśli ktoś chce przejrzeć moją prezentację (zanim organizatorzy wrzucą ją na parleys'a), to jest ona tu:&amp;nbsp; &lt;br /&gt;&lt;a href="http://www.pragmatists.pl/Downloads/Pragmatists%20-%20I%20Twoj%20zespol%20moze%20byc%20zwinny.pdf"&gt;I Twój zespół może być zwinny.&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;I jeszcze jedno. Strasznie mnie wkurza zwrot "w agile'u" (wielokrotnie słyszałem go na warsjawie). Po angielsku słowo &lt;i&gt;agile&lt;/i&gt; jest przymiotnikiem. To tak jakby powiedzieć "w zwinny'u używamy iteracji" :-P&lt;br /&gt;Zresztą większość zdań tego typu jest i tak nieprawdziwych - manifest zwinnego rozwijania oprogramowania bardzo mało mówi o konkretnych praktykach. Zamiast tego lepiej powiedzieć "w scrum'ie" albo "w XP" gdy odnosimy się do praktyk konkretnej metodyki.&lt;br /&gt;Z drugiej strony, utożsamianie zwinnego myślenia (jako podejścia, filozofii) z konkretną metodyką jest również błędem (szczególnie częste jest to w przypadku scrum'a, i szczególnie nieprawdziwe) - metodyki definiują procesy i praktyki, nie skupiają się raczej na wartościach (no, poza XP oczywiście).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2338976640977990159-6419090671019387078?l=sprawnainzynieriaoprogramowania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2338976640977990159&amp;postID=6419090671019387078' title='Komentarze (2)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/6419090671019387078'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/6419090671019387078'/><link rel='alternate' type='text/html' href='http://sprawnainzynieriaoprogramowania.blogspot.com/2009/10/po-warsjawie.html' title='Po WarsJawie'/><author><name>Paweł Lipiński</name><uri>http://www.blogger.com/profile/02772675014904905654</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-2338976640977990159.post-8896906213951291928</id><published>2009-10-21T02:04:00.001+02:00</published><updated>2010-02-19T16:28:57.898+01:00</updated><title type='text'>Wprowadzenie do zwinnego rozwijania oprogramowania</title><content type='html'>W związku ze zbliżającą się konferencją warsjawa (na której będę opowiadał o transformacji zespołów na zwinne metodyki), oraz brakiem czegoś podobnego w języku polskim, poświęciłem parę wieczorów i napisałem wprowadzenie do zwinnego rozwijania oprogramowania (zwykle nazywane jest to agile introduction). &lt;br /&gt;&lt;br /&gt;W czasie warsjawy nie będzie żadnej prezentacji wprowadzającej do zwinnego myślenia i zwinnych metodyk, więc jeśli ktoś nie miał z nimi dotychczas praktycznego kontaktu, nieskromnie polecam!&lt;br /&gt;&lt;br /&gt;&lt;a href="http://pragmatists.pawellipinski.com/Downloads/Pragmatists%20-%20Zwinne%20Rozwijanie%20Oprogramowania.pdf"&gt;http://pragmatists.pawellipinski.com/Downloads/Pragmatists%20-%20Zwinne%20Rozwijanie%20Oprogramowania.pdf&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2338976640977990159-8896906213951291928?l=sprawnainzynieriaoprogramowania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2338976640977990159&amp;postID=8896906213951291928' title='Komentarze (1)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/8896906213951291928'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/8896906213951291928'/><link rel='alternate' type='text/html' href='http://sprawnainzynieriaoprogramowania.blogspot.com/2009/10/wprowadzenie-do-zwinnego-rozwijania.html' title='Wprowadzenie do zwinnego rozwijania oprogramowania'/><author><name>Paweł Lipiński</name><uri>http://www.blogger.com/profile/02772675014904905654</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-2338976640977990159.post-3670967785184191755</id><published>2009-10-14T10:26:00.000+02:00</published><updated>2009-10-14T10:26:29.599+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><category scheme='http://www.blogger.com/atom/ns#' term='zwinność'/><category scheme='http://www.blogger.com/atom/ns#' term='wydajność'/><title type='text'>Przedwczesna optymizacja</title><content type='html'>Przeglądając stronę wikipedii dotyczącą eXtreme Programming znalazłem wśród praktyk programistycznych następujące zalecenie: 'leave optimization till last'. No i faktycznie zdaje się, że jest to dość uznana zasada. Przywołuje na myśl znane zdanie Donalda Knutha&lt;br /&gt;&lt;blockquote&gt;Premature optimization is the root of all evil.&lt;/blockquote&gt;Z drugiej strony zwinne metodyki zalecają utrzymywanie projektu przez cały czas jego rozwoju w stanie gotowości do wdrożenia. Scrum nazywa to &lt;i&gt;potentially shippable product&lt;/i&gt; - na koniec każdej iteracji przygotowujemy więc wszystko co niezbędne, żeby produkt tej iteracji można było wdrożyć (nie dlatego, żeby to faktycznie co iterację robić, tylko dlatego, by utrzymywać taką możliwość i dać klientowi prawo do decyzji co do tego kiedy chce aplikację wdrożyć, zaprezentować użytkownikom itp. Poza tym robiąc to jesteśmy pewni, że projekt jest cały czas zintegrowany, i że nasz system CI i proces tworzenia oprogramowania są dobre. No i jeszcze kwestia morale zespołu, gdy wie, że projekt jest non-stop w stanie jakościowo gotowym na produkcję).&lt;br /&gt;&lt;br /&gt;Wracając do zostawiania optymizacji na koniec, zupełnie nie zgadzam się z tym. To klasyczny przypadek zostawiania gdzieś praktyk fazowych (waterfall'owych). Jak można nazwać aplikację potencjalnie gotową do wdrożenia, jeśli nie jest wystarczająca wydajnościowo?&lt;br /&gt;Tak więc optymizujmy kod w czasie jego rozwijania. Może nawet warto dodać do Definition of Done zadań zespołu warunek akceptowalności pod względem wydajnościowym.&lt;br /&gt;&lt;br /&gt;Oczywiście we wszystkim należy zachować umiar. Ważne jest, by wydajność była akceptowalna / zadowalająca. To może oczywiście oznaczać bardzo rygorystyczne warunki np. dla systemów RT. Szczegółowy fine-tuning wydajności jakichś elementów aplikacji można jednak faktycznie zostawić na później. To znaczy jak się już okaże, że faktycznie jest problem wydajnościowy i będzie wiadomo dokładnie gdzie. Oczywiście nie sądzę, żeby było dobrym pomysłem czekanie aż okaże się to w środowisku produkcyjnym - dla aplikacji dla których wysoka wydajność jest ważna można ją kontrolować stale w czasie rozwoju aplikacji w przeznaczonym do tego środowisku CI z automatycznymi testami wydajnościowymi. Natomiast powinniśmy dbać o nieograniczanie (głównie architektonicznie) naszych możliwości optymizacji.&lt;br /&gt;&lt;br /&gt;Z resztą powyższy cytat z Knuth'a nie jest kompletny (a większość programistów zna tylko ten jego fragment). Kompletny brzmi tak:&lt;br /&gt;&lt;blockquote&gt;&lt;span class="Apple-style-span" style="line-height: 19px;"&gt;&lt;span style="font-family: inherit;"&gt;We should forget about &lt;b&gt;small efficiencies&lt;/b&gt;, say about 97% of the time: premature optimization is the root of all evil.&lt;/span&gt;&lt;/span&gt;&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2338976640977990159-3670967785184191755?l=sprawnainzynieriaoprogramowania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2338976640977990159&amp;postID=3670967785184191755' title='Komentarze (3)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/3670967785184191755'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/3670967785184191755'/><link rel='alternate' type='text/html' href='http://sprawnainzynieriaoprogramowania.blogspot.com/2009/10/przedwczesna-optymizacja.html' title='Przedwczesna optymizacja'/><author><name>Paweł Lipiński</name><uri>http://www.blogger.com/profile/02772675014904905654</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-2338976640977990159.post-7655258439175560715</id><published>2009-09-21T22:42:00.001+02:00</published><updated>2009-09-21T22:45:50.289+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><category scheme='http://www.blogger.com/atom/ns#' term='zwinność'/><category scheme='http://www.blogger.com/atom/ns#' term='architektura'/><category scheme='http://www.blogger.com/atom/ns#' term='konferencja'/><title type='text'>Agileee retrospective</title><content type='html'>This post is in english, since the conference was mainly in english (and maybe some agileeestas would like to read it.)&lt;br /&gt;&lt;br /&gt;So, the conference was simply great. Maybe not perfect, but great.&lt;br /&gt;I even had a little influence on its shape by having a talk there (the slides are&amp;nbsp;&lt;a href="http://www.slideshare.net/pragmatists/evolution-of-architecture-in-agile-projects"&gt;here&lt;/a&gt;...)&lt;br /&gt;&lt;br /&gt;So let me summarise it:&lt;br /&gt;&lt;br /&gt;WHAT WAS GOOD:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;venue&lt;/li&gt;&lt;li&gt;lunch&lt;/li&gt;&lt;li&gt;keynotes (Jutta Eckstein with her 'distributed agile' talk - have heard her already twice with a similar subject before, but there's always something new; David Hussman with a really touching closing talk underlining how important it is to follow what you believe in)&lt;/li&gt;&lt;li&gt;many talks&lt;/li&gt;&lt;li&gt;speaker's night out (and I thought that Poles drink a lot...)&lt;/li&gt;&lt;li&gt;lots of nice, clever and experienced people&lt;/li&gt;&lt;li&gt;ratio: cost / value&amp;nbsp;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;WHAT COULD BE BETTER:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;coffee and water not always available&amp;nbsp;&lt;/li&gt;&lt;li&gt;some talks really for agile-beginners (maybe there should be some 'experience level' mark by each talk, so that you go to the level you're at)&lt;/li&gt;&lt;li&gt;stage in Russian (I mean I could be better and speak Russian, there must have been a lot of valueable stuff, otherwise unavailable for a non-ex-soviet-country guy)&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;PLANS TO HAVE A BETTER AGILEEE IN FUTURE:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;learn Russian&lt;/li&gt;&lt;li&gt;don't loose the conference schedule and read in advance where you plan to go to&lt;/li&gt;&lt;li&gt;meet even more people on corridors&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;So in total I'd say 8/10 (just to leave the organisers some place for kaizen...)&lt;br /&gt;I really hope to be there next year, and wish it to you all!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2338976640977990159-7655258439175560715?l=sprawnainzynieriaoprogramowania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2338976640977990159&amp;postID=7655258439175560715' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/7655258439175560715'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/7655258439175560715'/><link rel='alternate' type='text/html' href='http://sprawnainzynieriaoprogramowania.blogspot.com/2009/09/agileee-retrospective.html' title='Agileee retrospective'/><author><name>Paweł Lipiński</name><uri>http://www.blogger.com/profile/02772675014904905654</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-2338976640977990159.post-4111153078454409806</id><published>2009-09-07T21:54:00.004+02:00</published><updated>2009-09-07T23:07:32.916+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><category scheme='http://www.blogger.com/atom/ns#' term='zwinność'/><category scheme='http://www.blogger.com/atom/ns#' term='zespół'/><title type='text'>Pierwszy release</title><content type='html'>Dziś w &lt;a href="http://www.pragmatists.pl"&gt;Pragmatists&lt;/a&gt; mieliśmy pierwsze wdrożenie pierwszego projektu. To taki miły moment, kiedy jest wreszcie chwila na zastanowienie się jak poszło. Na przemyślenie co można następnym razem lepiej. Jak nie popełniać pewnych błędów, jak pomagać klientom nie wpadać w pułapki.&lt;br /&gt;&lt;br /&gt;Projekt był hybrydowy - z naszej strony staraliśmy się robić wszystko zwinnie - zaczęliśmy klasycznie od ustalenia z klientem o co mu chodzi, utworzyliśmy masę &lt;span style="font-style: italic;"&gt;User Stories&lt;/span&gt;, zrobiliśmy estymacje, backlogi, pracowaliśmy w parach, TDD, itp. itd. Z drugiej strony nasz klient, choć z grubsza chętny do zwinnego podejścia, jednak z własną historią i przyzwyczajeniami (bardzo niezwinnymi). I do tego z projektem, który miał już wyznaczony termin wdrożenia, choć jeszcze nie wiadomo było dokładnie co ma być zrobione. I to jest pierwsza pułapka i chyba bardzo częsta. Terminy rzadko ustala zespół. To często element negocjacji, jakby niemerytoryczny - ustalany między managerami i salesami. W naszym przypadku nasz klient naprawdę nie wiedział czego chce ich klient (który jest użytkownikiem aplikacji) poza ogólnikami i własnymi domysłami (z resztą błędnymi, więc po pierwszych 2 miesiącach pracy zakomunikowano nam, że trzeba zacząć od nowa i zrobić coś zupełnie innego :)). Myśmy na to przystali (no cóż, nie zdobywa się klientów od stawiania im warunków...) i skutek był taki, że ostatnie 4 tygodnie były zmaganiem z czasem, wymaganiami (prośba o ostatnią zmianę w aplikacji pojawiła się wczoraj, w niedzielę, o 22:30...) i stresem własnym i klienta.&lt;br /&gt;To podstawowa różnica między projektem zwinnym a klasycznym - w zwinnym &lt;span style="font-weight: bold;"&gt;termin jest funkcją zakresu wymagań i prędkości zespołu&lt;/span&gt;. Dlatego staramy się dostarczać aplikacje przyrostowo, wtedy terminy przestają być kluczowe, bo klient zaczyna dostawać aplikację wcześniej i ma realny wpływ na jej zawartość, a więc również na termin kiedy zacznie ją wykorzystywać. A więc:&lt;br /&gt;&lt;blockquote&gt;Action Point 1: zachęcić klienta do spróbowania teraz (po tych średnio miłych doświadczeniach ostatniego miesiąca) "naszego" sposobu - nie tylko pokazywać, ale dostarczać kolejne wersje aplikacji na produkcję co 2 tygodnie. Dzięki temu nie będzie gorączki przedwdrożeniowej, ale stały jasny dla wszystkich proces regularnego dostarczania już-nie-tylko-&lt;span style="font-style: italic;"&gt;potentially shippable product&lt;/span&gt;'u (mamy zadbane środowisko CI, więc jakby się uprzeć, to z technicznego punktu widzenia moglibyśmy dostarczać nawet codziennie).&lt;br /&gt;&lt;/blockquote&gt;Kolejne doświadczenie to komunikacja. Tutaj mamy wciąż dużo do poprawy. To, że nie mamy bezpośredniego kontaktu z użytkownikiem wpływa na naszą niepewność co do tego, czego on może tak naprawdę potrzebować. Jak chciałby pracować z aplikacją. Np. dwa tygodnie przed wdrożeniem dowiedzieliśmy się, że użytkownik lubi na raz pracować z excel'ami o setkach wierszy, bo wtedy "wszystko widzi" - a nasz a'la-excel'owy mechanizm wspiera raczej nie więcej niż 50 wierszy.&lt;br /&gt;Nasz klient jest 1300km od nas i sprawność komunikacji jest kluczowa. Maile nie zawsze starczają a cotygodniowe spotkania iteration review/planning  nie dają nam odpowiedzi na kluczowe pytania: czy aplikacja się podoba, czy są zadowoleni (z aplikacji, postępu,itp.)&lt;br /&gt;&lt;blockquote&gt;Action Point 2: Bardziej cisnąć o informacje w czasie planowania - w czasie trwania iteracji MUSIMY wiedzieć dokładnie co mamy robić i czemu to ma służyć.&lt;/blockquote&gt;Zespół = Ludzie + Interakcje. Widzę to codziennie. Są dni, kiedy widać jak na dłoni, że pracując razem stanowimy dużo więcej niż gdyby każdy pracował oddzielnie. Wpadamy na lepsze pomysły (bo dużo dyskutujemy, a więc projektujemy), tworzymy lepszy kod (bo wiele osób go czyta i pisze, a więc musi być zrozumiały), nakręcamy się do pracy (bo to nie tylko nasz chleb, ale głównie nasza pasja), zachęcamy się do nauki i ciągłego ulepszania samych siebie ("kuuuurde, chłopaki, ale książkę znalazłem...", "ej, Kamil, jest tam coś ciekawego w tym artykule?", "Paweł, w mordę, nie pisz takiego szitu, przecież to można ładniej zrobić!") Są dni, kiedy wychodząc z pracy dobrze rozumiem dlaczego moje dzieci płaczą, że nie chcą jeszcze wracać gdy ich odbieram z przedszkola.&lt;br /&gt;&lt;blockquote&gt;Action Point 3: jeszcze więcej pracy w parach, jeszcze więcej dyskusji przy tablicy, jeszcze więcej chłonięcia wiedzy od siebie i wspólnego tworzenia nowej.&lt;/blockquote&gt;Testy, testy i jeszcze raz testy (automatyczne). To jedyny sposób robienia oprogramowania wysokiej jakości. To jedyny sposób żeby być pewnym, że możesz dostarczyć aplikację KIEDY TYLKO KLIENT ZECHCE. To jedyny sposób na uniknięcie długich niezrozumiałych metod i niejasnych rozwiązań. To jedyny sposób na weryfikowanie poprawności twoich pomysłów gdy aplikacja już się rozrosła (inaczej marnujesz długie godziny na klikanie i debugowanie). To w końcu jedyny sposób by móc sobie powiedzieć: zrobiłem (done) i jestem tego pewien. A to jedno z milszych uczuć jakie mamy w naszej pracy. Nie wierzę, że może twierdzić inaczej ktoś kto choć raz brał udział w tak rozwijanym projekcie (jest to zdecydowanie najwyższej jakości projekt w jakim brałem udział w życiu, a mam za sobą ponad 10 lat pracy w developmencie i pewnie ponad 20 projektów różnego rozmiaru za sobą).&lt;br /&gt;Testy dają nam poczucie pewności a naszemu klientowi możliwość prawie dowolnego kształtowania i modyfikowania wymagań - a to przekłada się w prostej linii na jego przewagę nad konkurencją.&lt;br /&gt;&lt;blockquote&gt;Action Point 4: weryfikacja (ciągła) pokrycia funkcjonalności testami (nie pokrycia linii kodu, ale pokrycia funkcjonalności) i dorabianie ich tam, gdzie ich brakuje.&lt;br /&gt;&lt;br /&gt;Action Point 5: definiowanie zakresu iteracji za pomocą testów akceptacyjnych (A-TDD) - to dotyczy zarówno kwestii elastyczności wymagań, jakości produktu, jak i (a może przede wszystkim) komunikacji z klientem.&lt;/blockquote&gt;To tak z grubsza większość moich przemyśleń co do tego projektu. Widziałem w tym czasie zaangażowanie, kreatywność i pasję. Obserwowałem (a trochę może też wpływałem na) tworzenie się z grupy ludzi zespołu. Rodzenia się odpowiedzialności i poczucia wspólnego celu. Wiele jeszcze oczywiście przed nami. Ale przecież to zaledwie początek.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2338976640977990159-4111153078454409806?l=sprawnainzynieriaoprogramowania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2338976640977990159&amp;postID=4111153078454409806' title='Komentarze (5)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/4111153078454409806'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/4111153078454409806'/><link rel='alternate' type='text/html' href='http://sprawnainzynieriaoprogramowania.blogspot.com/2009/09/pierwszy-release.html' title='Pierwszy release'/><author><name>Paweł Lipiński</name><uri>http://www.blogger.com/profile/02772675014904905654</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-2338976640977990159.post-3407946159594939346</id><published>2009-08-27T22:44:00.002+02:00</published><updated>2009-08-27T23:04:58.506+02:00</updated><title type='text'>EA - niepewność? zweryfikuj to w kodzie</title><content type='html'>Architekci bardzo często podejmują decyzje bazując na swoim doświadczeniu. Często jest ono szerokie i faktycznie wystarczające do podjęcia decyzji. Ale wielokrotnie pewne decyzje podejmowane są w pośpiechu i tak naprawdę na zasadzie "tak powinno być dobrze" albo "to raczej wystarczy". Architekci zdecydowanie zbyt rzadko weryfikują swoje pomysły w kodzie. Nie jest tak, że nigdy - tam gdzie pracowałem jako architekt miałem szczęście, że zawsze była możliwość spędzenia trochę czasu na poszukiwaniach dobrego rozwiązania. Ale często podjąć decyzję w oparciu o "duże szanse, że tak jest ok" jest dużo łatwiej niż zweryfikować ją. Tak z ręką na sercu - często się po prostu nie chce. Gdy plany architektoniczne powstają niezależnie od właściwej aplikacji (przed) zweryfikowanie czegokolwiek w kodzie wymaga napisania często naprawdę dużych ilości kodu.&lt;br /&gt;&lt;br /&gt;Przy ewolucyjnym podejściu do architektury, nie dość, że decyzje są raczej mniejsze, bazujące na ciągle rosnącej wiedzy o systemie, ale również są one łatwiej weryfikowalne. Często jakiś pomysł architektoniczny można zweryfikować w oparciu o istniejącą aplikację - mniej kodu do pisania, a i bardziej pewny będzie wynik. Z resztą programujący architekt ma dużą wprawę w pisaniu kodu (nie zapomina jak to jest, a to akurat się dość łatwo zapomina) więc i napisanie odpowiedniego POC'a nie jest dużym problemem.&lt;br /&gt;&lt;br /&gt;Bardzo często decyzje wpływające na wydajność aplikacji podejmuje się w oparciu o założenia: że maszyna wirtualna zoptymalizuje kod, że sprzęt jest wystarczający, że to zadanie przecież wcale nie jest takie kosztowne czasowo, itp. Czasem wystarczy też dosłownie pół dnia pracy na zweryfikowanie takich założeń jakimś kawałkiem kodu. Biorąc pod uwagę koszty ewentualnych późniejszych zmian (choćby tylko czasowe, związane z przepisywaniem) raczej warto posiedzieć i sprawdzić czy nasze pomysły naprawdę są aż tak dobre :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2338976640977990159-3407946159594939346?l=sprawnainzynieriaoprogramowania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2338976640977990159&amp;postID=3407946159594939346' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/3407946159594939346'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/3407946159594939346'/><link rel='alternate' type='text/html' href='http://sprawnainzynieriaoprogramowania.blogspot.com/2009/08/ea-niepewnosc-zweryfikuj-to-w-kodzie.html' title='EA - niepewność? zweryfikuj to w kodzie'/><author><name>Paweł Lipiński</name><uri>http://www.blogger.com/profile/02772675014904905654</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-2338976640977990159.post-5214744834210439379</id><published>2009-07-31T22:40:00.003+02:00</published><updated>2009-07-31T23:28:28.980+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><category scheme='http://www.blogger.com/atom/ns#' term='zespół'/><title type='text'>Self Organizing Teams</title><content type='html'>W świecie agile'owym promuje się  samoorganizację zespołów. Gdy zespół sam potrafi prowadzić swoją pracę, gdy bierze odpowiedzialność za swoje zobowiązania, ma wszelkie uprawnienia by je realizować i to robi można go nazwać samoorganizującym się. Takie zespoły działają dużo efektywniej niż prowadzone klasycznie metodą poleceń i kontroli ich wykonania. Po pierwsze bardziej im się chce, bo czują się odpowiedzialni za swoją pracę. Po drugie mają większą satysfakcję, ponieważ mają dużo większą wolność. Po trzecie nie czują się traktowani jak dzieci (na temat związku idei agile'owych z wychowaniem dzieci też mam swoją teorię, ale nie o tym ten post :-))&lt;br /&gt;&lt;br /&gt;Od samego początku firmy &lt;a href="http://www.pragmatists.pl"&gt;Pragmatists&lt;/a&gt; chciałem stworzyć takie środowisko, w którym branie odpowiedzialności, zaangażowanie i samoorganizacja będą czymś normalnym. Środowisko, w którym o wszystkim decyduje zespół mając na względzie dobro swoje (wzajemnie poszczególnych osób w zespole), firmy i klientów. Gdzie zespół uzgadnia swój sposób pracy, co może zrobić i na kiedy, gdzie stoją biurka i jaką chcą pić kawę. Ale również chciałem by było miejsce na zrozumienie i szacunek dla potrzeb innych, dla decyzji klientów, dla możliwości firmy.&lt;br /&gt;&lt;br /&gt;I to się udalo - mimo projektu w toku (a jego pierwszej fazy to właściwie pod koniec) wyjechałem na 3-tygodniowe wakacje zostawiając zespół na pastwę projektu i klienta :-). Przez ten czas funkcjonalności były dodawane wcale nie wolniej niż ze mną (niektórzy sądzą, że nawet szybciej...), odbywały się regularnie standupy i retrospekcje, zakupione zostały lepsze klawiatury i mleko do kawy, odbywał się ciągły kontakt z klientem i w końcu nawet potrzeba drobnej regulacji kontaktów z klientem z moim drobnym udziałem.&lt;br /&gt;Był to w jakiejś mierze test realizacji moich oczekiwań (niniejszym patentuję termin &lt;span style="font-style: italic;"&gt;Test-Driven Company Development&lt;/span&gt;). Teraz oczywiście pora na małą refaktoryzację, by jeszcze poprawić już dobrze działający mechanizm :)&lt;br /&gt;&lt;br /&gt;Mój Drogi Zespole, bardzo Wam dziękuję!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2338976640977990159-5214744834210439379?l=sprawnainzynieriaoprogramowania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2338976640977990159&amp;postID=5214744834210439379' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/5214744834210439379'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/5214744834210439379'/><link rel='alternate' type='text/html' href='http://sprawnainzynieriaoprogramowania.blogspot.com/2009/07/self-organizing-teams.html' title='Self Organizing Teams'/><author><name>Paweł Lipiński</name><uri>http://www.blogger.com/profile/02772675014904905654</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-2338976640977990159.post-2789612929551663798</id><published>2009-07-31T21:17:00.003+02:00</published><updated>2009-07-31T22:38:46.067+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><category scheme='http://www.blogger.com/atom/ns#' term='zwinność'/><category scheme='http://www.blogger.com/atom/ns#' term='architektura'/><title type='text'>EA - KISS</title><content type='html'>&lt;span style="font-style: italic;"&gt;Keep It Simple, Stupid!&lt;/span&gt; mówi starobrytyjskie porzekadło. Jak jest ono prawdziwe wie każdy, kto choć raz przedzierał się przez gąszcz klas, chaszcze metod i bagna logiki przesadnie zaprojektowanych aplikacji. Chęć przewidzenia przyszłych wymagań pcha nas często w pułapkę używania skomplikowanych konstrukcji tam gdzie dużo prostsze  były by wystarczające. A skomplikowane struktury, gdy kod nie komunikuje jasno ich celu, rozwijają się szybko w totalnie niezrozumiałe monstra. Wystarczy dorzucić do nich jednego if-a tu, i jeszcze dwa tam, i początkowo śliczna implementacja wzorca przeradza się we włoskie danie z sosem bolognese.&lt;br /&gt;W zwinnych projektach staramy się bronić przed takimi sytuacjami przez ciągłe projektowanie i refaktoryzację aplikacji (TDD).  Praca w parach pozwala nam na ciągłe weryfikowanie wprowadzanego kodu niejako z zewnątrz - przez kolegę, który być może trzeźwiejszym okiem oceni nasze zapędy.&lt;br /&gt;Ale to techniki które można stosować na poziomie kodu. A co z architekturą? Przecież cała idea definiowania architektury to przewidywanie przyszłości. Przecież to właśnie dzięki dobrym wstępnym decyzjom aplikację będzie można np. prawie liniowo skalować, czy umożliwić jej łatwą integrację z korporacyjnym ESB.&lt;br /&gt;&lt;br /&gt;Żeby nie wpaść w pułapki podjęcia błędnych decyzji, lub roztrząsania zupełnie nieistotnych kwestii posługujemy się terminem &lt;span style="font-style: italic;"&gt;last responsible moment.&lt;/span&gt; Jest to ten moment przed którym podjęcie decyzji może być przedwczesne (niewystarczające/niepełne informacje mogą spowodować podjęcie błędnej decyzji), a po którym jej niepodjęcie może powodować jakieś straty (np. zbyt wczesne podjęcie decyzji o wyborze Oracla a nie MySQL może narazić nas na ogromne koszty, zbyt późne podjęcie decyzji może oznaczać konieczność przepisania fragmentów aplikacji). Staramy się więc powstrzymywać od podejmowania decyzji w kwestiach które nas aktualnie nie dotyczą, ale bardzo pilnie obserwować i dyskutować te które mają wpływ na naszą aktualną pracę.&lt;br /&gt;&lt;br /&gt;Aby móc pracować w taki sposób utrzymujemy naszą architekturę maksymalnie prostą, ale zawsze w takim stanie, by umożliwić jej modyfikację. Bo gdy założymy, że architektura ewoluuje wraz z rozwojem systemu, możemy też założyć, że ma ona wspierać wyłącznie te własności które są niezbędne TERAZ i których wymagalności jesteśmy absolutnie pewni (YAGNI). Z resztą czym prostsza architektura tym łatwiej ją komunikować w ramach zespołu i tym łatwiej zapanować nad nią zespołowi. A czym większy zespół tym bardziej jest to prawdziwe.&lt;br /&gt;&lt;br /&gt;Podobnie jak w przypadku projektowania na niższym poziomie, staramy się cały czas patrzeć kiedy prostota techniczna rozwiązanie zaczyna przeszkadzać w utrzymaniu prostoty wyrazu. Taką sytuację można zwykle poznać po liczbie bezpośrednich zależności - jeśli jest ich za dużo, prostota techniczna naszego rozwiązania przestaje być wartością - trzeba więc poszukać rozwiązania bogatszego technicznie i poprawiającego komunikatywność, zrozumiałość naszego pomysłu. Powinniśmy cały czas utrzymywać balans między prostotą techniczną i prostotą wyrazu.&lt;br /&gt;&lt;br /&gt;Dbamy więc symetrię, modularność &lt;span style="font-style: italic;"&gt;(high cohesion, low coupling)&lt;/span&gt;, rozdzielenie warstw, oddzielenie dziedziny od elementów infrastrukturalnych, uniezależnienie od zewnętrznych bibliotek / frameworków, itp. Jeśli pomyślimy o tych cechach w kontekście prostoty, to to jest to, co one faktycznie promują. Kod podzielony na małe moduliki jest prostszy od monolitycznej masy. Każdy z modułów z dobrze wydzieloną pojedynczą odpowiedzialnością jest prostszy niż masa if-ów i switch'y weryfikujących poszczególne przypadki.&lt;br /&gt;&lt;br /&gt;Pilnowanie i dbanie o prostotę rozwiązań oraz zachowywanie zasady wysokiej wewnętrznej spójności i małego poziomu uzależnienia od zewnętrznych elementów (na każdym poziomie), ułatwia tworzenie zwinnych architektur pozwalających na reagowanie na zmiany wymagań.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2338976640977990159-2789612929551663798?l=sprawnainzynieriaoprogramowania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2338976640977990159&amp;postID=2789612929551663798' title='Komentarze (2)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/2789612929551663798'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/2789612929551663798'/><link rel='alternate' type='text/html' href='http://sprawnainzynieriaoprogramowania.blogspot.com/2009/07/ea-kiss.html' title='EA - KISS'/><author><name>Paweł Lipiński</name><uri>http://www.blogger.com/profile/02772675014904905654</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-2338976640977990159.post-5717277505133219846</id><published>2009-07-21T21:37:00.003+02:00</published><updated>2009-07-31T22:39:37.898+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><category scheme='http://www.blogger.com/atom/ns#' term='zwinność'/><category scheme='http://www.blogger.com/atom/ns#' term='architektura'/><title type='text'>EA - zespół który koduje system musi go projektować</title><content type='html'>Poprzednim razem pisałem ogólnie o architekturze w projektach zwinnych. Generalna zasada jest taka, że nad architekturą staramy się zastanawiać nie (wyłącznie) na początku, ale w każdej iteracji. Ale żeby móc coś takiego osiągnąć &lt;span style="font-weight: bold;"&gt;zespół który koduje system musi go projektować&lt;/span&gt;.  By decyzje architektoniczne były świadome a nie tylko pobożnymi życzeniami muszą być podejmowane na podstawie danych - faktów. A te ujawniają się w dużej mierze w czasie developmentu. Również informację o kosztach (w sensie czasowym) decyzji i zmian architektonicznych zna tylko zespół. Tak więc to zespół jest najbliżej wszystkich danych niezbędnych do podejmowania decyzji.&lt;br /&gt;&lt;br /&gt;Podejmowanie decyzji architektonicznych przez zespół ma poza tym wpływ na jego zaangażowanie w projekt i wzmaga odpowiedzialność za projekt. Przekazywanie władzy "w dół" (team empowerment) to dobry sposób budowania zespołu. Kto nie chciałby pracować przy projekcie ze zmotywowanymi i zaangażowanymi współpracownikami? Jak poza tym pomagać mniej doświadczonym członkom zespołu zwiększać swoją wiedzę jak nie przez angażowanie ich w takie dyskusje?&lt;br /&gt;&lt;br /&gt;Architektura projektu w przypadku większych rozwiązań czy firm o zdefiniowanej polityce w tym zakresie może wymagać uczestnictwa architekta. To on dba o zachowanie zgodności z polityką architektoniczną firmy, ale również może służyć zespołowi swoim doświadczeniem - ale do tego celu musi on być obecny w zespole przez cały czas developmentu. Czasem wymaga to zmiany funkcjonowania organizacji - gdy w firmie jest dział architektury, który zajmuje się tworzeniem dokumentacji architektonicznej przed rozpoczęciem developmentu, może być ciężko zaangażować architekta w działania zespołu - najpewniej ma on już kolejne systemy do projektowania.&lt;br /&gt;&lt;br /&gt;Oczywiście w przypadku dużych projektów nie ma możliwości by cały zespół projektowy (np. parędziesiąt osób) podejmowało wszystkie decyzje. Wtedy możliwe są rozwiązania takie jak zespół architektoniczny złożony z programistów z poszczególnych podzespołów. Pozwala to na zachowanie spójnej architektury całego systemu przy zachowaniu decyzji co do jego kształtu na właściwym poziomie (dalej robią to programiści aktywnie zaangażowani w development). Rotowanie osób w tym zespole pomaga dodatkowo rozprzestrzeniać wiedzę o produkowanym systemie oraz zwiększać ogólną wiedzę i doświadczenie w zespole.&lt;br /&gt;&lt;br /&gt;W niektórych projektach widziałem spotkania w rodzaju "architecture review" podczas których architekt który zaprojektował system siedział z zespołem i przeglądał system pod kątem realizacji jego założeń. Takie spotkania oczywiście zwiększają szansę na to, że system będzie zgodny z założoną architekturą, ale nie koniecznie wpływają na to, że będzie ona zgodna z wymaganiami co do systemu. Poza tym takie przeglądy są zwykle dość powierzchowne. To coś a'la code review - dobrze je robić jeśli się nie korzysta z programowania w parach i TDD. Jeśli jednak uda nam się wprowadzić te techniki, code review jest w większości przypadków zbędne. Co więcej przeglądy architektury (podobnie jak przeglądy kodu) mają formę hierarchiczną: o to architekt sprawdza czy programistyczna masa nie zniszczyła jego dzieła - architektury (no, może trochę przerysowałem...) Praca architektów w zespole ręka w rękę z mniej doświadczonymi programistami dużo lepiej wpływa na pozyskiwanie wiedzy tych drugich i całościową pracę zespołu umożliwiając dużo efektywniejszą jego pracę.&lt;br /&gt;Ciągłe dbanie o utrzymywanie, weryfikowanie i modyfikowanie architektury umożliwia jej lepszą jakość i odpowiedniość wymaganiom, do tego zmiejszając szanse na to, że będzie niezbędna jej gruntowna (kosztowna) zmiana.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2338976640977990159-5717277505133219846?l=sprawnainzynieriaoprogramowania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2338976640977990159&amp;postID=5717277505133219846' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/5717277505133219846'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/5717277505133219846'/><link rel='alternate' type='text/html' href='http://sprawnainzynieriaoprogramowania.blogspot.com/2009/07/ea-zespo-ktory-koduje-system-musi-go.html' title='EA - zespół który koduje system musi go projektować'/><author><name>Paweł Lipiński</name><uri>http://www.blogger.com/profile/02772675014904905654</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-2338976640977990159.post-3959631645723684011</id><published>2009-07-21T20:26:00.005+02:00</published><updated>2009-07-21T21:48:39.116+02:00</updated><title type='text'>Ewolucja Architektury - intro</title><content type='html'>&lt;div style="text-align: justify;"&gt;&lt;span style="font-size:85%;"&gt;JAVArsovia minęła (prawie 3 tyg temu...) więc zdecydowałem się zamieścić tu główne idee tematu który prezentowałem, czyli zagadnienie Ewoluującej Architektury, czy szerzej: architektury w zwinnych projektach. Część tych zagadnień bazuje na książce Dean'a Leffingwell'a &lt;span style="font-style: italic;"&gt;Scaling Software Agility&lt;/span&gt;. Wszystkie zaś związane są z moim doświadczeniem i obserwacjami co do funkcjonowania działów architektury, developmentu i ich wzajemnych relacji.&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Achitektura definiowana jest jako te elementy systemu, które powinny pozostać niezmienne. Te które decydują o kształcie i paramaterach niefunkcjonalnych systemu. Z tego względu chcemy zapewnić je jak najwcześniej. Architektura to zwykle również drogowskaz który mówi programistom tworzącym system jak rozwiązać krytyczne jego elementy. Z tego względu tworzona jest ona przez najbardziej doświadczone osoby, które już na początku potrafią przewidzieć okoliczności wykorzystania aplikacji, znają wymagania i mają niezbędne kompetencje techniczne by architekturę zdefiniować.&lt;br /&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div style="text-align: justify;"&gt;"Architektura" to termin, który wiele osób stara się zdefiniować, ale trudno wypracować jedną definicję. Są dwa wspólne elementy: pierwszym jest wysokopoziomowy podział systemu na części; drugi - decyzje, które ciężko zmienić.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: right;"&gt;&lt;span style="font-style: italic;"&gt;Martin Fowler, PoEAA&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div style="text-align: justify;"&gt;W projektach programistycznych przywykliśmy jednak do tego, że projekty, których wymagania się nie zmieniają w czasie ich rozwoju prawie się nie zdarzają. Że znaczna część wymagań ujawnia się dopiero w czasie tworzenia systemu. Że systemy jednak czasem muszą ewoluować - obsługiwać większe obciążenie, pozwolić na integrację z jakimś systemem zewnętrznym, itp. itd. Stąd u podstaw zwinnych projektów leży:&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;blockquote&gt;Welcome changing requirements, even late in  development. Agile processes harness change for  the customer's competitive advantage.&lt;br /&gt;&lt;br /&gt;The best architectures, requirements, and designs  emerge from self-organizing teams.&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: right;"&gt;&lt;span style="font-style: italic;"&gt;Agile Manifesto, principles #2 &amp;amp; #11&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div style="text-align: justify;"&gt;Gdzie więc w zwinnych projektach miejsce na architekturę, na niezmienniki, na stanowisko architekta? Otóż staramy się stosować coś co nazywam ewoluującą architekturą. Jest to takie podejście do architektury, które zakłada, że nawet decyzje na najwyższym poziomie mogą się zmieniać. Np. że względem aplikacji w tej chwili monolitycznej mogą z czasem pojawić się wymagania modularności. Że aplikacja bazująca na współdzielonym stanie może z czasem wymagać modyfikacji na bezstanową. Zakładamy również, że część wymagań co do struktury aplikacji może ujawnić się dopiero na jakimś etapie jej rozwoju - np. nie mogły być przewidziane wcześniej, lub po prostu nie były wzięte pod uwagę (np. na jakimś etapie okazuje się, że aplikacja nie spełni zakładanych wymagań wydajnościowych ze względu na swoją architekturę).&lt;br /&gt;&lt;br /&gt;Takie podejście do architektury zakłada, że podobnie jak inne elementy zwinnego projektu (kod, testy, dokumentacja), architektura rozwija się przez cały czas jego trwania - przez cały okres developmentu. Przecież na końcu architektura to nie to co było wstępnie pobożnie zakładane, ale struktura aplikacji - a więc kod. W najbliższych paru postach postaram się przedyskutować podstawowe elementy, które uważam za niezbędne do wprowadzenia i utrzymywania ewoluującej architektury (albo po prostu zwinnej architektury) i rolę architekta w zwinnych projektach.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;div style="text-align: justify;"&gt;Z perspektywy zmiany, rola architektury w zwinnym rozwoju oprogramowania staje się zupełnie jasna: dobra architektura jest responsywna i wspiera zwinność; kiepska będzie się opierać i ją ograniczać.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: right; font-style: italic;"&gt;Kevlin Henney&lt;/div&gt;&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2338976640977990159-3959631645723684011?l=sprawnainzynieriaoprogramowania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2338976640977990159&amp;postID=3959631645723684011' title='Komentarze (3)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/3959631645723684011'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/3959631645723684011'/><link rel='alternate' type='text/html' href='http://sprawnainzynieriaoprogramowania.blogspot.com/2009/07/ewolucja-architektury-intro.html' title='Ewolucja Architektury - intro'/><author><name>Paweł Lipiński</name><uri>http://www.blogger.com/profile/02772675014904905654</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-2338976640977990159.post-2085816720935851566</id><published>2009-07-03T23:18:00.002+02:00</published><updated>2009-07-03T23:20:20.266+02:00</updated><title type='text'>Ewolucja Architektury</title><content type='html'>Zapraszam jutro na mój wykład o ewolucji architektury w zwinnych projektach na javarsovię. Ekipa konferencji nie zamieściła szczegółów które im przesłałem :) więc wrzucam tutaj:&lt;br /&gt;&lt;br /&gt;Opis prelekcji:&lt;br /&gt;Ewolucja Architektury&lt;br /&gt;Architektura oprogramowania to ten jego składnik, co do którego&lt;br /&gt;decyzje podejmowane są zwykle na samym początku projektu. Na czym&lt;br /&gt;bardziej zaawansowanym etapie jest projekt, tym bardziej ryzykowne i&lt;br /&gt;kosztowne są jej zmiany. Czasem jednak takie zmiany są niezbędne.&lt;br /&gt;Czasem architektura ma oczywiste błędy. Czasem wymagania co do&lt;br /&gt;funkcjonowania systemu zmieniają się do tego stopnia, że oryginalna&lt;br /&gt;jego architektura nie może im sprostać. Paweł omówi sposoby radzenia&lt;br /&gt;sobie w takich sytuacjach. Opisze jak kwestie ewolucji architektury&lt;br /&gt;podejmowane są  w projektach prowadzonych przy pomocy zwinnych&lt;br /&gt;metodyk. Wskaże sposoby tworzenia aplikacji w taki sposób by jak&lt;br /&gt;najmniej wiązać logikę aplikacji z jej architekturą, tak by umożliwić,&lt;br /&gt;a czasem nawet promować jej ewolucję.&lt;br /&gt;&lt;br /&gt;O mnie:&lt;br /&gt;Paweł Lipiński jest programistą, architektem, trenerem zespołów. Przez&lt;br /&gt;ostatnie parę lat pracował jako architekt aplikacji i systemowy,&lt;br /&gt;głównie przy projektach klasy enterprise. Aktualnie pracuje w firmie&lt;br /&gt;Pragmatists (będąc przy okazji jej właścicielem) zajmującej się&lt;br /&gt;usługami dla zespołów programistycznych (coaching, szkolenie,&lt;br /&gt;prowadzenie zespołów), pomocą zespołom i organizacjom w transformacji&lt;br /&gt;na Scrum/XP, wyprowadzaniem projektów na prostą oraz tworzeniem&lt;br /&gt;oprogramowania przy użyciu zwinnych metodyk. Posiada certyfikat&lt;br /&gt;Certified Scrum Practitioner oraz niezliczone certyfikaty techniczne&lt;br /&gt;związane z platformą Java/JEE.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2338976640977990159-2085816720935851566?l=sprawnainzynieriaoprogramowania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2338976640977990159&amp;postID=2085816720935851566' title='Komentarze (1)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/2085816720935851566'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/2085816720935851566'/><link rel='alternate' type='text/html' href='http://sprawnainzynieriaoprogramowania.blogspot.com/2009/07/ewolucja-architektury.html' title='Ewolucja Architektury'/><author><name>Paweł Lipiński</name><uri>http://www.blogger.com/profile/02772675014904905654</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-2338976640977990159.post-1627322464117417948</id><published>2009-06-05T09:17:00.003+02:00</published><updated>2009-06-05T09:30:27.042+02:00</updated><title type='text'>Praktyki Zwinnego Programisty</title><content type='html'>Jeśli ktoś nie śledzi Warszawskiego JUGa, to pewnie nie wie, że w najbliższy wtorek będzie (wszystkich zainteresowanych oczywiście zapraszam):&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;from Jacek Laskowski &lt;jacek@laskowski.net.pl&gt;&lt;br /&gt;reply-to warszawa-jug@googlegroups.com&lt;br /&gt;to Warszawa-JUG &lt;warszawa-jug@googlegroups.com&gt;&lt;br /&gt;date Thu, Jun 4, 2009 at 11:44 PM&lt;br /&gt;subject [warszawa-jug] 49. spotkanie Warszawa JUG - IncuBIT &lt;br /&gt;rozpoczyna, a po kwadransie "Praktyki Zwinnego Programisty"&lt;br /&gt;Pawła Lipińskiego&lt;br /&gt;mailing list &lt;warszawa-jug.googlegroups.com&gt; Filter messages from this mailing list&lt;br /&gt;mailed-by googlegroups.com&lt;br /&gt;signed-by googlegroups.com&lt;br /&gt; &lt;br /&gt;Cześć!&lt;br /&gt;&lt;br /&gt;Warszawska Grupa Użytkowników Technologii Java (Warszawa JUG) [1]&lt;br /&gt;zaprasza na 49. spotkanie, które odbędzie się 09.06.2009 (wtorek) o&lt;br /&gt;godzinie 18:00 w sali 5440 Wydziału MIMUW przy ul. Banacha 2 w&lt;br /&gt;Warszawie.&lt;br /&gt;&lt;br /&gt;Temat prezentacji: Praktyki Zwinnego Programisty&lt;br /&gt;Prelegent: Paweł Lipiński&lt;br /&gt;&lt;br /&gt;Przed wystąpieniem Pawła o praktykach gościem specjalnym będzie&lt;br /&gt;przedstawiciel firmy IncuBIT.pl - inkubatora innowacyjnych technologii&lt;br /&gt;z zakresu Internet/Mobile współfinansowanym z PO IG 3.1. Jest to&lt;br /&gt;organizacja non-profit, której celem jest wspieranie pomysłowych i&lt;br /&gt;energicznych ludzi w realizacji ich pomysłów. Wystąpienie zajmie 15&lt;br /&gt;minut i jej celem jest przedstawienie możliwości skorzystania z&lt;br /&gt;funduszy Unii Europejskiej do finansowania własnych przedsięwzięć.&lt;br /&gt;&lt;br /&gt;Dalsza część spotkania to występ Pawła Lipińskiego z jego tematem&lt;br /&gt;agile'owym. Paweł opowie o wszystkich głównych zagadnieniach&lt;br /&gt;związanych z pracą w zwinnym/agile'owym zespole. Pokaże jak wygląda&lt;br /&gt;zwinny projekt zarówno od strony zarządzania (organizacja zespołu,&lt;br /&gt;pracy, komunikacji z klientem, planowanie i estymacja wymagań) jak i&lt;br /&gt;praktyk programistycznych (TDD, programowanie w parach, ciągła&lt;br /&gt;integracja, itp.) Opowie o różnicach w pracy między klasycznym&lt;br /&gt;projektem i zespołem programistycznym i pracy w środowisku agile'owym.&lt;br /&gt;&lt;br /&gt;Paweł Lipiński [2] jest programistą, architektem, trenerem zespołów&lt;br /&gt;programistycznych. Przez ostatnie lata pracował jako agile coach oraz&lt;br /&gt;architekt aplikacji i systemowy, głównie przy systemach klasy&lt;br /&gt;enterprise. Aktualnie pracuje w firmie Pragmatists (będąc przy okazji&lt;br /&gt;jej właścicielem), która zajmuje się usługami dla zespołów&lt;br /&gt;programistycznych (coaching, szkolenia, prowadzenie zespołów), pomocą&lt;br /&gt;przy projektach typu 'death march', oraz tworzeniem oprogramowania z&lt;br /&gt;wykorzystaniem zwinnych metodyk i praktyk. Posiada certyfikat&lt;br /&gt;Certified Scrum Practitioner i niezliczone techniczne certyfikaty&lt;br /&gt;głównie ze świata Java/JEE.&lt;br /&gt;&lt;br /&gt;Planowany czas prezentacji to 1,5 godziny, po której planuje się&lt;br /&gt;15-30-minutową dyskusję.&lt;br /&gt;&lt;br /&gt;Wstęp wolny!&lt;br /&gt;&lt;br /&gt;Zapraszam w imieniu prelegenta i grupy Warszawa JUG!&lt;br /&gt;&lt;br /&gt;[1] http://www.warszawa.jug.pl&lt;br /&gt;[2] http://www.pawellipinski.com/&lt;br /&gt;&lt;br /&gt;Jacek&lt;br /&gt;&lt;br /&gt;--&lt;br /&gt;Jacek Laskowski&lt;br /&gt;Notatnik Projektanta Java EE - http://www.JacekLaskowski.pl&lt;br /&gt;&lt;br /&gt;--~--~---------~--~----~------------~-------~--~----~&lt;br /&gt;Otrzymałeś/-aś tę wiadomość, ponieważ jesteś zapisany/-a do grupy "Warszawa Java User Group (Warszawa JUG)" w serwisie Grupy dyskusyjne.&lt;br /&gt; Aby publikować na tej grupie, wyślij wiadomość e-mail na adres warszawa-jug@googlegroups.com&lt;br /&gt; By wypisać się z grupy, wyślij e-mail do warszawa-jug+unsubscribe@googlegroups.com&lt;br /&gt; Więcej opcji na stronie grupy http://groups.google.com/group/warszawa-jug?hl=pl&lt;br /&gt;-~----------~----~----~----~------~----~------~--~---&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2338976640977990159-1627322464117417948?l=sprawnainzynieriaoprogramowania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2338976640977990159&amp;postID=1627322464117417948' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/1627322464117417948'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/1627322464117417948'/><link rel='alternate' type='text/html' href='http://sprawnainzynieriaoprogramowania.blogspot.com/2009/06/praktyki-zwinnego-programisty.html' title='Praktyki Zwinnego Programisty'/><author><name>Paweł Lipiński</name><uri>http://www.blogger.com/profile/02772675014904905654</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-2338976640977990159.post-852307637846682789</id><published>2009-05-19T23:37:00.004+02:00</published><updated>2009-05-20T00:22:50.029+02:00</updated><title type='text'>Pragmatyczna Prywata</title><content type='html'>Nie pisałem nic od półtora miesiąca. Powodów było parę, ale główny oczywiście odwieczny brak czasu. Tym razem jednak nie był to brak czasu w rodzaju 'wdrożenie miałem' ani nawet 'projekt nam się wali'. W sumie wręcz odwrotnie.&lt;br /&gt;&lt;br /&gt;Dnia dwudziestego kwietnia rozpoczęła działalność moja firma &lt;span style="font-style: italic;"&gt;Pragmatists&lt;/span&gt;. Cały wolny czas poświęcałem więc ostatnio lataniu po urzędach, zmaganiem się z biurokracją, itp. Na szczęście udało się to wszystko załatwić i wreszcie mogę skupić się na meritum.&lt;br /&gt;&lt;br /&gt;Ta firma to trochę eksperyment mojego "poszukiwania białych nosorożców" dość widocznego we wpisach w tym blogu. Eksperyment stawiania na jakość. Eksperyment szacunku, szczerości względem nas samych i naszych klientów, oraz całkowitej przezroczystości działań. Partnerskiego modelu tworzenia oprogramowania, gdzie dostawca i zamawiający mają wspólny cel.&lt;br /&gt;Stosujemy zwinne metodyki tak na poziomie prowadzenia projektu jak i praktyk programistycznych (wraz z TDD i programowaniem w parach) i na pierwszym miejscu stawiamy jakość.&lt;br /&gt;&lt;br /&gt;Tak więc przy okazji pozwolę sobie na mały anons:&lt;br /&gt;&lt;pre class="prettyprint"&gt;public class Pragmatists {&lt;br /&gt; public String miasto = "Warszawa";&lt;br /&gt; public String rejon = "Metro Wilanowska";&lt;br /&gt; public String kontakt = "contact@pragmatists.pl";&lt;br /&gt;&lt;br /&gt; private Session chetniDoPracy;&lt;br /&gt;&lt;br /&gt; List&lt;programista&gt; znajdzProgramiste() {&lt;br /&gt;     Programista takiJakMy = new Programista();&lt;br /&gt;&lt;br /&gt;     takiJakMy&lt;br /&gt;         .lubiSwojZawod(true)&lt;br /&gt;         .uwielbiaSieUczyc(true)&lt;br /&gt;         .dbaOJakosc(true)&lt;br /&gt;         .wieCzymJestAgile(true)&lt;br /&gt;         .znaJezyki(Jezyk.JAVA, Jezyk.Angielski)&lt;br /&gt;         .znaFrameworki(Framework.HIBERNATE, Framework.SPRING, Framework.JEE)&lt;br /&gt;         .maDoswiadczenie(Calendar.YEAR, Criteria.MIN, 3);&lt;br /&gt;&lt;br /&gt;     return chetniDoPracy&lt;br /&gt;               .createCriteria(Programista.class)&lt;br /&gt;               .add(Example.create(takiJakMy))&lt;br /&gt;               .list();&lt;br /&gt; }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;i&gt;Sapienti sat! &lt;/i&gt;:)&lt;i&gt;&lt;br /&gt;&lt;/i&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2338976640977990159-852307637846682789?l=sprawnainzynieriaoprogramowania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2338976640977990159&amp;postID=852307637846682789' title='Komentarze (5)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/852307637846682789'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/852307637846682789'/><link rel='alternate' type='text/html' href='http://sprawnainzynieriaoprogramowania.blogspot.com/2009/05/pragmatyczna-prywata.html' title='Pragmatyczna Prywata'/><author><name>Paweł Lipiński</name><uri>http://www.blogger.com/profile/02772675014904905654</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-2338976640977990159.post-5468119756262996898</id><published>2009-04-01T21:57:00.005+02:00</published><updated>2009-04-01T22:35:04.598+02:00</updated><title type='text'>Nadszedł czas... jakości</title><content type='html'>&lt;div&gt;&lt;img src="http://blog.pawellipinski.com/uploaded_images/csp.jpg" /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;Na jednym z blogów (&lt;a href="http://www.nomachetejuggling.com/2009/02/21/i-love-pair-programming/"&gt;dokładnie to tu&lt;/a&gt;) znalazłem taki wpis:&lt;/div&gt;&lt;div&gt;&lt;blockquote&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;blockquote&gt;&lt;div&gt;The biggest challenge for me personally was essentially mourning for the death of “Programmer Man”. Programmer Man is how I think of myself when I’ve got my headphones in, speed metal blaring in my ears, and I’m coding like a motherfucker. My fingers can’t keep up with my brain. I’m In The Zone. For most of my career, this image is what I’ve considered to be the zenith. When I come home and was in Programmer Man Mode most of the day, I feel like I’ve had a good day.&lt;/div&gt;&lt;div&gt;Pair Programming undeniably killed Programmer Man. This was a tough adjustment, since I’ve considered that mode to be my favorite for so long. I now see, however, that Programmer Man was, without me knowing it, Technical Debt Man.&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;/div&gt;&lt;div&gt;'Coding like a motherfucker' od razu przypomniało mi nasze polskie 'Nadszedł czas napi**lania':&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;img src="http://blog.pawellipinski.com/uploaded_images/czas_dev.jpg" /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Nie wiem kto kiedy dlaczego i jak na to wpadł (to z tym czasem) ale naprawdę dobrze odzwierciedla to częste podejście do realizowania projektów informatycznych. Jakość nie gra roli - ważne jest dotrzymanie terminu. Co będzie po 'przebiciu piłki przez siatkę' nie interesuje dostawcy - niech się z tym buja klient.&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Ciekawa jest analogia między tymi dwoma tekstami. Jak czytam tego gościa, to przypominają mi się moje postawy w projektach parę lat temu. Takie napi**lanie kodu. Samotność w sieci.&lt;/div&gt;&lt;div&gt;Ale tak fajnie jest tylko na początku. Po paru miesiącach takiego developmentu wracamy do domu zmęczeni i sfrustrowani. To jest nasza normalność. Nasza szara rzeczywistość. I niczym matka-polka szorująca gary i piorąca brudne skarpety swojego popijającego piwo przed TV męża (ekscytującego się, że 40 milionowy kraj może wygrać w piłkę z San Marino...) godzimy się na takie życie. Na początku przynosi nam to zadowolenie, że dopisaliśmy kolejne stosy kodu. Potem jest już tylko frustracja i niecierpliwe czekanie na coś nowego. Na wyjście z mroku.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Programowanie to sport grupowy. Dlatego właśnie nazwa Scrum odwołuje się do sportu. Bo projekty wymagają współpracy. Ciągłej. We wszystkim. Praca w grupie powoduje podnoszenie jakości. I Twojej i Twojego kodu. Ciągłe. Wspólne.&lt;/div&gt;&lt;div&gt;Ale żeby móc osiągnąć takie środowisko - środowisko ciągłego uczenia się, wzajemnego poprawiania, ekscytacji pracą - niezbędna jest praca zespołowa. Stąd w Scrumie tyle spotkań. Stąd coraz częściej czerpane z XP praktyki z TDD i programowaniem w parach na czele. Bo to nic innego jak ciągłe poznawanie innych i siebie, w tym co robimy. To przeglądanie się jako programiści w kodzie swoim i innych jak w lustrze. To nabywanie doświadczeń przez nieustanną obserwację innych przy pracy. I ciągłe, nieustanne czytanie kodu. Bo Twoim klientem jako programisty nie jest jakiś bank, czy portal, nie ubezpieczyciel czy operator komórkowy, tylko drugi developer. Ten który będzie czytał twój kod i próbował go zrozumieć. To do niego kierujesz kod.&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Panie i Panowie - nadszedł czas jakości!&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;PS. Nie wiem jak tam mecz. Ja jestem po whisky, ciesząc się świeżym certyfikatem CSP właśnie czytam hipershitowy kod. I żałuję, że jego autor nie czytał zanim go napisał tego co tu właśnie spłodziłem  :)&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2338976640977990159-5468119756262996898?l=sprawnainzynieriaoprogramowania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2338976640977990159&amp;postID=5468119756262996898' title='Komentarze (2)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/5468119756262996898'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/5468119756262996898'/><link rel='alternate' type='text/html' href='http://sprawnainzynieriaoprogramowania.blogspot.com/2009/04/nadszed-czas-jakosci.html' title='Nadszedł czas... jakości'/><author><name>Paweł Lipiński</name><uri>http://www.blogger.com/profile/02772675014904905654</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-2338976640977990159.post-8064367479496033869</id><published>2009-03-31T09:20:00.002+02:00</published><updated>2009-03-31T10:38:55.872+02:00</updated><title type='text'>To zależy...</title><content type='html'>Rozwijanie oprogramowania to zajęcie inheretnie intelektualne. Taki truizm mi się nasunął :)&lt;div&gt;Ale zdaje mi się, że wielu programistów o tym zapomina. Myślę, że są ku temu dwa powody - przyzwyczajenia i błędne założenia.&lt;/div&gt;&lt;div&gt;Klasyczny wodospadowy model produkcji oprogramowania zakłada, że najpierw tworzona jest architektura i projekt oprogramowania (i tu jest myślenie - od tego jest Architekt i Projektant, którzy za pomocą Drogiego Narzędzia CASE/UML tworzą Architekturę) a potem trzeba to &lt;i&gt;po prostu&lt;/i&gt; zakodować. Tak jak z budynkiem, tylko cegły się ciężej układa, więc przydadzą się studia. I programiści w jakimś stopniu to kupują i programują tak jak im się akurat przydarzy.&lt;/div&gt;&lt;div&gt;Ale w wielu firmach, szczególnie mniejszych software house'ach nie ma działu architektury. Tam ludzie przyzwyczajeni są - jeszcze może z czasów studiów - że myśli to się o algorytmach, o drzewach czerwono-czarnych, o ray-tracingu, może nawet o szeregowaniu zadań w systemie operacyjnym, ale przecież nie w aplikacji webowej. Tę każdy wie jak napisać - tu nie ma o czym myśleć.&lt;/div&gt;&lt;div&gt;Programiści oczekują gotowych rozwiązań. Że książka, blog, prezentacja dadzą im konkretne odpowiedzi. Że zasugerowane w czasie wykładu, rozmowy wzorce będą dobre na każdą sytuację.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Ale oprogramowanie to nie budynki (choć nic nie wiem o tym, może tam też trzeba myśleć...) Tu odpowiedzi są ogólne i niepewne. Bez drobiazgowej znajomości wymagań i reszty aplikacji nie sposób dać stu procentowej odpowiedzi. Nad każdym szczegółem, najdrobniejszym detalem powinno się posiedzieć. Przemyśleć. Zbadać siły działające w tej sytuacji. Przemyśleć jak dany kod będzie wykorzystywany. Ani reguły SOLID ani wzorce GoF ani jakieś cechy języka nie zastąpią myślenia.&lt;/div&gt;&lt;div&gt;Czasem trzeba brać pod uwagę kwestie merytoryczne - wydajność jakiegoś rozwiązania, bezpieczeństwo, itp. Czasem percepcyjne - jak zorganizowany kod jest czytelniejszy, co łatwiej jest zrozumieć. Czasem w końcu organizacyjno-psychologiczne - że baza danych zależna jest od kogo innego i często się zmienia, że większość zespołu woli jakiś inny sposób formatowania, itp.&lt;/div&gt;&lt;div&gt;Dlatego właśnie Big Design Up Front nie może dać dobrej aplikacji (tzn. może się komuś uda, ale generalnie...) Bo nie da się bez kodu i zespołu przemyśleć tego wszystkiego odpowiednio dokładnie.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Zapytał mnie niedawno kolega z pracy jakie rozwiązanie jest lepsze (zainspirowany moim ostatnim wpisem) - mieć oddzielne DAO czy metody operacji na danych bezpośrednio w encjach (Active Record). I nie ma tu dobrej odpowiedzi. W jakimś stopniu jest to kwestia estetyki, w jakimś designu reszty aplikacji. Może tez wchodzić w grę doświadczenie programistów, wybór technologii do przechowywania danych itp. itd.&lt;/div&gt;&lt;div&gt;Czasem używanie tych samych obiektów jako dziedziny (wraz z zachowaniami) i reprezentantów bazy danych (ORM, DTO) jest ok, a czasem (no dobra, częściej) warto trzymać swoje obiekty oddzielnie i nie wystawiać wszystkich ich pól do publicznego dostępu (w ten sposób wiążąc implementacje innych elementów kodu z &lt;i&gt;wyłącznie naszą&lt;/i&gt; implementacją dziedziny) a dla Hibernate'a wystawiać DTO (inna reprezentacja danych w bazie a inna w dziedzinie, zmieniająca się struktura bazy, itp.)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Na wiele pytań nie ma jednoznacznych odpowiedzi na samym początku.  Na wiele nie ma ich też później, dlatego robimy oprogramowanie tak, by na bieżąco dostosowywać je (refaktoryzować)  do zmieniających się warunków (a przecież warunki się ciągle zmieniają w czasie developmentu, bo dodawane są kolejne funkcjonalności). Oprogramowanie nie jest z kamienia ani żelbetu, tylko jest realizacją naszych (elastycznych) myśli. &lt;/div&gt;&lt;div&gt;Tylko od Ciebie zależy jak je budujesz.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2338976640977990159-8064367479496033869?l=sprawnainzynieriaoprogramowania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2338976640977990159&amp;postID=8064367479496033869' title='Komentarze (1)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/8064367479496033869'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/8064367479496033869'/><link rel='alternate' type='text/html' href='http://sprawnainzynieriaoprogramowania.blogspot.com/2009/03/to-zalezy.html' title='To zależy...'/><author><name>Paweł Lipiński</name><uri>http://www.blogger.com/profile/02772675014904905654</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-2338976640977990159.post-685421726828600688</id><published>2009-03-19T10:05:00.006+01:00</published><updated>2009-03-20T09:30:35.388+01:00</updated><title type='text'>Repozytoria w DDD</title><content type='html'>W czasie prezentacji o DDD (albo zaraz potem) zadał mi ktoś pytanie o realizację Repozytoriów w javie. Jeśli traktować Repozytoria jako klasyczny wzorzec DAO, to realizacja jest prosta. Robimy generyczne DAO, który obsługuje wszystkie zwyczajne przypadki (CRUD) a tam, gdzie potrzebujemy jakichś szczególnych (bardziej biznesowych) metod, doimplementowujemy to w klasie dziedziczącej po tymże DAO. DAO można zrobić np. tak jak w przykładzie na stronach &lt;a href="http://www.hibernate.org/328.html"&gt;Hibernate&lt;/a&gt;. To rozwiązanie niestety wymaga podawania explicite tego DAO, wszczepiania go tam gdzie chcemy go użyć itp. Oddzielność tej warstwy jest ewidentna (można dyskutować czy to dobrze czy to źle, ale to głównie estetyka). Niektórzy wolą więc zarządzanie obiektami dziedziny w sposób a'la Grails/GORM:&lt;div&gt;&lt;pre class="prettyprint"&gt;public class RepositoryInsideDomain {&lt;br /&gt; &lt;br /&gt; @Test&lt;br /&gt; public void checkSaveFindDelete () {&lt;br /&gt;  Author author = new Author();&lt;br /&gt;  author.setName("Pawel");&lt;br /&gt;  &lt;br /&gt;  author.save();  &lt;br /&gt;  assertTrue(Author.isStored(author));&lt;br /&gt;  &lt;br /&gt;  assertNotNull(Author.findById("Pawel"));&lt;br /&gt;  assertEquals(author, Author.findById("Pawel"));&lt;br /&gt;&lt;br /&gt;  author.delete();  &lt;br /&gt;  assertFalse(Author.isStored(author));   &lt;br /&gt; }&lt;br /&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;Co niestety wymaga albo pobrudzenia obiektów dziedziny dodaniem odpowiednich metod z DAO i delegacji do nich (trywialne, nieutrzymywalne i nieładne, więc nawet nie będę pokazywał, bo ktoś powie że to promuję :)),  albo pobawieniem się aspektami. I to rozwiązanie może być ciekawe, więc je tu pokażę (zrealizowane za pomocą aspectj'a). Do tego potrzebujemy zrobić Repozytorium (tu strywializowane, ale oczywiście może być dowolnie bardziej złożone):&lt;/div&gt;&lt;div&gt;&lt;pre class="prettyprint"&gt;public class Repository {&lt;br /&gt; static Map storage = new HashMap();&lt;br /&gt;&lt;br /&gt; public Repository() {&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public static Object findById (Object id) {&lt;br /&gt;  return storage.get(id);&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public void save () {&lt;br /&gt;  storage.put(this.toString(), this);&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; public void delete () {&lt;br /&gt;  storage.remove(this.toString());&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; public static boolean isStored (Object o) {&lt;br /&gt;  return storage.containsKey(o.toString());&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;i jeszcze aspekt który pomiksuje to wszystko razem:&lt;/div&gt;&lt;pre class="prettyprint"&gt;public aspect RepositoryInjector {&lt;br /&gt; declare parents: com.lipinski.domaininjection.domain.* extends Repository; &lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;Tak niewiele trzeba, by odpowiednie metody repozytorium były dostępne bezpośrednio z klas dziedziny. Dzięki temu nie musimy wszczepiać nigdzie repozytoriów, operujemy wyłącznie na klasach domenowych. Z drugiej strony na poziomie kodu mamy ładną separację dziedziny od infrastruktury. jedyna wada tego rozwiązania, to że nie jest to pure java, i póki się nie zajrzy do tego aspektu to nijak nie wiadomo skąd te metody się znalazły. Ale jeśli to podejście stosujemy konsekwentnie w całej aplikacji, to nie powinien być problem.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2338976640977990159-685421726828600688?l=sprawnainzynieriaoprogramowania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2338976640977990159&amp;postID=685421726828600688' title='Komentarze (2)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/685421726828600688'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/685421726828600688'/><link rel='alternate' type='text/html' href='http://sprawnainzynieriaoprogramowania.blogspot.com/2009/03/repozytoria-w-ddd.html' title='Repozytoria w DDD'/><author><name>Paweł Lipiński</name><uri>http://www.blogger.com/profile/02772675014904905654</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-2338976640977990159.post-6563998775466908229</id><published>2009-03-18T10:21:00.002+01:00</published><updated>2009-03-18T10:56:29.323+01:00</updated><title type='text'>Po speechu z DDD</title><content type='html'>Na wczorajszym speechu z DDD w Warszawkim JUGu zgromadziło się 70 osób, co wg. organizatorów jest dość dużo (mi też się tak wydaje...) To bardzo cieszy, bo wskazuje na to, że jednak może kryzys w oprogramowaniu nie jest aż tak wielki, albo przynajmniej, że jest trochę ludzi, którzy chcą pisać dobry soft. Którym zależy na jakości.&lt;br /&gt;&lt;br /&gt;Wszystkim obecnym chciałem podziękować za miłe przyjęcie. Fajnie jest widzieć zainteresowanie i zaangażowanie.&lt;br /&gt;&lt;br /&gt;Prezentacja dla chętnych do ponownego obejrzenia dostępna jest na &lt;a href="https://docs.google.com/Presentation?docid=ddkr7r9_28ggnqq3dq&amp;amp;hl=en"&gt;google docs&lt;/a&gt;.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;Do tego jest dość aktywny wątek poprezentacyjny na stronach JUGa: &lt;a href="http://groups.google.com/group/warszawa-jug/browse_thread/thread/0dc9eaecd7eaa795/93ab4d0193e3e084"&gt;tu&lt;/a&gt;.&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2338976640977990159-6563998775466908229?l=sprawnainzynieriaoprogramowania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2338976640977990159&amp;postID=6563998775466908229' title='Komentarze (1)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/6563998775466908229'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/6563998775466908229'/><link rel='alternate' type='text/html' href='http://sprawnainzynieriaoprogramowania.blogspot.com/2009/03/po-speechu-z-ddd.html' title='Po speechu z DDD'/><author><name>Paweł Lipiński</name><uri>http://www.blogger.com/profile/02772675014904905654</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-2338976640977990159.post-4290957022873245680</id><published>2009-03-16T13:59:00.003+01:00</published><updated>2009-03-16T18:49:31.809+01:00</updated><title type='text'>Manifest Rzemieślnika Oprogramowania</title><content type='html'>&lt;img src="http://blog.pawellipinski.com/uploaded_images/ski.png"/&gt;&lt;br /&gt;W czasie gdy ja w miarę bezrefleksyjnie oddawałem się swojej drugiej pasji (na obrazku), powstał appendix do manifestu agile. Oryginalny manifest mówił o tym na co w zwinnym podejściu do rozwoju oprogramowania kładziony jest głównie nacisk, a co jest 'tylko' wartościowe. Były to: &lt;div&gt;Osoby i Interakcje nad Procesy i Narzędzia&lt;/div&gt;&lt;div&gt;Działające Oprogramowanie nad Szczegółową Dokumentację &lt;/div&gt;&lt;div&gt;Współpraca z Klientem nad Negocjacjowanie Kontraktu&lt;/div&gt;&lt;div&gt;Odpowiadanie na Zmiany nad Działanie Zgodnie z Planem.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;div&gt;Robert C. Martin już od jakiegoś czasu postulował dodanie jeszcze czegoś, co definiowało by podejście do jakości w projektach/zespołach agile'owych. Sam nazwał to w zeszłym roku 'Craftsmanship over Crap', ale zdaje się, że to jednak nie pasuje (w końcu elementy po prawej miały też przedstawiać jakąś wartość, tyle że mniejszą...) i nie brzmi zbyt poprawnie politycznie. Stąd twórcy appendixu zwanego &lt;a href="http://manifesto.softwarecraftsmanship.org/"&gt;Manifesto for Software Craftsmanship&lt;/a&gt; ubrali różne myśli krążące od pewnego czasu po książkach i blogach agile'owych w ładne słowa i powstało:&lt;/div&gt;&lt;div&gt;Nie tylko Działające Oprogramowanie, ale również Niezła Robota (moje domorosłe tłumaczenie 'well-crafted')&lt;/div&gt;&lt;div&gt;Nie tylko Odpowiadanie na Zmiany, ale również Ciągłe Dodawanie Wartości&lt;/div&gt;&lt;div&gt;Nie tylko Osoby i Interakcje, ale również Społeczność Zawodowców&lt;/div&gt;&lt;div&gt;Nie tylko Współpraca z Klientem, ale również Produktywne Partnerstwa&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Manifest mówi, że do osiągnięcia elementów po lewej niezbędne jest istnienie tych po prawej. No więc po kolei:&lt;/div&gt;&lt;div&gt;Żeby oprogramowanie Działało, spełniało swoje zadania i nie wymagało Szczegółowej Dokumentacji, musi być to Niezła Robota - wysokiej jakości oprogramowanie.&lt;/div&gt;&lt;div&gt;Żeby móc odpowiadać na zmiany, trzeba móc ciągle dodawać wartość. A do tego warunkiem sine qua non jest kod łatwo modyfikowalny, o czystej architekturze, zrozumiały.&lt;/div&gt;&lt;div&gt;Osoby odpowiedzialne za projekt tworzą się, kształcą poprzez interakcję z innymi. Z lepszymi od siebie, ale ze słabszymi od siebie również. Do tego niezbędna jest społeczność osób związanych ze sobą zainteresowaniami, pracą, pasją. Stąd potrzeba społeczności profesjonalistów.&lt;/div&gt;&lt;div&gt;W końcu produktywne partnerstwo jako efekt ale i warunek dobrej współpracy. Jeśli firmy szanują się nawzajem, jeśli ufają swojemu profesjonalizmowi i mają jasne, przezroczyste reguły współpracy, takie partnerstwo (czyli równość stron) może być produktywne. Obie firmy mogą osiągnąć swój cel - wzajemne przynoszenie sobie wartości.&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Ten manifest, zupełnie jak ten oryginalny, jest idealistyczny. Zakłada dobre chęci, profesjonalizm, budowanie wzajemnego zaufania. To nie środki, ale cel. Coś do czego powinniśmy dążyć całym sobą, ucząc się ciągle i poprawiając. Na początek na naszym małym podwórku jednego projektu, jednego zespołu, jednej aplikacji. Z czasem może uda nam się zarazić tym innych, firmę, społeczność. To dzięki takim właśnie postawom mamy dziś cały ruch agile.&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2338976640977990159-4290957022873245680?l=sprawnainzynieriaoprogramowania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2338976640977990159&amp;postID=4290957022873245680' title='Komentarze (3)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/4290957022873245680'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/4290957022873245680'/><link rel='alternate' type='text/html' href='http://sprawnainzynieriaoprogramowania.blogspot.com/2009/03/manifest-rzemieslnika-oprogramowania.html' title='Manifest Rzemieślnika Oprogramowania'/><author><name>Paweł Lipiński</name><uri>http://www.blogger.com/profile/02772675014904905654</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-2338976640977990159.post-5693936367794638909</id><published>2009-03-05T12:03:00.002+01:00</published><updated>2009-03-06T14:27:46.882+01:00</updated><title type='text'>Speech z DDD</title><content type='html'>Tym razem trochę czystej prywaty. W następny wtorek, 17 marca, zapraszam na mój speech w ramach Warszawskiego JUGa. Tematem będzie Domain Driven Design. Oczywiście nie obędzie się bez ewangelizacji zwinnego podejścia do tworzenia projektów, czyli po prostu edżajla.&lt;div&gt;&lt;br /&gt;&lt;div&gt;Kto nie będzie mógł przyjść, będzie mógł obejrzeć sobie slajdy, ale jak mawiała moja nauczycielka Polskiego "Lipiński, lepiej gadasz niż piszesz", więc pogadanka będzie pewnie bardziej wartościowa niż suchy PDF.&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2338976640977990159-5693936367794638909?l=sprawnainzynieriaoprogramowania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2338976640977990159&amp;postID=5693936367794638909' title='Komentarze (2)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/5693936367794638909'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/5693936367794638909'/><link rel='alternate' type='text/html' href='http://sprawnainzynieriaoprogramowania.blogspot.com/2009/03/speech-z-ddd.html' title='Speech z DDD'/><author><name>Paweł Lipiński</name><uri>http://www.blogger.com/profile/02772675014904905654</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-2338976640977990159.post-2955783243880024413</id><published>2009-03-02T09:56:00.003+01:00</published><updated>2009-03-03T10:25:56.562+01:00</updated><title type='text'>SOLID - Liskov Substitution Principle</title><content type='html'>Pisanie naprawdę obiektowego kodu nie jest popularne. Tak naprawdę nie widziałem zbyt wielu projektów pisanych obiektowo. A w javie piszę już 10 lat. W tzw. aplikacjach enterprise nie ma prawie dziedziczenia, nie ma hierarchii. Aplikacje są totalnie płaskie, proceduralne, z niejasną strukturą, z czasem bardzo trudne do utrzymania.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Wartość dziedziczenia przy strukturyzowaniu kodu pokazywałem już w poprzednich postach, w szczególności przy okazji zasady zamknięcia-otwartości. Natomiast zasada o której teraz trochę napiszę dotyczy nie tego jak ma wyglądać struktura, ale co ma być w klasach dziedziczących. Zasada podstawiania Liskov brzmi mniej-więcej tak:&lt;/div&gt;&lt;div&gt;&lt;blockquote&gt;Jeśli twój kod oczekuje jakiejś klasy, to zamiast niej powinieneś móc podstawić dowolną klasę z niej dziedziczącą bez zmieniania żadnych oczekiwanych zachowań.&lt;/blockquote&gt;&lt;/div&gt;&lt;div&gt;Oznacza to tyle, że jeśli przeciążamy jakąś metodę w podklasie, to musi ona zachować semantykę odpowiedniej metody nadklasy.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Ta zasada mówi jedną bardzo ważną rzecz: jeśli przeciążasz metodę, napisz ją tak, by użyta polimorficznie działała poprawnie. Wyobraźmy sobie taką sytuację: mamy aplikację składającą się z modułów. Są tam zwykli użytkownicy oraz administratorzy modułów. Mamy użytkownika:&lt;/div&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;public class User {&lt;br /&gt;  protected String login;&lt;br /&gt;  protected String password;&lt;br /&gt;  protected List&lt;module&gt; modules;&lt;br /&gt;&lt;br /&gt;  public void addAccessToModule(Module module) {&lt;br /&gt;      modules.add(module);&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  public boolean canAccess(Module module) {&lt;br /&gt;      if (modules.contains(module))&lt;br /&gt;          return true;&lt;br /&gt;      return false;&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/module&gt;&lt;/pre&gt;&lt;br /&gt;Mamy też administratora:&lt;br /&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;public class Admin extends User {&lt;br /&gt;  private List&lt;module&gt; administeredModules;&lt;br /&gt;&lt;br /&gt;  public boolean canAccess(Module module) {&lt;br /&gt;      if (administeredModules.contains(module))&lt;br /&gt;          return true;&lt;br /&gt;      return false;&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/module&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ja widzimy metoda &lt;span class="Apple-style-span" style="font-style: italic;"&gt;canAccess&lt;/span&gt; jest przeciążona w klasie &lt;span class="Apple-style-span" style="font-style: italic;"&gt;Admin&lt;/span&gt; i sprawdza czy dany użytkownik jest administratorem podanego modułu (programista zaimplementował w ten sposób wymaganie, że administrator ma dostęp do wszystkich modułów jako zwykły użytkownik, a jako administrator do pewnego ich podzbioru). Wyobraźmy też sobie, że moduły emitują zdarzenia, na których otrzymywanie użytkownicy mogą się zapisać:&lt;br /&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;public void subscribeToEvents(User user, Module module) {       &lt;br /&gt;   if (! user.canAccess(module)) {&lt;br /&gt;       user.addAccessToModule(module);&lt;br /&gt;   }&lt;br /&gt;   module.sendEventsTo(user);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Na pierwszy rzut oka nie widać żadnego błędu - jeśli ktoś jeszcze nie ma dostępu do jakiegoś modułu, to jest on mu przyznawany i dopisywany jest on do listy użytkowników notyfikowanych o zdarzeniach. Ale niestety przez to, że programista nie zastosował się do zasady podstawiania, kod ten jest poprawny tylko dla zwykłych użytkowników. Wielokrotne wywoływanie tej metody dla obiektów klasy &lt;span class="Apple-style-span" style="font-style: italic;"&gt;Admin&lt;/span&gt; spowoduje ciągłe dodawanie tych samych modułów do do kolekcji &lt;span class="Apple-style-span" style="font-style: italic;"&gt;modules &lt;/span&gt;klasy&lt;span class="Apple-style-span" style="font-style: italic;"&gt; User&lt;/span&gt;, choć metoda &lt;span class="Apple-style-span" style="font-style: italic;"&gt;canAccess&lt;/span&gt; w klasie &lt;span class="Apple-style-span" style="font-style: italic;"&gt;Admin&lt;/span&gt; w ogóle jej nie sprawdza.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Nie zachowywanie zasady podstawiania Liskov powoduje powstawanie błędów często bardzo trudnych do wykrycia. Błąd jest prawie zawsze w klasie, której w kodzie wołającym w ogóle nie widać - w końcu są to wywołania polimorficzne. Przy bogatszych hierarchiach i duplikacji w kodzie szukanie błędów może się zmienić w wielogodzinną walkę. Co więcej, jeśli nie dbamy o jakość naszego kodu (właściwe hierarchie, duplikacje, właściwe umiejscowienie metod), nawet szczegółowe testy jednostkowe ze 100% pokryciem kodu może nic nie pomóc (w powyższym przykładzie wystarczy, by był jeszcze jakiś inny sposób na dodanie modułu do kolekcji &lt;span class="Apple-style-span" style="font-style: italic;"&gt;modules&lt;/span&gt;, by testy jednostkowe nie wychwyciły tego problemu).&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2338976640977990159-2955783243880024413?l=sprawnainzynieriaoprogramowania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2338976640977990159&amp;postID=2955783243880024413' title='Komentarze (1)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/2955783243880024413'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/2955783243880024413'/><link rel='alternate' type='text/html' href='http://sprawnainzynieriaoprogramowania.blogspot.com/2009/03/solid-liskov-substitution-principle.html' title='SOLID - Liskov Substitution Principle'/><author><name>Paweł Lipiński</name><uri>http://www.blogger.com/profile/02772675014904905654</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-2338976640977990159.post-8556700613478279436</id><published>2009-02-24T09:16:00.002+01:00</published><updated>2009-02-24T11:46:03.635+01:00</updated><title type='text'>SOLID - Open-Closed Principle</title><content type='html'>W oryginalnej wersji zasada otwartości-zamknięcia brzmi tak: &lt;span class="Apple-style-span" style="font-style: italic;"&gt;Elementy oprogramowania (klasy, moduły, funkcje) powinny być otwarte na rozszerzanie ale zamknięte na zmiany.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Hm, zwykle gdy chcemy dodać jakąś funkcjonalność po prostu dopisujemy odpowiedni kod. Weźmy przykład:&lt;br /&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;public class User {&lt;br /&gt; private String login;&lt;br /&gt; private String password;&lt;br /&gt;  &lt;br /&gt; private UserRepository repo;&lt;br /&gt;&lt;br /&gt; public void delete () {&lt;br /&gt;     repo.delete(this);&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public User findByName(String name) {&lt;br /&gt;     return repo.findByName(name);&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public class UserRepository {&lt;br /&gt; private EntityManager em;&lt;br /&gt;&lt;br /&gt; public void delete(User user) {&lt;br /&gt;     em.remove(user);&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public User findByName(String name) {&lt;br /&gt;     return (User) em.createQuery("from User u where u.name=:name")&lt;br /&gt;             .setParameter("name", name)&lt;br /&gt;             .getSingleResult();&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Klasy proste, śliczne (oczywiście troszkę uproszczone :)). I nagle przychodzi wymaganie: użytkownik który ma uprawnienia administratora ma mieć flagę &lt;span class="Apple-style-span" style="font-style: italic;"&gt;deleted&lt;/span&gt; która oznacza, że tak naprawdę nie ma być usuwany, tylko zaznaczony jako usunięty i nie prezentowany już potem w GUI. No to pierwsze podejście pewnie będzie takie:&lt;br /&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;public class User {&lt;br /&gt; private String login;&lt;br /&gt; private String password;&lt;br /&gt; private boolean admin;&lt;br /&gt; private boolean deleted;&lt;br /&gt;  &lt;br /&gt; private UserRepository repo;&lt;br /&gt;&lt;br /&gt; public void delete () {&lt;br /&gt;     repo.delete(this);&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public User findByName(String name) {&lt;br /&gt;     return repo.findByName(name);&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public class UserRepository {&lt;br /&gt; private EntityManager em;&lt;br /&gt;&lt;br /&gt; public User findByName(String name) {&lt;br /&gt;     return (User) em.createQuery("from User u where u.name=:name and deleted=false")&lt;br /&gt;             .setParameter("name", name)&lt;br /&gt;             .getSingleResult();&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public void delete(User user) {&lt;br /&gt;     if (user.isAdmin()) {&lt;br /&gt;         user.setDeleted(true);&lt;br /&gt;         em.persist(user);&lt;br /&gt;     } else {&lt;br /&gt;         em.remove(user);&lt;br /&gt;     }&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;No, gotowe! Tylko, czy to jest dobry design? Już &lt;span class="Apple-style-span" style="font-style: italic;"&gt;if&lt;/span&gt; w metodzie usuwającej wskazuje, że dzieje się tam więcej niż jedna rzecz. Co więcej, zasada pojedynczej odpowiedzialności dużo nam tu nie pomoże, możemy co jakwyżej osiągnąć coś takiego:&lt;br /&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;public class User {&lt;br /&gt; private String login;&lt;br /&gt; private String password;&lt;br /&gt; private boolean admin;&lt;br /&gt; private boolean deleted;&lt;br /&gt;  &lt;br /&gt; private UserRepository repo;&lt;br /&gt;&lt;br /&gt; public void delete () {&lt;br /&gt;     if (! admin)&lt;br /&gt;         repo.deleteNonAdmin(this);&lt;br /&gt;     else {&lt;br /&gt;         repo.deleteAdmin(this);&lt;br /&gt;     }&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public User findByName(String name) {&lt;br /&gt;     return repo.findByName(name);&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public class UserRepository {&lt;br /&gt; private EntityManager em;&lt;br /&gt;&lt;br /&gt; public User findByName(String name) {&lt;br /&gt;     return (User) em.createQuery("from User u where u.name=:name and deleted=false")&lt;br /&gt;             .setParameter("name", name)&lt;br /&gt;             .getSingleResult();&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public void deleteNonAdmin(User user) {&lt;br /&gt;     em.remove(user);&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public void deleteAdmin(User user) {&lt;br /&gt;     user.setDeleted(true);&lt;br /&gt;     em.persist(user);&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Zwiększyliśmy trochę ilość kodu (twój manager już jest zadowolony - kolejna wskaźnik postępu zwiększony!), może trochę lepiej widać na czym polega różnica między usuwaniem administratora i nie-administratora, ale tak naprawdę kod wiele się nie poprawił. Jeśli będą dochodziły kolejne wymagania jak to, nasza metoda &lt;span class="Apple-style-span" style="font-style: italic;"&gt;delete&lt;/span&gt; zmieni się wkrótce w wielki ciąg &lt;span class="Apple-style-span" style="font-style: italic;"&gt;if-else. &lt;/span&gt;I tu właśnie jest miejsce do zastosowania zasady otwartości-zamknięcia. &lt;div&gt;&lt;span class="Apple-style-span" style="font-style: italic;"&gt;Kod powinien być otwarty na rozszerzanie a zamknięty na modyfikację.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Co to znaczy w praktyce?&lt;br /&gt;Dziedziczenie.&lt;br /&gt;&lt;br /&gt;Jeśli przypomnimy sobie, że w językach obiektowych możemy dziedziczyć, okaże się, że ten kod jest jeszcze do uratowania :)&lt;br /&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;public class User {&lt;br /&gt;  protected String login;&lt;br /&gt;  protected String password;&lt;br /&gt;&lt;br /&gt;  protected UserRepository repo;&lt;br /&gt;&lt;br /&gt;  public User findByName(String name) {&lt;br /&gt;      return repo.findByName(name);&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  public void delete() {&lt;br /&gt;      repo.delete(this);&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public class AdminUser extends User {&lt;br /&gt;  boolean admin;&lt;br /&gt;  private boolean deleted;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;public class UserRepository {&lt;br /&gt;  protected EntityManager em;&lt;br /&gt;&lt;br /&gt;  public User findByName(String name) {&lt;br /&gt;      return (User) em.createQuery("from User u where u.name=:name")&lt;br /&gt;              .setParameter("name", name).getSingleResult();&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  public void delete(User user) {&lt;br /&gt;      em.remove(user);&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public class AdminUserRepository extends UserRepository {&lt;br /&gt;  public User findByName(String name) {&lt;br /&gt;      return (User) em.createQuery("from User u where u.name=:name and deleted=false")&lt;br /&gt;              .setParameter("name", name)&lt;br /&gt;              .getSingleResult();&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  public void delete(AdminUser user) {&lt;br /&gt;      user.setDeleted(true);&lt;br /&gt;      em.persist(user);&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Teraz &lt;span class="Apple-style-span" style="font-style: italic;"&gt;if-else &lt;/span&gt;w ogóle nie istnieje. Kod wołający metody &lt;span class="Apple-style-span" style="font-style: italic;"&gt;findByName&lt;/span&gt; i &lt;span class="Apple-style-span" style="font-style: italic;"&gt;delete &lt;/span&gt;dalej nie musi wiedzieć, że dana instancja klasy &lt;span class="Apple-style-span" style="font-style: italic;"&gt;User&lt;/span&gt; jest administratorem, ale nowa struktura kodu wyeliminowała potrzebę tworzenia warunków (zwykle było by ich więcej niż tylko w jednym miejscu, więc jeśli w kodzie masz gdzieś ten sam warunek sprawdzany parę razy w różnych metodach, to prawdopodobnie powinieneś zastanowić się nad dziedziczeniem). Kod jest teraz dużo bardziej przejrzysty (np. od razu wiadomo gdzie szukać jeśli coś jest nie tak z administratorem). &lt;br /&gt;&lt;br /&gt;Ta zasada wydaje się zupełnie oczywista. Nie trzeba doktoratu z informatyki, żeby wpaść na takie rozwiązanie. Jednak jakże często dodajemy funkcjonalności do kodu bez większego zastanowienia. Po prostu dodajemy kod. Pilnowanie zasady otwartości-zamknięcia jest kolejnym sposobem na nie zwiększanie długu technicznego (nie pogorszanie jakości kodu) wraz z dodawaniem funkcjonalności.&lt;br /&gt;&lt;br /&gt;Pisanie i projektowanie aplikacji poprzez stosowanie TDD powoduje, że czas na zastanowienie się nad najlepszym rozwiązaniem staje się nieodłączną częścią procesu rozwoju oprogramowania wykonywaną z resztą co parę minut, co oczywiście ma bezpośredni wpływ na jakość kodu który po sobie pozostawiamy. Istnienie testów powoduje, że nie mamy obaw związanych z wprowadzaniem większych zmian do oprogramowania - np. tak jak w powyższym przykładzie z wymianą warunków na dziedziczenie.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Od tego w jaki sposób wprowadzamy rozszerzenia do naszego projektu zależy bardzo dużo. Czas developmentu, ryzyko błędu, może nawet w końcu przepisywanie projektu. Wszystko to sprowadza się do marnowania dużych ilości pieniędzy naszego pracodawcy / klienta, może nawet osłabić jego konkurencyjność, a przecież nikt nie dał nam do tego prawa. I jeśli Twój project manager czy klient ciśnie Cię terminami, to może zamiast bezwolnie poddawać się tej presji lepiej dokładnie mu to wytłumaczyć. To nie jest Twoja rola, żeby podejmować decyzje o stałym obniżaniu jakości kodu przez byle jakie wrzucanie nowych linii do istniejącego kodu, więc zrzuć to na osoby które takie decyzje są władne podjąć. Niech twój PM podpisze się własną krwią pod zdaniem: &lt;/div&gt;&lt;div&gt;&lt;blockquote&gt;Tak, chcę doprowadzić do obniżenia jakości oprogramowania. Bardziej niż na jakości zależy mi na terminach. Jestem skłonny raczej w przyszłości mieć ciągłe problemy z ukańczaniem funkcjonalności i błędami niż zmienić termin tego releasu.&lt;/blockquote&gt;&lt;/div&gt;&lt;div&gt;Jeśli to zrobi (co niestety się zdarza), przynajmniej będziesz miał czyste sumienie. I nikt nie zarzuci ci braku profesjonalizmu i nieodpowiedzialności.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2338976640977990159-8556700613478279436?l=sprawnainzynieriaoprogramowania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2338976640977990159&amp;postID=8556700613478279436' title='Komentarze (3)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/8556700613478279436'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/8556700613478279436'/><link rel='alternate' type='text/html' href='http://sprawnainzynieriaoprogramowania.blogspot.com/2009/02/solid-open-closed-principle.html' title='SOLID - Open-Closed Principle'/><author><name>Paweł Lipiński</name><uri>http://www.blogger.com/profile/02772675014904905654</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-2338976640977990159.post-3785494016924873331</id><published>2009-02-19T15:16:00.000+01:00</published><updated>2009-02-19T16:57:19.232+01:00</updated><title type='text'>SOLID - SRP część 2 - klasy</title><content type='html'>Ostatnio pisałem o Regule Pojedynczej Odpowiedzialności skupiając się na metodach. Ale ta reguła dotyczy w równym stopniu strukturyzowania klas. Tym razem będzie mniej kodu, bo skupię się tylko na sygnaturach pokazując o co chodzi.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Reguła Pojedynczej Odpowiedzialności brzmi w tym przypadku tak: powinien być dokładnie jeden powód do dokonywania zmian w klasie. Oznacza to, że kod powinien mieć taką strukturę, żeby każda klasa miała dokładnie jedną odpowiedzialność: np. wyświetlanie komponentu, komunikacja z bazą danych, logika biznesowa.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Najbardziej klasycznym przykładem zastosowania tej reguły jest wzorzec MVC. Oddzielenie od siebie danych, mechanizmu wyświetlania i obsługa operacji UI.&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;To przecież jasne! Każdy to wie, nie?&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;No to zobaczmy czy napewno. Mamy sobie taką klasę:&lt;/div&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;@Stateless&lt;br /&gt;@Local&lt;br /&gt;public class UserManagerBean {&lt;br /&gt;&lt;br /&gt;  @PersistenceContext(type = PersistenceContextType.TRANSACTION)&lt;br /&gt;  private EntityManager em;&lt;br /&gt;  private LoginManager loginManager;&lt;br /&gt;&lt;br /&gt;  public User findUserByName(String name) {&lt;br /&gt;      return (User) em.createQuery("from User u where u.name=:name")&lt;br /&gt;              .setParameter("name", name).getSingleResult();&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  public boolean isUserValid(User user) {&lt;br /&gt;      if (user.getNumWrongLogins() &amp;gt; 3&lt;br /&gt;              &amp;amp;&amp;amp; (System.currentTimeMillis() - user.getLastLoginTrial() &amp;lt; 5000))&lt;br /&gt;          user.block();&lt;br /&gt;&lt;br /&gt;      if (user.isBlocked() || user.isAccountExpired())&lt;br /&gt;          return false;&lt;br /&gt;      return true;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  public String login(User user) {&lt;br /&gt;      boolean result = loginManager.login(user.getName(), user.getPassword());&lt;br /&gt;      if (result)&lt;br /&gt;          return "You logged in successfully!";&lt;br /&gt;      return "Logging in failed";&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Ten kod na pierwszy rzut oka wygląda ok. Gdyby to był poprzedni wpis, przyczepiłbym się tylko metody isUserValid, bo robi dwie rzeczy zamiast jednej (weryfikuje czy blokować Usera i ew. blokuje, oraz sprawdza czy User może się logować). Ale z punktu widzenia Reguły Pojedynczej Odpowiedzialności klas ten kod jest zupełnie do niczego... a dokładniej to do wszystkiego :)  (jak z resztą większość EJB na tym świecie, ponieważ ten model promuje takie programowanie). Ta klasa w jednej metodzie komunikuje się z bazą danych, w drugiej zawiera logikę, w trzeciej zwraca tekst do wyświetlenia w UI. Brrrrr. Straszne.&lt;div&gt;&lt;br /&gt;&lt;div&gt;W przykładzie klasy, która ma 35 linii może jeszcze to tak nie kłuje w oczy, ale taka klasa mogła by mieć 30 różnych metod i wtedy przestaje być jasne za co taka klasa jest odpowiedzialna, co gdzie należy zmienić jeśli chce się wprowadzić nową funkcjonalność lub zmodyfikować istniejącą. Przy dużej liczbie takich komponentów aplikacja przestaje być utrzymywalna. Odpowiedzialności mieszają się ze sobą, obiekty wołają nawzajem różne swoje metody tworząc sieć zależności i oczekiwań. W w dużych aplikacjach ze skomplikowanymi procesami brak poprawnego i dokładnego rozdzielenia odpowiedzialności powoduje, że zmiany w jednej metodzie powodują często powstawanie błędów w wielu innych miejscach aplikacji.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Jak więc należało by ten problem rozwiązać? Ja proponowałbym kod bazodanowy wyprowadzić do odpowiedniego modułu/warstwy (DAO, repozytorium, etc.) a dostęp do niego zrealizować np. jako metodę samego obiektu User (np. a'la Grails'owy GORM: User.findByName(name)). Weryfikacja poprawności użytkownika albo do obiektu walidacji, albo do klasy User (jako User.isValid()). Kod zwracający treść do wyświetlenia przerzucić na stronę wyświetlającą (albo jako tag czy fragment) a samo wywołanie logowania (linia wołająca obiekt loginManager) jest już odpowiednie dla kontrolera UI. &lt;/div&gt;&lt;div&gt;I w ten sposób... nie ma już więcej UserManagerBean'a :) (tak, to taki sprytny sposób podprogowego przekazania myśli, że EJB nie powinny być wykorzystywane do metod które nie korzystają bezpośrednio z transakcyjności, bezpieczeństwa czy remotingu)&lt;/div&gt;&lt;div&gt;Jeśli będzie zmiana w strukturze danych w bazie albo zmieni się wymaganie co do zapytania zwracającego użytkownika, jest jasne gdzie tego szukać - w klasie reprezentującej repozytorium obiektów User. Jeśli będziemy chcieli dodać i18n, będzie to w miejscu odpowiedzialnym za wyświetlanie. Jeśli będzie trzeba zwiększyć dostępną liczbę nieudanych prób logowania Użytkownika, to też łatwo będzie ustalić gdzie jest odpowiedni kod.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Przy definiowaniu przynależności metod do klas można wykorzystać heurystykę częstotliwości odwołań do różnych klas w ramach metody. Jeśli w jakiejś metodzie większość wywołań metod dotyczy jednej klasy, to z dużym prawdopodobieństwem ta metoda powinna w tej klasie się znaleźć (zmniejszając ilość kodu o odwołania do obiektu i poprawiając jego logiczne rozłożenie).&lt;/div&gt;&lt;div&gt;Jeśli dbamy o to, by metody były krótkie, tych odwołań nie będzie dużo i łatwiej o dobry (sprawny) design, stąd jeszcze jeden powód do pilnowania pojedynczej odpowiedzialności metod. W ten sposób dużo łatwiej jest osiągnąć Święty Graal projektowania obiektowego: High Cohesion with Loose Coupling&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Choć w sumie Zasada Pojedynczej Odpowiedzialności dotyczy zupełnie czego innego w przypadku metod niż w przypadku klas, wykorzystywanie jej w obu (rozdzielone małe metody o jednej odpowiedzialności umieszczone w odpowiednich klasach) ma niebagatelny wpływ na jakość naszego kodu a więc na łatwość jego zrozumienia przez innych oraz jego utrzymywalność. &lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2338976640977990159-3785494016924873331?l=sprawnainzynieriaoprogramowania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2338976640977990159&amp;postID=3785494016924873331' title='Komentarze (3)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/3785494016924873331'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/3785494016924873331'/><link rel='alternate' type='text/html' href='http://sprawnainzynieriaoprogramowania.blogspot.com/2009/02/solid-srp-czesc-2-klasy.html' title='SOLID - SRP część 2 - klasy'/><author><name>Paweł Lipiński</name><uri>http://www.blogger.com/profile/02772675014904905654</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-2338976640977990159.post-1019611612356957725</id><published>2009-02-13T13:25:00.002+01:00</published><updated>2009-02-19T16:57:55.889+01:00</updated><title type='text'>SOLID - Single Responsibility Principle - część 1 - metody</title><content type='html'>Pisałem już wcześniej o zasadach SOLID, ale pomyślałem, że tak blisko oddają one ducha zwinności designu, że przejdę przez nie po kolei, pokazując jak można zmienić kod napisany przeciętnie w kod napisany dobrze. Co więcej takie zmiany poprawiają czytelność (a więc jakość) kodu ogromnie, a kosztują zwykle bardzo mało. Ubocznym efektem jest łatwiejsze wykrywanie błędów logicznych i duplikowania kodu.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Pierwsza na tapecie jest zasada pojedynczej odpowiedzialności. Jedna metoda odpowiedzialna za jedną funkcję. Jedna klasa reprezentuje jedną rzeczywistość (nie znalazłem lepszego słowa...)&lt;/div&gt;&lt;div&gt;Jako przykład wziąłem metodę z jednego z projektów w których kiedyś brałem udział (zastanawiałem się nad napisaniem kawałka kodu specjalnie pod ten tekst, ale takie przypadki są zwykle nierzeczywiste, więc wziąłem coś co jest z prawdziwego projektu). System realizował workflow, w którym każdy element mógł być na jednym z paru etapów (klasa Stage w kodzie). Ta metoda służyła do przejścia do kolejnego etapu. W czasie aktywowania jednego etapu trzeba było zdezaktywować poprzednio aktywny, ustawić datę aktywowania, deadline dla jego zakończenia, komentarz itp. A oto i kod oryginalnej metody, która to robiła:&lt;/div&gt;&lt;div&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;/** Activates stage&lt;br /&gt;* SAVES TO DB&lt;br /&gt;*/&lt;br /&gt;void activateStageDeactivatingCurrentlyActive(Stage forActivation)&lt;br /&gt;{&lt;br /&gt;Assert.assertNotNull(forActivation);&lt;br /&gt;Stage forDeactivation = null;&lt;br /&gt;&lt;br /&gt;if (forActivation.getDirection() == Stage.IN_DIRECTION)&lt;br /&gt;    forDeactivation = findActiveStageIn();&lt;br /&gt;else if (forActivation.getDirection() == Stage.OUT_DIRECTION)&lt;br /&gt;    forDeactivation = findActiveStageOut();&lt;br /&gt;else&lt;br /&gt;    throw new IllegalStateException("Please supply proper direction");&lt;br /&gt;&lt;br /&gt;//if activated stage is not null and is not the same as previous active one&lt;br /&gt;if (!forActivation.sameAs(forDeactivation)){&lt;br /&gt;    if (forDeactivation != null) {&lt;br /&gt;        forDeactivation.deactivate();&lt;br /&gt;        if (forActivation.isRemoved()) {&lt;br /&gt;            forActivation.setComment(forDeactivation.getId().toString());&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    // fix: #372 update start_date,&lt;br /&gt;    // set only when planed started was not set&lt;br /&gt;    if (forActivation.getStartDate() == null) {&lt;br /&gt;        if (forDeactivation == null){ //when no active stage present before set sysdate&lt;br /&gt;            forActivation.setStartDate(&lt;br /&gt;                forActivation.getDeadline() == null ? new Date() : forActivation.getDeadline()&lt;br /&gt;            );&lt;br /&gt;        } else {&lt;br /&gt;            forActivation.setStartDate(forDeactivation.getDeadline());&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    if (null != forActivation) {&lt;br /&gt;        forActivation.activate();&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Pierwszy podstawowy warunek dobrego kodu spełniony - mieści się na jednej stronie ;) Generalnie ta metoda nie jest jakaś strasznie długa (na pewno każdy pisał w życiu dłuższe), a pewnie wielu pomyśli, że jest nawet całkiem ok pod względem zawartości i czytelności. Ale ja sądzę, że ta metoda robi jednak o parę rzeczy za dużo, co więcej trudno powiedzieć na pierwszy rzut oka co robi, więc po kolei postaram się doprowadzić ten kod do porządku.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Najpierw usunę nic nie mówiący komentarz i zmienię nazwę metody na samo activateStage. W klasie Stage można napisać, że możliwa jest aktywność tylko jednego, więc w nazwie metody to nie jest potrzebne. Następnie usuwam weryfikację, czy parametr metody nie jest null'em. Takie coś jest na pewno w paru miejscach w kodzie, więc zrobię aspekt, który nie dopuści w ogóle do wywołania tej metody z nullowym parametrem (w ogóle bardzo się zdziwiłem, że w produkcyjnym kodzie jest takie odwołanie do junita...) Moja metoda wygląda więc teraz tak:&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;void activateStage(Stage forActivation) {&lt;br /&gt;Stage forDeactivation = null;&lt;br /&gt;&lt;br /&gt;if (forActivation.getDirection() == Stage.IN_DIRECTION)&lt;br /&gt;    forDeactivation = findActiveStageIn();&lt;br /&gt;else if (forActivation.getDirection() == Stage.OUT_DIRECTION)&lt;br /&gt;    forDeactivation = findActiveStageOut();&lt;br /&gt;else&lt;br /&gt;    throw new IllegalStateException("Please supply proper direction");&lt;br /&gt;.......&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Aspekt tu ominę, bo nie o niego tu chodzi. Ma być &lt;span class="Apple-style-span" style="font-style: italic;"&gt;before execution&lt;/span&gt; i tam pewnie wyjątek jeśli null.&lt;br /&gt;&lt;br /&gt;Teraz cały fragment odpowiedzialny za wybranie ostatnio aktywnego etapu wywalam do oddzielnej metody (findPreviouslyActiveStage), co mi daje:&lt;br /&gt;&lt;div&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;void activateStage(Stage forActivation) {&lt;br /&gt;Stage forDeactivation = findPreviouslyActiveStage(forActivation);&lt;br /&gt;&lt;br /&gt;//if activated stage is not null and is not the same as previous active one&lt;br /&gt;if (!forActivation.sameAs(forDeactivation)){&lt;br /&gt;    if (forDeactivation != null) {&lt;br /&gt;......&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Teraz zmieniam warunek otaczający całą resztę tej metody na odwrotny (bez negacji, za to wcześniejszy return), co daje taki kod:&lt;br /&gt;&lt;div&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;void activateStage(Stage forActivation) {&lt;br /&gt;Stage forDeactivation = findPreviouslyActiveStage(forActivation);&lt;br /&gt;if (forDeactivation.sameAs(forActivation))&lt;br /&gt;    return;&lt;br /&gt;&lt;br /&gt;if (forDeactivation != null) {&lt;br /&gt;......&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Następny etap to ekstrakcja do nowej metody (deactivateStage) fragmentu odpowiedzialnego za deaktywację poprzedniego etapu:&lt;br /&gt;&lt;div&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;void activateStage(Stage forActivation) {&lt;br /&gt;Stage forDeactivation = findPreviouslyActiveStage(forActivation);&lt;br /&gt;if (forDeactivation.sameAs(forActivation))&lt;br /&gt;    return;&lt;br /&gt;deactivateStage(forActivation, forDeactivation);&lt;br /&gt;&lt;br /&gt;// fix: #372 update start_date,&lt;br /&gt;// set only when planed started was not set&lt;br /&gt;if (forActivation.getStartDate() == null) {&lt;br /&gt;......&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Kolejny etap to ustawienie daty początkowej nowego etapu (jeśli nie była ona ustawiona wcześniej), które również zasługuje&lt;br /&gt;na własną metodę:&lt;br /&gt;&lt;div&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;void activateStage(Stage forActivation) {&lt;br /&gt;Stage forDeactivation = findPreviouslyActiveStage(forActivation);&lt;br /&gt;if (forDeactivation.sameAs(forActivation))&lt;br /&gt;    return;&lt;br /&gt;deactivateStage(forActivation, forDeactivation);&lt;br /&gt;updateStartDate(forActivation, forDeactivation);&lt;br /&gt;&lt;br /&gt;if (null != forActivation) {&lt;br /&gt;    forActivation.activate();&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;br /&gt;No i teraz łatwo mi się zorientować, że forActivation nie może nigdy być null, więc mogę opuścić tę weryfikację przy aktywacji, co daje ostateczną wersję metody:&lt;br /&gt;&lt;div&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;public void activateStage(Stage forActivation) {&lt;br /&gt;Stage forDeactivation = findPreviouslyActiveStage(forActivation);&lt;br /&gt;if (forDeactivation.equals(forActivation))&lt;br /&gt;    return;&lt;br /&gt;deactivateStage(forActivation, forDeactivation);&lt;br /&gt;updateStartDate(forActivation, forDeactivation);&lt;br /&gt;forActivation.activate();&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;No, teraz widać co ta metoda robi. Przede wszystkim sama robi tylko jedną rzecz - aktywuje nowy etap. Cała reszta jest wyciagnięta na do innych metod. Komentarze też nie są tu potrzebne, bo widać co sie dzieje.&lt;br /&gt;Również metody wykorzystywane przez nią zostały poprawione i każda jest odpowiedzialna tylko za jedną rzecz i ew. deleguje inne dalej (już nie będę męczył tu całym refactoringiem...):&lt;br /&gt;&lt;div&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;private Stage findPreviouslyActiveStage(Stage forActivation) {&lt;br /&gt;switch(forActivation.getDirection()) {&lt;br /&gt;    case Stage.IN_DIRECTION:&lt;br /&gt;        return findActiveStageIn();&lt;br /&gt;    case Stage.OUT_DIRECTION:&lt;br /&gt;        return findActiveStageOut();&lt;br /&gt;    default:&lt;br /&gt;        throw new IllegalStateException("Please supply proper direction");&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;private void deactivateStage(Stage forActivation, Stage forDeactivation) {&lt;br /&gt;if (forDeactivation == null)&lt;br /&gt;    return;&lt;br /&gt;forDeactivation.deactivate();&lt;br /&gt;setCommentIfStageRemoved(forActivation, forDeactivation);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;private void setCommentIfStageRemoved(Stage forActivation, Stage forDeactivation) {&lt;br /&gt;if (forActivation.isRemoved())&lt;br /&gt;    forActivation.setComment(forDeactivation.getId().toString());&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;private void updateStartDate(Stage forActivation, Stage forDeactivation) {&lt;br /&gt;if (forActivation.getStartDate() != null)&lt;br /&gt;    return;&lt;br /&gt;&lt;br /&gt;if (forDeactivation != null) {&lt;br /&gt; forActivation.setStartDate(forDeactivation.getDeadline());&lt;br /&gt; return;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;forActivation.setStartDate(&lt;br /&gt;    forActivation.getDeadline() == null ? new Date() : forActivation.getDeadline()&lt;br /&gt;);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Pewnie część ludzi woli i tak zapis oryginalny metody :) Do czytania to on może jest lepszy (choć to kwestia opatrzenia się z tak pisanym kodem, którego wszędzie jest pełno), ale zrozumienie tego co robi kod jest bez wątpienia łatwiejsze w zapisie zrefaktoryzowanym. Wystarczy popisać tak parę dni i od razu nawyki się zmieniają. &lt;div&gt;Gdy szukamy konkretnego miejsca w kodzie (np. dlatego, że tam jest błąd), łatwiej jest poruszać się po hiearchii małych jednozadaniowych metod, szczególnie jeśli mają łatwo zrozumiałe nazwy.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Ten kod nie jest jeszcze do końca czysty. Trzeba by pewnie pozmieniać parę nazw zmiennych i może przeorganizować logikę, tak by wszystko było na swoim miejscu, ale to już nie jest kwestia pojedynczych odpowiedzialności metod, więc to sobie w tym przykładzie odpuszczam.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Dbanie o zapewnianie pojedynczej odpowiedzialności (a więc unikanie pisania zbyt wiele w jednej metodzie) jest pewnym nawykiem, który trzeba w sobie wyrobić - tak jak unikanie copy-paste, czy za dużo if-else. Oczywiście pisać byle jak jest łatwiej i jasne, że to jest kuszące. Szczególnie gdy koniec projektu blisko, inni nie dbają, stary kodu jest do niczego...  Ale to właśnie te małe wysiłki powodują, że z każdym dniem możesz stać się lepszy w swoim zawodzie. Że to ty możesz zmienić swój projekt, zawstydzić swój zespół, wzbudzić zdrową zazdrość.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2338976640977990159-1019611612356957725?l=sprawnainzynieriaoprogramowania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2338976640977990159&amp;postID=1019611612356957725' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/1019611612356957725'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/1019611612356957725'/><link rel='alternate' type='text/html' href='http://sprawnainzynieriaoprogramowania.blogspot.com/2009/02/solid-single-responsibility-principle.html' title='SOLID - Single Responsibility Principle - część 1 - metody'/><author><name>Paweł Lipiński</name><uri>http://www.blogger.com/profile/02772675014904905654</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-2338976640977990159.post-1575592805352651948</id><published>2009-02-13T11:16:00.000+01:00</published><updated>2009-02-13T13:06:25.033+01:00</updated><title type='text'>Jakość nie ma znaczenia</title><content type='html'>Ostatnio wśród speców od programowania rozgorzała dyskusja nad jakością kodu/designu versus czas rozwijania.  Rozpoczął ją Joel Spolsky wypuszczając podcast w którym pada zdanie: &lt;blockquote&gt;&lt;span class="Apple-style-span" style="font-style: italic;"&gt;And I find, sadly, to be completely honest with everybody listening, quality really doesn't matter that much, in the big scheme of things...&lt;/span&gt;&lt;/blockquote&gt;W tym samym podcast'cie Joel mówi tak:&lt;blockquote&gt;&lt;span class="Apple-style-span" style="font-style: italic;"&gt;Last week I was listening to a podcast on Hanselminutes, with Robert Martin talking about the SOLID principles. (...)It's object-oriented design, and they're calling it agile design, which it really, really isn't. It's principles for how to design your classes, and how they should work. And, when I was listening to them, they all sounded to me like extremely bureaucratic programming that came from the mind of somebody that has not written a lot of code, frankly.&lt;/span&gt;&lt;/blockquote&gt;No więc co znaczy &lt;span class="Apple-style-span" style="font-style: italic;"&gt;agile&lt;/span&gt; w kontekście oprogramowania? Mniej więcej to samo co w kontekście prowadzenia projektów: reagowanie na zmiany. I z tego punktu widzenia zasady SOLID (o których było parę postów temu) są bardzo zwinne, bo pozwalają z dużo większą łatwością dodawać nowe funkcje do systemu i modyfikować istniejące. Nie bardzo wiem z czym można tu dyskutować. Programowanie które nie jest w tym sensie "biurokratyczne" to programowanie chaotyczne. &lt;div&gt;A mówienie o Robercie C. Martinie, Martinie Fowlerze, Kencie Becku i innych ludziach stojących za zwinnością w sensie technologicznym, że nie napisali wiele kodu jest po prostu żenujące.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Pierwszy cytat dotyczący jakości to jasny dowód na to, że jego autor jest PMem...  Dba o TEN projekt, o TĘ kasę, o TE terminy. Dług techniczny zaciągnięty w tym czasie nie jest dla niego ważny, bo przecież później się to posprząta.  Z resztą ten cytat mówi sam za siebie:&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="line-height: 22px; "&gt;&lt;span class="Apple-style-span" style="font-style: italic;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="line-height: 22px; "&gt;&lt;span class="Apple-style-span" style="font-style: italic;"&gt;The way real software works is that you create these very imperfect things, and they work great. They really do. And then you have a little problem, and you go and you fix the little problem, because it's code, and you have an editor, and you edit it. &lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-style: italic;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;Taaak. Przykładów oprogramowania, które &lt;span class="Apple-style-span" style="font-style: italic; "&gt;works great&lt;/span&gt; jest faktycznie wiele... &lt;br /&gt;&lt;/div&gt;&lt;div&gt;Dług techniczny nazbierany przez lata powoduje, że właśnie nie da się po prostu otworzyć edytora i poprawić kodu. Z resztą zwrot &lt;span class="Apple-style-span" style="font-style: italic;"&gt;little problem&lt;/span&gt; też pokazuje nastawienie pana Spolsky'ego. No ale on robi soft do rejestrowania błędów, więc zależy mu na tym, żeby było ich jak najwięcej - wtedy więcej kopii sprzeda :)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Straszne, że ktoś tak wpływowy w świecie oprogramowania pisze takie rzeczy.&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Takie krótkowzroczne spojrzenie jest ze stratą dla wszystkich. Programiści się frustrują i nie chcą potem pracować z takim kodem. Klient dostaje coraz dłuższe terminy (a więc i większe kwoty), albo te co są są niedotrzymywane. PM ma zmarnowane życie prywatne i wrzody żołądka (choć na to to akurat sobie zasłużył :)). &lt;br /&gt;&lt;/div&gt;&lt;div&gt;Jedną z podstawowych wartości ruchu agile jest transparentność i szczerość. I dotyczy to procesów (wiadomo kto, co i kiedy robi), efektów (ukończonych zadań), kosztów. Ale mało kto mówi, że dotyczy to również kodu. I to nie tylko w zespole programistów. Kto informuje swojego klienta o powstającym na skutek jego presji długu technicznym? Kto mówi, że żeby robić release'y na czas wprowadził do systemu taki shit, że robienie nowych funkcjonalności zajmie 20% czasu więcej (a więc 20% więcej będzie kosztować, co może przekona klienta)?&lt;/div&gt;&lt;div&gt;Odpowiedzialny zaspół zgłasza swojemu Product Owner'owi (a ten klientowi) informacje o wpływie jego decyzji na jakość. Jakość jest wartością biznesową a nie techniczną i jako taka powinna być uświadamiana klientowi. Jeśli twój PM nie pozwala Ci dbać odpowiednio o jakość (ciśnie terminami, siedzisz po godzinach, nie testujesz kodu itp.) to działa na szkodę klienta (to on ostatecznie dostanie shit) i na szkodę Twojej firmy. Warto więc uświadamiać w tym zakresie osoby niezaangażowane bezpośrednio w projekt, a mogące podejmować decyzje.&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2338976640977990159-1575592805352651948?l=sprawnainzynieriaoprogramowania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2338976640977990159&amp;postID=1575592805352651948' title='Komentarze (1)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/1575592805352651948'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/1575592805352651948'/><link rel='alternate' type='text/html' href='http://sprawnainzynieriaoprogramowania.blogspot.com/2009/02/jakosc-nie-ma-znaczenia.html' title='Jakość nie ma znaczenia'/><author><name>Paweł Lipiński</name><uri>http://www.blogger.com/profile/02772675014904905654</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-2338976640977990159.post-2932142487986791739</id><published>2009-02-06T08:59:00.000+01:00</published><updated>2009-02-06T10:33:48.360+01:00</updated><title type='text'>Ekstremalna obiektowość</title><content type='html'>Kto mnie zna, wie, że jestem stuknięty jeśli chodzi o obiektowość. Tak od paru lat. Z każdym projektem w którym uczestniczę (ew. który przeglądam...) coraz bardziej. Od czasu kiedy stworzyłem parę lat temu klasę-potwora - półtoratysiąca linii, z których z 500 było w jednej metodzie i nie dane mi było tej Augiaszowej stajni posprzątać, z wszystkich rzeczy w programowaniu dbam najbardziej o zachowywanie zasady pojedynczej odpowiedzialności. Jeśli miewam w nocy jakieś koszmary, to dotyczą one zawsze refactoringu tej klasy :)&lt;div&gt;&lt;br /&gt;&lt;div&gt;W związku z tym moim małym zboczeniem, z wielką ciekawością przeczytałem (parokrotnie) jeden z rozdziałów w książce, którą aktualnie mam na tapecie - &lt;a href="http://www.amazon.com/ThoughtWorks-Anthology-Technology-Innovation-Programmers/dp/193435614X/ref=pd_bbs_sr_1?ie=UTF8&amp;amp;s=books&amp;amp;qid=1233907788&amp;amp;sr=8-1"&gt;The Thoughtworks Anthology&lt;/a&gt;. Rozdział nosi tytuł Object Calisthenics (można go gdzieś w necie znaleźć jako .doc). Jeff Bay proponuje w nim 9 reguł dotyczących tworzenia kodu (przykłady są w javie, ale większość reguł odnosić się może do w miarę dowolnego języka, szczególnie OO). Są to&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Tylko jeden poziom zagłębienia na metodę&lt;/li&gt;&lt;li&gt;Nie używaj słowa kluczowego &lt;span class="Apple-style-span" style="font-style: italic;"&gt;else&lt;/span&gt;&lt;/li&gt;&lt;li&gt;Opakowuj wszystkie prymitywy i Stringi (w klasy o specyficznej dla zastosowania nazwie)&lt;/li&gt;&lt;li&gt;Używaj tylko jednej kropki na linię&lt;/li&gt;&lt;li&gt;Nie skracaj nazw&lt;/li&gt;&lt;li&gt;Pilnuj wszystkie encje by były małe&lt;/li&gt;&lt;li&gt;Nie używaj klas o więcej niż dwóch polach&lt;/li&gt;&lt;li&gt;Klasa której polem jest kolekcja nie powinna mieć żadnych innych pól (opakowywanie kolekcji w klasy specyficzne dla kontekstu wykorzystania)&lt;/li&gt;&lt;li&gt;Nie używaj getterów/setterów/własności&lt;/li&gt;&lt;/ul&gt;Wow - pomyślałem. To jak tu w ogóle pisać? Ale Mr. Bay jest w swoim tłumaczeniu dość przekonujący. Wolałbym co prawda więcej przykładów w artykule, ale już samo przedstawione przez niego &lt;span class="Apple-style-span" style="font-style: italic;"&gt;rationale&lt;/span&gt; przekonuje mnie do większości z tych stwierdzeń. Co więcej, większość z nich i tak bardzo często stosuję (opakowywanie kolekcji i prymitywów, jeden poziom zagłębienia, nieskracanie nazw), ale autor przekonuje, żeby stosować te reguły wręcz fanatycznie. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Parę rzeczy jest pewnych: &lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;taki kod jest bardziej obiektowy (podział odpowiedzialności, właściwe opakowywanie, itp.)&lt;/li&gt;&lt;li&gt;taki kod jest bardziej testowalny (małe metody, proste testy - taki design sam się prosi o TDD)&lt;br /&gt;&lt;/li&gt;&lt;li&gt;taki kod jest bardziej reużywalny (łatwiej znaleźć wiele zastosowań dla małej metody o dobrze określonej odpowiedzialności niż dla metody, która robi pięć rzeczy)&lt;/li&gt;&lt;li&gt;taki kod sam się dokumentuje (krótkie jednoznaczne nazwy metod powodują, że kod się czyta prawie jak zwykły tekst)&lt;/li&gt;&lt;li&gt;trudniej zrobić a łatwiej wykryć błąd w metodzie o 5 liniach niż w metodzie o 500 (to akurat wiem dobrze)&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;Może więc jednak warto naciskać na obiektowość i doprowadzać ją do ekstremum. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Mimo, że generalnie artykuł Jeffa Bay'a jest bardzo blisko moich własnych praktyk programistycznych, wydaje mi się on zbyt ekstremalny. Póki co do niektórych reguł (a raczej ich fanatycznego stosowania) jestem trochę sceptycznie nastawiony, szczególnie jesli wziąć pod uwagę, że nasz kod zależy czasem od zewnętrznych frameworków/bibliotek które nie pozwalają nam na pełną elastyczność (jak na przykład pogodzić takie rozdrobnienie, brak getterów i setterów itp. z np. mapowaniem hibernate'owym). &lt;/div&gt;&lt;div&gt;Tak czy siak autor zachęca do zrobienia ćwiczenia: 1000 linii kodu napisanego trzymając się tych reguł. A że w poniedziałek i wtorek mam szkolenie poza Warszawą, przynajmniej połowę z tego wyrobię :)&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2338976640977990159-2932142487986791739?l=sprawnainzynieriaoprogramowania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2338976640977990159&amp;postID=2932142487986791739' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/2932142487986791739'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/2932142487986791739'/><link rel='alternate' type='text/html' href='http://sprawnainzynieriaoprogramowania.blogspot.com/2009/02/ekstremalna-obiektowosc.html' title='Ekstremalna obiektowość'/><author><name>Paweł Lipiński</name><uri>http://www.blogger.com/profile/02772675014904905654</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-2338976640977990159.post-2034464768143624858</id><published>2009-02-02T09:50:00.000+01:00</published><updated>2009-02-02T10:21:54.405+01:00</updated><title type='text'>Narty</title><content type='html'>Skończyłem właśnie ferie zimowe w czasie których jeździłem trochę na nartach i już pierwszego dnia na stoku miałem następujące skojarzenie: &lt;div&gt;Co ma wspólnego stok narciarski z R&amp;amp;D? Większość ludzi na stoku myśli, że umie jeździć jak zasuwa na krechę z nogami rozstawionymi jakby drzewo z obu stron na raz chcieli wyminąć, kijkami na boki i wrzaskiem 'uwaaaagaaa'. W naszej działce bieg do zakończenia projektu wygląda podobnie - ma być szybko, więc często jest byle jak.&lt;div&gt;Ludzie którzy jeżdżą na nartach zwykle są zadowoleni jak umieją zjechać z górki bez przewrócenia się i to jest koniec ich ambicji. I dlatego trudniejsze trasy są puste. Bardziej wymagający śnieg powoduje, że wszyscy leżą, a następnego dnia stok jest pusty. Brak umiejętności wychodzi od razu gdy warunki nie są idealne.&lt;/div&gt;&lt;div&gt;Programiści mogą być skazani na ten sam los. Jeśli nie będziemy się rozwijać, uczyć, ciągle poprawiać, dyskutować z innymi, patrzeć na cudzy kod, jakiekolwiek zawirowanie w projekcie, presja czasu czy trudne zagadnienie, od razu powodują porażkę.&lt;/div&gt;&lt;div&gt;Znane z metodyki &lt;span class="Apple-style-span" style="font-style: italic;"&gt;lean&lt;/span&gt; pojęcie kaizen (continous improvement) dotyczy dokładnie tego: ciągły rozwój, zwiększanie swojej wiedzy, doświadczenia. Idealnie wpasowuje się to w parę idei z książki Pragmatic Programmer, np. co roku naucz się nowego języka programowania - nie? &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Ja w na ten rok zaplanowałem uaktualnienie wiedzy o Springu, dobre poznanie Scali (może jeszcze Clojure?) i hiszpański (mało programistyczne zagadnienie... :) )&lt;/div&gt;&lt;div&gt;&lt;br /&gt;A ty czego zamierzasz nauczyć się w najbliższym czasie?&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;PS. W czasie ferii byłem na niekonferencji Cooluary w Krakowie. Atmosfera fajna,  ludzie konkretni i z wiedzą, dyskusje ciekawe i cena przystępna. Mówiąc krótko polecam wszysktim na przyszły rok!&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2338976640977990159-2034464768143624858?l=sprawnainzynieriaoprogramowania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2338976640977990159&amp;postID=2034464768143624858' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/2034464768143624858'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/2034464768143624858'/><link rel='alternate' type='text/html' href='http://sprawnainzynieriaoprogramowania.blogspot.com/2009/02/narty.html' title='Narty'/><author><name>Paweł Lipiński</name><uri>http://www.blogger.com/profile/02772675014904905654</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-2338976640977990159.post-5605897103633153412</id><published>2009-01-13T22:17:00.000+01:00</published><updated>2009-01-13T22:33:33.957+01:00</updated><title type='text'>Białe Nosorożce</title><content type='html'>Podszedł dziś do mnie w pracy kolega i stwierdził, że poszukuję białego nosorożca. I że jak jest ciśnienie w projekcie to wszystkie te rzeczy, o których tu pisałem rzuca się w cholerę i wali prosto do celu. No i tak faktycznie jest w większości wypadków. Ale wg. mnie świadczy to wyłącznie o tym, że pewne praktyki (testowanie, refactoring) nie są naszą naturą, ale że ciągle jesteśmy w stadium poznawania. I gdy tylko grunt mamy trochę niepewny, wracamy do dobrze znanych i wyuczonych nawyków.&lt;div&gt;Poza tym zastanawiam się czy czasem nie zbyt samodzielnie podejmujemy decyzję o rzuceniu dobrych praktyk na rzecz zakończenia projektu przed deadline'm. Może klient jednak wolałby dostać soft 2 tygodnie później ale dostać produkt wyższej jakości. Jak zwykle w agile, chodzi tu o relację zaufania i szczerość między klientem a zespołem. Jeśli do tego mamy krótkie iteracje, klient będzie na bieżąco wiedział jaki jest status projektu i wszystkie te kwestie można ustalić dużo wcześniej zmniejszając ryzyko i frustrację wszystkich zaangażowanych osób.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;A że szukam białych nosorożców to wiem od dawna. Dzięki temu z każdym dniem staję się lepszym programistą. &lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2338976640977990159-5605897103633153412?l=sprawnainzynieriaoprogramowania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2338976640977990159&amp;postID=5605897103633153412' title='Komentarze (1)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/5605897103633153412'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/5605897103633153412'/><link rel='alternate' type='text/html' href='http://sprawnainzynieriaoprogramowania.blogspot.com/2009/01/biae-nosoroce.html' title='Białe Nosorożce'/><author><name>Paweł Lipiński</name><uri>http://www.blogger.com/profile/02772675014904905654</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-2338976640977990159.post-8649842351041252920</id><published>2008-11-26T19:43:00.001+01:00</published><updated>2009-06-05T09:11:55.035+02:00</updated><title type='text'>Agile OOD w skrócie</title><content type='html'>Dziś trochę o jakości kodu. Oczywiście jasne jest, że powinna być jak najwyższa. Tylko nie jest już tak jasne jak to osiągnąć. Zwinne techniki, głównie pochodzące z XP zalecają TDD jako mechanizm wspierający jakość kodu. I faktycznie tak rozwijany kod ma dużo większe szanse na powodzenie (poprawność, utrzymywalność, itp) m.in. ze względu na jego refaktoryzację, a więc wielokrotne myślenie  o tym samym kodzie (często przez wiele osób przy programowaniu w parach i współwłasności kodu) i poprawianie jego jakości. Tylko skąd wiedzieć, że refaktoryzacja przez nas stosowana faktycznie poprawia jakość kodu? Jak przewidzieć czy kod będzie dzięki temu bardziej utrzymywalny, łatwiejszy do zrozumienia, elastyczniejszy w użyciu? No więc tu przychodzi nam z pomocą parę podstawowych zasad strukturyzowania kodu obiektowego.  No to po kolei:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Zasada pojedynczej odpowiedzialności (single responsibility principle):&lt;/span&gt;&lt;br /&gt;Każda klasa powinna mieć tylko jedną odpowiedzialność. Wszystkie usługi które udostępnia powinny być z nią ściśle związane. Czasem mówi się, że to oznacza, że powinien być dokładnie jeden powód do zmiany klasy. Na przykład jeśli mamy klasę zarządzającą użytkownikami, która definiuje ich uprawnienia i dokonuje odpowiednich wpisów w bazie danych, to są przynajmniej dwa powody do jej zmiany (dwie odpowiedzialności): struktura użytkownika i mechanizm komunikacji z bazą danych. W takim przypadku powinniśmy mieć oddzielne klasy: regulującą uprawnienia i realizującą komunikację z bazą danych.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Zasada otwartości-zamknięcia (open-closed principle):&lt;/span&gt;&lt;br /&gt;Klasy powinny być otwarte na rozszerzenia i zamknięte na modyfikacje.  Z tym związane są podstawowe zasady obiektowości: hermetyzacja  - to dzięki niej możemy zamknąć klasę na modyfikacje (metody prywatne) - oraz dziedziczenie, dzięki któremu możemy klasę rozszerzyć.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Zasada podstawiania Liskov:&lt;/span&gt;&lt;br /&gt;Klasy dziedziczące muszą móc być wykorzystywane tak jak ich klasa bazowa. Z tego wynika, że klasy dziedziczące nie powinny zmieniać kontraktu metod przy ich przeładowywaniu (redefiniowaniu w klasie dziedziczącej). To może spowodować, że klient klasy bazowej nieświadomy tego jaką jej implementację dostaje może czynić jakieś założenia co do jej funkcjonowania (i się rozczarować...) Jak tego uniknąć mówi kolejna zasada:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Design by Contract:&lt;/span&gt;&lt;br /&gt;Warunki wstępne (pre-conditions) dla przeładowywanych metod w podklasie (czyli założenia co do wartości ich parametrów) być takie same albo słabsze niż dla metody która jest przeładowywana w nadklasie. Odwrotnie dla warunków wyjściowych (post-conditions - wynik metody, wyjątki) - te powinny być takie same bądź mocniejsze/węższe niż dla tej metody w nadklasie. Dzięki temu metody podklasy wykorzystywane przez klienta jako metody nadklasy (przez polimorfizm) zawsze będą spełniać kontrakt ich oryginałów w klasie bazowej, nie spowodują więc nieoczekiwanych efektów po stronie klienta.&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Zasada odwrócenia zależności:&lt;/span&gt;&lt;br /&gt;Tam gdzie to tylko możliwe bądź zależny od abstrakcji a nie konkretów. Czyli jeśli chcesz mieć w klasie pole typu lista, to nie deklaruj LinkedList, ArrayList ani nic takiego, tylko po prostu List. To ułatwi ci refaktoryzację jeśli okaże się, że trzeba skorzystać z innej implementacji.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Zasada segregacji interfejsów:&lt;/span&gt;&lt;br /&gt;Klasa powinna udostępniać drobnoziarniste interfejsy dostosowane do potrzeb jej klienta. Czyli, że klienci nie powinni mieć dostępu do metod których nie używają. Ta zasada powoduje, że kod klienta twojej klasy będzie bardziej czytelny. Nie koniecznie należy wiązać te interfejsy z tym co oznacza &lt;span style="font-style: italic;"&gt;interface&lt;/span&gt; w javie (z resztą zasada jest ogólna, a nie tylko dla javy, więc dotyczy również języków w których nie ma interface'ów). Często dużo lepszym interfejsem specyficznym dla klienta jest klasa dziedzicząca po tej którą chcesz udostępnić i definiująca odpowiednie metody lub składająca parę metod swojej bazowej w jedną. W językach które udostępniają poza dziedziczeniem kompozycję (np. scala poprzez mechanizm &lt;span style="font-style: italic;"&gt;trait&lt;/span&gt;) można też wykorzystać ten mechanizm do składania klas z elementów specyficznych dla klienta (w ten sposób odwracając ten mechanizm - nie udostępniamy różnych interfejsów dla tej samej klasy, ale składamy tę klasę z interfejsów (i oczywiście implementacji) - &lt;span style="font-style: italic;"&gt;trait&lt;/span&gt;'y w scali są do tego idealne).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Prawo Demeter:&lt;br /&gt;&lt;/span&gt;Mówi ono, że metoda ma prawo wołać metody należące do:&lt;br /&gt;- tej samej klasy&lt;br /&gt;- obiektów będących polami własnej klasy&lt;br /&gt;- własnych parametrów&lt;br /&gt;- obiektów które tworzy&lt;br /&gt;ale&lt;br /&gt;- nie wołaj metod bezpośrednio na obiektach, które otrzymałeś w wyniku innego wywołania&lt;br /&gt;- nie wołaj metod globalnych obiektów&lt;br /&gt;Choć takie podejście ułatwia późniejszą refaktoryzację, czasem jego złamanie jest niezbędne. Poza tym przestrzeganie tej zasady powoduje utrzymywanie wysokiej spójności klas (i minimalizacji zależności).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Mów, ale nie pytaj (Tell, don't ask):&lt;/span&gt;&lt;br /&gt;To dodatkowa zasada z tej samej grupy co Prawo Demeter. Mówi ona, że jest jak najbardziej ok żeby pobierać stan obiektu (wartość jego pól), ale nie wolno wykonywać żadnych funkcji związanych z tym obiektem (tym stanem) poza tym obiektem. Wszystkie decyzje dotyczące obiektu bazujące wyłącznie na jego stanie powinny być podejmowane wewnątrz niego samego.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Takich zasad można stworzyć pewnie więcej. Całe tony tych i podobnych (wraz ze szczegółowymi wyjaśnieniami i odniesieniami do literatury) spisane są na wiki Warda Cunninghamma (&lt;a href="http://c2.com/cgi/wiki"&gt;http://c2.com/cgi/wiki&lt;/a&gt;) które polecam do czytania.&lt;br /&gt;Teraz już poprawianie jakości kodu powinno być dla Ciebie trywialne... :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2338976640977990159-8649842351041252920?l=sprawnainzynieriaoprogramowania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2338976640977990159&amp;postID=8649842351041252920' title='Komentarze (2)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/8649842351041252920'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/8649842351041252920'/><link rel='alternate' type='text/html' href='http://sprawnainzynieriaoprogramowania.blogspot.com/2008/11/agile-ood-w-skrcie.html' title='Agile OOD w skrócie'/><author><name>Paweł Lipiński</name><uri>http://www.blogger.com/profile/02772675014904905654</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-2338976640977990159.post-2458951855545060374</id><published>2008-11-25T10:45:00.000+01:00</published><updated>2008-11-25T11:12:26.494+01:00</updated><title type='text'>50 in 50</title><content type='html'>&lt;p&gt;W tym roku na konferencji JAOO w Århus w Danii miałem okazję być na dość niezwykłykłej prezentacji w wykonaniu Guy'a L. Steele i Richarda P. Gabriela znanych (?) ekspertów od języków programowania. Obaj przez lata zajmowali się Lispem, Steele stworzył Scheme, brał udział w specyfikacji Javy, Common Lispa, C i jeszcze pewnie paru innych języków (aktualnie prowadzi zespół tworzący język Fortress - następcę Fortrana.) Prezentacja &lt;span style="font-weight: bold; font-style: italic;"&gt;50 in 50&lt;/span&gt; dotyczy właśnie tego teamtu - języków programowania. Panowie w niesamowitej happeningowo-postmodernistycznej prezentacji przeszli przez 50 lat programowania, 50 języków od mainstreamowych (Java, C) po najbardziej ezoteryczne (befunge, shakespeare). Prezentacja miała trwać oczywiście 50 min, ale troszeczkę się im wyciągnęła, co akurat biorąc pod uwagę temat (przynajmniej dla mnie) jest czymś dobrym :) Na zakończenie Panowie oddali hołd wszystkim chyba zmarłym naukowcom zajmującym się językami programowania. Całość była naprawdę zaskakująca - czasem śmieszna (kod w języku shakespeare w formie filmu, piosenka God wrote in Lisp code, czy rapujący Guy Steele), czasem pobudzająca do refleksji (panteon ludzi którzy swoją pracą i zaangażowaniem stworzyli świat w którym sie poruszamy zawodowo) i przez cały czas ściśle techniczna. Choć videocast to nie to samo co obecność na miejscu, polecam spędzić najbliższą godzinkę na oglądaniu:&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;embed src="http://blip.tv/play/6VbaqWQA" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" height="470" width="600"&gt;&lt;/embed&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2338976640977990159-2458951855545060374?l=sprawnainzynieriaoprogramowania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2338976640977990159&amp;postID=2458951855545060374' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/2458951855545060374'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/2458951855545060374'/><link rel='alternate' type='text/html' href='http://sprawnainzynieriaoprogramowania.blogspot.com/2008/11/w-tym-roku-na-konferencji-jaoo-w-rhus-w.html' title='50 in 50'/><author><name>Paweł Lipiński</name><uri>http://www.blogger.com/profile/02772675014904905654</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-2338976640977990159.post-8773055034798224795</id><published>2008-10-29T14:01:00.000+01:00</published><updated>2008-11-05T15:45:49.884+01:00</updated><title type='text'>MDD</title><content type='html'>No więc to nie będzie o UMLu, ani o MDA ani o MDSD ani niczym podobnym. Tylko o projektowaniu aplikacji OO.&lt;br /&gt;- Jak Ty zaczynasz swoją aplikację?&lt;br /&gt;- Hmm, no więc... zwykle to... jakoś tak wychodzi...&lt;br /&gt;- No, no! Przyznaj się! Od UI czy od bazy danych?&lt;br /&gt;&lt;br /&gt;No więc? Od czego?&lt;br /&gt;Jakoś tak wychodzi, że zastraszająco dużo projektów zaczyna się od tzw. d* strony. Czyli właśnie albo od UI albo od DB. Generalnie od jakiejś infrastruktury. Od frameworków. Od bibliotek. I myślę, że jednym z powodów jest brak jasnej wizji aplikacji na początku jej tworzenia. A jak wykorzystać frameworki wiadomo. Jak ma wyglądać UI też zwykle (przynajmniej z grubsza) wiadomo. A potem się gdzieś te funkcjonalności wsadzi. A żeby móc zacząć pisać funkcjonalności trzeba mieć konkretną wizję systemu, którą można mieć wyłącznie poprzez wcześniejsze jego zamodelowanie.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Model-Driven Design&lt;/span&gt;&lt;br /&gt;Model-Driven Design oznacza, że development aplikacji prowadzimy (drive'ujemy :) ) modelem.&lt;br /&gt;W książce o DDD Eric Evans wyróżnił 8 głównych wzorców budowy aplikacji. I tak naprawdę nic nowego pewnie tu nie ma poza tym, że pewnie powinni tego uczyć na każdym kursie OO na uczelniach. A że chyba nikt tego nie robi, więc są tu :)&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Layered Architecture&lt;/li&gt;&lt;li&gt;Entities&lt;/li&gt;&lt;li&gt;Value Objects&lt;/li&gt;&lt;li&gt;Services&lt;/li&gt;&lt;li&gt;Modules&lt;/li&gt;&lt;li&gt;Aggregates&lt;/li&gt;&lt;li&gt;Factories&lt;/li&gt;&lt;li&gt;Repositories&lt;/li&gt;&lt;/ul&gt;Zachowałem oryginalne angielskie nazewnictwo, bo tak naprawdę są to wzorce projektowe a częścią idei wzorców jest uwspólnienie języka. &lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;Layered Architecture&lt;/span&gt;&lt;br /&gt;Jeśli warstwowość rozumiemy jako oddzielenie zagadnień (&lt;span style="font-style: italic;"&gt;separation of concerns&lt;/span&gt;) czyli np. nie wrzucanie do jednej klasy kodu UI, DB i jeszcze funkcjonalności aplikacji, to jest to oczywiście rzecz wielce porządana. Zwykle wyróżnia się: UI, aplikacja (koordynacja aplikacji, bez logiki biznesowej), dziedzina (obiekty dziedziny wraz z logiką i stanem), infrastruktura (komunikacja między warstwami, utrwalanie obiektów, dodatkowe funkcje usługowe dla aplikacji, etc.)&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Entities&lt;/span&gt;&lt;br /&gt;To te elementy dziedziny, które mają określony identyfikator. I to nie atrybuty tych obiektów decydują o tym czym są, tylko właśnie identyfikator. Typowe przykłady to Klient, Firma, Faktura itp.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Value Objects&lt;/span&gt;&lt;br /&gt;To przeciwieństwo entities. Tu wyróżnikiem jest zawartość obiektu, jego atrybuty,  a nie identyfikator. Przykłady to np.  Pieniądz (ważna zwykle wartość a nie nr seryjny) czy Książka (ważny jest autor i tytuł a nie konkretny egzemplarz).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Services&lt;/span&gt;&lt;br /&gt;Czasem się okazuje, że są takie elementy aplikacji które kiepsko pasują do idei modelowania i dziedziny, a muszą być zaimplementowane.  Czasem jakaś funkcjonalność nie pasuje do żadnego z wyróżnionych obiektów a jednak ich dotyczy. Albo dotyczy wielu różnych obiektów i modelowanie jej za pomocą dziedziczenia psuło by tylko model. Pisałem kiedyś aplikację w której musieliśmy zwracać w postaci RSS różne zupełnie obiekty (nie miały ze sobą nic wspólnego) i dodawanie funkcjonalności eksportu w postaci RSS do każdego z nich nie miało sensu. I wtedy taka usługa abstrahująca od typu obiektu była idealna (Tak trochę off-topic to są języki w których można to zrobić ładnie i w ramach dziedziny. Np. w Scali można zrobić &lt;span style="font-style: italic;"&gt;trait&lt;/span&gt; i zaaplikować do wszystkich obiektów o które nam chodzi.  W aspectj, groovym i rubym można zrobić mixin. Więc co właściwie pasuje do tej kategorii zależy trochę od języka z którego korzystasz.)&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Modules&lt;/span&gt;&lt;br /&gt;To normalna praktyka programistyczna. Dzielenie aplikacji (w tym przypadku chodzi głównie o model dziedziny) na moduły o niskim poziomie zależności pomiędzy nimi, ale o wysokiej wewnętrznej spójności (zarówno z punktu widzenia komunikacji jak i funkcjonalności).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Aggregates&lt;/span&gt;&lt;br /&gt;To znowu wzorzec strukturalny. Tym razem chodzi o zebranie w jeden agregat tych obiektów dziedziny które mają wspólny cykl życia (tworzenie, usuwanie). To powoduje zmniejszenie liczby relacji między obiektami dziedziny (zamiast odnosić się do poszczególnych drobnoziarnistych obiektów, dotyczą całego agregatu). Dobry agregat ma dobrze określone granice dostępu do niego, tzn. jest w nim jeden główny obiekt (korzeń) i tylko przez niego (przez jego relacje) możemy dostać się do obiektów zależnych. Zewnętrzne obiekty nie mogą mieć odniesień do żadnych elementów wewnętrznych agregatu poza tym jednym - korzeniem.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Factories&lt;/span&gt;&lt;br /&gt;Biorąc pod uwagę, że tworzenie encji, a tym bardziej agregatów, może być dość złożone dla bardziej skomplikowanych obiektów, warto wykorzystać fabrykę (a'la GoF) . &lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Repositories&lt;/span&gt;&lt;br /&gt;Jednym z podstawowych założeń dobrego projektu jest minimalna zależność dziedziny od reszty aplikacji. W szczególności dotyczy to kontaktu z UI i infrastrukturą (np. DB). Dlatego dobry rozwiązaniem jest obiekt, który realizuje CRUD na obiektach dziedziny. Dzięki temu nie muszą one same dostawać się do innych (przez bezpośredni dostęp do bazy ani DAO) lecz mają specyfikowany wygodny interfejs, który w dodatku może realizować dodatkowe funkcjonalności takie jak caching czy rozwiązywanie zależności.&lt;br /&gt;&lt;br /&gt;Oczywiście najważniejszym elementem w MDD jest modelowanie dziedziny. I to nie raz, na początku projektu. To ciągła weryfikacja i modyfikacja poprawności, logiczności, sensowności struktury aplikacji. Wraz z jej rozwojem i Twoim rozumieniem dziedziny. Tutaj kłania się oczywiście TDD, ale to inna bajka.&lt;br /&gt;A jak to się ma do tego jak robisz swoje aplikacje?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2338976640977990159-8773055034798224795?l=sprawnainzynieriaoprogramowania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2338976640977990159&amp;postID=8773055034798224795' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/8773055034798224795'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/8773055034798224795'/><link rel='alternate' type='text/html' href='http://sprawnainzynieriaoprogramowania.blogspot.com/2008/10/mdd.html' title='MDD'/><author><name>Paweł Lipiński</name><uri>http://www.blogger.com/profile/02772675014904905654</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-2338976640977990159.post-4081584825938096456</id><published>2008-10-20T16:36:00.000+02:00</published><updated>2008-10-23T15:24:01.649+02:00</updated><title type='text'>Wszechobecny język</title><content type='html'>2 lata temu powstała książka 'Domain Driven Design' Erica Evansa. Kto nie czytał - polecam. Książkę można podsumować jednym zdaniem: Object-Oriented design done right. Treść nie powinna zaskoczyć żadnego programisty OO, ale i tak warto przeczytać, ponieważ dość zgrabnie podsumowuje podstawowe zasady projektowania aplikacji obiektowych. Składa się ona z trzech podstawowych części:&lt;br /&gt;- Wszechobecny Język (Ubiquitous Language)&lt;br /&gt;- Model-Driven Design&lt;br /&gt;- Zachowywanie spójności modelu&lt;br /&gt;&lt;br /&gt;Zamieszczam tu telegraficzny skrót tej książki, bo uważam ją za ważny element edukacji programistycznej.&lt;br /&gt;&lt;br /&gt;Tak więc w tym poście podstawowy element DDD:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Wszechobecny Język&lt;/span&gt; to idea jednego wspólnego języka dla dziedziny (tak jak rozumie ją użytkownik/klient/biznes), aplikacji i języka komunikacji programistów. Brzmi dość logicznie - tych samych nazw używamy w rozmowie z biznesem (klientem, analitykami, ekspertami, itp. itd...), w kodzie i w zespole - to ułatwia komunikację (najwięcej problemów w projektach leży właśnie tu) i zmniejsza ryzyko nieporozumień.&lt;br /&gt;Wszystko świetnie brzmi jak się ma klienta anglojęzycznego. W większości projektów mamy jednak Polskojęzycznego klienta. Polskie (czy generalnie nieangielskie) nazwy w kodzie (zmienne, metody, komentarze) uważam za zły pomysł ze względu na 2 rzeczy - globalność naszego zawodu (dziś kod piszesz ty, jutro firma w Indiach albo Chinach) oraz czytelność (findFirmaByUlica czyta się strasznie) . Jestem więc zwolennikiem tłumaczeń na angielski, choć czasami nie jest to możliwe (NIP, Pesel itp. są kiepsko tłumaczalne).&lt;br /&gt;Wszechobecny język to również idea sposobu komunikacji z biznesem - używanie ich języka to nie wszystko. Trzeba by dodać jeszcze nieużywanie naszego. Jak ekspert od ubezpieczeń mów: &lt;blockquote&gt;"Chciałbym, żeby się dało usuwać polisy."&lt;/blockquote&gt; a ty zapytasz go:&lt;br /&gt;&lt;blockquote&gt;"A wystarczy jak usunę rekord z tabelki? Czy mam dorzucać nowy z markerem, że usunięte?"&lt;br /&gt;&lt;/blockquote&gt;To boję się, że jest szansa na poziomie 50%, że on nie wie o czym mówisz, a 90% że nie wie po co ten marker i  jakie są tego następstwa takiej decyzji. Nie mówiąc o tym, że decydowanie na tym etapie o implementacji jest pewnie przedwczesne. Powinieneś więc pewnie raczej zapytać np.:&lt;br /&gt;&lt;blockquote&gt;"A czy potrzebujecie zachowywać kompletną historię dla każdej polisy?"&lt;br /&gt;"A co z ochroną danych osobowych?"&lt;/blockquote&gt;Tak więc to właśnie od programisty/projektanta oczekuje się mówienia językiem biznesu i projektowanie w tych właśnie terminach a nie od analityka / eksperta znajomości nomenklatury i idei technologicznych. Dzięki temu dobrze napisany kod (nawet w Javie) może być czytelny prawie jak specyfikacja funkcjonalności i jakby się uprzeć, to można go pokazać ekspertowi i zapytać czy o to chodzi.&lt;br /&gt;Poniżej kod z jednego z projektów które pisałem.&lt;br /&gt;&lt;blockquote style="font-family: courier new;"&gt;&lt;span style="font-size:85%;"&gt;class Contract {&lt;br /&gt;&amp;nbsp;&amp;nbsp;...&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void suspendThisAndRelatedContracts () {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if (alreadySuspended())&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;makeSuspended();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Collection&lt;contract&gt; contracts = findRelatedContracts();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;suspendGivenConracts(contracts);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;executeSuspensionWorkflow();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&amp;nbsp;&amp;nbsp;...&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private void suspendGivenConracts(Collection&lt;contract&gt; contracts) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for (Contract c : contracts)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;c.suspendThisAndRelatedContracts();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&amp;nbsp;&amp;nbsp;...&lt;br /&gt;}&lt;br /&gt;&lt;/span&gt;&lt;/blockquote&gt;Nawet bez znajomości dziedziny można dokładnie powiedzieć co się dzieje. Co więcej taki kod można dość łatwo wytłumaczyć i przedyskutować jego poprawność w sensie funkcjonalności z ekspertem/klientem.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2338976640977990159-4081584825938096456?l=sprawnainzynieriaoprogramowania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2338976640977990159&amp;postID=4081584825938096456' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/4081584825938096456'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/4081584825938096456'/><link rel='alternate' type='text/html' href='http://sprawnainzynieriaoprogramowania.blogspot.com/2008/10/najpierw-dziedzina.html' title='Wszechobecny język'/><author><name>Paweł Lipiński</name><uri>http://www.blogger.com/profile/02772675014904905654</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-2338976640977990159.post-4793304539055580695</id><published>2008-10-17T23:11:00.000+02:00</published><updated>2008-10-18T00:07:00.123+02:00</updated><title type='text'>OO</title><content type='html'>&lt;div style="text-align: justify;"&gt;Dobrze pamiętam 2 rok studiów. Przedmiot: Programowanie Obiektowe. Język: C++. Projekt na zaliczenie: Komisariat Policji. Trzeba było zrobić 5 klas na krzyż wykorzystać słowa kluczowe virtual, friend, protected i miało się ocenę. Normalnie ekstra.&lt;br /&gt;Ale jednak teoria była dość jasna. Książka do tego pewnie jakaś była (nawet nie pamiętam czy była...)  i generalnie człowiek uwierzył, że tak się pisze oprogramowanie (choć przez wcześniejsze dwa semestry wmawiali co innego...)&lt;br /&gt;&lt;br /&gt;A potem poszedłem do pracy. A tam servlety (tak, tak, wtedy pisało się servlety...), JSP, Struts i z dnia na dzień okazało się, że jednak nie. Że kod realizujący funkcje oczekiwane przez klienta pisze się we frameworku. To daje ogromne możliwości. Po pierwsze szybko się pisze - wystarczy podziedziczyć (mówiłem, że OO) po klasie Action. Po drugie framework daje Ci wszystko czego możesz potrzebować. Tak czy siak cała moja nauka o OO na którą pracował stolarz w Radomiu, piekarz w Ciechanowie i pucybut w Galerii Mokotów (no i pewnie jeszcze paru innych podatników) poszła na marne.&lt;br /&gt;&lt;br /&gt;Ale do rzeczy. Bo może jednak nie poszła. To będzie takie mini przypomnienie absolutnych podstaw OO. Przeczytaj i zastanów się jak aplikacja, nad którą aktualnie pracujesz ma się do tego.&lt;br /&gt;&lt;br /&gt;Kod aplikacji powinien być w obiektach. Nie w akcjach. Nie w komendach. Nie w managerach. Ani nawet nie w Session Beanach EJB3. Tylko w obiektach. Dokładniej to w klasach, bo java realizuje obiekty wyłącznie poprzez instancje klas, więc powiedzmy, że w klasach. (Martin Fowler nazwał je POJO w odróżnieniu właśnie od klas związanych ze wszelkimi wzorcami, frameworkami, platformami itp.)&lt;br /&gt;&lt;br /&gt;Poza &lt;span style="font-weight: bold;"&gt;skrajnymi&lt;/span&gt; przypadkami &lt;span style="font-weight: bold;"&gt;każda&lt;/span&gt; aplikacja powinna być rozpoczynana od &lt;span style="font-weight: bold;"&gt;modelowania&lt;/span&gt; (tak, to jest agile - przypomnę, że słówko "agile" nie oznacza "bezmyślnie", tylko "sprawnie" - sprawniej jest pomyśleć i potem zrobić niż zrobić i sprawdzić czy a nuż działa). Czyli wymyślenia obiektów które będą realizowały funkcje aplikacji poprzez wzajemne relacje i przekazywanie sobie komunikatów. Czyli zanim zaczniesz pisać kod musisz wiedzieć jak wygląda twój świat. Jakie są w nim elementy. Jak mogą się komunikować. Nie do najdrobniejszych szczegółów. Ale tak, żebyś wiedział co piszesz i dlaczego.&lt;br /&gt;A teraz spójrz na swoją aplikację i sprawdź jaki procent jej wymagań funkcjonalnych jest zrealizowanych wewnątrz klas reprezentujących dziedzinę twojej aplikacji.&lt;br /&gt;&lt;br /&gt;To jest nie tylko kwestia praktyk czy podejścia. To kwestia profesjonalizmu. Odpowiedzialności. Nawet etyki zawodowej.&lt;br /&gt;Jeżeli aplikacja ma żyć dłużej niż rok to jakiekolwiek wiązanie funkcjonalności aplikacji z jakimś frameworkiem/platformą/biblioteką jest marnowaniem pieniędzy klienta.&lt;br /&gt;Ale jeśli nawet nie wiążemy się z żadnym frameworkiem (tajna broń EJB3) ale aplikacja nie ma przejrzystych obiektów dziedziny a zamiast tego funkcjonalności ukryte w komendach/managerach/fasadach/akcjach itp. To i tak ryzykujemy pieniędzmi i czasem klienta (czas wdrożenia nowych programistów będzie znacząco większy). Czy ktoś daje nam do tego prawo?&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2338976640977990159-4793304539055580695?l=sprawnainzynieriaoprogramowania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2338976640977990159&amp;postID=4793304539055580695' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/4793304539055580695'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/4793304539055580695'/><link rel='alternate' type='text/html' href='http://sprawnainzynieriaoprogramowania.blogspot.com/2008/10/oo.html' title='OO'/><author><name>Paweł Lipiński</name><uri>http://www.blogger.com/profile/02772675014904905654</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-2338976640977990159.post-1336293923689570554</id><published>2008-10-08T15:32:00.001+02:00</published><updated>2008-10-17T22:50:37.411+02:00</updated><title type='text'>Sprawny Inżynier?</title><content type='html'>&lt;div style="text-align: justify;"&gt;W sierpniu na konferencji Agile 2008 Robert C. Martin (aka Uncle Bob) zaproponował dodanie do Manifestu Agile jeszcze jednego elementu:&lt;br /&gt;&lt;span style="font-style: italic;"&gt;   &lt;blockquote&gt;Craftsmanship over Crap&lt;/blockquote&gt;&lt;/span&gt;Nasza dziedzina (przynajmniej światek javowy, który oglądam na co dzień) pogrążona jest w odmętach totalnego braku profesjonalizmu. Mamy masę nowoczesnych technologii (bibliotek, frameworków), masę mądrych ludzi dookoła, setki publikacji, jesteśmy bodajże najnowocześniejszą z wszystkich grup zawodowych, a przy tym jesteśmy całkowicie nieprofesjonalni.&lt;br /&gt;&lt;br /&gt;Studenci medycyny słyszą od pierwszego roku, że ich błąd może kosztować kogoś życie. Co więcej za błędy mogą znaleźć się w więzieniu. Podobnie z prawnikami - za błędy mogą odpowiadać przed sądem i płacić za nie własnym majątkiem. A czy ktoś słyszał o programiście skazanym za:&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;  &lt;span style="font-size:85%;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;blockquote&gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-size:85%;"&gt;try {&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=";font-family:courier new;font-size:85%;"  &gt;   ....&lt;/span&gt;&lt;br /&gt;&lt;span style=";font-family:courier new;font-size:85%;"  &gt;   } catch (SQLException e) { &lt;/span&gt;&lt;br /&gt;&lt;span style=";font-family:courier new;font-size:85%;"  &gt;      // maaaan! this can neeeever happen!&lt;/span&gt;&lt;br /&gt;&lt;span style=";font-family:courier new;font-size:85%;"  &gt;   }&lt;/span&gt;&lt;/blockquote&gt;Audytowałem kiedyś aplikację e-bankingową. Paręnaście tysięcy klas. Prawie wszystkie dziedziczyły po&lt;br /&gt;&lt;code&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;   &lt;/span&gt;&lt;/code&gt;&lt;blockquote&gt;&lt;code&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;org.apache.struts.action.Action&lt;/span&gt;&lt;/code&gt;&lt;/blockquote&gt;&lt;br /&gt;Proponuję 3 lata więzienia.&lt;br /&gt;&lt;br /&gt;Innym razem przepisywałem system przetwarzający SMSy.  W oryginalnym kodzie roiło się od takich linii:&lt;br /&gt;&lt;code&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;&lt;span style="font-family:Georgia,serif;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;blockquote&gt;&lt;code&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;&lt;span style="font-family:Georgia,serif;"&gt;Thread.sleep(375); &lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/blockquote&gt;Potem autor tłumaczył, że sprawdził, że jak te wątki czekają odpowiednią liczbę ms to aplikacja działa...&lt;br /&gt;Rok w celi.&lt;br /&gt;&lt;br /&gt;Znowu: klasa 1500 linii kodu. Maszyna stanowa (ponad 20 stanów) zrealizowana za pomocą jednego &lt;span style="font-size:85%;"&gt;&lt;span style="font-family:courier new;"&gt;switch&lt;/span&gt;&lt;/span&gt;.&lt;br /&gt;3 miesiące.&lt;br /&gt;(Oj, nie! To mój kod akurat był...)&lt;br /&gt;&lt;br /&gt;Właśnie - dlaczego na uczelniach uczą nas raytraycingu, drzew patricia, czy algorytmów mrówkowych a nikt nie robi ćwiczeń z projektowania kodu. Dlaczego nikt nie powiedział, że kod lepiej się pisze i jest się go pewniejszym (i jeszcze na dodatek jest utrzymywalny!) jak zacznie się od testów? (ktoś w ogóle słyszał słowo test na uczelni?) Czemu napalonym na kodowanie 20-latkom nie mówią, że nie jest fajny konkurs na najmniej czytelny kod w C/Perlu?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Agile Software Engineering - Sprawna Inżynieria Oprogramowania, czy Inżynieria Sprawnego Oprogramowania?&lt;br /&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;b class="glowka"&gt;sprawny &lt;/b&gt;&lt;span class="glowka"&gt;(za SJP PWN)&lt;/span&gt;&lt;br /&gt;&lt;b&gt;1. &lt;/b&gt;«dobrze wyćwiczony fizycznie, zręczny w ruchach, w wykonywaniu czegoś; też: będący objawem, dowodem czyjejś zręczności»&lt;br /&gt;&lt;b&gt;2. &lt;/b&gt;«świadczący o dobrym opanowaniu przez kogoś jakiejś umiejętności»&lt;br /&gt;&lt;b&gt;3. &lt;/b&gt;«właściwie urządzony, zorganizowany»&lt;br /&gt;&lt;b&gt;4. &lt;/b&gt;«o urządzeniu: dobrze działający, funkcjonujący»&lt;/blockquote&gt;&lt;div style="text-align: justify;"&gt;Czy odnosi się to do mnie i do mojego kodu?&lt;br /&gt;&lt;br /&gt;Jeżeli inżynieria, to najpierw rzemiosło! Tak więc proponuję zacząć od terminowania. Najpierw zostań czeladnikiem, na sztukę nadejdzie czas (może...) Wolałbym być operowany przez sprawnego chirurga, niż chirurga artystę :)&lt;br /&gt;&lt;br /&gt;Taki jest plan na ten blog - krzewienie wiedzy (również własnej) w zakresie inżynierii oprogramowania. Nie chcę nigdy wstydzić się swojego kodu.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2338976640977990159-1336293923689570554?l=sprawnainzynieriaoprogramowania.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2338976640977990159&amp;postID=1336293923689570554' title='Komentarze (5)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/1336293923689570554'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2338976640977990159/posts/default/1336293923689570554'/><link rel='alternate' type='text/html' href='http://sprawnainzynieriaoprogramowania.blogspot.com/2008/10/zrczny-inynier.html' title='Sprawny Inżynier?'/><author><name>Paweł Lipiński</name><uri>http://www.blogger.com/profile/02772675014904905654</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></feed>
