<?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/"
	 xmlns:media="http://search.yahoo.com/mrss/" >

<channel>
	<title>Java &#8211; Nearshore Software Development Company &#8211; IT Outsourcing Services</title>
	<atom:link href="https://nearshore-it.eu/pl/tag/java-pl/feed/" rel="self" type="application/rss+xml" />
	<link>https://nearshore-it.eu/pl/</link>
	<description>We are Nearshore Software Development Company with 14years of experience in delivering a large scale IT projects in the areas of PHP, JAVA, .NET, BI and MDM.</description>
	<lastBuildDate>Thu, 07 Nov 2024 14:01:34 +0000</lastBuildDate>
	<language>pl-PL</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.8.3</generator>

<image>
	<url>https://nearshore-it.eu/wp-content/uploads/2023/01/cropped-inetum-favicon-300x300-1-32x32.png</url>
	<title>Java &#8211; Nearshore Software Development Company &#8211; IT Outsourcing Services</title>
	<link>https://nearshore-it.eu/pl/</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Wprowadzenie do Kotlina</title>
		<link>https://nearshore-it.eu/pl/artykuly/kotlin/</link>
					<comments>https://nearshore-it.eu/pl/artykuly/kotlin/#respond</comments>
		
		<dc:creator><![CDATA[Mateusz Budnik]]></dc:creator>
		<pubDate>Wed, 29 Jun 2022 12:21:01 +0000</pubDate>
				<category><![CDATA[Artykuły]]></category>
		<category><![CDATA[Technologie]]></category>
		<category><![CDATA[Java]]></category>
		<guid isPermaLink="false">https://nearshore-it.eu/artykuly/kotlin/</guid>

					<description><![CDATA[Kotlin jest językiem programowania ogólnego przeznaczenia stworzonym przez firmę JetBrains, a jego pierwsza stabilna wersja ukazała się w 2016 roku. Ten język łączy w sobie elementy programowania funkcyjnego, imperatywnego i obiektowego. Czy warto uczyć się programowania w języku Kotlin? Jakie są jego zalety i zastosowania? Dlaczego developer programujący w Javie miałby się przestawić na ten właśnie język? W jakich projektach warto go wykorzystać? Sprawdźmy!]]></description>
										<content:encoded><![CDATA[
<div class="table-of-contents">
    <p class="title">Przejdź do: </p>
    <ol>
                    <li><a href="#Języki-JVM">1.  Języki JVM</a></li>
                    <li><a href="#Kotlin-vs-Java">2.  Kotlin vs Java</a></li>
                    <li><a href="#Co-ma-Kotlin,-czego-nie-ma-Java?">3.  Co ma Kotlin, czego nie ma Java?</a></li>
                    <li><a href="#Czego-nie-ma-Kotlin,-a-ma-to-Java?">4.  Czego nie ma Kotlin, a ma to Java?</a></li>
                    <li><a href="#Zastosowanie-języka-Kotlin">5.  Zastosowanie języka Kotlin</a></li>
                    <li><a href="#Kotlin-Android-Development">6.  Kotlin Android Development</a></li>
                    <li><a href="#Programuję-w-Javie-czy-warto-się-przestawić-na-Kotlin?">7.  Programuję w Javie – czy warto się przestawić na Kotlin?</a></li>
                    <li><a href="#Czy-Kotlin-zastąpi-Javę?">8.  Czy Kotlin zastąpi Javę?</a></li>
                    <li><a href="#Podsumowanie">9.  Podsumowanie</a></li>
                    <li><a href="#Skąd-czerpać-wiedzę?">10.  Skąd czerpać wiedzę? </a></li>
            </ol>
</div>


<h2 class="wp-block-heading" id="Języki-JVM">Języki JVM</h2>



<p><strong>„Napisz raz, uruchamiaj wszędzie”</strong> – taka idea inspirowała twórców Javy. Aby to osiągnąć, potrzebowali czegoś, co uniezależniałoby kod aplikacji od konkretnej platformy sprzętowej. Stworzyli więc wirtualną maszynę Javy (JVM), która interpretuje kod bajtowy niezależnie od urządzenia, na którym jest zainstalowana. Z czasem powstało więcej języków, które kompilowane są do tego samego kodu pośredniego i mogą być uruchamiane poprzez JVM. Wśród nich pojawiły się między innymi <strong>Groovy, Scala oraz Kotlin.</strong></p>



<h2 class="wp-block-heading" id="Kotlin-vs-Java">Kotlin vs Java</h2>



<p>O Kotlinie często mówi się, że jest następcą Javy. Język ten wprowadza pewne ułatwienia, które sprawiają, że kod jest bardziej zwięzły i przejrzysty. Mechanizmy, które Kotlin oferuje, mogą sprawić, że praca programisty będzie efektywniejsza, a kod bardziej odporny na błędy. Ponadto język ten oferuje interoperacyjność z Javą. &nbsp;Oznacza to, że mamy możliwość użycia obu języków w tworzonym przez nas projekcie, jak i korzystania z bibliotek i frameworków znanych z Javy.</p>



<p><strong>Chciałbym zwrócić uwagę na niektóre z różnic pomiędzy Javą a Kotlinem.</strong></p>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>


<div class="wp-block-image">
<figure class="aligncenter size-full"><img decoding="async" src="https://nearshore-it.eu/wp-content/uploads/2024/09/jpro_2022.06.29_graphic_2.png" alt="Kotlin vs Java – porównanie obu języków programowania" class="wp-image-66819" title="Wprowadzenie do Kotlina 1"></figure></div>


<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading" id="Co-ma-Kotlin,-czego-nie-ma-Java?">Co ma Kotlin, czego nie ma Java? – przykłady</h2>



<h3 class="wp-block-heading">Obsługa typów nie pustych (ang. non-nullable types)</h3>



<p>W Kotlinie rozróżniane są typy, które mogą przyjmować wartości puste lub nie. Aby zmienna mogła przyjąć wartość „null”, musimy ją oznaczyć, dodając znak „?”, tak jak w poniższym przykładzie.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">1.	val a: String? = null</pre>



<p>Mechanizm ten pozwala na uniknięcie wielu błędów typu „NullPointerException”, które spowodowane są odwołaniem się do pola nieistniejącego obiektu. Już na poziomie kompilacji programista zostanie poinformowany, że coś jest nie tak.</p>



<p>Istnieje jeszcze operator „!!”, który konwertuje dowolną wartość na typ nieakceptujący wartości pustych. Jeżeli wykorzystamy ten mechanizm, musimy się liczyć z możliwością wystąpienia „NullPointerException”. Ten operator powinien być stosowany bardzo ostrożnie, tylko wtedy, gdy jest się przekonanym, że wartości nie będą puste w momencie ich użycia.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">1.   val a: String? = null 

2.   println(a!!.length)    // NullPointerException </pre>



<p>Gdy nie jesteśmy pewni, czy możemy odwołać się do danego pola, z pomocą przychodzi nam operator bezpiecznego wywołania (ang.<em> safe call operator</em>) „?.”, który sprawdza, czy referencja ma wartość pustą bez wyrzucania wyjątku „NullPointerException”. </p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">1.   val a: String? = "Kotlin" 

2.   val b: String? = null 

3.   println(a?.length)  // 6 

4.   println(b?.length) // null </pre>



<p>Java wraz z nadejściem wersji 8 otrzymała mechanizm pozwalający wyrazić potencjalny brak wartości. Dodana została klasa „Optional”, która wzbogaca zmienną, na której pracujemy, o dodatkowe metody pozwalające obsłużyć brak zasobu. Jednakże Kotlin radzi sobie z tym problemem w sposób generalnie bardziej zwięzły. Użycie operatorów wymaga mniej kodu niż odwoływanie się do wartości opakowanej w dodatkową klasę.&nbsp;</p>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>


<div class="wp-block-image">
<figure class="aligncenter size-full"><img decoding="async" src="https://nearshore-it.eu/wp-content/uploads/2024/09/jpro_2022.06.29_graphic_1.png" alt="Zalety języka Kotlin - odporność na błędy" class="wp-image-66829" title="Wprowadzenie do Kotlina 2"></figure></div>


<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading">Domniemanie typów</h2>



<p>W Kotlinie, inaczej niż w Javie, typ w wielu przypadkach jest określany automatycznie na podstawie kontekstu (możemy pominąć deklarację typu). Ilustruje to poniższy przykład, w którym zmiennej „a” zostanie przydzielony typ „int”.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">1.   var a = 1 

2.   a = 5 </pre>



<p>Podczas deklaracji zmiennych mamy do dyspozycji dwa słowa kluczowe „var” i „val”. Użycie pierwszego z nich („var”) powoduje to, że wartość będzie mogła zostać zmieniona. Natomiast pole zadeklarowane z „val” nie będzie mogło ulec modyfikacji. Zatem kod:<strong></strong></p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">1.   val a = 1 

2.   a = 5 // błąd </pre>



<p>zostanie potraktowany jako błąd.</p>



<h3 class="wp-block-heading">Inteligentne rzutowanie (ang. <em>smart casts</em>)<strong></strong></h3>



<p>Kompilator Kotlina jest w stanie samodzielnie zapamiętać sprawdzenie typu i odpowiednio rzutować zmienną na dany typ. W ten sposób w większości przypadków można automatycznie używać zmiennych zgodnie z potrzebami, bez konieczności ręcznego wykonywania oczywistych rzutowań.</p>



<p>Przykład:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">1.  fun printStringLength(any:Any) { 

2.  if(any is String) { 

3.    println(any.length) 

4.  } 

5. }  </pre>



<p>Zmienna „any” jest automatycznie rzutowana na typ String.</p>



<h3 class="wp-block-heading">Funkcje rozszerzające (ang. <em>extension functions</em>)</h3>



<p>Zdarza się, że jakaś klasa (np. z biblioteki) nie posiada metod, które mogłyby być dla nas bardzo przydatne. Funkcje rozszerzające pozwalają w łatwy sposób rozszerzyć daną klasę o nową funkcjonalność. Takie rozwiązanie pozwala nam po prostu na dodanie nowej funkcji do danej klasy.&nbsp;</p>



<p>Przykład: </p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">1. fun Activity.showToast(message:String){ 

2.   Toast.makeText(this, message, Toast.LENGTH_LONG).show() 

3. }  </pre>



<h3 class="wp-block-heading">Wartości domyślne</h3>



<p>Kotlin oferuje także wsparcie dla wartości domyślnych. Definiując funkcję, możemy ustawić domyślny parametr, którego nie trzeba już będzie podawać w wywołaniu funkcji.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">1.   fun sayHello(name: String = „World”){ 

2.   	println(„Hello $name”) 

3.   } 

 

1.    sayHello()    // Hello World </pre>



<h3 class="wp-block-heading">„Data classes”</h3>



<p>To klasy, które są tylko kontenerem na dane. Domyślnie implementują metody takie jak <em>equals(), hashCode()</em>, <em>toString(), </em>które w Javie należałoby samodzielnie zaimplementować.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">1.   data class User(val name: String, val age: Int)</pre>



<h3 class="wp-block-heading">Brak getterów i setterów</h3>



<p>W Kotlinie gettery i settery są generowane automatycznie. Pozwala to na zaoszczędzenie wielu linii kodu i czasu poświęconego na ich pisanie.&nbsp;</p>



<p>Oczywiście w Javie również powstały narzędzia, które pozwalają zredukować powtarzalny kod. „Lombok” jest biblioteką, która na podstawie adnotacji automatycznie generuje kod w celu ograniczenia tzw. „boilerplate code”.</p>



<h2 class="wp-block-heading" id="Czego-nie-ma-Kotlin,-a-ma-to-Java?">Czego nie ma Kotlin, a ma to Java?</h2>



<h3 class="wp-block-heading">Typy prymitywne</h3>



<p>Podstawowe typy danych takie, jak: boolean, byte, short, int, long, float, double, char. Nie przechowują one obiektów, lecz pojedyncze wartości. A operacje na nich są szybsze niż w przypadku typów złożonych.</p>


<div class="special-content-box style-1">
    <div class="box">
                <div class="content">
                                </div>
    </div>
</div>



<h3 class="wp-block-heading">„Checked exceptions”</h3>



<p>Wyjątki, które muszą być obsłużone przez programistę. Żeby skompilować kod, programista musi „naprawić” błąd wyrzucony przez wywołaną funkcję (użyć <strong>instrukcji try…catch…).</strong></p>



<p>Jest to kontrowersyjny koncept. Niektórzy uważają, że nie poprawia to jakości kodu, a zmniejsza produktywność programisty. Narzucenie konieczności obsługi wyjątków czasami skutkuje pustymi blokami „catch”. Obsługa wyjątków np. typu „IOException” w niskopoziomowej metodzie nie zawsze ma sens. Być może lepiej byłoby obsłużyć je gdzieś na wyższym poziomie. Kotlin świadomie nie przyjął tego konceptu.</p>



<h3 class="wp-block-heading">Słowo kluczowe „static”</h3>



<p>Kotlin nie posiada słowa kluczowego „static”. Zamiast tego ma mechanizmy takie jak „companion object”, czy deklarowanie zmiennej/funkcji poza klasą (ang. top-level declaration).</p>



<p>“Companion object” to obiekt typu “singleton”, powiązany z klasą, w której się znajduje, i zawierający pola i metody, do których możemy się odwołać w ten sam sposób co do elementów statycznych w Javie. </p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">1.   class MyClass { 

2.       companion object Factory { 

3.           fun create(): MyClass = MyClass() 

4.       } 

5.   } 

 

1.   val myClass = MyClass.create() 
</pre>



<h2 class="wp-block-heading" id="Zastosowanie-języka-Kotlin">Zastosowanie języka Kotlin</h2>



<p>Odkąd w 2019 r. Google ogłosiło Kotlin rekomendowanym językiem dla aplikacji na ich system operacyjny na urządzenia mobilne, może być on przez wielu developerów kojarzony głównie z Androidem. Jednak warto pamiętać, że to niejedyne zastosowanie Kotlina. </p>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>


<div class="wp-block-image">
<figure class="aligncenter size-full"><img decoding="async" src="https://nearshore-it.eu/wp-content/uploads/2024/09/jpro_2022.06.29_graphic_3.png" alt="Język Kotlin" class="wp-image-66823" title="Wprowadzenie do Kotlina 3"></figure></div>


<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<p>Język ten sprawdza się też w przypadku tworzenia aplikacji serwerowych czy desktopowych. Ogólnie rzecz ujmując, sprawdzi się wszędzie tam, gdzie może być używana Java (z ciekawostek – Kotlin został wykorzystany przy tworzeniu zintegrowanego środowiska developerskiego IntelliJ IDEA)</p>



