<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Xoft</title>
	<atom:link href="http://www.xoft.pl/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.xoft.pl</link>
	<description>O programowaniu i innych rzeczach</description>
	<lastBuildDate>Wed, 12 Jan 2011 08:51:48 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.4</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Programista Java w Rubylandzie, część 2. Pierwsza aplikacja.</title>
		<link>http://www.xoft.pl/2011/01/12/programista-java-w-ruby-landzie-czesc-2/</link>
		<comments>http://www.xoft.pl/2011/01/12/programista-java-w-ruby-landzie-czesc-2/#comments</comments>
		<pubDate>Wed, 12 Jan 2011 08:51:48 +0000</pubDate>
		<dc:creator>Piotr Kochański</dc:creator>
				<category><![CDATA[RAILS]]></category>
		<category><![CDATA[RUBY]]></category>

		<guid isPermaLink="false">http://www.xoft.pl/?p=201</guid>
		<description><![CDATA[Ok, w poprzednim odcinku okazało się, że daje się zainstalować Rubyego i Railsy. Zobaczymy teraz, że nasz naiwny obraz Świata zostanie zburzony.
Będziemy chcieli utworzyć aplikację blog, taką samą, która jest w tutorialu Railsów na ich stronie, tyle, że działającą z normalną bazą danych, czyli w tym wypadku z Postgresem. Brzmi prosto? O nie, nie, nie. [...]]]></description>
			<content:encoded><![CDATA[<p>Ok, w poprzednim odcinku okazało się, że daje się zainstalować Rubyego i Railsy. Zobaczymy teraz, że nasz naiwny obraz Świata zostanie zburzony.</p>
<p>Będziemy chcieli utworzyć aplikację blog, taką samą, która jest w tutorialu Railsów na ich stronie, tyle, że działającą z normalną bazą danych, czyli w tym wypadku z Postgresem. Brzmi prosto? O nie, nie, nie. Może pod Linuksem albo MacOs-em idzie to normalnie, ale nie pod Windowsem.</p>
<p>Pierwsza rzecz to instalacja Postgresa. Lepiej się nie rzucać na wersję 9 (nie jest oficjalnie wspierana przez Rails &#8211; chyba nie jest), i nie należy dotykać się wersji 64 bit. Jeżeli ktoś nie lubi ćwiczeń w rodzaju podawanie w różnych, losowo wybranych miejscach ścieżki do Postgresa jako C:\Progra~1\PostgreSQL\8.4\bin to lepiej nie instalować Postgresa w <em>Program Files</em> tylko gdzieś, gdzie nie ma spacji w ścieżce.</p>
<p>Druga rzecz, to sterownik (czyli w ichniej terminologii, adapter) Rubyego do Postgresa. W Rubym instalacja jest tożsama z instalacją odpowiedniego gem-a. Wchodzimy więc na stronę <a href="http://wiki.rubyonrails.org/database-support/postgres">wiki</a>, żeby się dowiedzieć, jak się ten gem nazywa. I od razu człowiek się cieszy, bo ma do wyboru aż 4 adaptery. Prawda, że super?</p>
<p>Sytuacja się na szczęście upraszcza. Rozwijanie adaptera <em>postgres</em> znudziło się jego twórcą w 2008 roku. Jego następcą jest <em>pg</em>, który jest &#8220;natywnym&#8221; adapterem, który wymaga zainstalowania kawałka linuksa pod Windowsem.</p>
<p>Jest też <em>postgres-pr</em>, który jest adapterem napisanym tylko w Rubym, co wróży nędzną wydajność, ale powinno pozwolić uniknąć kłopotów z instalacją. Dodatkowo ostatnio ktoś się do niego dotykał w marcu 2009, co jest według autora wiki &#8220;sign of active development&#8221;. Zdaje się, że ostatnia wersja jest z grudnia 2009.</p>
<p>Jest jeszcze ruby-postgres, ale strona projektu wskazuje, że wszyscy jego deweloperzy zajęli się dawno czymś innym.</p>
<p>Najbardziej sensowną opcją jest użycie <em>pg</em>. Weźmy się więc za to.</p>
<p>Pierwsza rzecz, to adapter ten jest napisany w C (czyli jest &#8220;natywny&#8221;), w związku z tym pod Windowsem trzeba sobie zainstalować <a href="https://github.com/oneclick/rubyinstaller/wiki/Development-Kit">Developnent Kit</a>. Instrukcję na tej stronie należy wykonać dokładnie, sprawdzając czy się gdzieś nie pomyliliśmy. Tutaj problemów nie napotkałem.</p>
<p>Następnie instalujemy gem <em>pg</em>: <code>gem install pg</code>? He, he, he. Takie rzeczy to tylko działają w tutorialach na stronie Railsów. To, co trzeba zrobić to:<br />
<code><br />
gem install pg --platform=mswin32 --version=0.9.0 -- --with-pg=c:\programs\PostgreSQL\8.4\<br />
</code><br />
Uwagi:</p>
<ol>
<li>mimo, że najnowszą wersją pg jest 0.10.0, to nie udało mi się z nią ruszyć, <a href="http://stackoverflow.com/questions/4335750/cant-install-pg-gem-on-windows">zresztą nie tylko mi</a>,</li>
<li>te dodatkowe dwa minusy za numerkiem wersji a przed <code>--with-pg</code> <em>są potrzebne</em>, to nie literówka,</li>
<li>ukośnik na końcu ścieżki Postgresa też jest potrzebny.</li>
</ol>
<p>Ja wiem, że niektórzy teraz przecierają oczy, że jakiś kawałem teoretycznie produkcyjnego kodu ma numer wersji 0.10, ale najwyraźniej tak jest.</p>
<p>Jak się wszystko poinstalowało, to możemy zająć się utworzeniem aplikacji.</p>
<p>Piszemy w konsoli<br />
<code>rails new c:\katalog\z\projektami\blog -d postgresql</code></p>
<p>Railsy generują gotowy do uruchomienia szkielet projektu. To znaczy niby on jest gotowy do uruchomienia, ale nie jest. Można się o tym łatwo przekonać wchodząc do utworzonego katalogu <em>blog</em> i pisząc w konsoli <strong>rails server</strong>.</p>
<p>Trzeba zrobić dwie rzeczy:</p>
<ul>
<li>w pliku <em>blog\config\database.yml</em> podajemy poprawne ustawienia dla baz danych: Rails pracuje z trzema bazami: deweloperską, testową i produkcyjną (i bardzo słusznie) &#8211; trzeba ustawić poprawnie nazwę użytkownika, nazwę bazy, itp,</li>
<li>w pliku <em>blog\Gemfile</em> poprawiamy <code>gem 'pg'</code> na <code>gem 'pg', '0.9.0'</code>, w innym przypadku Rails sobie doinstaluje sam najnowszą wersję <em>pg</em>, która nie chciała mi działać.</li>
</ul>
<p>Uff teraz piszemy w konsoli, w katalogu projektu, <code>bundle install</code>, a następnie <code>rails server</code> i na http://localhost:3000 powinna się pojawić strona powitalne naszej aplikacji.</p>
<p>Póki co aplikacja nic nie robi, ale to już temat na kolejny wpis.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.xoft.pl/2011/01/12/programista-java-w-ruby-landzie-czesc-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Programista Java w Rubylandzie, część 1. Początki.</title>
		<link>http://www.xoft.pl/2011/01/11/programista-java-w-ruby-landzie/</link>
		<comments>http://www.xoft.pl/2011/01/11/programista-java-w-ruby-landzie/#comments</comments>
		<pubDate>Tue, 11 Jan 2011 10:50:55 +0000</pubDate>
		<dc:creator>Piotr Kochański</dc:creator>
				<category><![CDATA[RAILS]]></category>
		<category><![CDATA[RUBY]]></category>

		<guid isPermaLink="false">http://www.xoft.pl/?p=191</guid>
		<description><![CDATA[Ruby to podobno fajny, miły i przyjemny język programowania. Spędziłem trochę czasu na pisaniu aplikacji w Ruby-on-Rails (zdaje się 90% wszystkiego pisanego w Ruby jest aplikacją Ruby-on-Rails) i chciałbym się podzielić swoimi doświadczeniami. Także z samym sobą, jak bym musiał sobie coś za rok przypomnieć.
Zacznijmy od instalacji. Dla porządku: instaluję wersję Rails 3.0.3, jak się [...]]]></description>
			<content:encoded><![CDATA[<p>Ruby to podobno fajny, miły i przyjemny język programowania. Spędziłem trochę czasu na pisaniu aplikacji w Ruby-on-Rails (zdaje się 90% wszystkiego pisanego w Ruby jest aplikacją Ruby-on-Rails) i chciałbym się podzielić swoimi doświadczeniami. Także z samym sobą, jak bym musiał sobie coś za rok przypomnieć.</p>
<p>Zacznijmy od instalacji. Dla porządku: instaluję wersję Rails 3.0.3, jak się przekonamy nawet zmiana na wersję 3.0.4 może spowodować, że poniższą instrukcję będzie sobie można wsadzić w railsa. Takie tu panują zwyczaje.  </p>
<p>Dodatkowo używam Windows 7 64 bit, warto od razu zaznaczyć, że nie ma sensu instalować czegokolwiek 64 bit. Ruby, Railsy itp. pod Windowsem żyją w świecie x86. Ale ogólnie, to instalacja na wszystkich platformach wygląda podobnie.</p>
<p>Zacznijmy wreszcie. Wchodzę na stronę <a href="http://rubyonrails.org/">http://rubyonrails.org/</a> i klikam dużą ikonę Get Started (wiadomo, Web 2.0, duże ikony, pastelowe kolorki).<br />
Ruby ma całkiem sympatyczny instalator windowsowy. Od razu mają plus. Ale co ja widzę:</p>
<blockquote><p>We recommend Ruby 1.8.7 or Ruby 1.9.2 for use with Rails. Ruby 1.8.6 and earlier are not supported, neither is version 1.9.1.</p></blockquote>
<p>Ok, rozumiem, że wersja wcześniejsza niż 1.8.7 nie jest wspierana (w Open Source to norma), ale dlaczego wersja 1.9.1 nie jest wspierana, a 1.9.2 jest??? Jak się człowiek przyzwyczaja, że aplikacja napisana w Java 10 lat temu ruszy na Java 6 z 2010, to się może lekko zdziwić.</p>
<p>Następna rzecz to RubyGems, czyli taki sprytny menadżer pakietów. Coś jak Maven.</p>
<blockquote><p>Download (extract, then run &#8220;ruby setup.rb&#8221;)</p></blockquote>
<p>I co? </p>
<blockquote><p>source_index.rb:62:in `installed_spec_directories&#8217;: undefined method `path&#8217; for Gem:Module (NoMethodError)</p></blockquote>
<p>No pięknie, jeszcze nic nie zacząłem robić, a już dostaję wyjątek, tfu, error. Szukam w googlu i okazuje się, że to wszystko moja wina. Przecież powinienem wyśledzić w changelogach itp. miejscach, że wersja 1.4.2 Rubygems nie współpracuje z Ruby 1.9.2. Oczywiście można wykonać szereg hakierskich sztuczek, odpowiednich upgradów i downgradów, żeby można było użyć&#8230; no dobrze, nie ważne.</p>
<p>RubyGems jest dostarczony z Ruby 1.9.2, więc można sobie krok instalacji Gems odpuścić. Nie to, żeby w instrukcji było to napisane.</p>
<p>Szukam programu <em>gem</em> w katalogu <em>bin</em> instalacji Rubyego i wpisuje magiczne <strong>gem install rails</strong> i czekam, czekam, czekam. Wreszcie, bez dalszych niespodzianek, wszystko się pięknie instaluje. W katalogu bin rubyego pojawia się program <em>rails</em>. Czas na test:</p>
<blockquote><p>rails new c:\TRASH\testapp<br />
cd c:\TRASH\testapp<br />
rails server</p></blockquote>
<p>Pierwsza linijka powoduje utworzenia szkieletu aplikacji (jak by ktoś nie wiedział, to Rails jest sprytnie wymyślonym generatorem aplikacji i frameworkiem Model-View-Controller w jednym &#8211; JBoss Seam, Grails, Spring Roo właśnie z tego rżnęli pomysły); trzecia linia uruchamia serwer WWW z gotową do działania aplikacją. To znaczy nie uruchamia, bo dostajemy</p>
<blockquote><p>
Could not find gem &#8217;sqlite3-ruby (>= 0, runtime)&#8217; in any of the gem sources listed in your Gemfile.<br />
Try running `bundle install`.
</p></blockquote>
<p>Jak ktoś chce być cool i używać dżezi technologies, to się musi trochę napocić.</p>
<p>Może porada <em>Try running `bundle install&#8217;</em> pomaga? Pomaga, jeżeli mamy zainstalowaną bazę sqlite. Ja nie mam i nie mam zamiaru mieć, więc poprzestańmy na tym, co mamy: jest Ruby, są Railsy, coś tam działa.</p>
<p>Konfiguracją normalnej bazy danych i odpaleniem prostego projektu zajmiemy się następnym razem. Dopiero wtedy zacznie się prawdziwa zabawa.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.xoft.pl/2011/01/11/programista-java-w-ruby-landzie/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Java FX na Olimpiadzie zimowej</title>
		<link>http://www.xoft.pl/2010/02/12/java-fx-na-olimpiadzie-zimowej/</link>
		<comments>http://www.xoft.pl/2010/02/12/java-fx-na-olimpiadzie-zimowej/#comments</comments>
		<pubDate>Fri, 12 Feb 2010 14:39:30 +0000</pubDate>
		<dc:creator>Piotr Kochański</dc:creator>
				<category><![CDATA[JAVA]]></category>
		<category><![CDATA[JAVAFX]]></category>
		<category><![CDATA[RIA]]></category>

		<guid isPermaLink="false">http://www.xoft.pl/?p=186</guid>
		<description><![CDATA[Jeszcze się okaże, że będę musiał zmienić swoje sceptyczne nastawienie do JavaFX. JavaFX zostało wybrane jako technologia do wizualizacji danych o medalach na stronie Olimpiady Vancouver 2010.
Wygląda toto faktycznie dobrze, nie da się odróżnić od Flasha, można złośliwie powiedzieć. Jak Oracz zainwestuje w poprawienie narzędzi deweloperskich i sensowną bibliotekę komponentów, to może coś z tego [...]]]></description>
			<content:encoded><![CDATA[<p>Jeszcze się okaże, że będę musiał zmienić swoje sceptyczne nastawienie do <a href="http://javafx.com/">JavaFX</a>. JavaFX zostało wybrane jako technologia <a href="http://www.vancouver2010.com/olympic-medals/geo-view/">do wizualizacji danych o medalach</a> na stronie Olimpiady Vancouver 2010.</p>
<p>Wygląda toto faktycznie dobrze, nie da się odróżnić od Flasha, można złośliwie powiedzieć. Jak Oracz zainwestuje w poprawienie narzędzi deweloperskich i sensowną bibliotekę komponentów, to może coś z tego będzie.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.xoft.pl/2010/02/12/java-fx-na-olimpiadzie-zimowej/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Extreme Programming w San Diego</title>
		<link>http://www.xoft.pl/2010/02/12/extreme-programming-w-san-diego/</link>
		<comments>http://www.xoft.pl/2010/02/12/extreme-programming-w-san-diego/#comments</comments>
		<pubDate>Fri, 12 Feb 2010 14:30:32 +0000</pubDate>
		<dc:creator>Piotr Kochański</dc:creator>
				<category><![CDATA[JAVA]]></category>

		<guid isPermaLink="false">http://www.xoft.pl/?p=181</guid>
		<description><![CDATA[Ubawił mnie niezwykle wpis Bruce Eckela na Artima.com:
Last night I went to the Extreme Programming San Diego meeting (it should probably be called &#8220;Agile&#8221; but I suspect the group is old enough that XP was what started it). A reader knew that I was in San Diego visiting my folks so he suggested it. I [...]]]></description>
			<content:encoded><![CDATA[<p>Ubawił mnie niezwykle <a href="http://www.artima.com/weblogs/viewpost.jsp?thread=281754">wpis</a> Bruce Eckela na Artima.com:</p>
<blockquote><p>Last night I went to the Extreme Programming San Diego meeting (it should probably be called &#8220;Agile&#8221; but I suspect the group is old enough that XP was what started it). A reader knew that I was in San Diego visiting my folks so he suggested it. I thought I&#8217;d dip my toe in the water and see if programming was any more interesting to me than the last time I checked. Especially since Agile practices tend to be more focused on people issues, which is where I seem to continue to drift.</p>
<p>The first thing I noticed was the turnout. I&#8217;m guessing there are thousands of programmers in San Diego, <strong>but we got maybe 10 people to show up</strong>.</p></blockquote>
<p>Chyba w San Diego już się połapali, że 90% Agile to wynalazek cwanych konsultantów&#8230; 10 osób to i tak niezły wynik.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.xoft.pl/2010/02/12/extreme-programming-w-san-diego/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Sun w łapach Oracla</title>
		<link>http://www.xoft.pl/2010/02/02/sun-w-lapach-oracla/</link>
		<comments>http://www.xoft.pl/2010/02/02/sun-w-lapach-oracla/#comments</comments>
		<pubDate>Mon, 01 Feb 2010 23:06:53 +0000</pubDate>
		<dc:creator>Piotr Kochański</dc:creator>
				<category><![CDATA[JAVA]]></category>

		<guid isPermaLink="false">http://www.xoft.pl/?p=173</guid>
		<description><![CDATA[No i stało się, firma Sun przeszła do historii. Oracle szumnie zapowiada, jak to będzie rozwijał i inwestował. Zapowiedzi mają niewielkie znaczenie, nawet pierwszy rzut oka wyglądają pięknie, ale parę nieprzyjemnych rzeczy z nich wynika. Nieprzyjemnych dla użytkowników produktów SUN-a.
Weźmy NetBeans. Oracle ogłosił:
Oracle will invest in the NetBeans IDE and NetBeans.org community, but it will [...]]]></description>
			<content:encoded><![CDATA[<p>No i stało się, firma Sun przeszła do historii. Oracle szumnie zapowiada, jak to będzie rozwijał i inwestował. Zapowiedzi mają niewielkie znaczenie, nawet pierwszy rzut oka wyglądają pięknie, ale parę nieprzyjemnych rzeczy z nich wynika. Nieprzyjemnych dla użytkowników produktów SUN-a.</p>
<p>Weźmy NetBeans. Oracle ogłosił:</p>
<blockquote><p>Oracle will invest in the NetBeans IDE and NetBeans.org community, but it will be limited to Java Standard Edition, scripting languages, mobile Java, JavaFX and Solaris. Oracle&#8217;s own Java IDE, JDeveloper IDE, will be Oracle&#8217;s enterprise application development tool.</p></blockquote>
<p>Czyli NetBeans będzie środowiskiem programistycznym do wszystkiego, tylko nie do Java EE. Ponieważ gro aplikacji Javowych jest pisanych właśnie w Java EE, to praktycznie oznacza utrupienie NetBeans na rzecz JDevelopera. Kto będzie chciał się wozić ze środowiskiem Javowym, w którym nie można napisać aplikacji JEE? Szkoda.</p>
<p>GlassFish ma być wspierany i rozwijany, ale jako serwer do aplikacji intranetowych:</p>
<blockquote><p>WebLogic will be sold as the company&#8217;s enterprise application server, while the free and open source Glassfish server will be Oracle&#8217;s department-level application server.
</p></blockquote>
<p>Myślałem, że Oracle będzie chciał podgryzać GlassFishem JBoss-a, ale wygląda na to, że nie. W takim razie, kto będzie chciał się bawić w serwer, który w założeniu ma być &#8220;gorszy&#8221; od WebLogic-a. GlassFish, czyli tak na prawdę Sun GlassFish Enterprise Server (dawniej Sun ONE Application Server), jakoś szczególnie nie ustępuje WebLogicowi, co więc zamierza Oracle? Ma już dwa serwery aplikacyjne, teraz dochodzi trzeci; obawiam się, że GlassFish może szybo odejść w odstawkę pod pretekstem nie przynoszenia zysków. Chyba, że faktycznie Oracle ma jakiś dobry pomysł na niego.</p>
<p>Wygląda na to, że z kolei Oracle zamierza inwestować w JavaFX. To akurat mocno mnie dziwi, bo póki co na tle Silverlighta czy Flex-a JavaFX nie wygląda najlepiej, przynajmniej od strony potencjału bycia czymś równie popularnym, jak konkurenci. Technologicznie JavaFX jest bardzo fajnym pomysłem, ale funkcjonalność, dostępne komponenty są lata świetlne za innymi wynalazkami. Może tutaj Oracle ma jakiś ciekawy pomysł na biznes?</p>
]]></content:encoded>
			<wfw:commentRss>http://www.xoft.pl/2010/02/02/sun-w-lapach-oracla/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Wstrzykiwanie zależności czyli Dependency Injection. Część 5: wykorzystanie Google Guice</title>
		<link>http://www.xoft.pl/2009/07/09/wstrzykiwanie-zaleznosci-czyli-dependency-injection-czesc-5-wykorzystanie-google-guice/</link>
		<comments>http://www.xoft.pl/2009/07/09/wstrzykiwanie-zaleznosci-czyli-dependency-injection-czesc-5-wykorzystanie-google-guice/#comments</comments>
		<pubDate>Thu, 09 Jul 2009 06:24:34 +0000</pubDate>
		<dc:creator>Piotr Kochański</dc:creator>
				<category><![CDATA[DEPENDENCY INJECTION]]></category>
		<category><![CDATA[GUICE]]></category>
		<category><![CDATA[JAVA]]></category>
		<category><![CDATA[GOOGLE GUICE]]></category>
		<category><![CDATA[WSTRZYKIWANIE ZALEŻNOŚCI]]></category>

		<guid isPermaLink="false">http://www.xoft.pl/?p=151</guid>
		<description><![CDATA[W poprzednim odcinku widzieliśmy, jak można sobie ułatwić życie wstrzykując zależności do klas przy pomocy Springa [reszta cyklu:  część 1., część 2., część 3.]. Dzisiaj czas na coś prostszego i przyjemniejszego: Google Guice!

Przypomnijmy sobie jaki problem rozwiązujemy. Otóż mamy klasę NewsService, która potrzebuje do działania dwóch innych klas, które są konkretnymi implementacjami interfejsów Authenticator [...]]]></description>
			<content:encoded><![CDATA[<p>W <a href="/2009/04/30/wstrzykiwanie-zaleznosci-czyli-dependency-injection-w-9-minut-i-59-sekund-czesc-4-wykorzystanie-spring-a/">poprzednim odcinku</a> widzieliśmy, jak można sobie ułatwić życie wstrzykując zależności do klas przy pomocy Springa [reszta cyklu:  <a href="http://www.xoft.pl/2008/12/23/depedency-injection-spring-intro-baddesing">część 1.</a>, <a href="http://www.xoft.pl/2008/12/28/depedency-injection-spring-intro">część 2.</a>, <a href="http://www.xoft.pl/2009/04/10/wstrzykiwanie-zaleznosci-czyli-dependency-injection-w-9-minut-i-59-sekund-czesc-3-jak-zle-uzywac-di">część 3.</a>]. Dzisiaj czas na coś prostszego i przyjemniejszego: <a href="http://code.google.com/p/google-guice">Google Guice</a>!<br />
<span id="more-151"></span><br />
Przypomnijmy sobie jaki problem rozwiązujemy. Otóż mamy klasę <code>NewsService</code>, która potrzebuje do działania dwóch innych klas, które są konkretnymi implementacjami interfejsów <code>Authenticator</code> oraz <code>Storage</code>. Dodatkowo <code>Storage</code> potrzebuje implementacji klasy<code> Driver</code>. </p>
<p>Dzięki temu, że <code>NewsService</code> zależy od interfejsów, a nie klas konkretnych możemy wstrzykiwać mu taką implementację danego interfejsu, jaka jest potrzebna w określonej sytuacji. Jak stwierdziliśmy, ręczne wstrzykiwanie na dłuższą metę jest męczące, w związku z tym postanowiliśmy użyć do tego celu Spring-a. Działa on w ten sposób, że w pliku konfiguracyjnym określamy zależności między klasami, które potem Spring już samodzielnie wstrzykuje we wskazana miejsce.</p>
<p>Podejście użyte przez Spring-a ma parę wad. Po pierwsze jest XML-owy plik konfiguracyjny, który musi być zsynchronizowany z kodem. Można w nim zrobić pomyłkę (dobre IDE pomaga unikać błędów), refaktoryzacja kodu jest utrudniona &#8211; dobre IDE pozwala w miarę niezawodnie przeprowadzać tę operację, ale czasem i ono może pomylić się, w końcu XML to tylko łańcuchy znaków. Wreszcie do pliku Springa czasem trzeba dodać więcej informacji, niż to jest tak na prawdę potrzebne (wersja 2.0 ograniczyła ten problem).</p>
<p>Czy można zrobić kontener DI lepiej? Narzuca się oczywiście użycie metadanych (ang. <em>annotations</em>), w końcu od Java 5.0 jest to nowa, skuteczna metoda kontroli zachowania aplikacji w określonym środowisku.</p>
<p>Warto się zastanowić dwa razy nad użyciem tego mechanizmu, bo zewnętrzna konfiguracja wcale nie jest taką złą rzeczą. Na przykład kwerendy nazwane dla JPA zdecydowanie wygodniej jest definiować w pliku, mimo, że można użyć metadanych. </p>
<p>Zobaczymy jednak, że Google Guice oferuje nam rozwiązanie, bazujące na wykorzystaniu metadanych, które faktycznie jest wygodniejsze w użyciu niż Spring. </p>
<p>Jak działa Guice? W kodzie umieszczamy metadane, które mówią gdzie potrzebujemy wstrzyknięcia zależności. Zajmuje się tym metadana <code>@Inject</code>.</p>
<p>Samo powiedzenie, że nasza klasa potrzebuje wstrzyknięcia instancji innej klasy to jeszcze za mało. Musimy powiedzieć o jaką konkretną implementację nam chodzi. W przypadku Spring-a ta informacja była zaszyta w konfiguracji w pliku XML. Google Guice podchodzi do tego tematu inaczej. Definicje zależności między klasami umieszczamy w osobnej klasie Java &#8211; module Guice. Dzięki temu definicje te są odporne na literówki i poddają się bezboleśnie refaktoryzacji.</p>
<p>Zobaczmy jak to wygląda w praktyce. Pierwsza rzecz, to trzeba <a href="http://code.google.com/p/google-guice">pobrać</a> Google Guice i dołączyć zawarte w ściągniętej paczce pliki JAR do ścieżki swojego projektu.</p>
<p>Gdy mamy już skonfigurowany do pracy projekt jesteśmy gotowi zacząć pracę z Guice. Przede wszystkim musimy zmodyfikować klasę NewsService:</p>
<pre class="brush: java;">
import com.google.inject.Inject;
import pl.erudis.newsservice.di.storage.Storage;
import pl.erudis.newsservice.di.auth.Authenticator;

public class NewsService {

  Storage storage;
  Authenticator authenticator;

  public NewsService() {
  }

  public NewsService(Storage storage) {
    this.storage = storage;
  }

  public Authenticator getAuthenticator() {
    return authenticator;
  }

  @Inject
  public void setAuthenticator(Authenticator authenticator) {
    this.authenticator = authenticator;
  }

  public Storage getStorage() {
    return storage;
  }

  @Inject
  public void setStorage(Storage storage) {
    this.storage = storage;
  }

  public void addNews(String news){
    if(authenticator != null){
      authenticator.authenticate();
    }
    storage.save(news.getBytes());
    System.out.println("News saved...");
  }
}
</pre>
<p>Klasa ta w zasadzie nie zmieniła się w stosunku do wersji używanej ze Springiem, czy w ogóle bez kontenera DI, jedyna rzecz, która się pojawiła, to metadana <code>@Inject</code> w tych miejscach, gdzie potrzebne jest nam wstrzyknięcie instancji odpowiedniej klasy.</p>
<p>Jest to bardzo ważna rzecz: użycie Guice tak jak Springa nie wymaga zmian w kodzie &#8211; metadane to nie jest tak na prawdę zmiana kodu, tylko szczególny sposób konfiguracji aplikacji na potrzeby jakiegoś narzędzia.</p>
<p>Podobnie musimy zmodyfikować klasę DBStorage:</p>
<pre class="brush: java;">
import com.google.inject.Inject;
import pl.erudis.newsservice.di.drivers.Driver;

public class DBStorage implements Storage{

  Driver driver;

  @Inject
  public DBStorage(Driver driver) {
    this.driver = driver;
  }

  public void save(byte[] data) {
    driver.openConnection();
    System.out.println("Saving in database: '" + new String(data) +"'");
    driver.closeConnection();
  }

}
</pre>
<p>Teraz pozostaje tylko powiedzieć co ma być wstrzykiwane w oznaczone metadaną <code>@Inject</code> miejsca. W tym celu definiujemy moduł:</p>
<pre class="brush: java;">
import com.google.inject.Binder;
import com.google.inject.Module;
import pl.erudis.newsservice.di.auth.Authenticator;
import pl.erudis.newsservice.di.auth.UsernamePassAuthenticator;
import pl.erudis.newsservice.di.drivers.Driver;
import pl.erudis.newsservice.di.drivers.SqlDbDriver;
import pl.erudis.newsservice.di.storage.DBStorage;
import pl.erudis.newsservice.di.storage.Storage;

public class NewsServiceModule implements Module{

  public void configure(Binder binder) {
    binder.bind(Authenticator.class).to(UsernamePassAuthenticator.class);
    binder.bind(Driver.class).to(SqlDbDriver.class);
    binder.bind(Storage.class).to(DBStorage.class);
  }
}
</pre>
<p>Moduł wiąże ze sobą interfejsy, których używamy w kodzie z konkretnymi implementacjami, wybranymi przez nas w danej sytuacji. Warto zwrócić uwagę na bardzo inteligentnie wybrane nazwy metod. Kod czyta się jak narrację, w końcu język programowania ma być językiem. Trudno się nie połapać co oznacza kod &#8220;powiąż Authenticator.class z UsernamePassAuthenticator.class&#8221;.</p>
<p>Widać też od razu, że bardzo łatwo dynamicznie tworzyć powiązania &#8211; wszystko robimy w kodzie Java.<br />
Wreszcie ostatni element, czyli klasa kliencka</p>
<pre class="brush: java;">
import com.google.inject.Guice;
import com.google.inject.Injector;

public class GuiceClient {
  public static void main(String[] args) {
    Injector i = Guice.createInjector(new NewsServiceModule());
    NewsService newsService = i.getInstance(NewsService.class);
    newsService.getAuthenticator().login(new String[]{"beer", "beer"});
    newsService.addNews("bla bla guice bla");
  }
}
</pre>
<p>Zarówno klasa kliencka jak i definicja modułów mają bardzo istotną zaletę w stosunku do Spring-a &#8211; nigdzie nie występują łańcuchy znaków reprezentujące klasy. Używały wyłącznie kompilowalnych artefaktów, dzięki czemu automatycznie odpada nam cała klasa przykrych błędów.</p>
<p>Jeżeli ktoś interesuje się działaniem Spring Framework, to pewnie wie, że od pewnego czasu także Spring może być konfigurowany przy pomocy metadanych, są jednak bardzo zasadnicze różnice pomiędzy sposobem robienia tego przez Spring-a i przez Guice, o tym będziemy mówić w kolejnym odcinku naszej serii.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.xoft.pl/2009/07/09/wstrzykiwanie-zaleznosci-czyli-dependency-injection-czesc-5-wykorzystanie-google-guice/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Wstrzykiwanie zależności czyli Dependency Injection w 9 minut i 59 sekund. Część 4: wykorzystanie Spring-a</title>
		<link>http://www.xoft.pl/2009/04/30/wstrzykiwanie-zaleznosci-czyli-dependency-injection-w-9-minut-i-59-sekund-czesc-4-wykorzystanie-spring-a/</link>
		<comments>http://www.xoft.pl/2009/04/30/wstrzykiwanie-zaleznosci-czyli-dependency-injection-w-9-minut-i-59-sekund-czesc-4-wykorzystanie-spring-a/#comments</comments>
		<pubDate>Thu, 30 Apr 2009 13:36:24 +0000</pubDate>
		<dc:creator>Piotr Kochański</dc:creator>
				<category><![CDATA[DEPENDENCY INJECTION]]></category>
		<category><![CDATA[JAVA]]></category>
		<category><![CDATA[SPRING]]></category>

		<guid isPermaLink="false">http://www.xoft.pl/?p=98</guid>
		<description><![CDATA[Jak widzieliśmy  [część 1., część 2., część 3.] wstrzykiwanie zależności jest całkiem sympatycznym pomysłem (o ile się go poprawnie używa), ale można zapytać się, na ile jest to kosztowne? Przez koszty rozumiem tutaj nakład pracy, jaki trzeba włożyć w używanie architektury wykorzystującej DI.
Wyobraźmy sobie, że nasza aplikacja często wykorzystuje klasę NewsService.  Co to [...]]]></description>
			<content:encoded><![CDATA[<p>Jak widzieliśmy  [<a href="http://www.xoft.pl/2008/12/23/depedency-injection-spring-intro-baddesing">część 1.</a>, <a href="http://www.xoft.pl/2008/12/28/depedency-injection-spring-intro">część 2.</a>, <a href="http://www.xoft.pl/2009/04/10/wstrzykiwanie-zaleznosci-czyli-dependency-injection-w-9-minut-i-59-sekund-czesc-3-jak-zle-uzywac-di">część 3.</a>] wstrzykiwanie zależności jest całkiem sympatycznym pomysłem (o ile się go poprawnie używa), ale można zapytać się, na ile jest to kosztowne? Przez koszty rozumiem tutaj nakład pracy, jaki trzeba włożyć w używanie architektury wykorzystującej DI.</p>
<p>Wyobraźmy sobie, że nasza aplikacja często wykorzystuje klasę <a href="http://www.xoft.pl/2008/12/28/depedency-injection-spring-intro/#listing.NewsService">NewsService</a>.  Co to oznacza w praktyce? Za każdym razem musimy wstrzykiwać do niej zależność, których potrzebuje. Nasz przykład jest dość prosty, zależności nie ma zbyt wiele, ale nawet tutaj powtarzanie przy każdym użyciu kodu</p>
<pre class="brush: java;">
public class Client {
  public static void main(String[] args) {
    Authenticator authenticator = new UsernamePassAuthenticator("beer","beer");
    Driver driver = new SqlDbDriver();

    //inject dependency #1
    Storage storage = new DBStorage(driver);
    //inject dependency #2
    NewsService newsService = new NewsService(storage);
    //inject dependency #3
    newsService.setAuthenticator(authenticator);

    newsService.addNews("ble ble ble");
  }
}
</pre>
<p>nie jest zbyt zachęcające. Czy nie lepiej jest użyć jednak jakiego wzorca <em>factory</em> czy <em>service locator</em>, żeby jednak <code>NewsService </code> sam sobie znalazł potrzebne klasy?<br />
<span id="more-98"></span><br />
Okazuje się, że problem można rozwiązać bez rezygnowania z DI wykorzystując <em>kontenera Dependency Injection</em>, taki jak <a href="http://www.springsource.org" target="_blank">Spring</a>, <a href="http://www.picocontainer.org">PicoContainer</a> czy <a href="http://code.google.com/p/google-guice">Google Guice</a>.</p>
<p>Cóż takiego nadzwyczajnego robią te kontenery, że ludzie ich używają. Ich działanie tak na prawdę sprowadza się do tego, że pozwalają w jakiś sposób w jednym miejscu powiedzieć, że dana klasa potrzebuje konkretnej implementacji interfejsu lub interfejsów.</p>
<p>W naszym przykładzie chcemy wskazać, że <code>NewsService</code> potrzebuje klasy <code>DBStorage</code>, która implementuje <code>Storage</code>, a klasa <code>DBStorage</code> potrzebuje klasy <code>SqlDbDriver</code>, implementującej interfejs <code>Driver</code>.</p>
<p>Kontenery różnią się od siebie sposobem definiowania zależności między klasami. Spring pozwala konfigurować te zależności w pliku XML-owym lub (od niedawna) przy pomocy metadanych (ang. <em>annotations</em>). Google Guice jest nowszym rozwiązaniem i bazuje na wykorzystaniu metadanych.</p>
<p>Można, rzecz jasna, napisać własnych &#8220;kontener DI&#8221;, czyli pojedynczą klasę, w której będzie zawarta informacją o zależnościach między klasami, ale to oznacza dodatkową pracę, zastanawianie się na ile nasz pomysł na kontener będzie uniwersalny, itp.</p>
<p>Zaletą centralnej konfiguracji zależności jest możliwość ich podmieniania w razie potrzeby. Na przykład na potrzeby testów możemy jako implementacji <code>Storage</code> używać jakiejś naszej klasy, która udaje <code>Storage</code> na tyle, na ile jest to potrzebne do testów jednostkowych czy funkcjonalnych. Dzięki temu testy wykonują się szybciej, nie jest potrzebna baza danych.</p>
<p>Dodatkowo, jeżeli klient zażyczy sobie, żeby dane były przechowywane w plikach tekstowych, a nie bazie danych, to wystarczy, że napiszemy odpowiednie implementację <code>Storage</code> i/lub <code>Driver</code> i zmienimy konfigurację wstrzykiwania zależności w ten sposób, żeby były użyte nowe implementacje.</p>
<p>Oczywiście nie ma nic za darmo, to my musimy utrzymywać plik konfiguracyjny, który potrafi być całkiem pokaźnych rozmiarów w większej aplikacji lub pilnować aktualizacji parametrów odpowiednich metadanych. </p>
<p>Swoją drogą jest jedna technologia, w której mamy do dyspozycji DI, a nie musimy sami nic konfigurować &#8211; to te paskudne EJB, przez wielu szczerze znienawidzone. Tam po prostu serwer aplikacji przechowuje informację o komponentach, które mają być udostępniane w ramach aplikacji i jeżeli chcemy jakiegoś komponentu użyć, to po prostu odwołujemy się do niego poprzez interfejs, a serwer sam nam wstrzykuje odpowiedni obiekt:</p>
<pre class="brush: java">
@Stateless
public class PierwszyBean implements PierwszyBeanInterfejs {
  //implementację DrugiBean wstrzyknie sam serwer aplikacji
  @EJB DrugiBeanInterfejs drugiBean;

  public void metoda(){
    drugiBean.zrobCos();
  }
}
</pre>
<p>Nie mamy żadnego pliku konfiguracyjnego, w którym byśmy mogli godzinami szukać źle zdefiniowanych zależności ;).</p>
<p>Ok, tak na serio pilnowanie zależności nie jest aż tak bardzo straszne. Użycie kontenerów zazwyczaj jednak ułatwia życie, zobaczmy więc jak działa najpopularniejszy z nich: Spring.</p>
<p>Pierwsza rzecz, to musimy sobie ściągnąć ze strony http://www.springsource.org/ Spring Framework. Ja używałem wersji 2.5.X. </p>
<p>Prościej sprawę można załatwić używając rozsądnego IDE, które ma wbudowane wsparcie dla Spring-a. W paczce dostajemy to razem z NetBeans, MyEclipse IDE, IntelliJ Idea. Jak ktoś używa Eclipse, to można sobie doinstalować odpowiednią wtyczkę. Użycie IDE ma głęboki sens, bo dostajemy podpowiadanie składni w XML-owym pliku konfiguracyjnym, a czasem nawet wizualne narzędzie, które pozawala łatwiej oglądać zależności.</p>
<p>Zakładamy zatem, że mamy na ścieżce klas dodane biblioteki Spring-a.</p>
<p>Co teraz? Czy musimy jakoś modyfikować klasy które już napisaliśmy? Na szczęście nie, nasza aplikacja używa już DI, więc nawet linijki kodu ruszyć nie musimy. Zrobić musimy dwie rzeczy. Po pierwsze musimy zadeklarować zależności między klasami. Po drugie musimy zrobić użytek z tej konfiguracji modyfikując odpowiednio klasę <code>Client</code>, która używa <code>NewsService</code>. </p>
<p>Zacznijmy od konfiguracji. Plik może mieć dowolną nazwę, tutaj jest to <em>springXMLConfig.xml</em>, a jego zawartość widzimy na poniższym listingu:</p>
<pre name="code" class="xml">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;beans xmlns=&quot;http://www.springframework.org/schema/beans&quot;
    xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
    xsi:schemaLocation=&quot;http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd&quot;&gt;

  &lt;bean name=&quot;sqldriver&quot; class=&quot;pl.erudis.newsservice.di.drivers.SqlDbDriver&quot;/&gt;

  &lt;bean name=&quot;dbstorage&quot; class=&quot;pl.erudis.newsservice.di.storage.DBStorage&quot;&gt;
    &lt;constructor-arg ref=&quot;sqldriver&quot;/&gt;
  &lt;/bean&gt;

  &lt;bean name=&quot;upauth&quot; class=&quot;pl.erudis.newsservice.di.auth.UsernamePassAuthenticator&quot; /&gt;

  &lt;bean name=&quot;newsService&quot; class=&quot;pl.erudis.newsservice.di.NewsService&quot; &gt;
    &lt;property name=&quot;authenticator&quot; ref=&quot;upauth&quot;/&gt;
    &lt;property name=&quot;storage&quot; ref=&quot;dbstorage&quot;/&gt;
  &lt;/bean&gt;
&lt;/beans&gt;
</pre>
<p>Co się tutaj dzieje. Na początku deklarujemy użycie klasy <code>SqlDbDriver</code>. Podobnie deklarujemy użycie klasy <code>DBStorage</code>, dodatkowo zaznaczamy, że klasa <code>DBStorage</code> będzie używała klasy <code>SqlDbDriver</code>. Odpowiada za to element</p>
<pre class="brush: xml">
<constructor-arg ref="sqldriver"/>
</pre>
<p>Mówi on Springowi, żeby przy inicjalizacji klasy <code>DBStorage</code> do konstruktora &#8220;wstrzyknął&#8221; obiekt wskazanej przez nas klasy, czyli <code>SqlDbDriver</code>.</p>
<p>Dalej wszystko robimy analogicznie, deklarujemy użycie klasy <code>UsernamePassAuthenticator</code>, a następnie informujemy Spring, że <code>NewsService</code> potrzebuje klas <code>DBStorage</code> oraz <code>UsernamePassAuthenticator</code>. W tym przypadku obiekty klas nie są przekazywane jako parametry konstruktora, tylko inicjalizują pola klasy <code>NewsService</code>, używając odpowiednich metod &#8220;set&#8221; dla pól.</p>
<p>Wreszcie nadszedł czas na nagrodę, czyli wykorzystanie Springa do zarządzania zależnościami, zobaczmy jak wygląda teraz klasa kliencka:</p>
<pre class="brush: java">
package pl.erudis.newsservice.di;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 *
 * @author Piotr Kochański, www.xoft.pl
 */
public class SpringClient {
  public static void main(String[] args) {
    ApplicationContext factory = new ClassPathXmlApplicationContext("META-INF/springXMLConfig.xml");
    NewsService newsService = (NewsService)factory.getBean("newsService");
    newsService.getAuthenticator().login(new String[]{"beer", "beer"});
    newsService.addNews("bla bla spring bla");
  }
}
</pre>
<p>Pierwszym krokiem jest inicjalizacja Springa, jest to robione przy użyciu klasy <code>ApplicationContext</code> &#8211; musimy po prostu powiedzieć Springowi, żeby wczytał z pliku konfiguracyjnego zestaw zależności. Zgodnie z często używaną konwencją plik konfiguracyjny Springa jest w katalogu META-INF, który muszą &#8220;widzieć&#8221; skompilowane klasy Java.</p>
<p>Po inicjalizacji zostaje już nie wiele do zrobienia, wyciągamy klasę, która nas interesuje, czyli <code>NewsService</code> przy pomocy <code>ApplicationContext</code> przekazując mu nazwę tej klasy skonfigurowaną w <em>springXMLConfig.xml</em>. Spring automatycznie przekaże do <code>NewsService</code> potrzebne zależności i dalej używamy jej zapominając o DI czy Springu.</p>
<p>Zaleta wykorzystania kontenera DI jest jasna &#8211; mamy spójny sposób deklarowania zależności między komponentami, dzięki czemu pisząc kod możemy się koncentrować na jego faktycznej funkcjonalności, a nie pilnować odpowiednich związków z innymi klasami.</p>
<p>Oczywiście Spring nie jest tylko samym kontenerem DI, potrafi znacznie więcej rzeczy, ale tutaj nas interesował tylko ten jego aspekt.</p>
<p>Źródła przykładowej aplikacji można ściągnąć klikając <a href="/wp-content/uploads/2009/04/newsservice-src.zip">tutaj</a>, jeżeli ktoś woli, to jest także do pobrania <a href="/wp-content/uploads/2009/04/newsservice-netbeans.zip">projekt NetBeans-a</a> w wersji 6.5, który zawiera tę aplikację.</p>
<p>W kolejnej części cyklu zobaczymy w jaki sposób użyć kontenera Google Guice do zarządzania zależnościami w DI.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.xoft.pl/2009/04/30/wstrzykiwanie-zaleznosci-czyli-dependency-injection-w-9-minut-i-59-sekund-czesc-4-wykorzystanie-spring-a/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Wstrzykiwanie zależności czyli Dependency Injection w 9 minut i 59 sekund. Część 3: jak źle używać DI</title>
		<link>http://www.xoft.pl/2009/04/10/wstrzykiwanie-zaleznosci-czyli-dependency-injection-w-9-minut-i-59-sekund-czesc-3-jak-zle-uzywac-di/</link>
		<comments>http://www.xoft.pl/2009/04/10/wstrzykiwanie-zaleznosci-czyli-dependency-injection-w-9-minut-i-59-sekund-czesc-3-jak-zle-uzywac-di/#comments</comments>
		<pubDate>Fri, 10 Apr 2009 08:22:57 +0000</pubDate>
		<dc:creator>Piotr Kochański</dc:creator>
				<category><![CDATA[DEPENDENCY INJECTION]]></category>
		<category><![CDATA[JAVA]]></category>
		<category><![CDATA[WSTRZYKIWANIE ZALEŻNOŚCI]]></category>

		<guid isPermaLink="false">http://www.xoft.pl/?p=92</guid>
		<description><![CDATA[Kontynuujemy dalej naszą przeprawę z DI [część 1., część 2.]. W tym odcinku postaramy się w końcu coś popsuć &#8211; radosny marsz ścieżką usłaną różami jest przyjemny ale nie zawsze pouczający.
Zastanówmy się na ile użycie wstrzykiwania zależności czyni nasze oprogramowanie odpornym na błędy przy projektowaniu architektury aplikacji. W końcu nawet najwspanialszy wzorzec projektowy nie zabroni [...]]]></description>
			<content:encoded><![CDATA[<p>Kontynuujemy dalej naszą przeprawę z DI [<a href="http://www.xoft.pl/2008/12/23/depedency-injection-spring-intro-baddesing">część 1.</a>, <a href="http://www.xoft.pl/2008/12/28/depedency-injection-spring-intro">część 2.</a>]. W tym odcinku postaramy się w końcu coś popsuć &#8211; radosny marsz ścieżką usłaną różami jest przyjemny ale nie zawsze pouczający.</p>
<p>Zastanówmy się na ile użycie wstrzykiwania zależności czyni nasze oprogramowanie odpornym na błędy przy projektowaniu architektury aplikacji. W końcu nawet najwspanialszy wzorzec projektowy nie zabroni nam popełniania błędów.</p>
<p>Przyjrzyjmy się nieco zmodyfikowanej klasie <code>NewsService</code></p>
<pre name="code" class="java">
public class NewsService {

  Storage storage;
  Authenticator authenticator;

  public NewsService(Driver driver) {
    storage = new DBStorage(driver);
  }

  public Authenticator getAuthenticator() {
    return authenticator;
  }

  public void setAuthenticator(Authenticator authenticator) {
    this.authenticator = authenticator;
  }

  public void login(String uname, String pass){
    ((UsernamePassAuthenticator)authenticator).setUname(uname);
    ((UsernamePassAuthenticator)authenticator).setPass(pass);
  }

  public void addNews(String news){
    if(authenticator != null){
      authenticator.authenticate();
    }
    storage.save(news.getBytes());
    System.out.println("News saved...");
  }
}
</pre>
<p>Różni się ona od poprzedniej wersji w jednym drobnym, ale bardzo istotnym szczególe. Klasa <code>NewsService</code> w konstruktorze pobiera jako parametr sterownik (obiekt <code>Driver</code>), a nie, jak poprzednio <code>Storage</code>. W rezultacie NewsService sam sobie musi utworzyć obiekt <code>Storage</code>.</p>
<p>Kod <code>NewsService</code> jest wówczas związany na sztywno z konkretną implementacją kontenera na dane <code>DBStorage</code>, co jest oczywiście niepożądane. Co się zatem stało, co zrobiliśmy nie tak &#8211; w końcu używamy DI? A no popełniliśmy błąd polegający na tym, że wstrzykujemy do <code>NewsService</code> nie ten obiekt, co trzeba!</p>
<p><code>NewsService</code> nie potrzebuje do niczego informacji o użytym sterowniku, <code>NewsService</code> potrzebuje tylko konkretnej implementacji <code>Storage</code> i to ona już ma się martwić o sterownik.</p>
<p>Ok. tutaj przypadek był prosty i ewidentny. W większych aplikacjach łatwo popełnić błąd polegający na wstrzyknięciu nie tego obiektu, który tak na prawdę jest wymagany. Także jeżeli widzimy, że gdzieś inicjalizacja klasy wymaga tworzenia obiektów, albo przekazujemy klasie jako parametr obiekty, które, logicznie rzecz biorąc, nie są jej potrzebne, to znaczy, że gdzieś położyliśmy architekturę aplikacji i błędnie użyliśmy DI.</p>
<p>Użycie DI wcale nie uwalnia nas od dobrego zaprojektowania aplikacji!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.xoft.pl/2009/04/10/wstrzykiwanie-zaleznosci-czyli-dependency-injection-w-9-minut-i-59-sekund-czesc-3-jak-zle-uzywac-di/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Wstrzykiwanie zależności czyli Dependency Injection w 9 minut i 59 sekund. Część 2: o tym, co tak właściwie robi DI</title>
		<link>http://www.xoft.pl/2008/12/28/depedency-injection-spring-intro/</link>
		<comments>http://www.xoft.pl/2008/12/28/depedency-injection-spring-intro/#comments</comments>
		<pubDate>Sun, 28 Dec 2008 16:09:58 +0000</pubDate>
		<dc:creator>Piotr Kochański</dc:creator>
				<category><![CDATA[DEPENDENCY INJECTION]]></category>
		<category><![CDATA[JAVA]]></category>

		<guid isPermaLink="false">http://www.xoft.pl/?p=59</guid>
		<description><![CDATA[W poprzednim wpisie znęcaliśmy się nad niezbyt gramotnie napisanym kawałkiem oprogramowania. Teraz przyszedł czas na napisanie wszystkiego tak, jak trzeba, w czym nam pomagać będzie właśnie wstrzykiwanie zależności.
Co nas najbardziej uwierało w poprzedniej wersji aplikacji? Tak na prawdę były to dwie rzeczy:

Powiązania między klasami były zrealizowane przy użyciu referencji do konkretnych klas: jeżeli NewsService potrzebował [...]]]></description>
			<content:encoded><![CDATA[<p>W <a href="http://www.xoft.pl/2008/12/23/depedency-injection-spring-intro-baddesing">poprzednim wpisie</a> znęcaliśmy się nad niezbyt gramotnie napisanym kawałkiem oprogramowania. Teraz przyszedł czas na napisanie wszystkiego tak, jak trzeba, w czym nam pomagać będzie właśnie wstrzykiwanie zależności.</p>
<p>Co nas najbardziej uwierało w poprzedniej wersji aplikacji? Tak na prawdę były to dwie rzeczy:</p>
<ol>
<li>Powiązania między klasami były zrealizowane przy użyciu referencji do konkretnych klas: jeżeli <code>NewsService</code> potrzebował mechanizmu do przechowywania informacji, to dawaliśmy mu referencję do klasy, która potrafiła przechowywać dane w SQL-owej bazie danych. Zmiana sposobu przechowywania danych na inny wymagała zmian w wielu miejscach w kodzie.</li>
<li>Jeżeli klasa potrzebowała do pracy innej klasy, to sama musiała sobie utworzyć odpowiedni obiekt: <code>NewsService</code> potrzebując klasy do przechowywania danych sam sobie tworzył jej instancję.</li>
</ol>
<p>Co w takim razie robi wstrzykiwanie zależności? Mówiąc ogólnie, w DI chodzi o to, żeby nie wiązać się z inną klasą poprzez użycie jej implementacji, tylko poprzez interfejs, pod który można podpiąć dowolną klasę go implementującą. </p>
<p>Dodatkowo, jeżeli nasza klasa potrzebuje konkretnej implementacji tego interfejsu, to nie powinna tej implementacji sama szukać czy jej tworzyć. Odpowiedni obiekt musi zostać do klasy &#8220;wstrzyknięty&#8221; w momencie inicjalizacji.</p>
<p>Zobaczmy, jak to wygląda w praktyce.<br />
<span id="more-59"></span><br />
Zacznijmy od klasy <code>NewsService</code>, której bezpośrednio używają klasy &#8220;interfejsu użytkownika&#8221;:<br />
<a name="listing.NewsService"></a>
<pre name="code" class="java">
public class NewsService {

  Storage storage;
  Authenticator authenticator;

  public NewsService() {
  }

  public NewsService(Storage storage) {
    this.storage = storage;
  }

  public Authenticator getAuthenticator() {
    return authenticator;
  }

  public void setAuthenticator(Authenticator authenticator) {
    this.authenticator = authenticator;
  }

  public Storage getStorage() {
    return storage;
  }

  public void setStorage(Storage storage) {
    this.storage = storage;
  }

  public void login(String uname, String pass){
    ((UsernamePassAuthenticator)authenticator).setUname(uname);
    ((UsernamePassAuthenticator)authenticator).setPass(pass);
  }

  public void addNews(String news){
    if(authenticator != null){
      authenticator.authenticate();
    }
    storage.save(news.getBytes());
    System.out.println("News saved...");
  }
}
</pre>
<p>Pierwsza rzecz, którą zrobiliśmy, to usunęliśmy referencje do konkretnej implementacji klasy odpowiedzialnej za przechowywanie danych (<code>DBStorage</code>) i zamiast niej umieściliśmy referencję do <em>interfejsu</em> <code>Storage</code>:</p>
<pre name="code" class="java">
public interface Storage {
  void save(byte[] data);
}
</pre>
<p>Dzięki temu będziemy mogli w klasie <code>NewsService</code> używać dowolnej implementacji <code>Storage</code>. Inicjalizując klasę <code>NewsService</code> będziemy jej &#8220;wstrzykiwać&#8221; odpowiednią klasę implementującą interfejs <code>Storage</code>. Z praktycznego punktu widzenia na tym właśnie polega cała magia Dependency Injection!</p>
<p>Szczególnie warto zwrócić uwagę na kluczowy element DI. W klasie <code>NewsService</code> nie ma kodu, który by wyszukiwał implementację interfejsu <code>Storage</code> &#8211; gdybyśmy coś takiego umieścili, to zamiast DI używalibyśmy wzorca projektowego <em>service locator</em>, który jest obecnie nieco <em>passe</em>. <code>NewsService</code> oczekuje, że w czasie inicjalizacji ktoś mu poda odpowiednią implementację <code>Storage</code>. W naszym przypadku robi to klasa <code>Client</code>, której listing jest na samym dole wpisu.</p>
<p>Komunikację między klasami poprzez interfejsy demonstruje w sposób wyraźny poniższy diagram klas dla aplikacji:</p>
<p><a href="http://www.xoft.pl/wp-content/uploads/2008/12/news-service-di-uml.png"><img src="http://www.xoft.pl/wp-content/uploads/2008/12/news-service-di-uml.png" alt="" title="news-service-di-uml" width="489" height="576" class="alignnone size-full wp-image-76" /></a></p>
<p>Widać, że tak, jak chcieliśmy, <code>NewsService</code> zależy od innych klas wyłącznie poprzez interfejsy, nie przez implementacje.</p>
<p>Analogicznie <code>DBStorage</code> zależy od sterownika także poprzez interfejs <code>Driver</code>. W poprzedniej wersji aplikacji <code>DBStorage</code> był powiązany z konkretną wersją sterownika &#8211; <code>DBDriver</code>. Zobaczmy, jak wygląda kod, który implementuje zawartość diagramu.</p>
<pre name="code" class="java">
public class DBStorage implements Storage{

  Driver driver;

  public DBStorage(Driver driver) {
    this.driver = driver;
  }

  public void save(byte[] data) {
    driver.openConnection();
    System.out.println("Saving in database: '" + new String(data) +"'");
    driver.closeConnection();
  }
}
</pre>
<p>Sam interfejs <code>Driver</code> wygląda następująco:</p>
<pre name="code" class="java">
public interface Driver {
  void openConnection();
  void closeConnection();
}
</pre>
<p>Konkretną implementacją sterownika jest u nas klasa <code>SqlDbDriver</code>:</p>
<pre name="code" class="java">
public class SqlDbDriver implements Driver{

  public void openConnection() {
    System.out.println("Openning the database connection");
  }

  public void closeConnection() {
    System.out.println("Closing the database connection");
  }
}
</pre>
<p>Pozostała jeszcze z poprzedniej wersji aplikacji byle jak zaimplementowana polityka uwierzytelniania. Teraz zrobimy to lepiej. W klasie <code>NewsService</code>, zgodnie z duchem DI, umieściliśmy odwołanie do interfejsu <code>Authenticator</code>:</p>
<pre name="code" class="java">
public interface Authenticator {
  void authenticate() throws AuthException;
}
</pre>
<p><code>AuthException</code> jest wyjątkiem czasu wykonywania:</p>
<pre name="code" class="java">
public class AuthException extends RuntimeException{

  public AuthException(Throwable cause) {
    super(cause);
  }

  public AuthException(String message, Throwable cause) {
    super(message, cause);
  }

  public AuthException(String message) {
    super(message);
  }

  public AuthException() {
  }
}
</pre>
<p>W naszym kodzie używamy konkretnej implementacji uwierzytelniania:</p>
<pre name="code" class="java">
public class UsernamePassAuthenticator implements Authenticator{
  private String uname;
  private String pass;

  public UsernamePassAuthenticator() {
  }

  public String getPass() {
    return pass;
  }

  public void setPass(String pass) {
    this.pass = pass;
  }

  public String getUname() {
    return uname;
  }

  public void setUname(String uname) {
    this.uname = uname;
  }

  public UsernamePassAuthenticator(String uname, String pass) {
    this.uname = uname;
    this.pass = pass;
  }

  /**
   * Username &#038; password authenticator: username must be the same as
   * password - do not use it in production system ;)
   */
  public void authenticate() {
    if(!uname.equals(pass)){
      throw new AuthException("Authorization failed");
    }
  }
}
</pre>
<p>No i wreszcie nagroda za nasze wysiłki, czyli klasa kliencka:</p>
<pre name="code" class="java">
public class Client {
  public static void main(String[] args) {
    Authenticator authenticator = new UsernamePassAuthenticator("beer","beer");
    Driver driver = new SqlDbDriver();

    //inject dependency #1
    Storage storage = new DBStorage(driver);
    //inject dependency #2
    NewsService newsService = new NewsService(storage);
    //inject dependency #3
    newsService.setAuthenticator(authenticator);

    newsService.addNews("ble ble ble");
  }
}
</pre>
<p>Widzimy, że przed użyciem <code>NewsService</code> musimy go skonfigurować, czyli &#8220;wstrzyknąć&#8221; mu obiekty klas, które są potrzebne mu do działania.</p>
<p>Na koniec ćwiczenie dla szanownego czytelnika. W końcu czasem warto się sprawdzić. Czy teraz już nasza aplikacja na prawdę wygląda tak, jak trzeba? Na pewno? Czy może gdzieś jeszcze coś nie gra tak jak trzeba? Może gdzieś oszukałem? Jakiś mały problemik, architektoniczna niedoskonałość?</p>
<p>???</p>
<p>Jeżeli ktoś poczuł ducha DI, to pewnie od razu zorientował się, gdzie jeszcze tkwi problem. W klasie <code>NewsService</code> nadal tkwi ukryta zależność od klasy konkretnej zamiast interfejsu &#8211; w metodzie <code>login</code> klasy <code>NewsService</code> jest robione rzutowanie na klasę konkretną <code>UsernamePassAuthenticator</code>.</p>
<p>Zależność ta jest o tyle nieprzyjemna, że można ją na pierwszy rzut oka przeoczyć, w szczególności nie widać jej na diagramie UML-owym.</p>
<p>Warto się pozbyć się tego niezbyt eleganckiego kodu, świadczy on tylko o tym, że źle zaplanowaliśmy odpowiedzialność klasy <code>NewsService</code>. Niby dlaczego nagle ma ona zajmować się logowaniem, skoro może to zrobić <code>Authenticator</code>. Metoda <code>login</code> jest zwyczajnie zbędna.</p>
<p>To prowadzi nas z kolei do następnego pytania, na ile łatwo jest błędnie zaprojektować architekturę aplikacji, gdy zdecydujemy się używać wstrzykiwania zależności? Zajmiemy się tym problemem w <a href="http://www.xoft.pl/2009/04/10/wstrzykiwanie-zaleznosci-czyli-dependency-injection-w-9-minut-i-59-sekund-czesc-3-jak-zle-uzywac-di">trzeciej</a> części cyklu.</p>
<p>Wreszcie dociekliwy czytelnik może zacząć się zastanawiać, jak będzie wyglądało to wstrzykiwanie zależności, jeżeli będziemy często używać <code>NewsService</code> &#8211; w końcu za każdym razem będziemy musieli mu wstrzykiwać te potrzebne klasy, co oznacza pisanie w kółko tego samego kodu. Czy nie lepiej jest użyć jednak jakiego wzorca <em>factory</em> czy <em>service locator</em>, żeby jednak <code>NewsService</code> sam sobie znalazł potrzebne klasy. Z tym problemem można sobie także poradzić najłatwiej przy użyciu kontenera <em>Dependency Injection</em>, takiego jak Spring, PicoContainer czy Guice. Temu będzie poświęcony <a href="http://www.xoft.pl/2009/04/30/wstrzykiwanie-zaleznosci-czyli-dependency-injection-w-9-minut-i-59-sekund-czesc-4-wykorzystanie-spring-a">czwarty</a> wpis z serii DI.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.xoft.pl/2008/12/28/depedency-injection-spring-intro/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Wstrzykiwanie zależności, czyli Dependency Injection w 9 minut i 59 sekund. Część 1: podręczny przewodnik tworzenia złych aplikacji</title>
		<link>http://www.xoft.pl/2008/12/23/depedency-injection-spring-intro-baddesing/</link>
		<comments>http://www.xoft.pl/2008/12/23/depedency-injection-spring-intro-baddesing/#comments</comments>
		<pubDate>Tue, 23 Dec 2008 12:02:51 +0000</pubDate>
		<dc:creator>Piotr Kochański</dc:creator>
				<category><![CDATA[DEPENDENCY INJECTION]]></category>
		<category><![CDATA[JAVA]]></category>
		<category><![CDATA[SPRING]]></category>

		<guid isPermaLink="false">http://www.xoft.pl/?p=40</guid>
		<description><![CDATA[Gdzie się człowiek nie obejrzy tam się czai Dependency Injection (DI), czyli wstrzykiwanie zależności. Żeby jeszcze było tego mało, jak się zaczyna grzebać w internecie, to się co chwila można potknąć o jakiś framework, kontener czy coś takiego, co nam samo może zrobić Dependency Injection.
Co to w ogóle jest, po co takie coś komukolwiek, jak [...]]]></description>
			<content:encoded><![CDATA[<p>Gdzie się człowiek nie obejrzy tam się czai Dependency Injection (DI), czyli wstrzykiwanie zależności. Żeby jeszcze było tego mało, jak się zaczyna grzebać w internecie, to się co chwila można <a href="http://en.wikipedia.org/wiki/Dependency_injection#Existing_frameworks">potknąć</a> o jakiś framework, kontener czy coś takiego, co nam samo może zrobić Dependency Injection.</p>
<p>Co to w ogóle jest, po co takie coś komukolwiek, jak tego używać? Okazuje się, że sprawa jest prosta, wręcz banalna, a jednocześnie prowadzi do całkiem interesujących zastosowań. Za chwilę postaramy się zrozumieć jak DI działa, zrobimy to w sposób praktyczny, obdarty z krążących wokół DI ideologii i zupełnie zbędnego adżajlowego bełkotu.</p>
<p>Przekonamy się, że DI jest jednym z wielu możliwych sposobów budowania architektury aplikacji tak, by była łatwa w rozbudowie i testowaniu.</p>
<p>Będziemy chcieli zobaczyć coś więcej, niż zupełnie trywialny przykład (takich jest mnóstwo w internecie), po którym w zasadzie można wzruszyć ramionami, bo nie specjalnie widać tam jakiekolwiek zalety architektury wykorzystującej DI. </p>
<p>Naszym celem będzie zbudowanie bardzo prostej aplikacji służącej do przechowywania informacji, będzie składała się ona z trzech warstw (trójka jest nieprzypadkowa, sporo aplikacji Java EE jest rozbijane na tyle warstw) i tyluż komponentów.</p>
<p>Naszą aplikację napiszemy na kilka sposobów:</p>
<ul>
<li>naiwne podeście z paskudną architekturą;</li>
<li><a href="http://www.xoft.pl/2008/12/28/depedency-injection-spring-intro">w miarę rozsądnie wyglądająca aplikacja</a>, wykorzystująca wstrzykiwanie zależności;</li>
<li><a href="http://www.xoft.pl/2009/04/10/wstrzykiwanie-zaleznosci-czyli-dependency-injection-w-9-minut-i-59-sekund-czesc-3-jak-zle-uzywac-di">aplikacja wykorzystująca wstrzykiwanie zależności, ale zrobiona źle</a> &#8211; warto wiedzieć, że wbrew wrażeniu, jakie można odnieść po ohah i ahah na temat DI, przy jego pomocy też można koncertowo skopać architekturę tworzonego oprogramowania.</li>
<li><a href="http://www.xoft.pl/2009/04/30/wstrzykiwanie-zaleznosci-czyli-dependency-injection-w-9-minut-i-59-sekund-czesc-4-wykorzystanie-spring-a">ta sama aplikacja, wykorzystująca wstrzykiwanie zależności i kontener Spring;</a></li>
<li><a href="/2009/07/09/wstrzykiwanie-zaleznosci-czyli-dependency-injection-czesc-5-wykorzystanie-google-guice/">jeszcze raz to samo, ale z wykorzystaniem Google Guice</a>;</li>
<li>następnie spróbujemy porównać działanie Spring i Google Guice;</li>
<li>wreszcie, na końcu trochę &#8220;filozofii&#8221;, czy faktycznie DI jest potrzebne, czy jest potrzebne tylko Javie, jak to jest z innymi językami.</li>
</ul>
<p>Zatem, do dzieła!<br />
<span id="more-40"></span><br />
Zaczniemy od pierwszej wersji naszej aplikacji. Głównym jej elementem jest klasa <code>NewsService</code>, która używa do przechowywania informacji klasy <code>DBStorage</code>, która to z kolei potrzebuje sterownika komunikującego się z bazą danych (<code>DBDriver</code>). Chcemy mieć także możliwość zmuszenia użytkownika naszej aplikacji do uwierzytelnienia się &#8211; zajmuje się tym <code>DBStorage</code> i <code>NewsService</code>. </p>
<p>Zobaczmy sobie po kolei te klasy:</p>
<pre name="code" class="java">
public class NewsService {
  DBStorage dBStorage = new DBStorage();

  public void addNews(String news){
    addNews(news, new DBStorage());
  }

  public void addNews(String news, String uname, String pass){
    addNews(news, new DBStorage(uname, pass));
  }

  public void addNews(String news, DBStorage dBStorage){
    this.dBStorage = dBStorage;
    dBStorage.save(news.getBytes());
  }
}
</pre>
<p>W tej klasie ważne są dwie rzeczy: użycie <code>DBStorage </code> oraz oczywiście metoda <code>addNews</code>.</p>
<pre name="code" class="java">
public class DBStorage {

  DBDriver driver;

  public DBStorage(String uname, String pass) {
    authenticate(uname, pass);
    driver = DBDriver.getInstance();
  }

  public DBStorage() {
    driver = DBDriver.getInstance();
  }

  public void authenticate(String uname, String pass){
    System.out.println("Authentication...");
  }

  public void save(byte[] data){
    driver.openConnection();
    System.out.println("Saving in database...");
    driver.closeConnection();
  }
}
</pre>
<p>Klasa <code>DBStorage</code> dzielnie sama sobie produkuje <code>DBDriver</code> i jeszcze na dodatek zajmuje się uwierzytelnianiem użytkowników. Metoda <code>save</code> wykonuje czarną robotę zapisywania danych w odpowiednim miejscu.</p>
<pre name="code" class="java">
public class DBDriver {

  private DBDriver() {
  }

  public static DBDriver getInstance(){
    return new DBDriver();
  }

  public void openConnection(){
    System.out.println("Openning the connection");
  }

  public void closeConnection(){
    System.out.println("Closing the connection");
  }
}
</pre>
<p>Zobaczmy też na listingu poniżej jak tego wszystkiego można użyć razem:</p>
<pre name="code" class="java">
public class Client {
  public static void main(String[] args) {
    NewsService newsService = new NewsService();
    newsService.addNews("ble ble ble");

    DBStorage dbStorage1 = new DBStorage();
    newsService.addNews("bla bla bla", dbStorage1);

    DBStorage dbStorage2 = new DBStorage("joe","beer");
    newsService.addNews("bla bla bla", dbStorage2);
  }
}
</pre>
<p>No dobrze, kod się kompiluje, działa, wydawałoby się, że wszystko jest ok, ale&#8230; No właśnie, coś tutaj jednak nie gra.</p>
<p>Pierwsza rzecz. Wyobraźmy sobie, że chcemy teraz zapisywać dane nie w bazie danych tylko, powiedzmy, w pliku XML-owym, albo pliku JSON czy CSV. Albo może nasze newsy mają być przechowywane jako zserializowane obiekty Java. Jednakże klasa <code>NewsService</code> zależy od klasy <code>DBStorage</code>, która potrafi dane przechowywać tylko w bazie danych.</p>
<p>Mało tego, klasa <code>DBStorage</code> jest powiązana ściśle z <code>DBDriver</code>, także podmiana klasy sterownika również nie jest prosta.</p>
<p>Jedyne wyście jakie nam pozostaje, gdy chcemy zmienić sposób działania aplikacji, to dodawać do klasy <code>NewsService</code> kolejne metody dodające informację, które będą wykorzystywały inne sposoby przechowywania danych. Powstanie w ten sposób kod, który będzie się w dużej mierze powtarzał, klasa <code>NewsService</code> będzie się coraz bardziej rozrastała, a jej użycie coraz trudniejsze.</p>
<p>Świetnie, krytykować zawsze jest łatwo. A co, jeśli docelowym sposobem przechowywania informacji jest baza danych i nie będziemy tutaj nic zmieniać?</p>
<p>To nas prowadzi do drugiego problemu &#8211; testowalności tej aplikacji. Jedynym sposobem testowania klasy <code>NewsService</code> jest dostarczenie jej instancji klasy <code>DBStorage</code> &#8211; bez niej <code>NewsService</code> nie może w ogóle działać. <code>DBStorage</code> z kolei używa konkretnego sterownika do bazy danych.</p>
<p>W rezultacie, jeśli chcemy napisać test jednostkowy, czy test funkcjonalny musimy odtworzyć pełne środowisko działania aplikacji. Jeżeli nawet da się to zrobić (chociaż może wcale tak nie być i często w rzeczywistych sytuacjach nie jest), to testy będą znacznie trudniejsze do napisania, będą dłużej się wykonywały. Przy takiej aplikacji jak nasza, pewnie to nie jest problemem, ale pracując z 500 tysiącami linii kodu może być to istotna sprawa.</p>
<p>Na koniec jeszcze jeden rzecz &#8211; problem uwierzytelniania. Abstrahując od tego, że przywiązujemy się tylko do jednego sposobu uwierzytelniania (hasło + nazwa użytkownika), to jeszcze sam proces uwierzytelniania jest rozwleczony pomiędzy klasę <code>NewsService</code> i <code>DBStorage</code>.</p>
<p>Co jest przyczyną wymienionych problemów? Popatrzmy sobie na to, co zrobiliśmy z lotu ptaka:</p>
<a href="http://www.xoft.pl/wp-content/uploads/2008/12/news-service-bad-design-uml.png"><img src="http://www.xoft.pl/wp-content/uploads/2008/12/news-service-bad-design-uml.png" alt="News Service - bad design" title="news-service-bad-design-uml" width="417" height="320" class="size-full wp-image-52" /></a>
<p>Teraz widać jaśniej, co zrobiliśmy źle:</p>
<ul>
<li>Klasa <code>NewsService</code> zależy od konkretnej implementacji <code>DBStorage</code>, przez co nie możemy go łatwo wymienić na inny typ kontenera na dane. </li>
<li><code>DBStorage</code> zależy także bezpośrednio od <code>DBDriver</code> &#8211; tutaj sytuacja jest odrobinę lepsza, bo <code>DBDriver</code> jest tworzony przy pomocy metody <em>factory</em>, co daję pewną elastyczność tworzenia tego obiektu. Niestety z punktu widzenia testowalności niewiele to nam daje &#8211; chcielibyśmy w miejsce tego sterownika podstawić obiekt symulujący zachowanie sterownika, na co obecna implementacja nie pozwala</li>
<li>W przypadku uwierzytelniania źle zaplanowaliśmy odpowiedzialność klas i zaszyliśmy na stałe konkretny sposób uwierzytelniania</li>
</ul>
<p>Jak przemodelować tę aplikację, żeby pozbyć wyeliminować powyżej opisane jej wady? Tym zajmiemy się w <a href="http://www.xoft.pl/2008/12/28/depedency-injection-spring-intro">kolejnym wpisie</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.xoft.pl/2008/12/23/depedency-injection-spring-intro-baddesing/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>

