<?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 &#187; SPRING</title>
	<atom:link href="http://www.xoft.pl/category/dependency-injection/spring/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.xoft.pl</link>
	<description>O programowaniu i innych rzeczach</description>
	<lastBuildDate>Fri, 12 Feb 2010 14:42:55 +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>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ęść 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>2</slash:comments>
		</item>
	</channel>
</rss>