<h3 class="wp-block-heading">Projekt Kotlin Multiplatform</h3>



<p>Warto wspomnieć też o tym, że rozwijany jest projekt o nazwie <strong>„Kotlin Multiplatform”.</strong> Dzięki niemu możliwe jest pisanie wspólnego kodu logiki biznesowej aplikacji, która będzie działać na wielu platformach, takich jak między innymi Android, iOS, Windows, Linux, macOS oraz jako aplikacja webowa.&nbsp;</p>



<h2 class="wp-block-heading" id="Kotlin-Android-Development">Kotlin Android Development</h2>



<p>Kotlin zyskał ogromną popularność dzięki Androidowi. Obecnie większość nowych aplikacji na tę platformę powstaje właśnie w tym języku. Jedne z najbardziej znanych aplikacji na Androida stworzonych z użyciem Kotlina to: <strong>Slack, Trello, Evernote, Pinterest, Tinder czy Uber.</strong></p>



<p>Także nowe narzędzia dla Android developerów, takie jak np. Jetpack Compose, wykorzystują cechy Kotlina i wymagają jego użycia. W wielu nowo powstających tutorialach przykładowy kod często jest również zaprezentowany w tym właśnie języku.</p>



<h2 class="wp-block-heading" id="Programuję-w-Javie-czy-warto-się-przestawić-na-Kotlin?">Programuję w Javie – czy warto się przestawić na Kotlin?</h2>



<p>Niełatwo jest porównywać języki programowania, ponieważ każdy ma swoje wady i zalety. Zarówno Kotlin, jak i Java ciągle są rozwijane i oferują coraz to nowsze mechanizmy. Java jest z nami od 1991 roku i od wielu lat znajduje się w czołówce najpopularniejszych języków programowania na świecie. Przez ten czas powstało wiele projektów. Czy warto więc się przestawić? To zależy.</p>



<h2 class="wp-block-heading" id="Czy-Kotlin-zastąpi-Javę?">Czy Kotlin zastąpi Javę?</h2>



<p>Choć dla tysięcy programistów na świecie <strong>królowa jest tylko jedna,</strong> wiele argumentów wskazuje na to, że Kotlin to godny następca Javy. Najważniejsze z nich to:</p>



<ul class="wp-block-list">
<li>Czytelniejszy kod</li>



<li>Odporność na błędy typu „NullPointerException”</li>



<li>Mechanizmy wspierające programowanie funkcyjne czy narzędzia (takie jak np. Jetpack Compose dla Androida)</li>
</ul>



<p></p>



<h2 class="wp-block-heading" id="Podsumowanie">Podsumowanie</h2>



<p>Moim zdaniem, rozpoczynając nowy projekt, <strong>warto się przestawić na język stworzony przez firmę JetBrains.</strong> Pozostaje jednak jeszcze pytanie, co z istniejącymi projektami napisanymi w Javie? Czy warto je migrować do Kotlina? Kotlin został zaprojektowany tak, żeby zachować pełną kompatybilność z Javą. Migracja może więc następować w sposób stopniowy. W bazie kodu mogą być dwa języki. Wiele firm wykorzystuje ten fakt i przekształca swoje aplikacje, aby mogły być one dalej rozwijane z wykorzystaniem zalet Kotlina. Jednakże dwa języki w kodzie mogą powodować pewne zamieszanie. Warto więc, jak zawsze, zachować szerszy kontekst i dopasować język indywidualnie do potrzeb i specyfiki projektu.</p>



<h2 class="wp-block-heading" id="Skąd-czerpać-wiedzę?">Kotlin – skąd czerpać wiedzę?</h2>



<h3 class="wp-block-heading">Strony internetowe</h3>



<ul class="wp-block-list">
<li>Oficjalna strona Kotlina – <a href="https://kotlinlang.org/" target="_blank" rel="noopener">https://kotlinlang.org/</a></li>



<li><a href="https://www.w3schools.com/kotlin/index.php" target="_blank" rel="noopener">https://www.w3schools.com/kotlin/index.php</a></li>



<li>Kotlin Academy – <a href="https://blog.kotlin-academy.com/" target="_blank" rel="noopener">https://blog.kotlin-academy.com/</a></li>
</ul>



<h3 class="wp-block-heading">Książki:</h3>



<ul class="wp-block-list">
<li>„Kotlin w Akcji” – Dmitry Jemerov, Svetlana Isakova</li>
</ul>



<h3 class="wp-block-heading">Materiały dla programistów Android:&nbsp;</h3>



<ul class="wp-block-list">
<li><a href="https://proandroiddev.com/" target="_blank" rel="noopener">https://proandroiddev.com/</a></li>



<li><a href="https://developer.android.com/kotlin" target="_blank" rel="noopener">https://developer.android.com/kotlin</a></li>
</ul>



<h3 class="wp-block-heading">Kanały na YouTube:</h3>



<ul class="wp-block-list">
<li><a href="https://www.youtube.com/c/AndroidDevelopers" target="_blank" rel="noopener">https://www.youtube.com/c/AndroidDevelopers</a></li>



<li><a href="https://www.youtube.com/stevdza_san" target="_blank" rel="noopener">https://www.youtube.com/stevdza_san</a></li>
</ul>



