<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Patryk Dobrowolski - Blog]]></title><description><![CDATA[Patryk Dobrowolski - Blog]]></description><link>https://blog.patrykdobrowolski.net</link><generator>RSS for Node</generator><lastBuildDate>Sun, 19 Apr 2026 11:25:49 GMT</lastBuildDate><atom:link href="https://blog.patrykdobrowolski.net/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[SRP - Reguła Jednej Odpowiedzialności]]></title><description><![CDATA[W świecie programowania obiektowego, zasady SOLID to fundament, na którym budujemy czysty, skalowalny i łatwy w utrzymaniu kod. Dziś przyjrzymy się pierwszej i być może najważniejszej z nich: Regule Jednej Odpowiedzialności (Single Responsibility Pri...]]></description><link>https://blog.patrykdobrowolski.net/srp-regula-jednej-odpowiedzialnosci</link><guid isPermaLink="true">https://blog.patrykdobrowolski.net/srp-regula-jednej-odpowiedzialnosci</guid><category><![CDATA[single responsibility principle]]></category><category><![CDATA[SOLID principles]]></category><category><![CDATA[Java]]></category><category><![CDATA[clean code]]></category><category><![CDATA[oop]]></category><category><![CDATA[OOP Design Principles]]></category><dc:creator><![CDATA[Patryk Dobrowolski]]></dc:creator><pubDate>Tue, 15 Jul 2025 09:42:49 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1752572279353/3038a1e8-4552-489a-bbf5-0391c4586330.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>W świecie programowania obiektowego, zasady SOLID to fundament, na którym budujemy czysty, skalowalny i łatwy w utrzymaniu kod. Dziś przyjrzymy się pierwszej i być może najważniejszej z nich: <strong>Regule Jednej Odpowiedzialności</strong> (Single Responsibility Principle - SRP). Co tak naprawdę oznacza i dlaczego jej ignorowanie może prowadzić do poważnych problemów w projekcie?</p>
<h3 id="heading-czym-jest-regula-jednej-odpowiedzialnosci">Czym jest Reguła Jednej Odpowiedzialności?</h3>
<p>Zasada sformułowana przez Roberta C. Martina (znanego jako "Wujek Bob") jest zwodniczo prosta:</p>
<blockquote>
<p><strong>Klasa powinna mieć tylko jeden powód do zmiany.</strong></p>
</blockquote>
<p>Co to oznacza w praktyce? Każda klasa w Twojej aplikacji powinna mieć jedną, jasno zdefiniowaną odpowiedzialność. Nie chodzi o to, by klasa miała tylko jedną metodę, ale o to, by wszystkie jej metody i pola były spójne i służyły jednemu, konkretnemu celowi. Jeśli możesz wskazać więcej niż jeden powód, dla którego klasa mogłaby wymagać modyfikacji w przyszłości, to znak, że łamiesz SRP.</p>
<p>Pomyśl o tym jak o szwajcarskim scyzoryku. Jest świetny na biwaku, ale w kuchni do krojenia chleba użyjesz noża do chleba, a do otwierania wina – korkociągu. Każde z tych narzędzi jest wyspecjalizowane i robi jedną rzecz naprawdę dobrze. Tak samo powinno być z Twoimi klasami.</p>
<h3 id="heading-przyklad-jak-zlamac-zasade-srp">Przykład: Jak złamać zasadę SRP?</h3>
<p>Wyobraźmy sobie klasę, która ma zarządzać danymi pracownika. Na pierwszy rzut oka, poniższy kod może wydawać się w porządku.</p>
<p><strong>Przykład złego kodu (naruszenie SRP):</strong></p>
<pre><code class="lang-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Pracownik</span> </span>{
    <span class="hljs-keyword">private</span> String imie;
    <span class="hljs-keyword">private</span> String stanowisko;
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">double</span> pensja;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">Pracownik</span><span class="hljs-params">(String imie, String stanowisko, <span class="hljs-keyword">double</span> pensja)</span> </span>{
        <span class="hljs-keyword">this</span>.imie = imie;
        <span class="hljs-keyword">this</span>.stanowisko = stanowisko;
        <span class="hljs-keyword">this</span>.pensja = pensja;
    }

    <span class="hljs-comment">// Odpowiedzialność 1: Logika biznesowa</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">awansuj</span><span class="hljs-params">(String noweStanowisko, <span class="hljs-keyword">double</span> podwyzka)</span> </span>{
        <span class="hljs-keyword">this</span>.stanowisko = noweStanowisko;
        <span class="hljs-keyword">this</span>.pensja += podwyzka;
        System.out.println(imie + <span class="hljs-string">" awansował na stanowisko: "</span> + noweStanowisko);
    }

    <span class="hljs-comment">// Odpowiedzialność 2: Zapis do bazy danych</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">zapiszWBazieDanych</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-comment">// Logika łącząca się z bazą danych i zapisująca obiekt...</span>
        System.out.println(<span class="hljs-string">"Zapisano pracownika "</span> + <span class="hljs-keyword">this</span>.imie + <span class="hljs-string">" w bazie danych."</span>);
    }

    <span class="hljs-comment">// Odpowiedzialność 3: Generowanie raportu</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">generujRaportXML</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-comment">// Logika formatująca dane pracownika do formatu XML...</span>
        <span class="hljs-keyword">return</span> <span class="hljs-string">"&lt;pracownik&gt;&lt;imie&gt;"</span> + <span class="hljs-keyword">this</span>.imie + <span class="hljs-string">"&lt;/imie&gt;&lt;stanowisko&gt;"</span> + <span class="hljs-keyword">this</span>.stanowisko + <span class="hljs-string">"&lt;/stanowisko&gt;&lt;/pracownik&gt;"</span>;
    }
}
</code></pre>
<p>Ta klasa ma aż <strong>trzy różne powody do zmiany</strong>:</p>
<ol>
<li><p><strong>Zmiana logiki biznesowej:</strong> Zmieniają się zasady awansowania pracowników.</p>
</li>
<li><p><strong>Zmiana technologii bazy danych:</strong> Przechodzimy z SQL na NoSQL i metoda <code>zapiszWBazieDanych()</code> musi zostać napisana od nowa.</p>
</li>
<li><p><strong>Zmiana formatu raportowania:</strong> Dział finansowy prosi o raporty w formacie JSON zamiast XML.</p>
</li>
</ol>
<p>Mieszanie tych trzech różnych odpowiedzialności w jednej klasie to prosta droga do kłopotów.</p>
<h3 id="heading-konsekwencje-braku-stosowania-srp">Konsekwencje braku stosowania SRP</h3>
<ul>
<li><p><strong>Trudności w utrzymaniu (wysokie sprzężenie):</strong> Zmiana w jednym obszarze (np. formacie raportu) wymusza modyfikację i ponowne testowanie całej klasy, co zwiększa ryzyko wprowadzenia błędu w zupełnie niepowiązanym module (np. logice biznesowej).</p>
</li>
<li><p><strong>Niska czytelność:</strong> Klasa staje się "boskim obiektem" (God Object), który robi wszystko. Nowym programistom w zespole trudno będzie zrozumieć jej przeznaczenie.</p>
</li>
<li><p><strong>Problemy z testowaniem:</strong> Jak napisać prosty test jednostkowy dla logiki awansu, skoro klasa ma zależności związane z bazą danych? Trzeba tworzyć skomplikowane mocki i zaślepki, co utrudnia proces testowania.</p>
</li>
<li><p><strong>Ograniczona reużywalność:</strong> Chciałbyś ponownie użyć logiki do generowania raportów w innym miejscu aplikacji? Niestety, ciągniesz za sobą cały bagaż związany z danymi pracownika i logiką biznesową.</p>
</li>
</ul>
<h3 id="heading-jak-to-naprawic-refaktoryzacja-z-srp">Jak to naprawić? Refaktoryzacja z SRP</h3>
<p>Zgodnie z zasadą jednej odpowiedzialności, powinniśmy rozbić naszą klasę <code>Pracownik</code> na mniejsze, wyspecjalizowane klasy.</p>
<p><strong>1. Klasa</strong> <code>Pracownik</code> (tylko dane i logika biznesowa) Ta klasa przechowuje już tylko stan obiektu i metody operujące na tym stanie.</p>
<pre><code class="lang-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Pracownik</span> </span>{
    <span class="hljs-keyword">private</span> String imie;
    <span class="hljs-keyword">private</span> String stanowisko;
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">double</span> pensja;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">Pracownik</span><span class="hljs-params">(String imie, String stanowisko, <span class="hljs-keyword">double</span> pensja)</span> </span>{
        <span class="hljs-keyword">this</span>.imie = imie;
        <span class="hljs-keyword">this</span>.stanowisko = stanowisko;
        <span class="hljs-keyword">this</span>.pensja = pensja;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">awansuj</span><span class="hljs-params">(String noweStanowisko, <span class="hljs-keyword">double</span> podwyzka)</span> </span>{
        <span class="hljs-keyword">this</span>.stanowisko = noweStanowisko;
        <span class="hljs-keyword">this</span>.pensja += podwyzka;
    }

}
</code></pre>
<p><strong>Powód do zmiany:</strong> Tylko zmiana w logice biznesowej dotyczącej pracownika.</p>
<p><strong>2. Klasa</strong> <code>PracownikRepository</code> (odpowiedzialność: persystencja) Ta klasa zajmuje się wyłącznie komunikacją z bazą danych.</p>
<pre><code class="lang-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">PracownikRepository</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">zapisz</span><span class="hljs-params">(Pracownik pracownik)</span> </span>{
        <span class="hljs-comment">// Logika zapisu do bazy danych...</span>
        System.out.println(<span class="hljs-string">"Zapisano pracownika "</span> + pracownik.getImie() + <span class="hljs-string">" w bazie danych."</span>);
    }
}
</code></pre>
<p><strong>Powód do zmiany:</strong> Tylko zmiana technologii lub sposobu zapisu danych.</p>
<p><strong>3. Klasa</strong> <code>RaportGenerator</code> (odpowiedzialność: raportowanie) Jej jedynym zadaniem jest tworzenie raportów na podstawie danych pracownika.</p>
<pre><code class="lang-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">RaportGenerator</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">generujRaportXML</span><span class="hljs-params">(Pracownik pracownik)</span> </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-string">"&lt;pracownik&gt;&lt;imie&gt;"</span> + pracownik.getImie() + <span class="hljs-string">"&lt;/imie&gt;&lt;stanowisko&gt;"</span> + pracownik.getStanowisko() + <span class="hljs-string">"&lt;/stanowisko&gt;&lt;/pracownik&gt;"</span>;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">generujRaportJSON</span><span class="hljs-params">(Pracownik pracownik)</span> </span>{
        <span class="hljs-comment">// Logika formatująca do JSON...</span>
        <span class="hljs-keyword">return</span> <span class="hljs-string">"{\"pracownik\":{\"imie\":\""</span> + pracownik.getImie() + <span class="hljs-string">"\",\"stanowisko\":\""</span> + pracownik.getStanowisko() + <span class="hljs-string">"\"}}"</span>;
    }
}
</code></pre>
<p><strong>Powód do zmiany:</strong> Tylko zmiana formatu lub zawartości raportu.</p>
<p>Dzięki takiemu podejściu każda klasa ma <strong>jedną, klarowną odpowiedzialność</strong>. Zmiana wymagań w jednym obszarze dotyka tylko jednej, małej klasy. Kod staje się prostszy do zrozumienia, testowania i ponownego użycia.</p>
<h3 id="heading-podsumowanie">Podsumowanie</h3>
<p>Reguła Jednej Odpowiedzialności to nie tylko akademicka zasada, ale praktyczne narzędzie, które pomaga pisać lepszy kod. Następnym razem, gdy będziesz tworzyć nową klasę lub modyfikować istniejącą, zadaj sobie pytanie: <strong>"Ile powodów do zmiany ma ta klasa?"</strong>. Jeśli odpowiedź brzmi "więcej niż jeden", wiesz już, co robić. Stosowanie SRP to inwestycja, która zwraca się z nawiązką w postaci czystszego i łatwiejszego w utrzymaniu oprogramowania.</p>
]]></content:encoded></item><item><title><![CDATA[Komendy kontra Zdarzenia]]></title><description><![CDATA[W świecie nowoczesnych architektur oprogramowania, zwłaszcza tych opartych o mikrousługi, komunikacja asynchroniczna jest jak system nerwowy – kluczowa dla funkcjonowania całości. Jednak, aby ten system działał sprawnie, musimy posługiwać się precyzy...]]></description><link>https://blog.patrykdobrowolski.net/komendy-kontra-zdarzenia</link><guid isPermaLink="true">https://blog.patrykdobrowolski.net/komendy-kontra-zdarzenia</guid><category><![CDATA[Asynchronous Communication ]]></category><category><![CDATA[event-driven-architecture]]></category><category><![CDATA[design patterns]]></category><category><![CDATA[Microservices]]></category><category><![CDATA[Event Sourcing]]></category><category><![CDATA[#CQRS]]></category><category><![CDATA[message broker]]></category><category><![CDATA[Command pattern]]></category><dc:creator><![CDATA[Patryk Dobrowolski]]></dc:creator><pubDate>Tue, 08 Jul 2025 08:51:37 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1752579043106/a50129f8-3d07-4069-9614-f023c998988a.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>W świecie nowoczesnych architektur oprogramowania, zwłaszcza tych opartych o mikrousługi, komunikacja asynchroniczna jest jak system nerwowy – kluczowa dla funkcjonowania całości. Jednak, aby ten system działał sprawnie, musimy posługiwać się precyzyjnym językiem. Dwa fundamentalne pojęcia, które często bywają mylone, to <strong>komenda (command)</strong> i <strong>zdarzenie (event)</strong>.</p>
<p>Zrozumienie różnicy między nimi oraz tego, kto jest "właścicielem" każdego typu komunikatu, to jeden z najważniejszych kroków do budowy elastycznych i skalowalnych systemów. Zanurzmy się w ten temat.</p>
<h2 id="heading-czym-jest-komenda-pomysl-o-niej-jak-o-rozkazie">Czym jest Komenda? Pomyśl o niej jak o rozkazie.</h2>
<p><strong>Komenda</strong> to dyrektywa. To prośba o wykonanie konkretnej akcji, która ma zmienić stan systemu w przyszłości.</p>
<ul>
<li><p><strong>Intencja:</strong> "Zrób coś!"</p>
</li>
<li><p><strong>Charakter:</strong> Jest imperatywna i skierowana do jednego, konkretnego odbiorcy. Nadawca wie, od kogo oczekuje wykonania zadania.</p>
</li>
<li><p><strong>Nazewnictwo:</strong> Używa trybu rozkazującego, np. <code>ZarejestrujUżytkownika</code>, <code>DodajProduktDoKoszyka</code>, <code>WyślijFakturę</code>.</p>
</li>
<li><p><strong>Wynik:</strong> Może zostać zaakceptowana lub odrzucona. Odbiorca ma prawo odmówić wykonania komendy, jeśli np. narusza ona reguły biznesowe (próba rejestracji na zajęty e-mail).</p>
</li>
</ul>
<p><strong>Właścicielem komendy jest jej konsument (odbiorca).</strong> To on definiuje, jakie operacje potrafi wykonać i jakich danych do tego potrzebuje. Publikuje niejako swoje API w postaci komend, które akceptuje.</p>
<blockquote>
<p><strong>Analogia:</strong> Wysyłając komendę, jesteś jak szef, który daje swojemu pracownikowi (konsumentowi) konkretne polecenie (<code>PrzygotujRaportSprzedaży</code>). Pracownik wie, co ma zrobić, ale może też odpowiedzieć: "Nie mogę tego zrobić, brakuje mi danych za ostatni kwartał".</p>
</blockquote>
<h2 id="heading-czym-jest-zdarzenie-to-informacja-z-pierwszej-reki">Czym jest Zdarzenie? To informacja z pierwszej ręki.</h2>
<p><strong>Zdarzenie</strong> to powiadomienie o fakcie, który już miał miejsce. Jest to zapis zmiany stanu, która dokonała się w przeszłości.</p>
<ul>
<li><p><strong>Intencja:</strong> "Coś się właśnie stało!"</p>
</li>
<li><p><strong>Charakter:</strong> Jest opisowe i rozgłaszane do wszystkich zainteresowanych (lub do nikogo). Producent zdarzenia nie wie, kto i czy w ogóle ktoś go słucha.</p>
</li>
<li><p><strong>Nazewnictwo:</strong> Używa czasu przeszłego, np. <code>UżytkownikZarejestrowany</code>, <code>ProduktDodanyDoKoszyka</code>, <code>FakturaWysłana</code>.</p>
</li>
<li><p><strong>Wynik:</strong> Jest faktem dokonanym, więc nie może zostać "odrzucone". Subskrybenci po prostu na nie reagują.</p>
</li>
</ul>
<p><strong>Właścicielem zdarzenia jest jego producent (wydawca).</strong> To on jest źródłem prawdy o tym, co wydarzyło się w jego domenie i to on decyduje, jakie informacje zawrzeć w komunikacie.</p>
<blockquote>
<p><strong>Analogia:</strong> Publikując zdarzenie, jesteś jak agencja prasowa, która podaje do wiadomości publicznej komunikat (<code>TrzęsienieZiemiWykryte</code>). Różne służby (subskrybenci) – straż pożarna, pogotowie, sejsmolodzy – mogą na tę informację zareagować, każda na swój sposób. Agencja nie kieruje komunikatu do żadnej z nich bezpośrednio.</p>
</blockquote>
<h2 id="heading-kluczowe-roznice-w-pigulce">Kluczowe Różnice w Pigułce</h2>
<table><tbody><tr><td><p></p></td><td><p><strong>Komenda (Command)</strong></p></td><td><p><strong>Zdarzenie (Event)</strong></p></td></tr><tr><td><p><strong>Intencja</strong></p></td><td><p>Nakazanie akcji</p></td><td><p>Poinformowanie o fakcie</p></td></tr><tr><td><p><strong>Czas</strong></p></td><td><p>Przyszłość (“zrób”)</p></td><td><p>Przesłość (“stało się”)</p></td></tr><tr><td><p><strong>Adresat</strong></p></td><td><p>Jeden konkretny odbiorca</p></td><td><p>Zero lub wielu odbiorców</p></td></tr><tr><td><p><strong>Własność</strong></p></td><td><p><strong>Konsument </strong>(odbiorca)</p></td><td><p><strong>Producent </strong>(wydawca)<strong></strong></p></td></tr><tr><td><p><strong>Sprzężenie</strong></p></td><td><p>Ścisłe (nadawca zna odbiorcę)</p></td><td><p>Lużne (nadawca nie zna odbiorców)</p></td></tr></tbody></table>

<h2 id="heading-dlaczego-to-takie-wazne">Dlaczego to takie ważne?</h2>
<p>Prawidłowe rozróżnienie komend i zdarzeń oraz respektowanie zasad ich własności pozwala budować systemy, które są:</p>
<ul>
<li><p><strong>Autonomiczne:</strong> Każdy serwis może rozwijać się niezależnie, o ile nie łamie zdefiniowanych kontraktów.</p>
</li>
<li><p><strong>Elastyczne:</strong> Łatwo możemy dodawać nowe serwisy, które reagują na istniejące zdarzenia, bez modyfikowania starych komponentów.</p>
</li>
<li><p><strong>Odporne na błędy:</strong> Awarie w jednym z subskrybentów zdarzenia nie wpływają na pracę producenta ani innych subskrybentów.</p>
</li>
</ul>
<p>Opanowanie tej koncepcji to fundament dla zaawansowanych wzorców architektonicznych, takich jak <strong>CQRS (Command Query Responsibility Segregation)</strong>. To nie tylko teoria – to praktyczna wiedza, która procentuje czystszym kodem i stabilniejszymi aplikacjami.</p>
]]></content:encoded></item></channel></rss>