<p></p>
]]></content:encoded>
					
					<wfw:commentRss>https://nearshore-it.eu/pl/artykuly/kotlin/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Pair Programming</title>
		<link>https://nearshore-it.eu/pl/artykuly/pair-programming/</link>
					<comments>https://nearshore-it.eu/pl/artykuly/pair-programming/#respond</comments>
		
		<dc:creator><![CDATA[Daniel Ogiński]]></dc:creator>
		<pubDate>Wed, 14 Jul 2021 04:00:58 +0000</pubDate>
				<category><![CDATA[Artykuły]]></category>
		<category><![CDATA[Technologie]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Project Management]]></category>
		<guid isPermaLink="false">https://nearshore-it.eu/artykuly/pair-programming/</guid>

					<description><![CDATA[W jaki sposób dostarczać kod lepszej jakości i minimalizować liczbę błędów? Jak radzić sobie z implementacją zawiłych zadań, a także tych, których poziom skomplikowania jest mniejszy, ale ich zakodowanie, ze względu na różne czynniki, wymaga sporego skupienia? Jak skutecznie dzielić się wiedzą i doświadczeniem programistycznym? Odpowiedzią na te pytania może być odpowiednio przeprowadzony Pair Programming.]]></description>
										<content:encoded><![CDATA[
<div class="table-of-contents">
    <p class="title">Przejdź do:</p>
    <ol>
                    <li><a href="#Czym-jest-Pair-Programming">1.  Czym jest Pair Programming</a></li>
                    <li><a href="#Korzysci-programowania-w-parach">2.  Korzyści programowania w parach</a></li>
                    <li><a href="#Programowanie-w-parach-techniki">3.  Programowanie w parach – techniki</a></li>
                    <li><a href="#Czy-to-faktycznie-dziala">4.  Czy to faktycznie działa?</a></li>
                    <li><a href="#Pair-Programming-online">5.  Pair Programming online</a></li>
                    <li><a href="#Podsumowanie">6.  Podsumowanie</a></li>
            </ol>
</div>


<h2 class="wp-block-heading" id="Czym-jest-Pair-Programming">Czym jest Pair Programming</h2>



<p>Pair Programming ewoluował przez dekady, zyskał jednak na popularności dzięki metodologii <strong>Extreme Programming (XP),</strong> która została sformalizowana przez Kenta Becka w książce<strong> „Extreme Programming Explained: Embrace Change”.</strong> Istnieje kilka technik programowania w parach, a każda<br>z nich charakteryzuje się innymi założeniami. Uogólniając, całość polega na współpracy dwóch programistów, współdzielących jedną stację roboczą, którzy razem pracują nad rozwiązaniem danego problemu programistycznego. Programista aktualnie piszący kod to tzw. driver, drugi to navigator, zwany również obserwatorem – on także aktywnie uczestniczy w procesie twórczym, jednak skupia się bardziej na ogólnym kierunku oraz na ciągłej weryfikacji kodu napisanego przez „kierowcę”.</p>



<h2 class="wp-block-heading" id="Korzysci-programowania-w-parach">Korzyści programowania w parach</h2>



<p>Z moich obserwacji wynika, że programiści pracujący w parach wzajemnie wywierają na siebie pewnego rodzaju presję. Zdają sobie oni sprawę, jak cenny jest czas ich partnerów, przez co chcą go maksymalnie wydajnie wykorzystać. W zależności od zastosowanej techniki (opowiem o nich w dalszej części artykułu) korzyści programowania w parach mogą być następujące:</p>



<ul class="wp-block-list">
<li>lepsza jakość kodu, przy czym istotne jest, aby osoba pisząca aktualnie kod formułowała swoje myśli na głos – często pozwala to rozwiązać dany problem, nawet bez znacznej ingerencji drugiej strony,</li>



<li>łatwiejsze dzielenie się wiedzą domenową między członkami zespołu,</li>



<li>szybszy rozwój mniej doświadczonych programistów dzięki parowaniu ich z tymi bardziej doświadczonymi,</li>



<li>potencjalnie większa odporność na zewnętrzne zakłócenia – jedna osoba z pary zawsze może pozostawać skupiona na zadaniu, podczas gdy druga może np. uczestniczyć w zewnętrznej dyskusji z pozostałymi członkami zespołu.</li>
</ul>



<p>Należy jednak pamiętać, że programowanie w parach jest trudne, bywa wyczerpujące, wymaga samodyscypliny i pokory, a także umiejętności udzielania i dawania feedbacku. Często już sama świadomość, że ktoś przez część dnia będzie nam zaglądał przez ramię i oceniał to, co robimy, może zdezorganizować wewnętrzny spokój. No bo kto nie lubi czasem założyć słuchawek, odciąć się od otoczenia i zanurzyć w jakimś ciekawym problemie?</p>



<h2 class="wp-block-heading" id="Programowanie-w-parach-techniki">Programowanie w parach – techniki</h2>



<h3 class="wp-block-heading">Dobre praktyki</h3>



<p>Zanim opiszę poszczególne techniki programowania w parach, rzecz najistotniejsza, niezależna od stosowanej techniki: chodzi o <strong>robienie przerw oraz oraz nieprzeznaczanie na programowanie w parach zbyt dużo czasu w ciągu dnia – celem jest tu utrzymanie wydajności. </strong>Zaczynając od krótkich sesji (1-2 godz.), z czasem można zwiększać liczbę godzin poświęconych na Pair Programming, jednak według mnie dobrze jest nigdy nie przekraczać 5-6 godz. Jak wspomniałem wcześniej, do wyboru mamy kilka technik, każda z nich ma swoje wady i zalety. Daną technikę należy dobierać do konkretnej sytuacji. Proces programowania w parach będzie wyglądał inaczej, jeżeli planujemy przekazać wiedzę lub przeprowadzić onboarding nowej osoby w zespole, a inaczej, jeżeli chcemy zaimplementować jakąś skomplikowaną funkcjonalność. Poniżej opiszę te, z którymi ja się spotkałem i które – według mnie – powinny znaleźć się w arsenale każdego szanującego się programisty.</p>



<h3 class="wp-block-heading">Backseat navigator</h3>



<p>Prawdopodobnie najpopularniejsza metoda, stosowana zazwyczaj instynktownie. Jest wykorzystywana w sytuacji, gdy rozwiązując jakiś problem, doszliśmy do ściany. Bywa, że tak bardzo skupiamy się na znalezieniu rozwiązania, że nie widzimy alternatywnych możliwości, dochodzimy do ślepej uliczki i koniec. W takim wypadku prosimy innego programistę o wsparcie – taka osoba będzie zdolna spojrzeć na naszą zagwozdkę z innej perspektywy. Z drugiej strony, wariant ten jest idealny dla mniej doświadczonych programistów pod kątem nauki nowych umiejętności. Mamy wtedy do czynienia z relacją <em>nowicjusz – ekspert</em>. Jedna strona pisze kod (nowicjusz), druga natomiast pełni rolę wsparcia / mentora (ekspert).</p>



<h3 class="wp-block-heading">Driver-navigator</h3>



<p>Klasyczny Pair Programming, zderzenie dwóch różnych perspektyw na kod. „Kierowca” (ang. driver) zajmuje się pisaniem kodu, skupia się na detalach implementacyjnych, nawigator (ang. navigator) natomiast myśli o rozwiązaniu bardziej ogólnie, jest partnerem do dyskusji, decyduje o kierunku, wychwytuje braki w implementacji oraz przypadkach testowych (real-time code review). Według mnie technika ta jest idealna do rozwiązywania złożonych problemów, gdzie mnogość reguł biznesowych znacząco wydłużyłaby samodzielne próby rozwiązania problemu.</p>



<h3 class="wp-block-heading">Ping-pong</h3>



<p>Bywa, że od początku znamy kierunek, w którym powinniśmy pójść, a dany problem nie jest dla nas wyzwaniem. Takie arcynudne zadania również wymagają od nas profesjonalnego podejścia. Jeżeli TDD (<a href="https://nearshore-it.eu/pl/artykuly/test-driven-development-na-co-dzien">Test-Driven Development</a>) nie jest nam obce, to ta technika sprawdzi się idealnie. Całość polega na naprzemiennym pisaniu testów oraz implementacji. <em>Ping</em> – pierwszy programista pisze nieprzechodzący test, <em>pong</em> – drugi programista pisze implementację, sprawiając, że test zaczyna przechodzić. Po tym następuje faza refaktoryzacji i cały proces rozpoczyna się od nowa.</p>



<h2 class="wp-block-heading" id="Czy-to-faktycznie-dziala">Czy to faktycznie działa?</h2>



<p><strong>Teoria teorią, ale czy Pair Programming faktycznie jest tak wyjątkowy i zawsze da nam oczekiwane efekty? </strong></p>



<p>Jak zwykle, to zależy. Osobiście miałem okazję stosować głównie dwie pierwsze techniki, niestety – rzadziej, niż bym chciał. Spowodowane jest to faktem, że w świecie IT mamy wokół siebie wielu ludzi, często świetnych specjalistów, jednak różnica charakterów jest czynnikiem, który znacząco ogranicza powodzenie wspólnego programowania.</p>



<p>Trzeba pamiętać, że przynoszący rezultaty Pair Programming to przede wszystkim budowanie relacji<br>z członkami zespołu oraz przełamywanie wszelkich barier komunikacyjnych. Poniżej przedstawię kilka wniosków z mojej przygody z Pair Programming, które według mnie poprawiają efektywność całego procesu:</p>



<ul class="wp-block-list">
<li>dobrze jest określić cel sesji, który będzie można zweryfikować po jej zakończeniu,</li>



<li>innym ważnym aspektem jest ustalenie przerw oraz częstotliwość zmian,</li>



<li>jeżeli rozwiązujemy jakiś skomplikowany problem, pierwsza w rolę nawigatora niech wcieli się osoba z większą wiedzą domenową. W przypadku zadania typowo technicznego, niech to będzie osoba z większym doświadczeniem / umiejętnościami,</li>



<li>będąc w roli drivera, komunikujmy na głos wszystko, co robimy – niejednokrotnie samo mówienie na głos o danym problemie pozwoliło mi znaleźć rozwiązanie.</li>
</ul>



<p>Te rzeczy sprawdziły się u mnie, jednak zdecydowanie jestem daleki od twierdzenia, że takie podejście jest idealne. Moja sugestia jest taka, aby po prostu zacząć, wyciągać wnioski i próbować usprawniać cały proces tak, aby czuć się komfortowo i czerpać z tego satysfakcję.</p>



<div class="wp-block-group table-of-contents"><div class="wp-block-group__inner-container is-layout-constrained wp-block-group-is-layout-constrained">
<h3 class="wp-block-heading has-white-color has-text-color has-link-color wp-elements-678d644e40712193d059672c86b821ac"><strong>Czy warto stosować BDD?</strong></h3>



<p class="has-white-color has-text-color has-link-color wp-elements-2d8191f58ba2c29ba352c8d01de9f3ff">Czym jest i w jakich sytuacjach warto zastosować podejście BDD? Jakie są plusy tego rozwiązania?</p>



<div class="buttons-box" style="justify-content: flex-start">
                    <a class="btn btn-arrow btn-green btn-inline " href="https://nearshore-it.eu/pl/artykuly/testy-bdd-czy-naprawde-sa-potrzebne">PRZECZYTAJ ARTYKUŁ </a>
        
</div></div></div>



<h2 class="wp-block-heading" id="Pair-Programming-online">Pair Programming online</h2>



<p>Pytanie, które pojawia się często w kontekście zdalnego programowanie w parach, brzmi: <strong>czy to w ogóle ma sens?</strong></p>



<p>Odpowiedź brzmi: zdecydowanie tak. O ile nasz zespół nie pracuje w sposób asynchroniczny, to według mnie zdalny Pair Programming nie różni się w zasadzie niczym od tego standardowego, przeprowadzanego w biurze. Co więcej, w dzisiejszych czasach, kiedy wszyscy przenieśliśmy się z biur do domów, może nieść za sobą ogrom korzyści, wymusza bowiem kontakt z innymi członkami zespołu, który z reguły jest bardziej naturalny w środowisku biurowym – rozmawiamy w pokoju, na korytarzu czy w kuchni. Jeżeli chodzi o narzędzia, istnieje ich wiele i tak naprawdę to, które wybierzemy, zależy od osobistych preferencji. Jednym wystarczy <strong>Google Meet, Skype</strong> czy jakiekolwiek inne narzędzie z opcją udostępniania ekranu, inni natomiast, chcąc ze zdalnego programowania w parach wyciągnąć jak najwięcej, skorzystają w tym celu z dedykowanego narzędzia. W zależności od preferowanego edytora kodu będą to <strong>Floobits, Saros, Live Share </strong>czy <strong>Teamhub.</strong></p>



<h2 class="wp-block-heading" id="Podsumowanie">Podsumowanie</h2>



<p>Niestety, pomimo tego, że większość osób zajmujących się zawodowo programowaniem słyszała o programowaniu w parach, to ciągle można zauważyć, że jest ono traktowane po macoszemu. Moim zdaniem wynika to poniekąd z faktu, że <strong>korzyści z jego stosowania nie zawsze są widoczne od razu.</strong> Jest to umiejętność, która wymaga systematycznego stosowania, dlatego warto regularnie poświęcać jej część czasu przeznaczonego na kodowanie. Po zakończonej sesji wskazane jest spisać to, co poszło dobrze, a co nie zadziałało, dać sobie nawzajem feedback, tak aby kolejne sesje były lepsze od poprzednich.</p>



<p></p>
]]></content:encoded>
					
					<wfw:commentRss>https://nearshore-it.eu/pl/artykuly/pair-programming/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Wsparcie dla Spring WebFlux we frameworku Pact JVM</title>
		<link>https://nearshore-it.eu/pl/artykuly/wsparcie-dla-spring-webflux-we-frameworku-pact-jvm/</link>
					<comments>https://nearshore-it.eu/pl/artykuly/wsparcie-dla-spring-webflux-we-frameworku-pact-jvm/#respond</comments>
		
		<dc:creator><![CDATA[Paweł Pelczar]]></dc:creator>
		<pubDate>Wed, 21 Oct 2020 06:26:45 +0000</pubDate>
				<category><![CDATA[Artykuły]]></category>
		<category><![CDATA[Technologie]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[QA]]></category>
		<guid isPermaLink="false">https://nearshore-it.eu/artykuly/wsparcie-dla-spring-webflux-we-frameworku-pact-jvm/</guid>

					<description><![CDATA[Pact JVM posiada wsparcie dla Springa od dość dawna, ale po stronie dostawcy usługi było ono niestety ograniczone tylko do mockowanego Spring MVC. Począwszy od wersji 4.7.1, Pact wspiera również endpointy Spring WebFlux. W tym artykule zademonstruję użycie Pact Consumer Driven Contracts do testowania serwisów wykonanych za pomocą Spring WebFlux oraz konsumentów tych usług. Zacznę od krótkiego wprowadzenia do Consumer Driven Contract Testing i Spring WebFlux. Następnie wyjaśnię, jak połączyć te dwie technologie, aby utworzyć kontrakt i zweryfikować za jego pomocą zarówno konsumenta (consumer), jak i dostawcę (provider) usługi.]]></description>
										<content:encoded><![CDATA[
<div class="table-of-contents">
    <p class="title">Przejdź do:</p>
    <ol>
                    <li><a href="#Czym-jest-Pact-Consumer-Driven-Contract-Testing">1.  Czym jest Pact Consumer Driven Contract Testing</a></li>
                    <li><a href="#Czym-jest-Spring-WebFlux">2.  Czym jest Spring WebFlux</a></li>
                    <li><a href="#Pact-i-WebFlux-jak-to-dziala-razem">3.  Pact i WebFlux – jak to działa razem</a></li>
                    <li><a href="#Podsumowanie">4.  Podsumowanie</a></li>
                    <li><a href="#Zrodla">5.  Źródła</a></li>
            </ol>
</div>


<h2 class="wp-block-heading" id="Czym-jest-Pact-Consumer-Driven-Contract-Testing">Czym jest Pact Consumer Driven Contract Testing</h2>



<p>Consumer Driven Contract Testing to wzorzec wykorzystywany w testowaniu kompatybilności pomiędzy konsumentami (consumer) i dostawcami (provider) serwisów. Ogólna idea jest taka, że pomiędzy tymi dwoma systemami istnieje kontrakt opisujący zachodzące między nimi interakcje. Jeżeli obydwa systemy wypełniają jego założenia, test kończy się powodzeniem. Podejście „Consumer driven” oznacza, że siłą napędową ewolucji kontraktu są konsumenci serwisu, a nie dostawca.</p>



<p>Wsparciem dla Consumer Contract Testing jest zestaw frameworków <a href="https://pact.io" target="_blank" rel="noopener">DiUS Pact</a><u>.</u> Frameworki te koncentrują się głównie na komunikacji HTTP, choć dla niektórych platform dostępne jest również wsparcie dla kolejek. Obecnie implementacje pokrywają większość popularnych środowisk uruchomieniowych, takich jak JVM, .NET, JavaScript czy Ruby.</p>



<h2 class="wp-block-heading" id="Czym-jest-Spring-WebFlux">Czym jest Spring WebFlux</h2>



<p>Spring WebFlux to reaktywny framework webowy wprowadzony w Springu 5. Jest to odpowiednik dobrze znanego Spring MVC, z tą różnicą, że opiera się na nieblokującym API dostarczanym przez <a href="https://www.reactive-streams.org/" target="_blank" rel="noopener">reactive streams</a>. WebFlux jest w stanie obsługiwać duże obciążenia na małej liczbie wątków, co skutkuje mniejszym zużyciem zasobów sprzętowych.</p>



<p>WebFlux oferuje dwa modele programowania:</p>



<ul class="wp-block-list">
<li>adnotowane kontrolery</li>



<li>endpointy funkcyjne</li>
</ul>



<p>Pact obsługuje oba modele, natomiast dla potrzeb tego artykułu skupię się na endpointach funkcyjnych.</p>



<h2 class="wp-block-heading" id="Pact-i-WebFlux-jak-to-dziala-razem">Pact i WebFlux – jak to działa razem</h2>



<p>Ponieważ to na kliencie spoczywa odpowiedzialność za dostarczanie kontraktu, testy Pact pisane są najpierw dla niego. Każdy z testów zawiera opis interakcji pomiędzy klientem i dostawcą, np. requesty i spodziewane odpowiedzi HTTP. Mając te dane, pact framework uruchomi tymczasowy serwer HTTP zwracający predefiniowane odpowiedzi i wykona testy klienta.</p>



<p>Niejako efektem ubocznym wykonania testu jest utworzenie pliku kontraktu. Ten sam plik zostanie później użyty do sprawdzenia, czy dostawca serwisu spełnia założenia kontraktu. Po stronie serwera Pact wykona testy, używając requestów zapisanych w kontrakcie i zweryfikuje poprawność odpowiedzi. Możemy tutaj dokonać wyboru, czy chcemy przetestować serwis jako całość, czy tylko jego wycinek odpowiedzialny za komunikację HTTP. W tym artykule opiszę ten drugi przypadek.</p>



<h3 class="wp-block-heading">Test dla klienta</h3>



<p>Załóżmy, że dostawca udostępnia endpoint HTTP. Odpowiada on na żądania HTTP <strong><em>GET</em></strong><em>,</em> zwracając <em>JSONa </em>reprezentującego kolekcję obiektów <strong><em>Foo</em></strong>. Użyjmy frameworka <a href="https://github.com/spockframework/spock" target="_blank" rel="noopener">Spock</a> do zakodowania pact-testu klienta.</p>



<p>Najpierw zdefiniujmy pakt w sekcji <strong><em>given</em></strong> naszego testu. Wykorzystajmy do tego celu klasę <strong><em>ConsumerPactBuilder,</em></strong> którą udostępnia biblioteka Pact:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="java" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">given:
def pact = ConsumerPactBuilder.consumer("consumerService")
    .hasPactWith("providerService")
    .uponReceiving("sample request")
    .method("GET")
    .path("/foo")
    .willRespondWith()
    .status(200)
    .headers(["Content-Type": "application/json"])
    .body("""
            [
                {"id": 1, "name": "Foo"},
                {"id": 2, "name": "Bar"}
            ]
        """.stripIndent())
    .toPact()
</pre>



<p>Widzimy tutaj, że &nbsp;kontakt definiuje interakcje nazwaną <strong><em>sample request</em></strong> pomiędzy klientem o nazwie <strong><em>consumerService</em></strong> i dostawcą <strong><em>providerService.</em></strong> W reakcji na żądanie będące wywołaniem metody HTTP <em>GET</em> na ścieżce <em>/foo</em>, dostawca powinien odpowiedzieć statusem <em>HTTP 200,</em> a w sekcji <strong><em>body</em></strong> odpowiedzi powinny być dostarczone reprezentacje dwóch obiektów <strong><em>Foo</em>.</strong></p>



<p>Zakodujmy teraz część z asercjami oraz wywołaniem naszego klienta w sekcji <strong><em>when</em>:</strong></p>



<pre class="EnlighterJSRAW" data-enlighter-language="java" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">when:
def result = ConsumerPactRunnerKt.runConsumerTest(
    pact, MockProviderConfig.createDefault()) { mockServer, context ->

    def webClient = WebClient.create(mockServer.getUrl())
    def consumerAdapter = new ConsumerAdapter(webClient)

    def resultFlux = consumerAdapter.invokeProvider()

    StepVerifier.create(resultFlux)
        .expectNext(new Foo(1l, 'Foo'))
        .expectNext(new Foo(2l, 'Bar'))
        .verifyComplete()
}
</pre>



<p>Do wykonania testu klienta użyjemy klasy <strong><em>ConsumerPactRunnerKt</em></strong> dostarczanej przez bibliotekę Pact. Metoda <strong><em>runConsumerTest</em>,</strong> przed wykonaniem kodu z domknięcia, uruchomi tymczasowy serwer, który będzie odpowiadać na żądania HTTP zdefiniowane wcześniej w pakcie. Zapisze również kontrakt w postaci pliku JSON, który będzie współdzielony z dostawcą usługi. Ostatnim z parametrów tej metody będzie blok kodu zawierający wywołanie napisanego przez nas klienta serwisu. W tym przypadku utworzymy reaktywnego <strong><em>webClienta</em></strong> i przekażemy mu URL utworzonego przez Pact serwera HTTP. Następnie stworzymy instancję naszego adaptera <strong>(<em>ConsumerAdapter</em>),</strong> na której wywołamy metodę <strong><em>invokeProvider()</em></strong> odpowiedzialną za interakcję HTTP z dostawcą. Ponieważ wynikiem tej interakcji będzie <em>Flux</em> do zbadania jej poprawności, możemy użyć <strong><em>StepVerifiera</em></strong> z projektu Reactor.</p>



<p>Ostatnią fazą będzie sprawdzenie w sekcji <strong><em>then,</em></strong> czy weryfikacja kontraktu się powiodła:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="java" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">then:
result instanceof PactVerificationResult.Ok</pre>



<p>To właśnie tutaj możemy sprawdzić, czy <strong><em>StepVerifier</em> </strong>nie wygenerował wyjątku (będzie on owinięty w klasie <strong><em>PactVerificationResult.Error</em>)</strong> lub jakaś opisana w kontakcie interakcja nie została wywołana lub była z nim niezgodna.</p>



<p>Napiszmy teraz kod przykładowego klienta wykorzystywanego w teście. Będzie to standardowy przypadek użycia reaktywnego <strong><em>webClienta</em> </strong>do odczytu danych z endpointu <em>/foo</em>:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="java" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">public Flux&lt;Foo> invokeProvider() { 
    return webClient 
            .get() 
            .uri("/foo") 
            .accept(MediaType.APPLICATION_JSON) 
            .retrieve() 
            .bodyToFlux(Foo.class); 
}</pre>



<p>Jesteśmy teraz gotowi do wykonania testu. Uruchomi on dostarczany przez framework serwer HTTP – wywoła go, używając należącej do klienta klasy adaptera, a następnie zweryfikuje odpowiedzi. Dodatkowo Pact utworzy w katalogu <strong><em>build/pacts</em></strong> plik JSON będący reprezentacją paktu. Plik ten należy następnie udostępnić testom kontraktu providera serwisu.</p>



<h3 class="wp-block-heading">Test dla dostawcy</h3>



<p>Ponieważ mamy już gotowy plik kontraktu, test dla providera serwisu będzie nieco bardziej zwięzły. Tym razem użyjemy frameworku <a href="https://junit.org" target="_blank" rel="noopener">JUnit</a><u>,</u> ponieważ Spockowy wzorzec <em>given &#8211; when &#8211; then</em> nie byłby tutaj zbyt pomocny:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="java" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@RunWith(RestPactRunner.class) 
@Provider("providerService") 
@PactFolder("pacts") 
public class ProviderRouterPactTest { 
 
    @TestTarget 
    public WebFluxTarget target = new WebFluxTarget(); 
 
    private ProviderHandler handler = new ProviderHandler(); 
    private RouterFunction&lt;ServerResponse> routerFunction 
            = new ProviderRouter(handler).routes(); 
 
    @Before 
    public void setup() { 
        target.setRouterFunction(routerFunction); 
    } 
}</pre>



<p>Jak możemy zauważyć, kod nie zawiera żadnych metod testowych. Dzieje się tak dlatego, że testowane wywołania i asercje są już obecne w pliku kontraktu. <strong><em>RestPactRunner</em> </strong>(wskazany w adnotacji <strong><em>@RunWith</em></strong>) użyje tego pliku i zajmie się wykonaniem przypadków testowych w nim opisanych oraz weryfikacją odpowiedzi. Musimy jeszcze poinformować runnera o lokalizacji kontraktów (w tym przypadku poprzez adnotację <strong><em>@PactFolder</em></strong> wskazujemy katalog na dysku) i nazwie dostawcy (za pomocą adnotacji <strong><em>@Provider</em></strong>). Nazwa ta jest o tyle istotna, że silnik Pactu będzie wybierać kontrakty do przetestowania, porównując ją z nazwą podaną w teście klienta jako <strong><em>.hasPactWith(&#8222;providerService&#8221;). </em></strong>Adnotacja <strong><em>@TestTarget</em></strong> jest odpowiedzialna za wskazanie celu do testowania. Dla endpointów WebFluxowych będzie to instancja <strong><em>WebFluxTarget</em>.</strong> Należy w niej ustawić już bezpośrednio <strong><em>routerFunction,</em></strong> której używamy w kodzie dostawcy. Wygodnym miejscem do zrobienia tego jest tutaj metoda <strong><em>setup()</em></strong> testu.</p>



<p>Należy jeszcze wspomnieć o klasach <strong><em>ProviderHandler</em> </strong>oraz <strong><em>ProviderRouter</em>.</strong> Są to elementy implementacji przykładowego dostawcy. Router jest odpowiedzialny za budowanie instancji <strong><em>RouterFunction,</em></strong> które wiążą ścieżki URL z kodem handlera:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="java" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Configuration 
@RequiredArgsConstructor 
@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) 
class ProviderRouter { 
 
    ProviderHandler handler; 
 
    @Bean 
    RouterFunction&lt;ServerResponse> routes() { 
        return route() 
                .GET("/foo", accept(APPLICATION_JSON), handler::getFoo) 
                .build(); 
    } 
 
}</pre>



<p>Natomiast metoda handler::getFoo z powyższego przykładu jest odpowiedzialna za zwracanie Mono zawierającego odpowiedź dostawcy:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="java" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Mono&lt;ServerResponse> getFoo(ServerRequest request) { 
    return ServerResponse 
            .ok() 
            .contentType(APPLICATION_JSON) 
            .body(Flux.just( 
                    new Foo(1l, "Foo"), 
                    new Foo(2l, "Bar") 
            ), Foo.class); 
}</pre>



<p>Handler zwraca tutaj dwa obiekty <em>Foo</em> tak jak jest to określone w kontakcie między dostawcą a klientem.</p>



<p>Uruchomienie testu dla dostawcy będzie teraz skutkować wczytaniem pliku kontraktu, dopasowaniem odpowiedniego dla ścieżki HTTP handlera, wywołaniem go i weryfikacją, czy odpowiedź systemu jest zgodna z tą określoną w kontrakcie.</p>



<h2 class="wp-block-heading" id="Podsumowanie">Podsumowanie</h2>



<p>Pact Consumer Driven Contracts to bardzo przydatne narzędzie do zapewniania spójności pomiędzy elementami złożonego systemu. Z pewnością jego zaletą jest szeroki wachlarz wspieranych technologii, który pozwala na testowanie oparte na kontraktach w heterogenicznym środowisku. Teraz do tego spektrum dołączył kolejny element – technologia Spring WebFlux, dzięki czemu zyskaliśmy możliwość wykonywania testów względem reaktywnych dostawców.</p>



<p>Kod źródłowy przykładów użytych w tym artykule jest dostępny w repozytorium <a href="https://github.com/paweusz/pactwebflux" target="_blank" rel="noopener">Githuba</a>.</p>



<h2 class="wp-block-heading" id="Zrodla">Źródła</h2>



<ul class="wp-block-list">
<li>Strona <a href="https://github.com/DiUS/pact-jvm" target="_blank" rel="noopener">Github</a> Pact JVM</li>



<li><a href="https://docs.spring.io/spring/docs/current/spring-framework-reference/web-reactive.html" target="_blank" rel="noopener">Dokumentacja</a> Spring WebFlux</li>



<li><a href="https://martinfowler.com/articles/consumerDrivenContracts.html" target="_blank" rel="noopener">„Consumer-Driven Contracts: A Service Evolution Pattern&#8221;</a><u>,</u> Ian Robinson</li>



<li>Przykład integracji Pact – WebFlux na <a href="https://github.com/paweusz/pactwebflux" target="_blank" rel="noopener">Githubie</a></li>
</ul>
]]></content:encoded>
					
					<wfw:commentRss>https://nearshore-it.eu/pl/artykuly/wsparcie-dla-spring-webflux-we-frameworku-pact-jvm/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Od kaczek do delegacji, czyli problemy z dziedziczeniem w Javie</title>
		<link>https://nearshore-it.eu/pl/artykuly/od-kaczek-do-delegacji-czyli-problemy-z-dziedziczeniem-w-javie/</link>
					<comments>https://nearshore-it.eu/pl/artykuly/od-kaczek-do-delegacji-czyli-problemy-z-dziedziczeniem-w-javie/#respond</comments>
		
		<dc:creator><![CDATA[Marcin Chrost]]></dc:creator>
		<pubDate>Wed, 30 Sep 2020 10:58:04 +0000</pubDate>
				<category><![CDATA[Artykuły]]></category>
		<category><![CDATA[Technologie]]></category>
		<category><![CDATA[Java]]></category>
		<guid isPermaLink="false">https://nearshore-it.eu/artykuly/od-kaczek-do-delegacji-czyli-problemy-z-dziedziczeniem-w-javie/</guid>

					<description><![CDATA[Poznaj problemy związane z dziedziczeniem i hierarchią klas w Javie oraz alternatywne podejścia, które te problemy rozwiązują.]]></description>
										<content:encoded><![CDATA[
<div class="table-of-contents">
    <p class="title">Przejdź do:</p>
    <ol>
                    <li><a href="#Wstep">1.  Wstęp</a></li>
                    <li><a href="#Reguly-pani-Barbary-Liskov">2.  Reguły pani Barbary Liskov</a></li>
                    <li><a href="#Czysta-abstrakcja">3.  Czysta abstrakcja</a></li>
                    <li><a href="#Wada-tego-podejscia">4.  Wada tego podejścia</a></li>
                    <li><a href="#Kompozytor-wyjezdza-w-delegacje">5.  Kompozytor wyjeżdża w delegację</a></li>
                    <li><a href="#Wady-kompozycji">6.  Wady kompozycji</a></li>
                    <li><a href="#Kaczki-a-kacze-typowanie">7.  Kaczki, a kacze typowanie</a></li>
                    <li><a href="#Lombok-na-ratunek">8.  Lombok na ratunek</a></li>
                    <li><a href="#Czas-na-podsumowanie">9.  Czas na podsumowanie</a></li>
            </ol>
</div>


<h2 class="wp-block-heading" id="Wstep">Wstęp</h2>



<p>Programując w Javie (a właściwie w każdym języku zorientowanym obiektowo), co chwilę korzystamy z dobrodziejstw tego, co oferuje nam programowanie obiektowe: <strong>klasy, interfejsy, polimorﬁzm, dziedziczenie.</strong> I można by tak jeszcze długo wymieniać. Szczególnie ta ostatnia opcja (dziedziczenie) pozwala nam w łatwy sposób opisać wiele podobnych do siebie bytów w prosty sposób – tę część, która jest dla nich wspólna, deklarujemy tylko raz w klasie nadrzędnej; natomiast część zmienną umieszczamy w kodzie klas podrzędnych po niej dziedziczących.</p>



<p><strong>Okazuje się jednak, iż zarówno w życiu codziennym (spadek z długami po dalekim krewnym, o którym nawet nie mieliśmy pojęcia!), jak i w programowaniu, dziedziczenie może nam przysporzyć wielu niespodziewanych trudności. Na czym polega problem?</strong> Aby to wyjaśnić, posłużymy się na początek rysunkiem odnoszącym się do zasady, o której będziemy mówić w dalszej części artykułu. Następnie zmienimy rysunek w prostą aplikację złożoną z kilku klas. Spójrzmy na dwa poniższe rodzaje kaczek:</p>



<div style="height:34px" aria-hidden="true" class="wp-block-spacer"></div>


<div class="wp-block-image is-resized">
<figure class="aligncenter"><img decoding="async" src="https://nearshore-it.eu/wp-content/uploads/2024/09/2020.09.30_jpro_graphic.jpg" alt=" class=" class="wp-image-30908" title="Od kaczek do delegacji, czyli problemy z dziedziczeniem w Javie 4"><figcaption class="wp-element-caption"><em>Rysunek 1: Złe użycie dziedziczenia na przykładzie kaczek</em></figcaption></figure></div>


<div style="height:34px" aria-hidden="true" class="wp-block-spacer"></div>



<p>A teraz spróbujmy zapisać powyższy obrazek za pomocą klas Javy. Teoretycznie powinny nam do tego wystarczyć dwie klasy – jedna reprezentująca żywą kaczkę, a druga kaczkę elektryczną. Żywa kaczka potrafi pływać i kwakać:</p>



<div style="height:34px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image"><img decoding="async" src="https://nearshore-it.eu/wp-content/uploads/2024/09/2020.09.30_code_1.png" alt=" class=" class="wp-image-30887" title="Od kaczek do delegacji, czyli problemy z dziedziczeniem w Javie 5"><figcaption class="wp-element-caption"><em>Listing 1: Klasa Duck</em></figcaption></figure>



<div style="height:34px" aria-hidden="true" class="wp-block-spacer"></div>



<p>Natomiast kaczka elektryczna zachowuje się tak jak żywa (i dlatego po niej dziedziczy)&#8230; O ile oczywiście ktoś pamiętał i włożył do niej baterie! W przeciwnym razie reaguje niespodziewanymi wyjątkami.</p>



<div style="height:34px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image"><img decoding="async" src="https://nearshore-it.eu/wp-content/uploads/2024/09/2020.09.30_code_2.png" alt=" class=" class="wp-image-30888" title="Od kaczek do delegacji, czyli problemy z dziedziczeniem w Javie 6"><figcaption class="wp-element-caption"><em>Listing 2: Klasa ElectricDuck</em></figcaption></figure>



<div style="height:34px" aria-hidden="true" class="wp-block-spacer"></div>



<p>Teraz (ponieważ jesteśmy w XXI wieku) zamiast tworzyć klasę z metodą&nbsp;main, napiszmy test, który sprawdzi poprawność działania klasy&nbsp;Duck:</p>



<div style="height:34px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image is-resized"><img decoding="async" src="https://nearshore-it.eu/wp-content/uploads/2024/09/2020.09.30_code_3.png" alt=" class=" class="wp-image-30889" title="Od kaczek do delegacji, czyli problemy z dziedziczeniem w Javie 7"><figcaption class="wp-element-caption">Listing 3: Klasa DuckTest</figcaption></figure>



<div style="height:34px" aria-hidden="true" class="wp-block-spacer"></div>



<p>Stworzony test celowo sparametryzowaliśmy tak, aby dało się przekazać do niego różne obiekty klasy&nbsp;Duck. Skoro bowiem przyjęliśmy, iż klasa Electric Duck dziedziczy po klasie Duck, to przekazanie do testu obiektu tej klasy nie powinno niczego zepsuć. Tymczasem czeka nas bardzo nieprzyjemna niespodzianka:</p>



<div style="height:34px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image is-resized"><img decoding="async" src="https://nearshore-it.eu/wp-content/uploads/2024/09/2020.09.30_code_4.png" alt=" class=" class="wp-image-30890" title="Od kaczek do delegacji, czyli problemy z dziedziczeniem w Javie 8"><figcaption class="wp-element-caption"><em>Listing 4: Wyniki testów klasy Duck</em></figcaption></figure>



<div style="height:34px" aria-hidden="true" class="wp-block-spacer"></div>



<p>Wygląda na to, że obiekt klasy&nbsp;ElectricDuck&nbsp;zachowuje się niestety inaczej niż obiekt klasy&nbsp;Duck. To bardzo niedobrze, gdyż w innej części systemu możemy mieć metody, które przyjmują obiekt kaczki i jeżeli przekażemy w takim miejscu kaczkę elektryczną (a możemy to zrobić, gdyż kaczka elektryczna dziedziczy po żywej), to system zachowa się w sposób nieprzewidziany! W takiej sytuacji pierwsze rozwiązanie, jakie przychodzi nam do głowy, to sprawdzenie, jaki typ kaczki otrzymaliśmy w rzeczywistości:</p>



<div style="height:34px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image"><img decoding="async" src="https://nearshore-it.eu/wp-content/uploads/2024/09/2020.09.30_code_5.png" alt=" class=" class="wp-image-30891" title="Od kaczek do delegacji, czyli problemy z dziedziczeniem w Javie 9"><figcaption class="wp-element-caption"><em>Listing 5: Naiwny sposób kontroli typu kaczki</em></figcaption></figure>



<div style="height:34px" aria-hidden="true" class="wp-block-spacer"></div>



<p>Jednakże takie podejście:</p>



<ul class="wp-block-list">
<li>po pierwsze – tak naprawdę nie pozwala nam skorzystać z zalet polimorﬁzmu</li>



<li>po drugie – powoduje, że z każdym kolejnym typem kaczki nasz kod brzydko się rozrasta o nowy if</li>
</ul>



<p>Wygląda na to, że sytuacja, do której doprowadziliśmy, ewidentnie złamała jakąś regułę programowania obiektowego. Nietrudno domyślić się, że chodzi tu o jedną z zasad SOLID, a konkretnie o odpowiadającą literze L – zasadę podstawienia Liskov. Zapoznajmy się z nią bliżej.</p>



<h2 class="wp-block-heading" id="Reguly-pani-Barbary-Liskov">Reguły pani Barbary Liskov</h2>



<p>Nazwa tej zasady pochodzi od nazwiska bardzo zasłużonej dla informatyki pani profesor Barbary Liskov [1]. Sama definicja zasady podstawienia Liskov jest dość prosta [2]:</p>



<p><strong>Funkcje, które używają wskaźników lub referencji do klas bazowych, muszą być w stanie używać również obiektów klas dziedziczących po klasach bazowych, bez dokładnej znajomości tych obiektów.</strong></p>



<p>Powyższe zdanie nie wygląda ani na zbyt skomplikowane, ani na trudne do wykorzystania w praktyce. Okazuje się jednak, że już w bardzo prostym przypadku mamy problem z powyższą regułą. Dlaczego? Odpowiedź tkwi w warunkach, które muszą być spełnione przez podklasę w stosunku do nadklasy, aby ta reguła była faktycznie spełniona. A oto one [3]:</p>



<ul class="wp-block-list">
<li>Typ zwracany przez metodę w podklasie musi być taki sam jak w klasie bazowej albo być jego podtypem</li>



<li>Typy argumentów przekazywane do metody w podklasie muszą być takie same jak w klasie bazowej – albo być ich nadtypem</li>



<li>Metoda podklasy może rzucać wyjątek tylko wtedy, jeśli czyni to metoda w klasie bazowej. Typ wyjątku musi być taki sam jak w klasie bazowej albo musi być jego podtypem</li>



<li>Warunki wejściowe metody w podklasie nie mogą być silniejsze niż warunki wejściowe w klasie bazowej</li>



<li>Warunki wyjściowe metody w podklasie nie mogą być słabsze niż warunki wyjściowe w klasie bazowej</li>



<li>Metoda w podklasie nie może niszczyć niezmienników klasy bazowej</li>
</ul>



<p>O ile spełnienie trzech pierwszych warunków skontroluje za nas kompilator Javy (w przypadku drugiego warunku nawet nadmiarowo – do metody w podklasie można przekazać tylko ten sam typ argumentu, a nie nadtyp), o tyle niestety o spełnienie pozostałych warunków musimy już zadbać sami. Tu pojawia się relatywnie wysokie ryzyko popełnienia błędu. <strong>Nietrudno domyśleć się, że w naszym konkretnym przypadku złamaliśmy czwarty warunek, ponieważ w klasie&nbsp;Duck&nbsp;metoda&nbsp;getVoice()&nbsp;nie posiada żadnych warunków wejściowych – można ją wywołać w dowolnym momencie.</strong></p>



<p>Natomiast w klasie Electric Duck nie jest to już niestety prawda – metoda nie wyrzuci wyjątku tylko wtedy, gdy wcześniej wywołamy metodę&nbsp;insertBatteries(). O czym kod korzystający z takiego obiektu może nawet „nie wiedzieć”, gdyż taka metoda nie występuje w ogóle w klasie Duck!</p>



<p>Jak widać, ze względu na łatwą możliwość złamania reguł, poprawne dziedziczenie w Javie wcale nie jest proste do przeprowadzenia. Co gorsza, kompilator nie zawsze wykryje, że miało to miejsce, a to skazuje nas na weryfikację kodu w sposób ręczny (a więc – zawodny). Jakie mamy wobec tego możliwości rozwiązania problemu?</p>



<h2 class="wp-block-heading" id="Czysta-abstrakcja">Czysta abstrakcja</h2>



<p>Pierwszą metodą, jaką moglibyśmy zastosować, jest modyﬁkacja istniejącej hierarchii klas tak, aby klasy reprezentujące konkretne byty (w naszym przypadku żywa kaczka i kaczka elektryczna) dziedziczyły po klasie abstrakcyjnej, do której przenosimy maksymalnie wiele wspólnego kodu. Ktoś może zapytać: „Co to właściwie daje, skoro dalej zostajemy przy dziedziczeniu, a kaczka elektryczna dalej będzie zachowywać się inaczej niż żywa?”. Otóż cały haczyk tego rozwiązania polega na tym, iż nie będzie można powiedzieć, że klasa dziedzicząca „psuje” zachowanie klasy bazowej, gdyż obiekty klasy bazowej&#8230; po prostu nie będą istniały (wszak jest abstrakcyjna)! A skoro nie będą istniały – to i nie będzie czego zepsuć.</p>



<p>Proste – czyż nie? Oczywiście puryści programowania obiektowego zapewne stwierdzą, że takie tłumaczenie jest mocno naciągane&#8230; Ale to nie matematyka – tu nie ma jednego słusznego rozwiązania. Można mieć raczej zastrzeżenia co do innych wad tego podejścia – ale o nich opowiemy później. Pokażmy zatem nasz kod w akcji! Zacznijmy od klasy abstrakcyjnej, do której przeniesiemy wspólny kod. Nazwiemy ją w sposób mało wysublimowany –&nbsp;Base Duck. Po tej klasie będą dziedziczyć klasy reprezentujące żywe kaczki:</p>



<div style="height:34px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image"><img decoding="async" src="https://nearshore-it.eu/wp-content/uploads/2024/09/2020.09.30_code_6.png" alt=" class=" class="wp-image-30892" title="Od kaczek do delegacji, czyli problemy z dziedziczeniem w Javie 10"><figcaption class="wp-element-caption"><em>Listing 6: Klasa abstrakcyjna BaseDuck</em></figcaption></figure>



<div style="height:34px" aria-hidden="true" class="wp-block-spacer"></div>



<p>Klasa reprezentująca żywą kaczkę w tej sytuacji staje się praktycznie pusta (gdyż funkcjonalność przeszła do klasy abstrakcyjnej) – wygląda jak wydmuszka:</p>



<figure class="wp-block-image is-resized"><img decoding="async" src="https://nearshore-it.eu/wp-content/uploads/2024/09/2020.09.30_code_7.png" alt=" class=" class="wp-image-30893" title="Od kaczek do delegacji, czyli problemy z dziedziczeniem w Javie 11"><figcaption class="wp-element-caption"><em>Listing 7: Praktycznie pusta klasa Duck</em></figcaption></figure>



<div style="height:34px" aria-hidden="true" class="wp-block-spacer"></div>



<p>Klasa odpowiedzialna za kaczkę elektryczną zmienia się nieco mniej, ale i w niej będą odwołania do klasy abstrakcyjnej:</p>



<div style="height:34px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image"><img decoding="async" src="https://nearshore-it.eu/wp-content/uploads/2024/09/2020.09.30_code_8.png" alt=" class=" class="wp-image-30894" title="Od kaczek do delegacji, czyli problemy z dziedziczeniem w Javie 12"><figcaption class="wp-element-caption"><em>Listing 8: Zmodyﬁkowana klasa ElectricDuck</em></figcaption></figure>



<div style="height:34px" aria-hidden="true" class="wp-block-spacer"></div>



<p>Nieco zmieniają się również testy do klasy&nbsp;Duck. Ponieważ klasa&nbsp;ElectricDuck&nbsp;nie dziedziczy już po tej klasie, nie możemy już przetestować jej zachowania w tym miejscu:</p>



<div style="height:34px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image"><img decoding="async" src="https://nearshore-it.eu/wp-content/uploads/2024/09/2020.09.30_code_9.png" alt=" class=" class="wp-image-30895" title="Od kaczek do delegacji, czyli problemy z dziedziczeniem w Javie 13"><figcaption class="wp-element-caption"><em>Listing 9: Zmodyﬁkowana klasa DuckTest</em></figcaption></figure>



<div style="height:34px" aria-hidden="true" class="wp-block-spacer"></div>



<p>W związku z powyższym klasę&nbsp;ElectricDuck&nbsp;musimy przetestować oddzielnie:</p>



<div style="height:34px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image"><img decoding="async" src="https://nearshore-it.eu/wp-content/uploads/2024/09/2020.09.30_code_10.png" alt=" class=" class="wp-image-30896" title="Od kaczek do delegacji, czyli problemy z dziedziczeniem w Javie 14"><figcaption class="wp-element-caption"><em>Listing 10: Nowa klasa ElectricDuckTest</em></figcaption></figure>



<div style="height:34px" aria-hidden="true" class="wp-block-spacer"></div>



<p>Może pojawić się w tym miejscu wątpliwość: „Czy nie jest błędem, że tak naprawdę zwiększyła się nam ilość kodu w testach?”. Wbrew pozorom, nie powinno nas to niepokoić. Duża ilość kodu testowego (jeżeli tylko napisanego czysto), nie jest uważana za błąd, <a href="https://nearshore-it.eu/pl/artykuly/test-driven-development-na-co-dzien">a w niektórych metodykach (np. TDD)</a> – jest to normalne zjawisko. Jak widać, rozwiązanie z klasą abstrakcyjną nie wydaje się być zbytnio skomplikowane oraz nie wymaga dużych zmian w kodzie. W wielu przypadkach to wystarcza.</p>



<h2 class="wp-block-heading" id="Wada-tego-podejscia">Wada tego podejścia</h2>



<p>Sygnalizowałem wcześniej, że to rozwiązanie ma wady. Otóż każda klasa reprezentująca w naszej hierarchii konkretny byt ma narzucone z góry, iż musi dziedziczyć po klasie abstrakcyjnej. To zamyka możliwość dziedziczenia po czymkolwiek innym (Java nie posiada dziedziczenia wielobazowego). Możemy boleśnie odczuć skutki na własnej skórze w momencie, gdy takie dziedziczenie będzie nam potrzebne przy integracji z jakimś frameworkiem lub biblioteką. Jest na to jednak sposób – o tym, jak poradzić sobie w sytuacji, gdy nie możemy sobie pozwolić na zablokowanie dziedziczenia dla naszych klas, napiszę w kolejnej części artykułu.</p>



<h2 class="wp-block-heading" id="Kompozytor-wyjezdza-w-delegacje">Kompozytor wyjeżdża w delegację</h2>



<p>Tak jak wspominałem na początku, dziedziczenie często stosujemy po to, aby uniknąć wielokrotnego pisania kodu. Kod staje się składową klasy bazowej, a klasy dziedziczące mogą dzięki temu również z niego skorzystać.<strong> Okazuje się jednak, że podobny efekt można osiągnąć poprzez ekstrakcję wspólnego kodu do oddzielnego obiektu, a następnie uczynienie tego obiektu składnikiem klasy</strong>. W efekcie można powiedzieć, że klasa nie dziedziczy jakiejś funkcjonalności, ale ta funkcjonalność jest w nią wkomponowana. Bardziej szczegółowo można takie podejście podzielić na dwa nurty: agregację i kompozycję [4].</p>



<p>My w dalszej części artykułu będziemy używać sformułowania „kompozycja”, aczkolwiek może być ono nie do końca ścisłe. Dodatkowo wkomponowany obiekt będziemy od tej pory nazywać „delegatem” – bo tak naprawdę delegujemy do niego odpowiedzialność za wykonanie części zadań naszej klasy. Tego typu podejście nazywane jest często kompozycją ponad dziedziczeniem [5]. <strong>W jaki sposób zrealizowalibyśmy to w przypadku naszych kaczek? Przede wszystkim należałoby stworzyć nasz obiekt – delegata:</strong></p>



<div style="height:34px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image is-resized"><img decoding="async" src="https://nearshore-it.eu/wp-content/uploads/2024/09/2020.09.30_code_11.png" alt=" class=" class="wp-image-30897" title="Od kaczek do delegacji, czyli problemy z dziedziczeniem w Javie 15"><figcaption class="wp-element-caption"><em>Listing 11: Delegat zachowania kaczki</em></figcaption></figure>



<div style="height:34px" aria-hidden="true" class="wp-block-spacer"></div>



<p>Zauważmy, że zawiera on mniej więcej to samo, co mamy w klasie abstrakcyjnej&nbsp;BaseDuck. Nic w tym dziwnego – w końcu delegat ma tę klasę zastąpić. A skoro tak – to w takim razie usuwamy ją, gdyż nie jest już nam potrzebna. Po usunięciu klasy abstrakcyjnej musimy zmodyﬁkować klasę&nbsp;Duck. Niezbędne jest dodanie metod, które dotychczas były zdefiniowane w klasie abstrakcyjnej, oraz ich implementacja z użyciem delegata:</p>



<div style="height:34px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image"><img decoding="async" src="https://nearshore-it.eu/wp-content/uploads/2024/09/2020.09.30_code_12.png" alt=" class=" class="wp-image-30898" title="Od kaczek do delegacji, czyli problemy z dziedziczeniem w Javie 16"><figcaption class="wp-element-caption"><em>Listing 12: Kaczka z delegatem</em></figcaption></figure>



<div style="height:34px" aria-hidden="true" class="wp-block-spacer"></div>



<p>I podobnie robimy w klasie&nbsp;ElectricDuck:</p>



<div style="height:34px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image is-resized"><img decoding="async" src="https://nearshore-it.eu/wp-content/uploads/2024/09/2020.09.30_code_13.png" alt=" class=" class="wp-image-30899" title="Od kaczek do delegacji, czyli problemy z dziedziczeniem w Javie 17"><figcaption class="wp-element-caption"><em>Listing 13: Kaczka elektryczna z delegatem</em></figcaption></figure>



<div style="height:34px" aria-hidden="true" class="wp-block-spacer"></div>



<p>I to na razie wszystko! Jeśli uruchomimy nasze testy, to dalej powinny działać. Potrzebna będzie tylko jedna zmiana – klasy, z której wykonujemy statyczne importy.</p>



<div style="height:34px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image is-resized"><img decoding="async" src="https://nearshore-it.eu/wp-content/uploads/2024/09/2020.09.30_code_14.png" alt=" class=" class="wp-image-30900" title="Od kaczek do delegacji, czyli problemy z dziedziczeniem w Javie 18"><figcaption class="wp-element-caption"><em>Listing 14: Klasa DuckTest po drobnej zmianie</em></figcaption></figure>



<div style="height:34px" aria-hidden="true" class="wp-block-spacer"></div>



<p>Nietrudno zauważyć, iż kompozycja ma wiele zalet w porównaniu do klasycznego dziedziczenia:</p>



<ul class="wp-block-list">
<li><strong>Jest o wiele bardziej elastyczna i naturalna</strong> – o wiele łatwiej jest opisać strukturę obiektów w systemie, używając kompozycji niż dziedziczenia – często to drugie jest tworzone trochę „na siłę”</li>



<li><strong>Zachowanie obiektu można modyﬁkować w trakcie działania programu (podmieniając wkomponowany obiekt na inny. Przy dziedziczeniu jest to niemożliwe</strong> – część odziedziczona jest „sztywna”</li>
</ul>



<h2 class="wp-block-heading">Wady kompozycji</h2>



<p>Oczywiście należy także wspomnieć o wadach kompozycji:</p>



<ul class="wp-block-list">
<li>Zwiększa się zużycie pamięci – używamy bowiem większej liczby małych obiektów</li>



<li>Lekko spada wydajność wywoływania metod – wywołując metodęnaobiekcie, tak naprawdę musimy wywołać metodę z delegata – jest to jedna ramka na stosie więcej</li>



<li>Klasy mające tę samą funkcjonalność i metody (w naszym przypadku&nbsp;Duck&nbsp;i&nbsp;ElectricDuck) stają się zupełnie rozłączne w hierarchii typów, co w przypadku niektórych języków uniemożliwia proste zastępowanie ich wzajemnie.</li>



<li>Powstaje sporo metod, których jedynym zadaniem jest wywołanie odpowiedniej metody delegata (tzw. metody przekazujące).</li>
</ul>



<p>Dwie ostatnie wady są zależne od języka, z jakiego korzystamy, i w niektórych językach programowania nie występują. Niestety w przypadku Javy tak nie jest i trzeba włożyć więcej pracy, żeby się od nich uwolnić. Piszę o tym w dwóch kolejnych częściach artykułu.</p>



<h2 class="wp-block-heading" id="Kaczki-a-kacze-typowanie">Kaczki, a kacze typowanie</h2>



<p>W poprzedniej części wspomnieliśmy, iż nasze klasy reprezentujące kaczki stały się zupełnie rozłączne w hierarchii typów. W związku z tym, mimo tego, iż współdzielą de facto te same metody <strong>(getVoice()&nbsp;i&nbsp;getSwimVoice()),</strong> dla kompilatora Javy są to zupełnie różne byty.</p>



<p>Dlaczego tak się dzieje?<strong> Otóż język Java jest językiem z silną kontrolą typów i o tym, jakie metody można wywołać na danym obiekcie, decyduje tylko i wyłącznie jego typ (klasa i implementowane interfejsy).</strong> Dlatego też nie ma w nim zastosowania tak zwane (nomen omen) kacze typowanie – w którym o możliwościach obiektu nie decyduje jego typ, lecz udostępnione przezeń metody [6]:</p>



<p>Jeśli coś chodzi jak kaczka i kwacze jak kaczka, to musi być kaczką.</p>



<p>Teoretycznie w Javie można wprowadzić kacze typowanie, posiłkując się mechanizmem reﬂeksji. Powstały w ten sposób kod wygląda jednak bardzo nieczytelnie. Co gorsza, pozbawia nas silnej kontroli typów (co moim zdaniem jest jednak sporą i często niedocenianą zaletą języka Java). Na szczęście jest też do zastosowania o wiele prostszy sposób – wystarczy wprowadzić interfejs opisujący zachowanie kaczki. W przeciwieństwie do dziedziczenia (gdzie możemy mieć maksymalnie jednego przodka), każda klasa może implementować dowolną ilość interfejsów. Wprowadźmy zatem taki interfejs&nbsp;DuckBehaviour:</p>



<div style="height:34px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image"><img decoding="async" src="https://nearshore-it.eu/wp-content/uploads/2024/09/2020.09.30_code_15.png" alt=" class=" class="wp-image-30901" title="Od kaczek do delegacji, czyli problemy z dziedziczeniem w Javie 19"><figcaption class="wp-element-caption"><em>Listing 15: Interfejs opisujący zachowanie kaczki</em></figcaption></figure>



<div style="height:34px" aria-hidden="true" class="wp-block-spacer"></div>



<p>A następnie zaimplementujmy go w klasach opisujących kaczki (nietrudno się domyślić, że nie wymaga to wielkich zmian)</p>



<figure class="wp-block-image"><img decoding="async" src="https://nearshore-it.eu/wp-content/uploads/2024/09/2020.09.30_code_16.png" alt=" class=" class="wp-image-30902" title="Od kaczek do delegacji, czyli problemy z dziedziczeniem w Javie 20"><figcaption class="wp-element-caption"><em>Listing 16: Kaczka z interfejsem</em></figcaption></figure>



<div style="height:34px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image"><img decoding="async" src="https://nearshore-it.eu/wp-content/uploads/2024/09/2020.09.30_code_17.png" alt=" class=" class="wp-image-30903" title="Od kaczek do delegacji, czyli problemy z dziedziczeniem w Javie 21"><figcaption class="wp-element-caption"><em>Listing 17: Kaczka elektryczna z interfejsem</em></figcaption></figure>



<div style="height:34px" aria-hidden="true" class="wp-block-spacer"></div>



<p><strong>Jak widać, rozwiązanie z delegatem pozwoliło nam pozbyć się problemów z błędnym dziedziczeniem.</strong> Jednocześnie kod odpowiedzialny za bazowe zachowanie kaczki istnieje tylko w jednym miejscu (w klasie delegata). Czyżby sukces? Niestety jeszcze nie! Radość psują nam bowiem metody przekazujące w klasach&nbsp;Duck&nbsp;i&nbsp;ElectricDuck. Musimy je napisać, aby odbywało się wywołanie odpowiedniej metody w delegacie. Co gorsza – te metody będziemy musieli stworzyć w każdej klasie reprezentującej kaczkę, więc nie wygląda to za dobrze. Czyżby „zamienił stryjek siekierkę na kijek?” Aby zaradzić temu problemowi, będziemy musieli jeszcze nieco przerobić kod i wezwać na ratunek dobrze wszystkim znanego Lomboka</p>



<h2 class="wp-block-heading" id="Lombok-na-ratunek"><strong>Lombok na ratunek</strong></h2>



<p><strong>Problem z metodami przekazującymi tak naprawdę wynika z faktu, iż język Java sam w sobie nie wspiera mechanizmu delegacji (w przeciwieństwie do języków takich jak Groovy czy Kotlin, pozostając w świecie JVM).</strong> Wiemy też, że często takie braki języka są w całkiem rozsądny sposób „łatane” przez bibliotekę Lombok (żeby np. wspomnieć o setterach i getterach).</p>



<p>Tak jest i tym razem, ale jest pewien haczyk. Lombok oferuje adnotację&nbsp;@Delegate, która rozwiązuje nasz problem. Należy jednak mieć na uwadze, że jest ona traktowana jako eksperymentalna. Oznacza to, że może w przyszłości zniknąć. Nie jest to idealna sytuacja, ale dobre i to! Aby móc skorzystać z tej adnotacji, musimy doprowadzić do sytuacji, w której wszystkie metody przekazujące nie zawierają żadnej logiki poza wywołaniem odpowiadającej metody delegata. W klasie&nbsp;Duck&nbsp;nie jest to problemem, gdyż już tak się dzieje. Natomiast w klasie&nbsp;ElectricDuck&nbsp;metody przekazujące wykonują dodatkowe sprawdzenie (czy baterie są włożone).</p>



<p>Musimy zatem wyciągnąć te sprawdzenia na zewnątrz, korzystając ze wzorca strategii i takie strategie przekazać do delegata. W naszym przypadku będą to zwykłe dwa pola typu&nbsp;Runnable&nbsp;reprezentujące blok kodu do wykonania przed wydaniem głosu i próbą płynięcia:</p>



<div style="height:34px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image"><img decoding="async" src="https://nearshore-it.eu/wp-content/uploads/2024/09/2020.09.30_code_18.png" alt=" class=" class="wp-image-30904" title="Od kaczek do delegacji, czyli problemy z dziedziczeniem w Javie 22"><figcaption class="wp-element-caption"><em>Listing 18: Delegat ze strategiami</em></figcaption></figure>



<div style="height:34px" aria-hidden="true" class="wp-block-spacer"></div>



<p>Dodatkowo dołożyliśmy stałą reprezentującą „pustą” strategię nierobiącą niczego. Ułatwi nam to za chwilę przerobienie klasy&nbsp;Duck. Samo użycie adnotacji&nbsp;@Delegate&nbsp;jest proste – wystarczy użyć jej na polu reprezentującym delegata. Następnie usuwamy metody przekazujące – i to wszystko!</p>



<p>Klasa&nbsp;Duck&nbsp;będzie prezentować się następująco:</p>



<div style="height:34px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image"><img decoding="async" src="https://nearshore-it.eu/wp-content/uploads/2024/09/2020.09.30_code_19.png" alt=" class=" class="wp-image-30905" title="Od kaczek do delegacji, czyli problemy z dziedziczeniem w Javie 23"><figcaption class="wp-element-caption"><em>Listing 19: Klasa Duck z adnotacją @Delegate</em></figcaption></figure>



<div style="height:34px" aria-hidden="true" class="wp-block-spacer"></div>



<p>Nietrudno w takim razie przerobić i klasę&nbsp;ElectricDuck:</p>



<div style="height:34px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image"><img decoding="async" src="https://nearshore-it.eu/pl/artykuly/wp-content/uploads/2023/04/2020.09.30_code_20.png" alt="2020.09.30 code 20" class="wp-image-30906" style="object-fit:cover" title="Od kaczek do delegacji, czyli problemy z dziedziczeniem w Javie 24"><figcaption class="wp-element-caption"><em>Listing 20: Klasa ElectricDuck z adnotacją @Delegate</em></figcaption></figure>



<div style="height:34px" aria-hidden="true" class="wp-block-spacer"></div>



<p>Możemy odetchnąć z ulgą, bo wynikowy kod wygląda już o niebo lepiej! Możemy teraz przyjrzeć się efektom pracy i spróbować przejść jeszcze raz wszystkie kroki.</p>



<h2 class="wp-block-heading" id="Czas-na-podsumowanie">Czas na podsumowanie</h2>



<p>Jak pokazał nam przedstawiony przykład, tworząc hierarchię obiektów w Javie, można relatywnie łatwo popełnić błąd przy dziedziczeniu z istniejącej klasy. Co prawda powinna nas chronić przed tym zasada podstawienia Liskov, ale niestety łatwo ją nieświadomie złamać. <strong>Dlatego zamiast prostego dziedziczenia warto rozważyć inne podejścia, takie jak wprowadzenie klasy abstrakcyjnej (prostsze) lub zastąpienie dziedziczenia kompozycją (bardziej złożone, ale dające większą elastyczność).</strong></p>



<p>W przypadku zastosowania kompozycji należy także pamiętać, iż z powodu silnej kontroli typów w Javie, należy stworzyć interfejs zawierający wspólne metody klas, tak aby w przyszłości nie zamykać sobie drogi do zamiany obiektu jednego typu na obiekt drugiego typu. Z kolei nadmiarowy kod spowodowany użyciem delegatów można skrócić z wykorzystaniem (eksperymentalnej co prawda) adnotacji&nbsp;@Delegate&nbsp;z Lomboka. Wymaga to czasami ekstrakcji dodatkowych interfejsów w delegacie, tak aby można było zastosować wzorzec strategii, ale w efekcie końcowym otrzymujemy maksymalnie prosty i elastyczny kod. Warto więc rozważyć i tę opcję.</p>



<p>Oczywiście kod zawarty w niniejszym artykule jest dostępny publicznie w moim&nbsp;<a href="https://github.com/chrosciu/ducks" target="_blank" rel="noopener">repozytorium na GitHubie</a>. Zapraszam zatem do klonowania i eksperymentowania na własną rękę. Przyjemnego tworzenia hierarchii i niech Wam obiekty lekkimi będą!</p>



<h3 class="wp-block-heading"><strong>Literatura</strong></h3>



<p>[1] „Barbara Liskov [online]. Wikipedia: wolna encyklopedia”,, 2020-07-13 12:48Z. [dostęp: 2020-07-20 13:24Z]. <a href="https://pl.wikipedia.org/wiki/Barbara_Liskov?oldid=60392345" target="_blank" rel="noopener">Dostępny w Internecie</a>.<br>[2] „Zasada podstawienia Liskov [online]. Wikipedia, wolna encyklopedia”, 2020-04-17 21:56Z. [dostęp: 2020-07-17 13:45Z]. <a href="https://pl.wikipedia.org/wiki/Zasada_podstawienia_Liskov?oldid=%2059480242" target="_blank" rel="noopener">Dostępny w Internecie</a>.<br>[3] Wikipedia contributors, „Liskov substitution principle — <a href="https://en.wikipedia.org/w/index.php?title=Liskov_substitution_principle&amp;oldid=966496218" target="_blank" rel="noopener">Wikipedia, the free encyclopedia</a>”, 2020. [Online; accessed 17July-2020].<br>[4] „Agregacja (programowanie obiektowe) [online]. Wikipedia, Wolna encyklopedia”, 2020-03-20 12:29Z. [dostęp: 2020-07-20 10:36Z]. <a href="https://pl.wikipedia.org/wiki/Agregacja_(programowanie_obiektowe)%20?oldid=59130793" target="_blank" rel="noopener">Dostępny w Internecie</a>.<br>[5] Wikipedia contributors, „Composition over inheritance — <a href="https://en.wikipedia.org/w/index.php?title=Composition_over_inheritance&amp;oldid=967172104" target="_blank" rel="noopener">Wikipedia, the free encyclopedia</a>” [Online; accessed 20-July-2020].<br>[6] „Duck typing [online]&#8221;. Wikipedia, wolna encyklopedia, 2020-04-17 21:54Z. [dostęp: 2020-07-20 12:06Z]. <a href="https://pl.wikipedia.org/wiki/Duck_typing?oldid=59480107" target="_blank" rel="noopener">Dostępny w Internecie</a>.</p>



<p></p>
]]></content:encoded>
					
					<wfw:commentRss>https://nearshore-it.eu/pl/artykuly/od-kaczek-do-delegacji-czyli-problemy-z-dziedziczeniem-w-javie/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Porty i adaptery w praktyce</title>
		<link>https://nearshore-it.eu/pl/artykuly/porty-i-adaptery-w-praktyce/</link>
					<comments>https://nearshore-it.eu/pl/artykuly/porty-i-adaptery-w-praktyce/#respond</comments>
		
		<dc:creator><![CDATA[Paweł Witkowski]]></dc:creator>
		<pubDate>Tue, 24 Sep 2019 03:47:27 +0000</pubDate>
				<category><![CDATA[Artykuły]]></category>
		<category><![CDATA[Technologie]]></category>
		<category><![CDATA[Java]]></category>
		<guid isPermaLink="false">https://nearshore-it.eu/artykuly/porty-i-adaptery-w-praktyce/</guid>

					<description><![CDATA[Podczas tworzenia systemów informatycznych pojawiają się pytania dotyczące wyboru architektury i organizacji kodu. W dzisiejszym artykule chciałbym bliżej przedstawić architekturę portów i adapterów (ports &#038; adapters) w praktyce oraz rozwiać wszelkie wątpliwości związane z tym wzorcem. Jakie są największe zalety architektury tupu porty i adaptery? Czy sprawdzi się ona w każdym przypadku?]]></description>
										<content:encoded><![CDATA[
<div class="table-of-contents">
    <p class="title">Idź do:</p>
    <ol>
                    <li><a href="#Architektura-wzorca-porty-i-adaptery">1.  Architektura wzorca porty i adaptery</a></li>
                    <li><a href="#Porty-i-adaptery-przykładowa-implementacja">2.  Porty i adaptery – przykładowa implementacja</a></li>
                    <li><a href="#Architektura-hexagonalna-organizacja-i-opis-pakietów">3.  Architektura hexagonalna – organizacja i opis pakietów</a></li>
                    <li><a href="#Architektura-hexagonalna-opis-implementacji-klas">4.  Architektura hexagonalna – opis implementacji klas</a></li>
                    <li><a href="#Porty-i-adaptery-najczęstsze-pytania">5.  Porty i adaptery – najczęstsze pytania</a></li>
                    <li><a href="#Podsumowanie">6.  Podsumowanie</a></li>
            </ol>
</div>


<h2 class="wp-block-heading" id="Architektura-wzorca-porty-i-adaptery">Architektura wzorca porty i adaptery</h2>



<p>Wzorzec <strong>porty i adaptery (ang. ports &amp; adapters) </strong>określany również jako architektura hexagonalna (ang. <strong>hexagonal architecture) </strong>to nic innego jak wzorzec narzucający sposób budowy i organizacji kodu aplikacji. Głównym założeniem tego wzorca jest tworzenie kodu w taki sposób, aby maksymalnie odseparować implementację logiki biznesowej od wszelkich zależności zewnętrznych, takich jak frameworki, bazy danych, usługi zewnętrzne itp. Dzięki temu zyskujemy większą kontrolę nad kodem i niezależność od zewnętrznych bibliotek oraz wprowadzanych w nich zmian.&nbsp;Przyjrzyjmy się bliżej wzorcowi:</p>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image"><img decoding="async" src="https://nearshore-it.eu/wp-content/uploads/2024/09/jpro_graphic_ports_adapters.png" alt="Porty i adaptery" class="wp-image-24109" title="Porty i adaptery w praktyce 25"></figure>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<p><strong>Wzorzec portów i adapterów dzieli strukturę kodu na dwa obszary:</strong></p>



<ul class="wp-block-list">
<li>wewnętrzny (application / domain)</li>



<li>zewnętrzny (infrastructure)</li>
</ul>



<p>Obszar wewnętrzny skupia się na rozwiązaniu i implementacji głównego problemu (use case). Obszar ten nie ma żadnych odniesień do frameworków, baz danych i innych usług lub bibliotek zewnętrznych, ani nie czerpie z nich. Obszar zewnętrzny z kolei zawiera implementację portów w postaci adapterów oraz klasy związane z frameworkami, jak na przykład Spring, Hibernate itp. Komunikacja pomiędzy obszarem wewnętrznym i zewnętrznym realizowana jest za pomocą portów i ich implementacji, czyli adapterów (stąd też nazwa wzorca).</p>



<p>Kilka podstawowych założeń architektury typu porty i adaptery:</p>



<ol class="wp-block-list">
<li>Obszar wewnętrzny, czyli właściwa implementacja logiki, „nic nie wie” o obszarze zewnętrznym. Nie ma zależności pomiędzy tym obszarem a frameworkami (jak wspomniane Spring, Hibernate itp.).</li>



<li>Logika rozwiązania problemu zamknięta jest w obszarze wewnętrznym. Dostęp do niej mamy wyłącznie za pośrednictwem klasy fasady domenowej, o której piszę więcej w dalszej części artykułu.</li>
</ol>



<h2 class="wp-block-heading" id="Porty-i-adaptery-przykładowa-implementacja">Porty i adaptery – przykładowa implementacja</h2>



<p>Głównym celem przykładu jest zaprezentowanie implementacji klas i organizacja pakietów w oparciu o idee architektury typu ports &amp; adapters. Za przykład niech posłuży obszar domeny odpowiedzialny za rejestrację nowych użytkowników w systemie. Zaimplementowane zostały tutaj dwa przypadki użycia:</p>



<ul class="wp-block-list">
<li>rejestracja nowego użytkownika – obejmuje funkcjonalności związane z wygenerowaniem kodu aktywacji konta oraz wysłanie maila aktywacyjnego.</li>



<li>aktywacja konta użytkownika – weryfikuje wygenerowany kod i aktywuje konto oraz wysyła komunikat do systemu zewnętrznego.</li>
</ul>



<h2 class="wp-block-heading" id="Architektura-hexagonalna-organizacja-i-opis-pakietów">Architektura hexagonalna – organizacja i opis pakietów</h2>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>


<div class="wp-block-image">
<figure class="aligncenter"><img decoding="async" src="https://nearshore-it.eu/wp-content/uploads/2024/09/jpro_graphic_2_ports_adapters.png" alt="Porty i adaptery " class="wp-image-24110" title="Porty i adaptery w praktyce 26"></figure></div>


<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<ol class="wp-block-list">
<li>Pakiet: <strong>user</strong></li>
</ol>



<p>To główny pakiet domeny, w obrębie której będziemy się poruszali. Czyli domeny użytkowników. Pakiet ten zawiera dwa podpakiety: <strong>crud </strong>oraz <strong>registration&nbsp;</strong></p>



<ol start="2" class="wp-block-list">
<li>Pakiet: <strong>user.crud&nbsp;</strong></li>
</ol>



<p>W pakiecie tym została zamknięta logika związana z prostymi operacjami pobierania danych. Ponadto może on zawierać inne operacje, które nie posiadają złożonej logiki biznesowej i służą wyłącznie prostym operacjom typu CRUD (od: <strong><em>c</em></strong><em>reate,&nbsp;<strong>r</strong>ead,&nbsp;<strong>u</strong>pdate and&nbsp;<strong>d</strong>elete)</em>.</p>



<ol start="3" class="wp-block-list">
<li>Pakiet: <strong>user.registration&nbsp;</strong></li>
</ol>



<p>Ten pakiet zawiera wszystkie klasy związane z logiką rejestracji nowych użytkowników w aplikacji (implementacja i obsługa wspomnianych wcześniej przypadków użycia).</p>



<ol start="4" class="wp-block-list">
<li>Pakiet: <strong>user.registration.domain</strong></li>
</ol>



<p>Pakiet zawiera klasy z główną implementację logiki biznesowej oraz definicje <strong>portów</strong> (interfejsy Java), za pośrednictwem których odbywa się komunikacja z innymi komponentami systemu. Pakiet <strong>core.user.registration.domain</strong> zawiera kod vanilla Java, tzn. kod, który nie jest zależny od frameworków i innych bibliotek zewnętrznych.&nbsp;Jedynym punktem dostępu do zaimplementowanej logiki w tym pakiecie jest klasa fasady. Co ważne: to, jakich bibliotek będziemy używali (np.: commons-lang, Dozer, Orika) wewnątrz pakietu, zależy od zespołu i ogólnych ustaleń w projekcie.</p>



<ol start="5" class="wp-block-list">
<li>Pakiet: <strong>user.registration.infrastructure</strong></li>
</ol>



<p>Pakiet ten zawiera implementację <strong>adapterów</strong>, które wykorzystywane są za pośrednictwem zdefiniowanych w kodzie domeny portów. W pakiecie zamknięta jest implementacja i konfiguracja komponentów korzystających z funkcji i metod frameworków. Często używane są tutaj biblioteki innych dostawców rozwiązań, które są odpowiedzialne np. za generowanie plików PDF, wysyłanie maili czy komunikację z systemami zewnętrznymi, takimi jak Kafka, SOAP itp.</p>



<ol start="6" class="wp-block-list">
<li>Pakiet: <strong>user.registration.infrastructure.config</strong></li>
</ol>



<p>W pakiecie tym powinna znaleźć się konfiguracja związana z tworzeniem i obsługą komponentów wykorzystywanego frameworka.</p>



<ol start="7" class="wp-block-list">
<li>Pakiet: <strong>user.registration.infrastructure.entrypoint</strong></li>
</ol>



<p>Pakiet ten zawiera klasy kontrolerów i klasy typu DTO, za pośrednictwem których inne systemy czy moduły mogą korzystać z funkcji naszej domeny. Klasy DTO opisują struktury danych wejściowych i wyjściowych dla REST API.<strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </strong></p>



<ol start="8" class="wp-block-list">
<li>Pakiet: <strong>user.registration.infrastructure.repository</strong></li>
</ol>



<p>Pakiet klas związanych z warstwą persystencji,&nbsp;czyli klasy odpowiedzialne za pobieranie i zapisywanie danych w bazie. Są to definicje modelu danych (ORM), klasy DAO. Pakiet ten zawiera m.in. implementację klasy adaptera dostępu do danych. W bardziej rozbudowanych przypadkach możemy mieć więcej klas modelu lub odwoływać się do klas modelu (ORM) z innych pakietów.</p>



<h2 class="wp-block-heading" id="Architektura-hexagonalna-opis-implementacji-klas">Architektura hexagonalna – opis implementacji klas</h2>



<ol class="wp-block-list">
<li>Klasy z pakietu <strong>user.registration.domain</strong>:</li>
</ol>



<ul class="wp-block-list">
<li><strong>UserRegistration </strong>– główna klasa implementacji logiki biznesowej. Dostęp do klasy ograniczony na poziomie pakietu.</li>



<li><strong>UserRegistrationDataProvider </strong>– port dla operacji wejścia / wyjścia (we/wy) związanych z dostępem do bazy danych,</li>



<li><strong>UserRegistrationNotifier </strong>– port wyjściowy do wysyłania komunikatów na kolejkę,</li>



<li><strong>ConfirmationMailSender </strong>– port wyjściowy do wysyłania wiadomości mailem.</li>
</ul>



<p>Wyżej wymienione porty to publiczne interfejsy klas Java, których implementacja odbywa się na poziomie pakietów infrastruktury.</p>



<p><strong>UserRegistrationFacade </strong>– fasada domeny. Klasa, za pośrednictwem której mamy dostęp do metod (funkcji) domeny. W przedstawionym przykładzie klasa fasady pełni funkcję wywołującą dla klasy <strong>UserRegistration, </strong>czyli pełni dla niej funkcję wrappera. W bardziej złożonych przypadkach możemy posiadać więcej klas zawierających logikę biznesową. Wówczas fasada stanowi punkt dostępu do wywołań wszystkich tych funkcji domeny. Czasami może się zdarzyć, że będziemy potrzebowali dołożyć na tym etapie określone walidacje związane z frameworkami. Może być to podyktowane tym, że niektóre inne obszary domenowe będą potrzebowały wykorzystać logikę z innej domeny. Można wówczas na poziomie fasady korzystać z funkcji walidacji. Oczywiście wszystko podobnie jak we wspomnianych wcześniej przypadkach zależy od ogólnych ustaleń i założeń projektowych w zespole.</p>



<ol start="2" class="wp-block-list">
<li>Klasy z pakietu <strong>user.registration.infrastructure</strong></li>
</ol>



<p>Implementacja adapterów:</p>



<ul class="wp-block-list">
<li><strong>ConfirmationMailSenderAdapter</strong></li>



<li><strong>UserRegistrationNotifierAdapter</strong></li>



<li><strong>UserRegistrationDataProviderAdapter</strong></li>
</ul>



<ol start="3" class="wp-block-list">
<li>Klasa <strong>UserRegistrationService </strong>jest odpowiedzialna za transakcyjność wykonywanych operacji. Klasa ta za pośrednictwem klasy fasady <strong>UserRegistrationFacade</strong> wywołuje kod logiki biznesowej.&nbsp;W przypadku bardziej złożonych operacji na poziomie tej klasy mogą być wstrzykiwane fasady pochodzące z innych obszarów.</li>



<li>Klasy z pakietu <strong>user.registration.entrypoint.</strong></li>



<li>Klasa kontrolera <strong>UserRegistrationController </strong>wystawia REST API. Używa klasy <strong>UserRegistrationService&nbsp;realizującej</strong> operacje wymagające. transakcji. W przypadku gdy operacje nie wymagają od nas transakcji, możemy w klasie tej bezpośrednio korzystać z klasy fasady.</li>
</ol>



<p>W przykładowej implementacji pakietu domain widać dużą liczbę klas – jest to jeden z atrybutów tego wzorca. Dzięki temu uzyskujemy hermetyczność implementacji logiki biznesowej i struktur z nią związanych. Punktem dostępu do funkcji domeny jest klasa fasady. Z założenia klasy pakietu domain nie powinny używać klas frameworków, stąd też większa liczba klas POJO (plain old Java object) związanych z danymi. W wypadku złożonych przypadków użycia można tworzyć większą liczbę klas z implementacją logiki biznesowej. W przykładzie można np. wydzielić aktywację konta do osobnej klasy.</p>



<p><strong>Przeczytaj także: <a href="https://nearshore-it.eu/pl/artykuly/test-driven-development-na-co-dzien">Test-Driven Development na co dzień</a></strong></p>



<h2 class="wp-block-heading" id="Porty-i-adaptery-najczęstsze-pytania">Porty i adaptery – najczęstsze pytania</h2>



<p><strong>Dlaczego musimy ograniczać dostęp do niektórych klas na poziomie pakietu?</strong></p>



<p>Za pomocą modyfikatorów dostępu do klas i metod ukrywamy szczegóły implementacji – czyli stosujemy tzw. hermetyzację klas. Zapewniamy tym samym kontrolę nad dostępem, stanem i zachowaniem obiektu. &nbsp;W naszym przykładzie w pakiecie domain dostęp publiczny posiadają: klasa fasady oraz klasy reprezentujące dane wejściowe i wyjściowe. Cała implementacja logiki jest zamknięta na poziomie pakietu i dostęp do operacji jest możliwy wyłącznie za pośrednictwem metod zdefiniowanych w klasie fasady.</p>



<p><strong>Co z bibliotekami typu Lombok, JSR 303 (walidacja) lub loggerami w pakiecie domain?</strong></p>



<p>Zgodnie z główną ideą architektury hexagonalnej nie powinniśmy używać bibliotek zewnętrznych. Praktyka dowodzi jednak czegoś innego. To, jakich bibliotek użyjemy wewnątrz domeny, zależy od decyzji zespołu, gdyż każda osoba w zespole ma inne doświadczenia i pomysły. Warto jednak zastosować pewne ograniczenia co do tych narzędzi. W projektach, w których brałem udział, ograniczaliśmy się głównie do bibliotek typu java commons, biblioteki mapperów oraz walidacji.</p>



<p><strong>Porty i adaptery – gdzie zakładać transakcje?</strong></p>



<p>Jednym z ważniejszych elementów implementacji operacji jest ich transakcyjność.<br>Często wymagana operacja będzie potrzebowała wykorzystać funkcję z innej domeny kodu lub będziemy chcieli wywołać funkcję domeny w transakcji. Wówczas musimy zapewnić transakcyjność dla wywołań tych funkcji. Dla takiego przypadku można zbudować dedykowany serwis, który będzie zawierał klasy fasad domenowych.<br>W przykładzie serwis został zaimplementowany w klasie <strong>UserRegistrationService.</strong></p>



<p><strong>Dlaczego nie powinniśmy zakładać transakcji w klasie fasady?</strong></p>



<p>Brak transakcji w klasie fasady wynika z założenia, że kod w pakiecie domain ma być wolny od wszelkich frameworków.</p>



<p><strong>Czy można używać DDD razem ze wzorcem ports &amp; adapters?</strong></p>



<p>DDD (Domain-Driven Design) skupia się na domenie i zawartej w niej logice biznesowej. Nie ma nic wspólnego z frameworkami i transakcjami. W przykładzie część związana z DDD została zaimplementowana w pakiecie domain. Wzorzec ports &amp; adapters pomaga nam uporządkować kod i odseparować dostęp do zaimplementowanej logiki. Można stwierdzić, że wzorzec ten bardziej odpowiada za warstwę aplikacyjną rozwiązania, ponieważ odpowiada m.in. za dostarczenie mechanizmów konfiguracji, transakcji czy persystencji. Podejście DDD oraz wzorzec ports &amp; adapters współgrają ze sobą w strukturach kodu. DDD rozwiązuje problem logiczny, a P&amp;A zapewnia dostęp do technicznych mechanizmów i bibliotek.</p>



<p><strong>Czy zawsze powinniśmy stosować wzorzec ports &amp; adapters?</strong></p>



<p>Jeżeli zastanawiamy się, kiedy stosować architekturę hexagonalną, decydujący będzie aspekt logiki biznesowej. Wzorzec ports &amp; adapters idealnie sprawdzi się w przypadku rozbudowanej logiki biznesowej, gdy chcemy skupić się na rozwiązaniu problemów, które zostały tam postawione. Kod jest wolny od wszelkich frameworków, dzięki czemu łatwo się nim zarządza i testuje. jest to, że testy uruchamia się szybko i pisze łatwo. Piszemy mniej testów integracyjnych – dużą część logiki pokrywają testy jednostkowe. W testach integracyjnych weryfikujemy krytyczne ścieżki.</p>



<p>Podejście to narzuca nam tworzenie większej liczby klas w celu odseparowania się od reszty kodu spoza pakietu, co na pierwszy rzut oka wydaje się nadmiarowe. Dzięki temu jednak łatwiej jest wydzielić logikę do osobnych niezależnych modułów (w architekturach mikroserwisowych często pojawia się potrzeba wydzielenia logiki do osobnej usługi).</p>



<p>W przypadku aplikacji, które posiadają mało logiki biznesowej lub wręcz jej nie ma (aplikacje typu CRUD), lepszym podejściem jest budowa struktury kodu w formie wielowarstwowej (Controller – Service – Repository). W przykładzie został wydzielony pakiet CRUD, w którym zaimplementowana została prosta operacja pobrania listy użytkowników.</p>



<h2 class="wp-block-heading" id="Podsumowanie">Podsumowanie</h2>



<p>Mam nadzieję, że udało mi się przedstawić główne idee budowy kodu w architekturze portów i adapterów oraz odpowiedzieć na część pytań, które mogą pojawić się podczas implementacji. Oczywiście w każdym projekcie może wyglądać to inaczej. Wszystko zależy od Was. To zespół tworzy oprogramowanie – organizacja i struktura kodu powinna być czytelna dla wszystkich i umożliwiać wygodną pracę. Tak naprawdę to, jak zaimplementowany zostanie wzorzec, zależy więc od zespołu i jego decyzji.</p>



<p><strong>Zobacz więcej: </strong></p>



<ul class="wp-block-list">
<li><strong><a href="https://github.com/pwitkowsdev/jc-ports-and-adapters" target="_blank" rel="noopener">przykładowa implementacja aplikacji</a></strong></li>



<li><strong><a href="https://nearshore-it.eu/pl/artykuly/clean-architecture">Clean architecture</a></strong></li>
</ul>



<p></p>
]]></content:encoded>
					
					<wfw:commentRss>https://nearshore-it.eu/pl/artykuly/porty-i-adaptery-w-praktyce/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Szaleństwo mikroserwisów</title>
		<link>https://nearshore-it.eu/pl/artykuly/szalenstwo-mikroserwisow/</link>
					<comments>https://nearshore-it.eu/pl/artykuly/szalenstwo-mikroserwisow/#respond</comments>
		
		<dc:creator><![CDATA[Dariusz Zbyrad]]></dc:creator>
		<pubDate>Wed, 30 May 2018 01:00:00 +0000</pubDate>
				<category><![CDATA[Artykuły]]></category>
		<category><![CDATA[Technologie]]></category>
		<category><![CDATA[Java]]></category>
		<guid isPermaLink="false">https://nearshore-it.eu/artykuly/szalenstwo-mikroserwisow/</guid>

					<description><![CDATA[Zainteresowanie mikroserwisami rośnie systematycznie od kilku lat. Czy są one jednak rzeczywiście panaceum na całe zło, jak twierdzą niektórzy, czy też może nieumiejętne użyte potrafią wyrządzić więcej szkody niż pożytku? W tym artykule postanowiłem krytycznie spojrzeć na temat mikroserwisów i odpowiedzieć na powyższe pytania.]]></description>
										<content:encoded><![CDATA[
<div class="table-of-contents">
    <p class="title">Przejdź do:</p>
    <ol>
                    <li><a href="#Mikroserwis-czyli-czy-rozmiar-ma-znaczenie">1.  Mikroserwis, czyli czy rozmiar ma znaczenie</a></li>
                    <li><a href="#Microserwis-vs-aplikacja-monolityczna">2.  Microserwis vs aplikacja monolityczna</a></li>
                    <li><a href="#Ograniczenia-architektury-mikroserwisowej">3.  Ograniczenia architektury mikroserwisowej</a></li>
                    <li><a href="#Bledne-zalozenia">4.  Błędne założenia</a></li>
                    <li><a href="#Mikroserwisy-czy-rozproszony-monolit">5.  Mikroserwisy czy rozproszony monolit?</a></li>
                    <li><a href="#Od-monolitu-do-mikroserwisow">6.  Od monolitu do mikroserwisów</a></li>
            </ol>
</div>


<p></p>



<p class="MsoNormal">Na początku należałoby jednak znaleźć odpowiedź na jeszcze inne pytanie: skąd taka popularność architektury mikroserwisowej? Odpowiedź wydaje się dosyć prosta: programiści zazwyczaj nie przepadają za rozwojem i utrzymaniem dużych, ciężkich projektów, a idea mikroserwisów zakłada rozwój niezależnych, małych projektów, nic więc dziwnego, że dla wielu z nich wydaje się być strzałem w dziesiątkę.</p>



<h2 class="wp-block-heading" id="Mikroserwis-czyli-czy-rozmiar-ma-znaczenie">Mikroserwis, czyli czy rozmiar ma znaczenie</h2>



<p class="MsoNormal">Ale co to właściwie znaczy, że pojedynczy mikroserwis jest mały? W Internecie można znaleźć wiele absurdalnych pomysłów na ten temat. Jedni uważają, że mikroserwis powinien mieć nie więcej niż tysiąc linii kodu. Inni, że zespół, który go tworzy, powinien być w stanie go napisać, żywiąc się przy tym jedynie trzema pizzami. Inny pomysł jest taki, że mikroserwis powinien być na tyle mały, żeby można go przepisać w ciągu jednego scrumowego sprintu, czyli około dwóch tygodni. Ja osobiście uważam, że mikroserwis powinien być tak mały, jak to możliwe i tylko tak duży, jak to jest absolutnie niezbędne.</p>



<p class="MsoNormal">Oczywiście rozmiar to tylko jeden z aspektów, który opisuje mikroserwisy. Mikroserwis poza tym powinien cechować się także pojedynczą odpowiedzialnością, czyli być zbudowany w oparciu o pojedynczą domenę biznesową. Jego implementacja powinna być ukryta, czyli komunikacja pomiędzy mikroseriwsami powinna się odbywać wyłącznie w oparciu o ustalony kontrakt. Kolejne cechy to niezależność wdrażania oraz odporność na awarie. Ta ostatnia cecha oznacza, że awaria jednego mikroserwisu nie powinna wpływać na pozostałe.</p>



<h2 class="wp-block-heading" id="Microserwis-vs-aplikacja-monolityczna">Microserwis vs aplikacja monolityczna</h2>



<p class="MsoNormal">Jeśli weźmiemy pod uwagę jedynie powyższe cechy, możemy dojść do pochopnego wniosku, że mikroserwisy w porównaniu do tradycyjnej, monolitycznej architektury, rzeczywiście zawsze wypadają znacznie lepiej. Programiści dostają to, czego chcieli, ale i biznes powinien być usatysfakcjonowany, ponieważ dostaje skalowalną i odporną na awarie aplikację. Niestety jest tak głównie w teorii, ponieważ praktyka przynosi wiele problemów i zagrożeń.</p>



<h2 class="wp-block-heading" id="Ograniczenia-architektury-mikroserwisowej">Ograniczenia architektury mikroserwisowej</h2>



<p class="MsoNormal">Największe wyzwanie związane z architekturą mikroserwisową dotyczy spójności danych. W systemach rozproszonych nie jest możliwe jednoczesne osiągnięcie spójności, dostępności i odporności na podział, musimy zawsze dokonać wyboru dwóch z pośród tych trzech cech. Jeżeli założymy, że w aplikacjach rozproszonych zawsze występuje podział sieci i odporność na nią musi być zapewniona, to do wyboru pozostaje spójność lub dostępność. W praktyce najczęściej wybierana jest dostępność kosztem spójności, co oznacza problemy dla biznesu, ponieważ może występować czasowa niespójność danych. Możliwe jest również utrzymanie spójności, ale bez gwarancji, że system będzie zawsze dostępny w 100%.</p>



<p><strong>Przeczytaj także: <a href="https://nearshore-it.eu/pl/artykuly/service-mesh-ale-komu-to-potrzebne/">Wykorzystujesz mikroserwisy? Poznaj Service Mesh i nowe możliwości, jakie daje!</a></strong></p>



<h2 class="wp-block-heading" id="Bledne-zalozenia">Błędne założenia</h2>



<p class="MsoNormal">Dodatkowo w dobie popularnych i ogólnodostępnych chmur obliczeniowych zbyt wiele osób zapomina o komunikacji sieciowej i problemach, jakie może ona stwarzać. Dwie aplikacje, które się ze sobą komunikują, nie robią tego w sposób magiczny. W tej komunikacji trzeba uwzględnić co najmniej kilka zagrożeń, które niestety zazwyczaj są bagatelizowane. Najczęściej występujące błędne założenia, dotyczące komunikacji między aplikacjami, zostały wskazane przez L. Petera Deutscha:</p>



<ul class="wp-block-list">
<li>Sieć jest niezawodna.</li>



<li>Opóźnienie wynosi zero.</li>



<li>Przepustowość jest nieskończona.</li>



<li>Sieć jest bezpieczna.</li>



<li>Topologia się nie zmienia.</li>



<li>Jest jeden administrator.</li>



<li>Koszt transportu wynosi zero.</li>



<li>Sieć jest jednorodna.</li>
</ul>



<p class="MsoNormal"><span style="text-indent: -18pt;">Jeżeli powyższe błędne założenia o sieci nie zostaną zweryfikowane i aplikacja rozproszona nie zostanie na nie odpowiednio przygotowana, to z dużym prawdopodobieństwem problemy w komunikacji pomiędzy mikroserwisami pojawią się szybciej niż się tego spodziewamy.</span></p>



<h2 class="wp-block-heading" id="Mikroserwisy-czy-rozproszony-monolit">Mikroserwisy czy rozproszony monolit?</h2>



<p class="MsoNormal">Jest jeszcze jeden często pojawiający się problem. Jak napisałem na początku tego artykułu, każdy mikroserwis powinien być związany z pojedynczą odpowiedzialnością, czyli być związany ściśle z określoną domeną biznesową. Ale nowo tworzone systemy mają to do siebie, że wymagania względem nich często się zmieniają, co może powodować zamazywanie granicy pomiędzy poszczególnymi mikroserwisami, poprzez migrację wzajemnych odpowiedzialności. Skutek jest taki, że system składa się wprawdzie z wielu mikroserwisów, ale każdy z nich odpowiada za wszystko. Nie ma to oczywiście nic wspólnego z aplikacją mikroserwisową, powstaje natomiast rozproszony monolit.</p>



<h2 class="wp-block-heading" id="Od-monolitu-do-mikroserwisow">Od monolitu do mikroserwisów</h2>



<p class="MsoNormal">Celem tego artykułu nie było przekonanie czytelnika do tego, że mikroserwisy są dobre lub złe, ale uświadomienie, jakie problemy mogą powodować. A także tego, że przejście z architektury monolitycznej na mikroserwisową nie rozwiązuje z automatu wszystkich problemów, a jedynie przenosi je w inne miejsce. Z drugiej jednak strony, jeżeli podejdziemy do mikroserwisów w sposób odpowiedzialny i przemyślany, to może się to okazać bardzo dobry wybór. Uważam jednak, że w przypadku nowych projektów warto rozważyć rozpoczęcie od monolitycznej architektury i przejście na mikroserwisową po wstępnej fazie rozwoju aplikacji, kiedy główne wymagania nie będą się już zmieniać tak często, a granica pomiędzy domenami nie będzie przesuwana. Zawsze bowiem łatwiej będzie nam wydzielić domeny i określić granice w monolicie, czyli czymś, co już istnieje, niż dzielić coś, czego jeszcze nawet nie ma.</p>



<p></p>
]]></content:encoded>
					
					<wfw:commentRss>https://nearshore-it.eu/pl/artykuly/szalenstwo-mikroserwisow/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
