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

<channel>
	<title>Java - bdabek.pl</title>
	<atom:link href="https://www.bdabek.pl/tag/java/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.bdabek.pl/tag/java/</link>
	<description>Bartosz Dąbek</description>
	<lastBuildDate>Mon, 17 Feb 2025 18:24:20 +0000</lastBuildDate>
	<language>pl-PL</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.1</generator>

<image>
	<url>https://www.bdabek.pl/wp-content/uploads/2020/10/cropped-5986134a-46ba-41ac-9c82-bb4ffb3a7bf3_200x200-1-150x150.png</url>
	<title>Java - bdabek.pl</title>
	<link>https://www.bdabek.pl/tag/java/</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Cache w Javie. Trochę wiedzy</title>
		<link>https://www.bdabek.pl/cache-java/</link>
					<comments>https://www.bdabek.pl/cache-java/#respond</comments>
		
		<dc:creator><![CDATA[Bartosz Dąbek]]></dc:creator>
		<pubDate>Mon, 17 Feb 2025 18:24:20 +0000</pubDate>
				<category><![CDATA[Programowanie]]></category>
		<category><![CDATA[Java]]></category>
		<guid isPermaLink="false">https://www.bdabek.pl/?p=3198</guid>

					<description><![CDATA[<p>Cześć. Dawno, dawno temu, na produkcji, pojawił nam się problem z wydajnością aplikacji. Analiza i rozwiązanie problemu pochłonęła nam dobre kilka dni. Debugowaliśmy, czytaliśmy dokumentację, analizowaliśmy logi. Nic nie mogliśmy znaleźć, do momentu, gdy nas oświeciło. Analizowaliśmy requesty i zauważyliśmy, że większość czasu żądania była na odczycie wartości z&#8230; cache. Problem był banalny. Zapychaliśmy cache&#8217;a&#8230;&#160;<a href="https://www.bdabek.pl/cache-java/" rel="bookmark">Dowiedz się więcej &#187;<span class="screen-reader-text">Cache w Javie. Trochę wiedzy</span></a></p>
<p>Artykuł <a href="https://www.bdabek.pl/cache-java/">Cache w Javie. Trochę wiedzy</a> pochodzi z serwisu <a href="https://www.bdabek.pl">bdabek.pl</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">Cześć.</p>



<p class="wp-block-paragraph">Dawno, dawno temu, na produkcji, pojawił nam się problem z wydajnością aplikacji. Analiza i rozwiązanie problemu pochłonęła nam dobre kilka dni. Debugowaliśmy, czytaliśmy dokumentację, analizowaliśmy logi. Nic nie mogliśmy znaleźć, do momentu, gdy nas oświeciło. Analizowaliśmy requesty i zauważyliśmy, że większość czasu żądania była na odczycie wartości z&#8230; cache. Problem był banalny. <strong>Zapychaliśmy cache&#8217;a generując za każdym razem uniwersalny klucz wartości</strong>. Chwilę wcześniej mergowaliśmy ogromnego PR, który pozmieniał w kodzie dużo &#8211; za dużo. Zmiany były w różnych częściach aplikacji &#8211; technicznych i biznesowych. To był nasz ogromny błąd.</p>



<p class="wp-block-paragraph">Uznałem, że artykuł, który w sposób początkujący przedstawi temat cache pomoże innym. Mi też będzie punktem referencyjnym w przyszłości. W dzisiejszym artykule:</p>



<ul class="wp-block-list">
<li><strong><a href="#czym_jest_cache">Czym jest cache</a></strong></li>



<li><strong><a href="#in-memory-vs-distributed">Cache lokalny vs rozproszony</a></strong></li>



<li><a href="#algorytmy_cache"><strong>Algorytmy przechowujące dane</strong></a></li>



<li><a href="#inwalidacja_cache"><strong>Inwalidacja cache</strong></a></li>



<li><a href="#monitorowanie_cache"><strong>Monitorowanie cache</strong></a></li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading"><h2 id="czym_jest_cache"> <a href="#czym_jest_cache"><span class="dashicons dashicons-admin-links"></span></a>Czym jest cache</h2></h2>



<p class="wp-block-paragraph">Cache w Javie to mechanizm przechowywania często używanych danych, w celu szybszego dostępu i poprawy wydajności aplikacji. Możemy zastosować go do operacji, które są <strong>czasochłonne</strong> lub <strong>kosztowne w wykonaniu</strong>. Dobrymi przykładami takich operacji są zapytania do bazy danych, requesty do API czy powtarzalne obliczenia matematyczne.</p>


<div class="wp-block-image">
<figure class="alignleft size-full is-resized"><img fetchpriority="high" decoding="async" width="512" height="512" src="https://www.bdabek.pl/wp-content/uploads/2025/02/cache_co_to.webp" alt="" class="wp-image-3424" style="width:202px;height:auto" srcset="https://www.bdabek.pl/wp-content/uploads/2025/02/cache_co_to.webp 512w, https://www.bdabek.pl/wp-content/uploads/2025/02/cache_co_to-300x300.webp 300w, https://www.bdabek.pl/wp-content/uploads/2025/02/cache_co_to-150x150.webp 150w" sizes="(max-width: 512px) 100vw, 512px" /></figure>
</div>


<p class="wp-block-paragraph">Załóżmy, że tworzymy aplikację pobierającą informacje o pogodzie. Informacje pobieramy z różnych lokalizacji, z zewnętrznego serwisu pogodowego za pomocą REST API. Pobierane dane zmieniają się co 3 godziny. Z naszej aplikacji dziennie korzysta około 50 000 osób, co przekłada się na średnio 2000 requestów na godzinę (upraszczamy, że ruch został rozłożony na całą dobę równomiernie). Użytkownicy pochodzą głównie z Polski i często pytają o te same lokalizacje. Aby uniknąć wywoływania zewnętrznego serwisu pogodowego wiele razy, możemy użyć mechanizmu cache. Przyspieszymy dostęp do informacji i unikniemy ciągłego zapytywania zewnętrznego API.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading"><h2 id="in-memory-vs-distributed"> <a href="#in-memory-vs-distributed"><span class="dashicons dashicons-admin-links"></span></a>Cache lokalny vs rozproszony</h2></h2>



<p class="wp-block-paragraph">Pamięć cache, możemy podzielić na dwa typy: lokalny i rozproszony. W tej sekcji postaram się opisać ich cechy, wady oraz zalety. Na końcu sekcji wrzuciłem też dwie tabele. Jedna porównująca cechy obydwu typów i druga z przykładami i rekomendacjami, który rodzaj wybrać w danej sytuacji.</p>



<h4 class="wp-block-heading"><strong>Cache lokalny (In-memory cache)</strong></h4>



<p class="wp-block-paragraph">In-memory cache to <strong>lokalny cache w procesie aplikacji</strong>, który przechowuje dane w pamięci RAM na jednym serwerze. Pozwala to na błyskawiczny dostęp do danych tam przechowywanych. Jest on najszybszy, ale ograniczony rozmiarem pamięci dostępnej w jednej instancji aplikacji. Jego główne cechy to:</p>


<figure class="wp-block-image alignright size-full is-resized"><img decoding="async" width="1000" height="892" class="wp-image-3406" style="width: 483px; height: auto;" src="https://www.bdabek.pl/wp-content/uploads/2025/02/memory_hierarchy.webp" alt="Hierarchia pamięci" srcset="https://www.bdabek.pl/wp-content/uploads/2025/02/memory_hierarchy.webp 1000w, https://www.bdabek.pl/wp-content/uploads/2025/02/memory_hierarchy-300x268.webp 300w, https://www.bdabek.pl/wp-content/uploads/2025/02/memory_hierarchy-768x685.webp 768w" sizes="(max-width: 1000px) 100vw, 1000px" /><figcaption class="wp-element-caption" style="text-align: center;"><em> Hierarchia pamięci</em></figcaption></figure>


<ul class="wp-block-list">
<li><strong>Lokalność:</strong> dane przechowywane są w pamięci RAM konkretnego procesu lub instancji aplikacji.</li>



<li><strong>Szybkość:</strong> dostęp do danych jest ekstremalnie szybki, ponieważ omijana jest komunikacja sieciowa i operacje na dysku.</li>



<li><strong>Prostota:</strong> może być implementowany za pomocą prostych struktur danych, np. <code>ConcurrentHashMap</code>, lub dedykowanych bibliotek, np. Caffeine.</li>



<li><strong>Brak współdzielenia:</strong> dane w cache są dostępne tylko dla jednego procesu lub instancji aplikacji (chyba że używana jest rozproszona implementacja in-memory, np. Hazelcast).</li>
</ul>



<p class="wp-block-paragraph"><strong>Zalety:</strong></p>



<ul class="wp-block-list">
<li><strong>Wysoka wydajność</strong>: zapewnia bardzo niski czas dostępu do danych, ponieważ przechowuje je w pamięci RAM. Odczyt danych z pamięci jest znacznie szybszy niż z dysku twardego czy bazy danych, co przyspiesza działanie aplikacji.</li>



<li><strong>Prosta implementacja</strong>: jest stosunkowo łatwa i nie wymaga skomplikowanej konfiguracji. Istnieje wiele gotowych rozwiązań, oferujących gotowe mechanizmy.</li>
</ul>



<p class="wp-block-paragraph"><strong>Wady:</strong></p>



<ul class="wp-block-list">
<li><strong>Ulotność danych</strong>: dane zostaną utracone w przypadku restartu serwera lub awarii aplikacji.</li>



<li><strong>Ograniczona pojemność</strong>: pojemność jest ograniczona przez dostępność pamięci RAM na serwerze. W przypadku dużych aplikacji lub intensywnego wykorzystania pamięci może to prowadzić do problemów z wydajnością lub brakiem miejsca na nowe dane (<code>OutOfMemoryError</code>).</li>



<li><strong>Trudności w skalowaniu</strong>: w architekturze rozproszonej każda instancja aplikacji ma swoją własną pamięć podręczną, co może prowadzić do problemów z synchronizacją danych między instancjami oraz zwiększonego ryzyka nieaktualnych informacji.</li>
</ul>



<h4 class="wp-block-heading"><strong>Cache rozproszony (Distributed cache)</strong></h4>



<p class="wp-block-paragraph">Działa na wielu serwerach w klastrze, umożliwiając szybki dostęp do często używanych danych. Pamięć współdzielona jest między wieloma instancjami aplikacji i umożliwia obsługę dużych wolumenów danych oraz zapewnia wysoką dostępność danych. Jego główne cechy:</p>



<ul class="wp-block-list">
<li><strong>Rozproszenie danych (eureka!):</strong> te same dane dostępne z różnych instancji aplikacji.</li>



<li><strong>Skalowalność</strong>: może być łatwo skalowany poprzez dodawanie nowych węzłów do klastra. To pozwala na zwiększenie pojemności cache i obsługę większej liczby żądań.</li>



<li><strong>Odporność na awarie</strong>: dzięki replikacji danych na różnych węzłach, nawet w przypadku awarii jednego z nich, dane pozostają dostępne.</li>



<li><strong>Partycjonowanie (sharding):</strong> każdy węzeł przechowuje <strong>tylko część</strong> danych, a aplikacja odwołuje się bezpośrednio do odpowiedniego serwera.</li>
</ul>


<figure class="wp-block-image alignright size-full is-resized"><img decoding="async" width="655" height="634" class="wp-image-3416 alignright" style="width: 582px; height: 564px;" src="https://www.bdabek.pl/wp-content/uploads/2025/02/distributed_cache_schema.webp" alt="" srcset="https://www.bdabek.pl/wp-content/uploads/2025/02/distributed_cache_schema.webp 655w, https://www.bdabek.pl/wp-content/uploads/2025/02/distributed_cache_schema-300x290.webp 300w" sizes="(max-width: 655px) 100vw, 655px" /><figcaption style="text-align: center;"><em>Schemat cache&#8217;u rozproszonego</em></figcaption></figure>


<p class="wp-block-paragraph"><strong>Zalety:</strong></p>



<ul class="wp-block-list">
<li><strong>Wysoka dostępność i odporność na awarie: </strong>dane mogą być replikowane na wielu węzłach, dzięki czemu awaria jednego serwera nie powoduje utraty danych.</li>



<li><strong>Szybkość i niskie opóźnienia:</strong> dane przechowywane są w pamięci RAM (z tym, że na wielu węzłach w porównaniu z lokalnym cache).</li>



<li><strong>Usprawnienie pracy mikroserwisów:</strong> w systemach mikroserwisowych cache rozproszony pozwala na szybką wymianę danych między usługami bez konieczności ciągłego odpytywania bazy danych.</li>



<li><strong>Obsługa dużych wolumenów danych</strong>: dzięki partycjonowaniu dane mogą być równomiernie rozłożone na węzłach, co pozwala na obsługę dużych zbiorów danych w rozproszonym środowisku.</li>
</ul>



<p class="wp-block-paragraph"><strong>Wady:</strong></p>



<ul class="wp-block-list">
<li><strong>Opóźnienia Sieciowe:</strong> cache działa na wielu serwerach, co oznacza, że każde zapytanie musi przejść przez sieć. Jeśli węzły są oddalone geograficznie, latencja wzrasta.</li>



<li><strong>Koszt Pamięci RAM:</strong> RAM jest znacznie droższy niż dysk, a cache rozproszony przechowuje dane w pamięci operacyjnej. Skalowanie dużych systemów wymaga serwerów z dużą ilością RAM-u.</li>



<li><strong>Nieścisłości w Danych (Data Inconsistency):</strong> dane na różnych węzłach mogą być przez chwilę niespójne. Możesz odczytać stare dane, zanim propagacja zmian się zakończy.</li>



<li><strong>Złożoność architektury:</strong> wprowadza dodatkową złożoność do architektury systemu. Wymaga planowania i zarządzania, aby zapewnić prawidłowe działanie i integrację z innymi komponentami systemu.</li>



<li><strong>Split-Brain:</strong> Jeśli węzły stracą komunikację między sobą, może dojść do stanu „split-brain”, gdzie różne węzły mają różne wersje danych. Część aplikacji może korzystać z nieaktualnych danych.</li>
</ul>



<h4 class="wp-block-heading">Rozproszony vs Lokalny</h4>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th><strong>Cecha</strong></th><th><strong>Rozproszony Cache</strong></th><th><strong>Lokalny Cache</strong></th></tr></thead><tbody><tr><td><strong>Lokalizacja danych</strong></td><td>Dane są przechowywane na wielu instancjach.</td><td>Dane są przechowywane w pamięci RAM lokalnej instancji aplikacji.</td></tr><tr><td><strong>Dostępność danych</strong></td><td>Dane są współdzielone między wszystkimi instancjami aplikacji w klastrze.</td><td>Dane są dostępne tylko dla jednej instancji aplikacji.</td></tr><tr><td><strong>Przykłady technologii</strong></td><td>Redis, Memcached, Hazelcast, Infinispan, Apache Ignite, Ehcache (tryb rozproszony)</td><td>Caffeine, Guava, Ehcache (tryb lokalny), ConcurrentHashMap <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /></td></tr><tr><td><strong>Szybkość dostępu</strong></td><td>Dostęp jest szybszy niż do bazy danych, ale wymaga komunikacji sieciowej.</td><td>Dostęp jest ekstremalnie szybki, ponieważ dane są przechowywane w pamięci lokalnej.</td></tr><tr><td><strong>Skalowalność</strong></td><td>Łatwo skalowalny dzięki rozproszonej architekturze – nowe węzły można dodawać w celu zwiększenia pojemności.</td><td>Skalowalność ograniczona do zasobów (RAM) jednej instancji aplikacji.</td></tr><tr><td><strong>Niezawodność danych</strong></td><td>Może obsługiwać replikację i trwałość danych.</td><td>Dane są ulotne – tracone w przypadku restartu aplikacji lub awarii instancji.</td></tr><tr><td><strong>Złożoność zarządzania</strong></td><td>Zazwyczaj wymaga dodatkowej konfiguracji.</td><td>Łatwe w zarządzaniu – wystarczy biblioteka lub struktura danych w aplikacji.</td></tr><tr><td><strong>Przeznaczenie</strong></td><td>Do współdzielenia danych między wieloma instancjami lub usługami w architekturze rozproszonej</td><td>Do lokalnego buforowania danych specyficznych dla jednej instancji aplikacji.</td></tr><tr><td><strong>Czas życia danych (TTL)</strong></td><td>Obsługuje globalne TTL dla danych, które są ważne niezależnie od instancji.</td><td>Dane wygasają tylko w kontekście jednej instancji aplikacji.</td></tr><tr><td><strong>Koszty</strong></td><td>Wymaga dodatkowych zasobów infrastruktury (np. serwery Redis, Memcached).</td><td>Niskie koszty – wykorzystuje lokalną pamięć aplikacji.</td></tr><tr><td><strong>Odporność na awarie</strong></td><td>Może być replikowany, co zwiększa odporność na awarie</td><td>Dane są tracone w przypadku awarii procesu aplikacji.</td></tr></tbody></table></figure>



<h4 class="wp-block-heading"><strong>Kiedy wybrać który?</strong></h4>



<div class="wp-block-group"><div class="wp-block-group__inner-container is-layout-constrained wp-block-group-is-layout-constrained">
<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-8f761849 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:100%">
<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th><strong>Scenariusz</strong></th><th><strong>Rekomendacja</strong></th></tr></thead><tbody><tr><td>Współdzielenie danych między wieloma instancjami.</td><td><strong>Distributed Cache</strong></td></tr><tr><td>Dane muszą być dostępne po awarii instancji.</td><td><strong>Distributed Cache</strong></td></tr><tr><td>Maksymalna szybkość dostępu bez komunikacji sieciowej.</td><td><strong>In-Memory Cache</strong></td></tr><tr><td>Aplikacja monolityczna z pojedynczym węzłem.</td><td><strong>In-Memory Cache</strong></td></tr><tr><td>Architektura mikrousługowa lub klaster aplikacji.</td><td><strong>Distributed Cache</strong></td></tr><tr><td>Buforowanie krótkotrwałych danych specyficznych dla jednej instancji.</td><td><strong>In-Memory Cache</strong></td></tr></tbody></table></figure>
</div>
</div>
</div></div>



<h2 class="wp-block-heading"><h2 id="algorytmy_cache"> <a href="#algorytmy_cache"><span class="dashicons dashicons-admin-links"></span></a>Algorytmy przechowujące dane</h2></h2>



<p class="wp-block-paragraph">Wiemy już czym jest cache i jakie są jego typy. Teraz pora poznać jakie algorytmy są implementowane najczęściej. Warto poznać co się dzieje pod bebechami, w jaki sposób nasze dane są organizowane w cache. W gotowych rozwiązaniach mamy możliwość customizowania, znając skróty (np. LRU, LFU) oraz teoretyczne działanie algorytmu, jesteśmy w stanie lepiej go ustawić.</p>


<figure class="wp-block-image aligncenter size-full"><img decoding="async" width="494" height="531" class="wp-image-3430" src="https://www.bdabek.pl/wp-content/uploads/2025/02/cache_algorytmy.webp" alt="" srcset="https://www.bdabek.pl/wp-content/uploads/2025/02/cache_algorytmy.webp 494w, https://www.bdabek.pl/wp-content/uploads/2025/02/cache_algorytmy-279x300.webp 279w" sizes="(max-width: 494px) 100vw, 494px" /><figcaption class="wp-element-caption" style="text-align: center;"><em>Książka do algorytmów</em> cache</figcaption></figure>


<ul class="wp-block-list marker:text-textOff list-disc pl-8">
<li><strong>Zastosowania i ograniczenia</strong>: Omówienie, kiedy i dlaczego warto stosować dany algorytm oraz ich potencjalne ograniczenia.</li>
</ul>



<p class="wp-block-paragraph">Najpopularniejsze algorytmy to: </p>



<ul class="wp-block-list">
<li><strong>LRU (Least Recently Used)</strong></li>



<li><strong>LFU (Least Frequently Used)</strong></li>



<li><strong>FIFO (First In, First Out)</strong></li>



<li><strong>ARC (Adaptive Replacement Cache)</strong></li>



<li><strong>SLRU (Segmented LRU)</strong></li>



<li><strong>2Q (Two-Queue)</strong></li>
</ul>



<h5 class="wp-block-heading mb-2 mt-6 text-lg first:mt-3">LRU (Least Recently Used)</h5>



<p class="wp-block-paragraph">Algorytm LRU usuwa najdawniej używane elementy z cache, aby zrobić miejsce dla nowych. Jest to jeden z najczęściej stosowanych algorytmów, ponieważ dobrze odzwierciedla rzeczywiste wzorce użycia danych. Warto go stosować gdy <strong>ważne są najświeższe dane</strong>.</p>


<div class="wp-block-image">
<figure class="aligncenter size-large"><img decoding="async" width="1024" height="235" src="https://www.bdabek.pl/wp-content/uploads/2025/02/cache_lru-1024x235.webp" alt="" class="wp-image-3445" srcset="https://www.bdabek.pl/wp-content/uploads/2025/02/cache_lru-1024x235.webp 1024w, https://www.bdabek.pl/wp-content/uploads/2025/02/cache_lru-300x69.webp 300w, https://www.bdabek.pl/wp-content/uploads/2025/02/cache_lru-768x176.webp 768w, https://www.bdabek.pl/wp-content/uploads/2025/02/cache_lru-1536x352.webp 1536w, https://www.bdabek.pl/wp-content/uploads/2025/02/cache_lru.webp 1983w" sizes="(max-width: 1024px) 100vw, 1024px" /><figcaption class="wp-element-caption"><em>Algorytm LRU</em></figcaption></figure>
</div>


<p class="wp-block-paragraph">Wyobraźmy sobie aplikację udostępniającą zdjęcia.&nbsp;Zdjęcia są przechowywane na dysku, a ich pobieranie zajmuje pewien czas. Aby przyspieszyć dostęp do często żądanych zdjęć, aplikacja może użyć cache LRU. Kiedy użytkownik żąda zdjęcia, aplikacja najpierw sprawdza, czy znajduje się ono w pamięci podręcznej. Jeśli tak, zdjęcie jest natychmiast zwracane. Jeśli zdjęcia nie ma w pamięci podręcznej, aplikacja pobiera go z dysku, zapisuje w pamięci podręcznej i zwraca użytkownikowi. Pamięć podręczna LRU ma ograniczoną pojemność, więc gdy jest pełna, algorytm <strong>usuwa najdawniej używane zdjęcie,</strong> aby zrobić miejsce dla nowego. Dzięki temu często żądane zdjęcia są szybko dostępne, co poprawia wydajność serwera i skraca czas ładowania strony dla użytkowników</p>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-8f761849 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow">
<p class="wp-block-paragraph"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong>Dlaczego warto?</strong></p>



<ul class="wp-block-list">
<li>Wykorzystuje lokalność czasową – elementy używane niedawno prawdopodobnie będą używane ponownie.</li>



<li>Sprawdza się w systemach z przewidywalnym wzorcem dostępu do danych.</li>



<li>Prosta i sprawdzona strategia &#8211; po prostu usuwa element, który był najdawniej używany.</li>



<li>Dobra wydajność dla większości zastosowań &#8211; operacje dostępu (<code>get</code> i <code>put</code>) są w czasie O(1) w <code>LinkedHashMap</code>, jeśli używamy listy podwójnie powiązanej.</li>
</ul>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow">
<p class="wp-block-paragraph"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/26a0.png" alt="⚠" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong>Ograniczenia:</strong></p>



<ul class="wp-block-list">
<li>Cache pollution – jeśli aplikacja chwilowo użyje dużej liczby rzadko używanych obiektów, cache może zostać „zalany” niepotrzebnymi danymi.</li>



<li>Wysokie koszty operacyjne &#8211; wymaga dodatkowej pamięci do przechowywania wskaźników (np. w <code>LinkedHashMap</code> jest to lista podwójnie powiązana).</li>



<li>Brak adaptacyjności &#8211; każdy nowy dostępny element traktowany jest jednakowo, co może prowadzić do błędnych decyzji o usunięciu. Jeśli aplikacja używa dwóch zestawów danych naprzemiennie, LRU może stale usuwać jedną grupę na rzecz drugiej.</li>
</ul>
</div>
</div>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h5 class="wp-block-heading mb-2 mt-6 text-lg first:mt-3">LFU (Least Frequently Used)</h5>



<p class="wp-block-paragraph">Algorytm LFU usuwa elementy, które były <strong>najrzadziej używane w danym okresie czasu</strong>. Wymaga on śledzenia liczby odwołań do każdego elementu w cache, co może zwiększać złożoność implementacji i obciążenie pamięci. Warto go stosować gdy <strong>ważna jest częstotliwość użycia</strong>.</p>


<div class="wp-block-image">
<figure class="aligncenter size-large is-resized"><img decoding="async" width="1024" height="546" src="https://www.bdabek.pl/wp-content/uploads/2025/02/cache_lfu-1024x546.webp" alt="" class="wp-image-3448" style="width:674px;height:auto" srcset="https://www.bdabek.pl/wp-content/uploads/2025/02/cache_lfu-1024x546.webp 1024w, https://www.bdabek.pl/wp-content/uploads/2025/02/cache_lfu-300x160.webp 300w, https://www.bdabek.pl/wp-content/uploads/2025/02/cache_lfu-768x409.webp 768w, https://www.bdabek.pl/wp-content/uploads/2025/02/cache_lfu.webp 1280w" sizes="(max-width: 1024px) 100vw, 1024px" /><figcaption class="wp-element-caption"><em>Algorytm LFU</em></figcaption></figure>
</div>


<p class="wp-block-paragraph">Wyobraź sobie, że tworzysz aplikację finansową, która pokazuje kursy walut w czasie rzeczywistym. Każdego dnia tysiące użytkowników sprawdza notowania, ale większość z nich interesuje się tylko kilkoma najpopularniejszymi walutami – np. USD, EUR i PLN. Zamiast za każdym razem pobierać dane z API, przechowujemy w pamięci najczęściej pobierane kursy walut, a rzadko używane usuwamy.</p>



<p class="wp-block-paragraph">1&#x20e3; Użytkownik pyta o kurs USD/PLN. Sprawdzamy, czy mamy go w LFU Cache.<br>2&#x20e3; Im częściej dana waluta jest wyszukiwana, tym dłużej pozostaje w cache.<br>3&#x20e3; Jeśli cache jest pełny, usuwamy najrzadziej pobierane waluty.</p>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-8f761849 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow">
<p class="wp-block-paragraph"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong>Dlaczego warto?</strong></p>



<ul class="wp-block-list">
<li>Idealny dla danych o wysokiej lokalności częstotliwościowej – rzadko używane obiekty są usuwane, a często odczytywane pozostają.</li>



<li>Sprawdza się w aplikacjach, gdzie dostęp do pewnych obiektów jest naturalnie „gorący” (np. ranking produktów w sklepie).</li>
</ul>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow">
<p class="wp-block-paragraph"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/26a0.png" alt="⚠" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong>Ograniczenia:</strong></p>



<ul class="wp-block-list">
<li>Problem zimnego startu – nowo dodane elementy mogą zostać szybko usunięte, zanim zdążą być użyte wystarczająco często.</li>



<li>Wysoka złożoność operacji – O(log n) zamiast O(1). W odróżnieniu od LRU Cache, który można zaimplementować w O(1), standardowa implementacja LFU wymaga struktury danych, która potrafi śledzić częstotliwość użycia i usuwać najrzadziej używany element.</li>



<li>Nie radzi sobie dobrze z nagłymi zmianami trendów &#8211; dane, które były często używane dawno temu, mogą długo pozostawać w cache, nawet jeśli nie są już potrzebne.</li>
</ul>
</div>
</div>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h5 class="wp-block-heading mb-2 mt-6 text-lg first:mt-3">FIFO (First In, First Out)</h5>



<p class="wp-block-paragraph">Algorytm FIFO usuwa najstarsze elementy z cache&#8217;a w momencie, gdy osiągnięty zostaje jego maksymalny rozmiar. Jest to <strong>prosty algorytm</strong>, ale <strong>może nie być optymalny</strong> w przypadku, gdy starsze dane są nadal często używane.</p>



<p class="wp-block-paragraph">Załóżmy, że budujemy <strong>serwer proxy</strong>, który buforuje strony internetowe, aby zmniejszyć liczbę żądań wysyłanych do serwera źródłowego. Kiedy użytkownik odwiedza stronę, jej zawartość jest zapisywana w pamięci podręcznej. Jeśli inny użytkownik zażąda tej samej strony, proxy zwróci ją z cache, zamiast pobierać ponownie z internetu.</p>



<p class="wp-block-paragraph">Jednak cache ma ograniczoną pojemność, więc <strong>najstarsze strony muszą być usuwane, aby zrobić miejsce na nowe</strong>. FIFO dobrze sprawdza się w tym przypadku, ponieważ <strong>starsze strony są mniej prawdopodobne do ponownego użycia</strong>.</p>


<div class="wp-block-image">
<figure class="aligncenter size-large"><img decoding="async" width="1024" height="279" src="https://www.bdabek.pl/wp-content/uploads/2025/02/cache_fifo-1024x279.webp" alt="" class="wp-image-3450" srcset="https://www.bdabek.pl/wp-content/uploads/2025/02/cache_fifo-1024x279.webp 1024w, https://www.bdabek.pl/wp-content/uploads/2025/02/cache_fifo-300x82.webp 300w, https://www.bdabek.pl/wp-content/uploads/2025/02/cache_fifo-768x209.webp 768w, https://www.bdabek.pl/wp-content/uploads/2025/02/cache_fifo.webp 1138w" sizes="(max-width: 1024px) 100vw, 1024px" /><figcaption class="wp-element-caption"><em>FIFO algorithm</em></figcaption></figure>
</div>


<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-8f761849 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow">
<p class="wp-block-paragraph"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong>Dlaczego warto?</strong></p>



<ul class="wp-block-list">
<li>Bardzo prosty do implementacji i tani obliczeniowo.</li>



<li>Może działać dobrze w sytuacjach, gdzie stare dane są naturalnie mniej istotne.</li>



<li>Brak kosztów obliczeniowych związanych z priorytetyzacją w przeciwieństwie do algorytmów takich jak LRU czy LFU, FIFO nie wymaga monitorowania częstotliwości ani czasu dostępu do danych.</li>



<li>Działa w przewidywalny sposób, ponieważ zawsze usuwa najstarszy element. Nie wymaga skomplikowanych heurystyk ani analizy częstości użycia danych.</li>
</ul>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow">
<p class="wp-block-paragraph"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/26a0.png" alt="⚠" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong>Ograniczenia:</strong></p>



<ul class="wp-block-list">
<li>Ignoruje rzeczywisty dostęp do danych – może usuwać często używane dane, jeśli zostały one załadowane wcześniej niż inne mniej używane elementy</li>



<li>Może prowadzić do niskiej efektywności cache (tzw. Problem Belady’ego) – zwiększenie rozmiaru cache może pogorszyć jego skuteczność zamiast ją poprawić.</li>



<li>Brak kontroli nad priorytetami danych &#8211; w FIFO wszystkie dane są traktowane jednakowo, niezależnie od ich ważności dla aplikacji.</li>
</ul>
</div>
</div>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h5 class="wp-block-heading mb-2 mt-6 text-lg first:mt-3">ARC (Adaptive Replacement Cache)</h5>



<p class="wp-block-paragraph">ARC to bardziej zaawansowany algorytm, który <strong>łączy cechy LRU i LFU</strong>. Dostosowuje się do zmieniających się wzorców użycia danych, starając się utrzymać równowagę między częstością a świeżością danych w cache&#8217;u. Algorytm <strong>opiera się na czterech listach</strong>, które służą do zarządzania pamięcią podręczną. Dwie główne listy, T1 i T2, odpowiadają za przechowywanie odpowiednio niedawno używanych oraz często używanych elementów. Dodatkowo istnieją dwie listy pomocnicze, B1 i B2, które przechowują referencje do elementów wcześniej usuniętych z T1 i T2, co pozwala na <strong>inteligentne dostosowanie algorytmu</strong> do zmieniających się wzorców dostępu do danych.</p>


<div class="wp-block-image">
<figure class="aligncenter size-large"><img decoding="async" width="1024" height="585" src="https://www.bdabek.pl/wp-content/uploads/2025/02/cache_ARC-1024x585.webp" alt="" class="wp-image-3455" srcset="https://www.bdabek.pl/wp-content/uploads/2025/02/cache_ARC-1024x585.webp 1024w, https://www.bdabek.pl/wp-content/uploads/2025/02/cache_ARC-300x171.webp 300w, https://www.bdabek.pl/wp-content/uploads/2025/02/cache_ARC-768x439.webp 768w, https://www.bdabek.pl/wp-content/uploads/2025/02/cache_ARC-1536x878.webp 1536w, https://www.bdabek.pl/wp-content/uploads/2025/02/cache_ARC.webp 1792w" sizes="(max-width: 1024px) 100vw, 1024px" /><figcaption class="wp-element-caption"><em>ARC algorithm</em></figcaption></figure>
</div>


<p class="wp-block-paragraph">Załóżmy, że mamy <strong>system rekomendacji filmów</strong> w serwisie streamingowym. Filmy mogą być często oglądane przez różnych użytkowników (np. hity kinowe), ale niektóre treści mogą być oglądane tylko raz przez jednego użytkownika (np. premierowe odcinki seriali). ARC może być tu użyty do cache&#8217;owania najczęściej oglądanych filmów, jednocześnie dostosowując się do zmieniającego się trendu popularności. Jeśli dany film jest nagle często oglądany przez wielu użytkowników, ARC zwiększy swoją pamięć dla takich elementów (T2). Jeśli użytkownicy konsumują głównie nowe treści (np. nowy sezon serialu), ARC dostosuje się do tego, zwiększając T1 i usuwając mniej popularne starsze filmy.</p>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-8f761849 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow">
<p class="wp-block-paragraph"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong>Dlaczego warto?</strong></p>



<ul class="wp-block-list">
<li>Lepsza adaptacja do zmieniających się wzorców dostępu – eliminuje problem wyboru między LRU i LFU.</li>



<li>Efektywne wykorzystanie cache – dynamiczne dostosowanie do obciążenia zapewnia mniejszą liczbę niepotrzebnych wymian.</li>



<li>Dobre działanie w przypadku zarówno skokowych zmian popularności, jak i stabilnych trendów.</li>
</ul>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow">
<p class="wp-block-paragraph"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/26a0.png" alt="⚠" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong>Ograniczenia:</strong></p>



<ul class="wp-block-list">
<li>Większa złożoność obliczeniowa niż LRU czy LFU – zarządzanie wieloma listami i dynamiczne dostosowywanie kosztuje więcej CPU.</li>



<li>Większe zużycie pamięci – dodatkowe struktury (B1, B2) zwiększają overhead.</li>



<li>Może nie sprawdzić się w scenariuszach z bardzo ograniczoną pamięcią – w ekstremalnie małych cache&#8217;ach, prostsze algorytmy jak LRU mogą działać lepiej.</li>
</ul>
</div>
</div>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h5 class="wp-block-heading mb-2 mt-6 text-lg first:mt-3">SLRU (Segmented LRU)</h5>



<p class="wp-block-paragraph">SLRU to wariant klasycznego algorytmu LRU, który wprowadza podział pamięci podręcznej na dwa segmenty: ochronny i próbny. Ochronny przechowuje często używane elementy, które zostały uznane za „ważne”, próbny natomiast nowe elementy, które jeszcze nie zostały uznane za istotne. Nowo wczytane elementy trafiają najpierw do segmentu próbnego. Jeśli element zostanie ponownie użyty, jest przenoszony do segmentu ochronnego. Elementy z segmentu ochronnego mają pierwszeństwo przed usunięciem – jeśli pamięć cache jest pełna, elementy usuwane są w pierwszej kolejności z segmentu próbnego, co zwiększa szanse na zachowanie często używanych danych.</p>


<div class="wp-block-image">
<figure class="aligncenter size-large"><img decoding="async" width="1024" height="585" src="https://www.bdabek.pl/wp-content/uploads/2025/02/cache_SLRU-1024x585.webp" alt="" class="wp-image-3457" srcset="https://www.bdabek.pl/wp-content/uploads/2025/02/cache_SLRU-1024x585.webp 1024w, https://www.bdabek.pl/wp-content/uploads/2025/02/cache_SLRU-300x171.webp 300w, https://www.bdabek.pl/wp-content/uploads/2025/02/cache_SLRU-768x439.webp 768w, https://www.bdabek.pl/wp-content/uploads/2025/02/cache_SLRU-1536x878.webp 1536w, https://www.bdabek.pl/wp-content/uploads/2025/02/cache_SLRU.webp 1792w" sizes="(max-width: 1024px) 100vw, 1024px" /><figcaption class="wp-element-caption"><em>SLRU algorithm</em></figcaption></figure>
</div>


<p class="wp-block-paragraph">Weźmy realny przykład z e-commerce. Każdy użytkownik, odwiedzając sklep internetowy, otrzymuje sesję, która może być wykorzystywana wielokrotnie, np. podczas dodawania produktów do koszyka, ale w wielu przypadkach jest jednorazowa – użytkownik przegląda stronę i nigdy nie wraca. W takim scenariuszu nowo utworzone sesje trafiają najpierw do segmentu próbnego pamięci podręcznej. Jeśli użytkownik podejmuje kolejne działania, jego sesja zostaje przeniesiona do segmentu ochronnego, co oznacza, że uznano ją za wartościową. W momencie, gdy pamięć cache się zapełni, system usuwa w pierwszej kolejności elementy z segmentu próbnego, pozostawiając w cache sesje użytkowników aktywnie korzystających z platformy. Dzięki takiemu podejściu unika się przechowywania w cache sesji użytkowników, którzy odwiedzili stronę tylko raz i nie wykazali żadnej aktywności.</p>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-8f761849 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow">
<p class="wp-block-paragraph"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong>Dlaczego warto?</strong></p>



<ul class="wp-block-list">
<li>Lepsza retencja często używanych danych – rzadko używane elementy są usuwane szybciej, co sprawia, że cache lepiej przechowuje istotne dane.</li>



<li>Unikanie problemu „jednorazowych” danych – nie przenosi od razu nowych elementów do segmentu ochronnego, co zapobiega przypadkowemu wyrzuceniu bardziej wartościowych danych.</li>
</ul>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow">
<p class="wp-block-paragraph"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/26a0.png" alt="⚠" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong>Ograniczenia:</strong></p>



<ul class="wp-block-list">
<li>Nieadaptacyjny – w przeciwieństwie do ARC, SLRU nie dostosowuje automatycznie swoich segmentów do zmieniających się wzorców dostępu.</li>



<li>Możliwa suboptymalna wymiana – jeśli segment ochronny jest pełny, rzadko używane elementy mogą utrzymywać się zbyt długo, zamiast zrobić miejsce na bardziej wartościowe dane.</li>
</ul>
</div>
</div>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h5 class="wp-block-heading mb-2 mt-6 text-lg first:mt-3">2Q (Two-Queue)</h5>



<p class="wp-block-paragraph">Algorytm 2Q to ulepszona wersja LRU, która lepiej radzi sobie z jednorazowymi dostępami do danych. Dzieli pamięć cache na dwie główne kolejki: A1 i Am. Nowe elementy trafiają najpierw do A1, która pełni funkcję filtra. Jeśli dany element zostanie użyty ponownie po usunięciu, przechodzi do Am, gdzie przechowywane są często wykorzystywane wpisy. Dzięki temu system unika sytuacji, w której jednorazowe żądania wypierają wartości bardziej istotne.</p>


<div class="wp-block-image">
<figure class="aligncenter size-large"><img decoding="async" width="1024" height="585" src="https://www.bdabek.pl/wp-content/uploads/2025/02/cache_2Q-1024x585.webp" alt="" class="wp-image-3458" srcset="https://www.bdabek.pl/wp-content/uploads/2025/02/cache_2Q-1024x585.webp 1024w, https://www.bdabek.pl/wp-content/uploads/2025/02/cache_2Q-300x171.webp 300w, https://www.bdabek.pl/wp-content/uploads/2025/02/cache_2Q-768x439.webp 768w, https://www.bdabek.pl/wp-content/uploads/2025/02/cache_2Q-1536x878.webp 1536w, https://www.bdabek.pl/wp-content/uploads/2025/02/cache_2Q.webp 1792w" sizes="(max-width: 1024px) 100vw, 1024px" /><figcaption class="wp-element-caption"><em>2Q algorithm</em></figcaption></figure>
</div>


<p class="wp-block-paragraph">Wyobraź sobie aplikację internetową dla sklepu online, który obsługuje zapytania użytkowników o szczegóły produktów. Każde zapytanie pobiera dane z bazy, co może powodować duże obciążenie serwera. Standardowy mechanizm cache oparty na LRU miałby problem, gdyby użytkownicy jednorazowo przeglądali wiele różnych produktów – te mniej popularne mogłyby wypierać z cache&#8217;a często wyszukiwane artykuły.</p>



<p class="wp-block-paragraph">Algorytm 2Q rozwiązuje ten problem poprzez wstępną kolejkę A1, do której trafiają nowo pobrane produkty. Jeśli dany produkt zostanie zapytany tylko raz, po krótkim czasie zostanie usunięty, nie wpływając na cache długoterminowy. Natomiast produkty często wyszukiwane zostaną przeniesione do kolejki Am, gdzie będą utrzymywane dłużej, co przyspieszy ich późniejsze ładowanie. Dzięki temu aplikacja efektywnie zarządza pamięcią cache, zmniejsza liczbę zapytań do bazy danych i poprawia czas odpowiedzi dla użytkowników.</p>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-8f761849 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow">
<p class="wp-block-paragraph"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong>Dlaczego warto?</strong></p>



<ul class="wp-block-list">
<li>Zamiast natychmiastowego usuwania elementów, algorytm przenosi je między kolejkami, co może zminimalizować usuwanie przy małym dostępie.</li>



<li>Dobre rozwiązanie, gdy nie wiemy, jaki wzorzec dostępu dominuje w systemie.</li>
</ul>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow">
<p class="wp-block-paragraph"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/26a0.png" alt="⚠" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong>Ograniczenia:</strong></p>



<ul class="wp-block-list">
<li>Wymaga więcej pamięci i złożonych struktur danych.</li>



<li>Nie zawsze najlepszy w systemach z bardzo małą pamięcią cache – może nie być opłacalny przy niewielkich zasobach.</li>
</ul>
</div>
</div>



<h5 class="wp-block-heading">Porównanie algorytmów</h5>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th><strong>Algorytm</strong></th><th><strong>Kiedy warto?</strong></th><th><strong>Ograniczenia</strong></th></tr></thead><tbody><tr><td><strong><strong>LRU</strong></strong></td><td>Lokalność czasowa, np. cache przeglądarki</td><td>Wrażliwy na zalanie cache nowymi danymi</td></tr><tr><td><strong><strong>LFU</strong></strong></td><td>Obiekty z wysoką częstotliwością dostępu (np. rankingi)</td><td>Problem zimnego startu, większa złożoność</td></tr><tr><td><strong><strong>FIFO</strong></strong></td><td>Proste przypadki (np. cache kolejki)</td><td>Nie uwzględnia lokalności czasowej</td></tr><tr><td><strong>ARC</strong></td><td>Zmienny wzorzec dostępu, wymagająca wydajność</td><td>Złożona implementacja</td></tr><tr><td><strong>SLRU</strong></td><td>Dobre dla mieszanej lokalności</td><td>Wymaga dostrajania wielkości segmentów</td></tr><tr><td><strong>2Q</strong></td><td>Przeciwdziała problemowi zimnego startu</td><td>Większe wymagania pamięciowe</td></tr></tbody></table></figure>



<h2 class="wp-block-heading"><h2 id="inwalidacja_cache"> <a href="#inwalidacja_cache"><span class="dashicons dashicons-admin-links"></span></a>Inwalidacja cache</h2></h2>


<div class="wp-block-image">
<figure class="aligncenter size-large"><img decoding="async" width="1024" height="585" src="https://www.bdabek.pl/wp-content/uploads/2025/02/cache_invalidation-1024x585.webp" alt="" class="wp-image-3485" srcset="https://www.bdabek.pl/wp-content/uploads/2025/02/cache_invalidation-1024x585.webp 1024w, https://www.bdabek.pl/wp-content/uploads/2025/02/cache_invalidation-300x171.webp 300w, https://www.bdabek.pl/wp-content/uploads/2025/02/cache_invalidation-768x439.webp 768w, https://www.bdabek.pl/wp-content/uploads/2025/02/cache_invalidation-1536x878.webp 1536w, https://www.bdabek.pl/wp-content/uploads/2025/02/cache_invalidation.webp 1792w" sizes="(max-width: 1024px) 100vw, 1024px" /><figcaption class="wp-element-caption"><em>Cache invalidation</em></figcaption></figure>
</div>


<p class="wp-block-paragraph">Inwalidacja cache to proces usuwania lub aktualizowania nieaktualnych danych w pamięci podręcznej. Jest kluczowa dla zapewnienia <strong>spójności danych</strong> i zapobiegania zwracaniu przestarzałych wartości. Istnieją różne strategie inwalidacji, zależnie od wymagań aplikacji.</p>



<h6 class="wp-block-heading"><strong>Inwalidacja oparta na czasie (TTL &#8211; Time-To-Live)</strong> / TTI (Time-To-Idle)</h6>



<p class="wp-block-paragraph">TTL jest najprostsza metodą, w której każdy wpis w cache ma określony <strong>czas życia</strong>. Po upływie tego czasu zostaje automatycznie usunięty. TTI powoduje usunięcie wpisu z cache, jeśli nie był on używany przez określony czas. <strong>TTI i TTL można łączyć</strong>, np. ustawić TTL na 30 min i TTI na 10 min, aby zapewnić zarówno maksymalny czas życia, jak i usuwanie nieaktywnych danych.</p>



<h6 class="wp-block-heading"><strong>Inwalidacja natychmiastowa (Explicit Invalidation)</strong></h6>



<p class="wp-block-paragraph">Aplikacja ręcznie usuwa wpisy z cache, gdy dane ulegną zmianie. Gwarantuje to aktualność danych, ale wymaga dokładnego zarządzania cachem.</p>



<h6 class="wp-block-heading"><strong>Inwalidacja oparta na polityce zastępowania (LRU/LFU)</strong></h6>



<p class="wp-block-paragraph">LRU usuwa najdawniej używane wpisy, a LFU najrzadziej używane wpisy. Sprawdza się, gdy cache ma ograniczony rozmiar. Jego wadą jest, że może przetrzymywać nieistotne dane, które znalazły się w cache a mogłyby już z niego wylecieć.</p>



<h6 class="wp-block-heading"><strong>Jaką strategię wybrać?</strong></h6>



<ul class="wp-block-list">
<li><strong>Dane szybko się zmieniają?</strong> → TTL + TTI + Explict Invalidation.</li>



<li><strong>Masz ograniczoną pamięć cache?</strong> → LRU/LFU.</li>



<li><strong>Dane muszą być zawsze aktualne?</strong> → Explict Invalidation.</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading"><h2 id="monitorowanie_cache"> <a href="#monitorowanie_cache"><span class="dashicons dashicons-admin-links"></span></a>Monitorowanie cache</h2></h2>



<p class="wp-block-paragraph">Monitorowanie cache to kluczowy proces, <strong>pomagający</strong> utrzymać wydajność, spójność danych i oszczędność zasobów. Aby efektywnie monitorować cache, należy zastanowić się nad metrykami.</p>


<div class="wp-block-image">
<figure class="aligncenter size-full is-resized"><img decoding="async" width="1024" height="1024" src="https://www.bdabek.pl/wp-content/uploads/2025/02/cache_metrics.webp" alt="" class="wp-image-3467" style="width:658px;height:auto" srcset="https://www.bdabek.pl/wp-content/uploads/2025/02/cache_metrics.webp 1024w, https://www.bdabek.pl/wp-content/uploads/2025/02/cache_metrics-300x300.webp 300w, https://www.bdabek.pl/wp-content/uploads/2025/02/cache_metrics-150x150.webp 150w, https://www.bdabek.pl/wp-content/uploads/2025/02/cache_metrics-768x768.webp 768w" sizes="(max-width: 1024px) 100vw, 1024px" /><figcaption class="wp-element-caption"><em>Metryki Cache w dashboardzie Grafany</em></figcaption></figure>
</div>


<h5 class="wp-block-heading">Jakie metryki warto zbierać?</h5>



<ul class="wp-block-list">
<li><strong>Hit Ratio </strong>– określa, jak często dane są znajdowane w cache, zamiast być pobierane z bazy.</li>



<li>*<strong>Miss Rate </strong>– pokazuje, ile zapytań nie znajduje danych w cache i musi iść do bazy. <strong>Jeśli zbyt wysoki</strong>, warto zwiększyć <strong>rozmiar cache</strong> lub poprawić strategię inwalidacji. Miss Rate i Hit Ratio wzajemnie sumują się do 100%, więc mierząc jeden, automatycznie otrzymujesz drugi. </li>



<li><strong>Eviction Rate (Wskaźnik usunięć)</strong> – Mierzy, ile obiektów zostało usuniętych z cache (z powodu przepełnienia, TTL lub inwalidacji). Zbyt wysoki wskaźnik oznacza, że cache jest za mały.</li>



<li><strong>Memory Usage (Zużycie pamięci)</strong> – ile RAM zajmuje cache.</li>



<li><strong>Latency (Opóźnienie)</strong> – ile trwa odczyt/zapis w cache.</li>
</ul>



<h5 class="wp-block-heading">Jak monitorować Cache w Javie?</h5>



<p class="wp-block-paragraph">W Javie istnieje kilka sposobów monitorowania cache. Dużo zależy od tego, jakiego typu aplikację rozwijamy/tworzymy. Jeżeli tworzysz aplikację w Spring Boot, możesz w prosty sposób dodać zależności do actuatora + micrometer&#8217;a i prometheusa.</p>


<pre class="crayon-plain-tag">&lt;dependency&gt;
    &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
    &lt;artifactId&gt;spring-boot-starter-actuator&lt;/artifactId&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
    &lt;groupId&gt;io.micrometer&lt;/groupId&gt;
    &lt;artifactId&gt;micrometer-registry-prometheus&lt;/artifactId&gt;
&lt;/dependency&gt;</pre>


<p class="wp-block-paragraph">Następnie w <code>application.properties</code> (lub analogicznie yaml z odpowiednią strukturą) wystarczy włączyć metryki i możemy strzelać do API:</p>



<pre class="crayon-plain-tag">management.endpoints.web.exposure.include=*

curl 'http://localhost:8080/actuator/caches' -i -X GET</pre>



<p class="wp-block-paragraph">Teraz można przenieść te dane do Prometheusa, zrobić dashboardy na Grafanie, dodać alerty i mamy gotowy system monitorujący. Nie jest to temat na ten artykuł. </p>



<p class="wp-block-paragraph">Natomiast jeżeli nie używamy Spring Boota, możemy <strong>użyć MBean&#8217;ów JMX&#8217;a</strong>. Jeżeli korzystasz z popularnego rozwiązania do cache&#8217;owania w Javie, to jest duża szansa, że to rozwiązanie daje możliwość udostępnienia danych przez JMX. Osobiście korzystając z tych metryk, używałem bezpośrednio DataDog&#8217;a, więc nie jestem w stanie powiedzieć czy integracja ze stackiem Prometheus + Grafana jest tu możliwa, ale zakładam, że tak.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading has-text-align-left">Podsumowanie</h2>


<div class="wp-block-image">
<figure class="aligncenter"><a href="https://www.bdabek.pl/jak-programista-moze-radzic-sobie-ze-stresem/light-bulb-symbol-png/" rel="attachment wp-att-3333"><img decoding="async" width="358" height="400" src="https://www.bdabek.pl/wp-content/uploads/2025/01/light-bulb-symbol-png.webp" alt="żaróweczka" class="wp-image-3333" srcset="https://www.bdabek.pl/wp-content/uploads/2025/01/light-bulb-symbol-png.webp 358w, https://www.bdabek.pl/wp-content/uploads/2025/01/light-bulb-symbol-png-269x300.webp 269w" sizes="(max-width: 358px) 100vw, 358px" /></a></figure>
</div>


<p class="wp-block-paragraph">Cache jest potężnym narzędziem, które może znacząco przyspieszyć działanie aplikacji. Poprzez inteligentne przechowywanie danych w pamięci podręcznej, możemy zmniejszyć czas dostępu do nich i zwiększyć wydajność. Warto zatem znać i rozważyć wykorzystanie cache&#8217;a.</p>



<p class="wp-block-paragraph">Jeżeli chciałbyś rozwinąć którąś z sekcji, podzielić się swoją opinią czy doświadczeniami, to zachęcam do dyskusji w komentarzach.</p>
<p>Artykuł <a href="https://www.bdabek.pl/cache-java/">Cache w Javie. Trochę wiedzy</a> pochodzi z serwisu <a href="https://www.bdabek.pl">bdabek.pl</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.bdabek.pl/cache-java/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Wyjątki. Czego unikać?</title>
		<link>https://www.bdabek.pl/wyjatki-czego-unikac/</link>
					<comments>https://www.bdabek.pl/wyjatki-czego-unikac/#comments</comments>
		
		<dc:creator><![CDATA[Bartosz Dąbek]]></dc:creator>
		<pubDate>Wed, 10 Feb 2021 19:04:16 +0000</pubDate>
				<category><![CDATA[Programowanie]]></category>
		<category><![CDATA[Java]]></category>
		<guid isPermaLink="false">https://www.bdabek.pl/?p=2852</guid>

					<description><![CDATA[<p>Java pozwala nam na używanie wyjątków do czego sobie zapragniemy. Jako developerzy wiemy natomiast, że wyjątki służą do sytuacji wyjątkowych i mamy do nich jakiś szacunek. Jednak, kiedy przychodzi do zaprojektowania pewnej części systemu zdarza nam się popełniać wykroczenia. Być może nie kosztują one nas za wiele, ale świadczą o niechlujstwie, co nie jest dobrą&#8230;&#160;<a href="https://www.bdabek.pl/wyjatki-czego-unikac/" rel="bookmark">Dowiedz się więcej &#187;<span class="screen-reader-text">Wyjątki. Czego unikać?</span></a></p>
<p>Artykuł <a href="https://www.bdabek.pl/wyjatki-czego-unikac/">Wyjątki. Czego unikać?</a> pochodzi z serwisu <a href="https://www.bdabek.pl">bdabek.pl</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Java pozwala nam na używanie wyjątków do czego sobie zapragniemy. Jako developerzy wiemy natomiast, że wyjątki służą do <strong>sytuacji wyjątkowych</strong> i mamy do nich jakiś <em>szacunek</em>. Jednak, kiedy przychodzi do zaprojektowania pewnej części systemu zdarza nam się popełniać wykroczenia. Być może nie kosztują one nas za wiele, ale świadczą o niechlujstwie, co nie jest dobrą cechą.</p>
<hr />
<h3>Cześć <img decoding="async" class="emoji" role="img" draggable="false" src="https://s.w.org/images/core/emoji/12.0.0-1/svg/1f642.svg" alt="&#x1f642;" /></h3>
<p>Na wstępie zaznaczę, że nie jest to pełna lista, czego warto unikać przy pracy z wyjątkami. Są to jednak przypadki, które zdarza mi się widzieć w kodzie produkcyjnym, a czasami bywa, że sam dokładam do tego jakąś cegiełkę (z czego nie jestem specjalnie dumny).</p>
<p><strong>Jeżeli masz jakiś pattern do dodania, napisz w komentarzu. Zaktualizuję listę.</strong></p>
<p>W dzisiejszym artykule:</p>
<ul>
<li><a href="#Zbyt szczegółowe informacje"><strong>Zbyt szczegółowe informacje</strong></a></li>
<li><a href="#Przerzucanie wyżej"><strong>Przerzucanie wyżej</strong></a></li>
<li><a href="#Dziesiątki podtypów"><strong>Dziesiątki podtypów</strong></a></li>
<li><a href="#Uciszanie wyjątkowych sytuacji"><strong>Uciszanie wyjątkowych sytuacji</strong></a></li>
<li><a href="#Finally z ostatecznym zdaniem"><strong>Finally z ostatecznym zdaniem</strong></a></li>
</ul>
<hr id="Zbyt szczegółowe informacje" />
<p><h2 id="Zbyt szczegółowe informacje"> <a href="#Zbyt szczegółowe informacje"><span class="dashicons dashicons-admin-links"></span></a>Zbyt szczegółowe informacje</h2></p>
<p>Zdarzyło Ci kiedykolwiek się zobaczyć stack trace błędu aplikacji tam, gdzie nie powinno go być? A może sam napisałeś kod, który podobne bagienko wyrzucał na zewnątrz?</p>
<p><a href="https://www.bdabek.pl/wyjatki-czego-unikac/stacktrace/" rel="attachment wp-att-2858"><img decoding="async" class="aligncenter size-full wp-image-2858" src="https://www.bdabek.pl/wp-content/uploads/2021/02/stacktrace.png" alt="" width="1338" height="700" srcset="https://www.bdabek.pl/wp-content/uploads/2021/02/stacktrace.png 1338w, https://www.bdabek.pl/wp-content/uploads/2021/02/stacktrace-300x157.png 300w, https://www.bdabek.pl/wp-content/uploads/2021/02/stacktrace-1024x536.png 1024w, https://www.bdabek.pl/wp-content/uploads/2021/02/stacktrace-768x402.png 768w" sizes="(max-width: 1338px) 100vw, 1338px" /></a></p>
<p>Jestem przekonany, że się z tym spotkałeś. Pamiętaj aby <strong>nie dawać końcowym użytkownikom zbyt szczegółowych informacji, gdy nie powinni mieć do niej dostępu</strong>. Co to znaczy nie powinni mieć dostępu?</p>
<p>Pisząc oprogramowanie, np. dla instytucji finansowej, na 100% nie chcesz zdradzać używanych technologii i frameworków. Nie jest jasne dlaczego wystąpił błąd (w teorii takie sytuacje przecież nie powinny się wydarzyć bo to wyjątki) i kto go spowodował. Być może ktoś właśnie przeprowadza atak i zbiera dodatkowe informacje. Ujawienie zbyt wielu szczegółów otwiera nowe wektory ataku &#8211; można wnioskować które wersje bibliotek są używane i szukać pod nie payload&#8217;ów.</p>
<hr id="Przerzucanie wyżej" />
<p><h2 id="Przerzucanie wyżej"> <a href="#Przerzucanie wyżej"><span class="dashicons dashicons-admin-links"></span></a>Przerzucanie wyżej</h2></p>
<p>Kolejnym często spotyknanym <em>mechanizmem</em> jest wyrzucanie wyjątków warstwę wyżej. Celowo użyłem słowa <strong>mechanizm</strong>, zamiast <em>błąd</em>. Ile razy zdarzyło Ci się widzieć jakiś <strong>Checked Exception</strong> (nie pasuje mi tu spolszczenie tego słowa), definiowany na poziomie metody w jakimś serwisie a następnie propagowanym w górę? A właściwie to wyżej i wyżej i tak aż do samego kontrolera.. który, też próbuje wyrzucić to warstwę wyżej.</p><pre class="crayon-plain-tag">class Controller {
  public Response serwis() throws Exception {
    return Response.of(new Service().metodaSerwisowa());
  }
}

class Service {
  public String metodaSerwisowa() throws Exception {
    return prywatnaMetodaSerwisowa();
  }

  private String prywatnaMetodaSerwisowa() throws Exception {
    // logika wyrzucająca Exception
    return "Nie istotne";
  }
}</pre><p><strong>Łap wyjątki jak najszybciej. </strong>Wacham się, żeby to napisać, bo wszystko zależy od kontekstu, <strong>ALE</strong> jeżeli nie wiesz jak obsłużyć ten wyjątek (nie jesteś pewny czy ktokolwiek powinien go łapać), zamień go na <strong>Runtime Exception</strong>. W przypadku błędu skończysz właściwie z tym samym.</p>
<hr id="Dziesiątki podtypów" />
<p><h2 id="Dziesiątki podtypów"> <a href="#Dziesiątki podtypów"><span class="dashicons dashicons-admin-links"></span></a>Dziesiątki podtypów</h2></p>
<p>Zdarzyło Ci się widzieć lub definiować specyficzne wyjątki dla poszczególnych case&#8217;ów tylko po to aby łatwiej móc zdiagnozować jego wystąpienie?</p>
<p><a href="https://www.bdabek.pl/wyjatki-czego-unikac/exceptions/" rel="attachment wp-att-2862"><img decoding="async" class="aligncenter size-full wp-image-2862" src="https://www.bdabek.pl/wp-content/uploads/2021/02/exceptions.png" alt="" width="339" height="165" srcset="https://www.bdabek.pl/wp-content/uploads/2021/02/exceptions.png 339w, https://www.bdabek.pl/wp-content/uploads/2021/02/exceptions-300x146.png 300w" sizes="(max-width: 339px) 100vw, 339px" /></a></p>
<p>Jest mi głupio, bo sam w to brnąłem. Tworzyłem nowe <em>wyspecjalizowane</em> wyjątki, których nie miałem zamiaru obsługiwać. <strong>Definiujesz customowy wyjątek</strong>? <strong>Rób to tylko i wyłącznie w przypadku, gdy wiesz, że będziesz go obsługiwał</strong>!</p>
<hr id="Uciszanie wyjątkowych sytuacji" />
<p><h2 id="Uciszanie wyjątkowych sytuacji"> <a href="#Uciszanie wyjątkowych sytuacji"><span class="dashicons dashicons-admin-links"></span></a>Uciszanie wyjątkowych sytuacji</h2></p>
<p>Co powiesz o takim kodzie? Zdarzyło Ci się widzieć lub napisać coś takiego?</p><pre class="crayon-plain-tag">public String doSmth() {
  try {
    businessMethodThatThrowsException();
  } catch(Exception e) {
    // TODO:
  }
}</pre><p><strong>Skoro już obsługujesz wyjątek, to zostaw po nim ślad!</strong> Unikaj łapania i wygłuszania wyjątków! Sama nazwa wyjątków mówi, że są to sytuacje wyjątkowe. Jeżeli już wydarzyła się ta wyjątkowa sytuacja, lepiej niech poleci jakakolwiek informacja na stdout. Dlaczego? Będziesz mieć więcej informacji o systemie z jakim pracujesz! Jeżeli będzie to bardzo uciążliwe, to ktoś się tym na pewno zajmie.</p>
<hr id="Finally z ostatecznym zdaniem" />
<p><h2 id="Finally z ostatecznym zdaniem"> <a href="#Finally z ostatecznym zdaniem"><span class="dashicons dashicons-admin-links"></span></a>Finally z ostatecznym zdaniem</h2></p>
<p>Java działa w taki sposób, że to blok finally ma ostateczne zdanie. Jeżeli kod wyrzuca wyjątek w bloku <em>try</em>, a następnie również w <em>finally</em>, to ostatecznie ten drugi będzie propagowany. Rozważ taki przykład, jak myślisz, co zostanie wyrzucone?</p><pre class="crayon-plain-tag">public String doSmth() {
  try {
    throw new IllegalArgumentException("try");
  } catch (RuntimeException e) {
    throw new IllegalStateException("catch", e);
  } catch (Exception e) {
    // nigdy się nie wykona
    System.out.println("oo?");
  }
  finally {
    throw new RuntimeException("finally");
  }
}</pre><p>Jeżeli powiedziałeś <em>RuntimeException</em>, to masz rację. Spójrz, jaki jest tutaj problem. <strong>Straciłeś informację o prawdziwym problemie</strong>. Pamiętaj, blok <em>finally</em> <strong>ZAWSZE</strong> ma ostatnie zdanie!</p>
<hr />
<h2>Podsumowanie</h2>
<p><a href="https://www.bdabek.pl/spring-boot-i-logi-ustawienia-logbacka/lightbulb/" rel="attachment wp-att-976" data-slb-active="1" data-slb-asset="1379905354" data-slb-internal="976"><img decoding="async" class="aligncenter wp-image-976 size-thumbnail lazyloaded" src="https://cdn.shortpixel.ai/client/to_webp,q_glossy,ret_img,w_150,h_150/https://www.bdabek.pl/wp-content/uploads/2020/05/Lightbulb-150x150.jpg" alt="" width="150" height="150" data-src="https://cdn.shortpixel.ai/client/to_webp,q_glossy,ret_img,w_150,h_150/https://www.bdabek.pl/wp-content/uploads/2020/05/Lightbulb-150x150.jpg" /></a></p>
<p>Nie jest to może za obszerny artykuł, natomiast są to sytuacje, które zdarza nam się widzieć i czasami popełniać. Jeżeli masz jakieś inne patterny do dodania, to dziel się śmiało :).</p>
<p>Źródła:</p>
<ul>
<li><strong><a href="https://youtu.be/LRwCE7GreSM">Victor Rentea &#8211; The Definitive Guide to Working with Exceptions in Java</a></strong></li>
<li><a href="http://victorrentea.ro/blog/presenting-exceptions-to-users/"><strong>Presenting Exceptions to Users</strong></a></li>
<li><a href="http://victorrentea.ro/blog/exception-handling-guide-in-java/"><strong>Exception Handling Guide in Java</strong></a></li>
</ul>
<p>Artykuł <a href="https://www.bdabek.pl/wyjatki-czego-unikac/">Wyjątki. Czego unikać?</a> pochodzi z serwisu <a href="https://www.bdabek.pl">bdabek.pl</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.bdabek.pl/wyjatki-czego-unikac/feed/</wfw:commentRss>
			<slash:comments>3</slash:comments>
		
		
			</item>
		<item>
		<title>Certyfikacja z Javy. Egzamin OCA i Moje Wnioski</title>
		<link>https://www.bdabek.pl/certyfikacja-z-javy/</link>
					<comments>https://www.bdabek.pl/certyfikacja-z-javy/#comments</comments>
		
		<dc:creator><![CDATA[Bartosz Dąbek]]></dc:creator>
		<pubDate>Thu, 28 Jan 2021 11:00:40 +0000</pubDate>
				<category><![CDATA[Programowanie]]></category>
		<category><![CDATA[Java]]></category>
		<guid isPermaLink="false">https://www.bdabek.pl/?p=2797</guid>

					<description><![CDATA[<p>Istnieją różne sposoby na poszerzanie wiedzy w zakresie języka programowania: własna aplikacja, udział w projektach open source, kursy, szkolenia. Większość z tych metod nie wydaje jednak poświadczenia, że faktycznie umiemy, to co umiemy. Na kursie czy szkoleniu mogliśmy przecież tylko być&#8230; Jak zatem potwierdzić, że faktycznie umiemy, to co deklarujemy? Jeżeli chodzi o poświadczenie wiedzy&#8230;&#160;<a href="https://www.bdabek.pl/certyfikacja-z-javy/" rel="bookmark">Dowiedz się więcej &#187;<span class="screen-reader-text">Certyfikacja z Javy. Egzamin OCA i Moje Wnioski</span></a></p>
<p>Artykuł <a href="https://www.bdabek.pl/certyfikacja-z-javy/">Certyfikacja z Javy. Egzamin OCA i Moje Wnioski</a> pochodzi z serwisu <a href="https://www.bdabek.pl">bdabek.pl</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Istnieją różne sposoby na poszerzanie wiedzy w zakresie języka programowania: własna aplikacja, udział w projektach open source, kursy, szkolenia. Większość z tych metod nie wydaje jednak poświadczenia, że faktycznie umiemy, to co umiemy. Na kursie czy szkoleniu mogliśmy przecież tylko być&#8230; Jak zatem potwierdzić, że faktycznie umiemy, to co deklarujemy?</p>
<hr />
<p>Jeżeli chodzi o poświadczenie wiedzy w zakresie Javy, to dobrą metodą jest uzyskanie certyfikatu. Aby otrzymać certyfikat, trzeba zaliczyć egzamin na odpowiednim poziomie — obecnie jest to 65% poprawnych odpowiedzi. Każde podejście to koszt około 1050 złotych (245$). Czy jest to najlepsza forma? Zapewne nie. Szczególnie dlatego, że sam egzamin nie pokazuje tego jak myślimy, a jedynie sprawdza naszą znajomość języka i jego specyfikacji, ale o tym w dalszej części artykułu.</p>
<p>Osobiście mam przeświadczenie, że niewiele osób decyduje się na pozyskiwanie certyfikatów (szczególnie w świecie Javy). Wydaje mi się, że jednym z głównych powodów jest rozpowszechnione myślenie, że certyfikaty niczego nie dają. Dają czy nie dają? Do tego wrócimy jeszcze we wnioskach&#8230;</p>
<p>W artykule będę zamiennie używał słów certyfikat / egzamin. Oba terminy odnoszą się po prostu do podjęcia próby zaliczenia egzaminu, czy też jego konsekwencji — uzyskania certyfikatu.</p>
<p>W dzisiejszym artykule:</p>
<ul>
<li><a href="#Ścieżki certyfikatów"><strong>Ścieżki certyfikatów &#8211; OCA, OCP. Co to?</strong></a></li>
<li><a href="#Przygotowania"><strong>Przygotowania do egzaminu OCA</strong></a></li>
<li><a href="#Zapis na egzamin"><strong>Zapis na egzamin</strong></a></li>
<li><a href="#Przebieg egzaminu"><strong>Przebieg egzaminu</strong></a></li>
</ul>
<hr id="Ścieżki certyfikatów" />
<h2><span style="color: #ff6600;">Ścieżki certyfikatów &#8211; OCA, OCP. Co to?</span></h2>
<p>Certyfikacja z Javy posiada <a href="https://en.wikipedia.org/wiki/Oracle_Certification_Program">kilka możliwych ścieżek</a>. Wybór zależy od potrzeby — naszej lub naszych przełożonych. Nie zawsze jednak<strong> <span style="color: #ff6600;">możemy</span></strong> ot, tak wybrać dowolną ścieżkę certyfikacyjną. Niektóre z egzaminów wymagają spełnienia pewnych warunków wstępnych. Informacje na temat warunków znajdziesz np. na platformie edukacyjnej Oracle&#8217;a lub na stronie konkretnego egzaminu (wpisz nazwę egzaminu — requirements).</p>
<p>Jaka jest różnica między OCA a OCP?</p>
<ul>
<li><a href="https://education.oracle.com/es/java-se-8-programmer-ii/pexam_1Z0-808"><strong>OCA</strong> </a>jest skrótem od <span style="color: #ff6600;"><strong>Oracle Certified Associate.</strong></span> W świecie certyfikacji jest to egzamin identyfikujący się pod nazwą: <span style="color: #ff6600;"><strong>1Z0-808 &#8211; Java SE 8 Programmer I</strong></span>. Obecnie (lipiec, 2022) egzamin składa się z 70 pytań, trwa 150 minut, kosztuje 245$ i aby go zaliczyć, trzeba poprawnie odpowiedzieć na 65% pytań.</li>
<li><a href="https://education.oracle.com/es/java-se-8-programmer-ii/pexam_1Z0-809"><strong>OCP</strong></a>, to skrót od <span style="color: #ff6600;"><strong>Oracle Certified Professional</strong></span>. Jego nazwa w systemie certyfikującym to <span style="color: #ff6600;"><strong>1Z0-809 &#8211; Java SE 8 Programmer II</strong></span>. Na lipiec 2022 egzamin posiada takie same parametry jak OCA, z wyjątkiem liczby pytań,<span style="color: #ff6600;"><strong> która wynosi 85</strong></span>!</li>
</ul>
<p>Zarówno OCA, jak i OCP są egzaminami sprawdzającymi naszą wiedzę w zakresie języka Java. Mają one jasno <span style="color: #ff6600;"><strong>zdefiniowane bloki tematyczne</strong></span>, wokół których możemy się spodziewać pytań. Nie jest więc tak, że zapisując się na egzamin, musimy znać Javę od A do Z. Moim zdaniem egzaminy OCA oraz OCP są najbardziej wiarygodnym poświadczeniem wiedzy w zakresie znajomości języka.</p>
<p>Ścieżka certyfikacji z Javy prezentuje się w sposób pokazany na obrazku poniżej. Jest to zdjęcie z jednego z <a href="https://enthuware.com/">popularniejszych serwisów</a> dających dostęp do zestawów testowych (<em>oczywiście za odpowiednią opłatą</em>).</p>
<p><figure id="attachment_2805" aria-describedby="caption-attachment-2805" style="width: 880px" class="wp-caption aligncenter"><a href="https://enthuware.com/" target="_blank" rel="attachment noopener wp-att-2805"><img decoding="async" class="wp-image-2805 size-full" src="https://www.bdabek.pl/wp-content/uploads/2021/01/java-certification-path-1z0-819.png" alt="" width="880" height="608" srcset="https://www.bdabek.pl/wp-content/uploads/2021/01/java-certification-path-1z0-819.png 880w, https://www.bdabek.pl/wp-content/uploads/2021/01/java-certification-path-1z0-819-300x207.png 300w, https://www.bdabek.pl/wp-content/uploads/2021/01/java-certification-path-1z0-819-768x531.png 768w" sizes="(max-width: 880px) 100vw, 880px" /></a><figcaption id="caption-attachment-2805" class="wp-caption-text">Zdjęcie z serwisu enthuware.com</figcaption></figure></p>
<hr id="Przygotowania" />
<h2><span style="color: #ff6600;">Przygotowania do egzaminu OCA</span></h2>
<p>Cały etap przygotowań podzieliłem na trzy sekcje: <strong><span style="color: #ff6600;">analiza</span>, </strong><strong><span style="color: #ff6600;">teoria</span> </strong>oraz <span style="color: #ff6600;"><strong>praktyka</strong></span></p>
<h3><span style="color: #ff6600;"><strong>Analiza</strong></span></h3>
<p>Na tym etapie nie wiedziałem jeszcze nic, o tym, jak wygląda ścieżka certyfikacyjna. Czym są poszczególne egzaminy, czego się spodziewać, od czego zacząć, jak i na który egzamin się zapisać.</p>
<p>Przed podejściem do egzaminu lepiej mieć wiedzę w tym zakresie. Pozwoli to prawidłowo zaplanować, co musimy powtórzyć, czego musimy się nauczyć, jak zapisać się na egzamin, co mieć ze sobą itp. Na całe szczęście nie trzeba wiedzieć aż tak dużo. Wybierając standardową drogę:</p>
<ol>
<li>Musisz wiedzieć, czym jest OCA, a czym OCP</li>
<li>Jaki jest zakres zagadnień poszczególnych egzaminów</li>
<li>Z jakich materiałów teoretycznych będziesz korzystać (więcej o tym w sekcji Teoria)</li>
<li>Z jakich materiałów praktycznych będziesz korzystać (więcej o tym w sekcji Praktyka)</li>
<li>Jak zapisać się na egzamin</li>
<li>Jak przygotować się do egzaminu online (nie omawiam tego w tym artykule, ale jeżeli jesteś ciekawy/a, daj znać)</li>
</ol>
<p>Jeżeli masz kogoś znajomego, kto przechodził podobną drogę, porozmawiaj z nim! W moim przypadku, kiedy podchodziłem do egzaminu, nie miałem nikogo, kto by przetarł przede mną drogę. Zatem, każdy z tych kroków musiałem eksplorować sam. Dzięki Bogu w Internecie jest ogrom informacji i znając język angielski (a podchodząc do egzaminu, powinieneś znać ten język) bez problemu znajdiesz odpowiedzi na większość pytań.</p>
<h3><span style="color: #ff6600;"><strong>Teoria</strong></span></h3>
<p>Na tym etapie trzeba zapoznać się z materiałem obowiązującym na egzaminie. Może to być przeczytanie książki, która przygotowuje do konkretnego egzaminu lub kurs online. Ja zachęcam do <span style="color: #ff6600;"><strong>wybrania książki</strong></span>! Jeżeli sami przeczytamy i przerobimy zadania, to więcej zostanie w głowie niż po obejrzeniu kursu.</p>
<p>Należy pamiętać, egzamin a programowanie na co dzień, to <span style="color: #ff6600;"><strong>dwa różne światy</strong></span>. Egzamin zawiera pytania pułapki i sprawdzi Twoją znajomość języka oraz składni. Pokusiłbym się nawet o takie stwierdzenie: egzamin postawi Cię w roli <span style="color: #ff6600;"><strong>kompilatora</strong></span>.</p>
<p>Natomiast bez obaw! Egzaminy są przeprowadzane od wielu lat i, pomimo że pytania się zmieniają, to struktura egzaminu <span style="color: #ff6600;"><strong>NIE</strong></span>! I dlatego na przestrzeni lat powstało kilka dobrych materiałów do nauki. Z mojej strony polecę Ci książkę, z której sam korzystałem i jestem zadowolony: <a href="https://amzn.to/3oaWl1m">OCA: Oracle Certified Associate Java SE 8 Programmer I Study Guide: Exam 1Z0-808</a>. Książka typowo pod egzamin. Autorzy dają wiele<span style="color: #ff6600;"><strong> wskazówek</strong> </span>odnośnie do samego egzaminu. Piszą, na co zwracać uwagę i jakich <em>pytań pułapek</em> można się spodziewać. Co więcej, dla każdego z rozdziałów (jest ich 6), <span style="color: #ff6600;"><strong>przygotowany jest zestaw pytań</strong></span>, sprawdzający w praktyce przeczytaną wiedzę. Dla osoby z kilkuletnim doświadczeniem książka wchodzi lekką ręką <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>
<p><a href="https://www.amazon.de/-/pl/dp/1118957407?__mk_pl_PL=%C3%85M%C3%85%C5%BD%C3%95%C3%91&amp;dchild=1&amp;keywords=OCA&amp;qid=1611416356&amp;sr=8-1&amp;linkCode=li3&amp;tag=dabek-21&amp;linkId=3ad8a75f8424a2c08e7384fd4b8c30c8&amp;language=pl_PL&amp;ref_=as_li_ss_il" target="_blank" rel="noopener"><img decoding="async" class="aligncenter" src="//ws-eu.amazon-adsystem.com/widgets/q?_encoding=UTF8&amp;ASIN=1118957407&amp;Format=_SL250_&amp;ID=AsinImage&amp;MarketPlace=DE&amp;ServiceVersion=20070822&amp;WS=1&amp;tag=dabek-21&amp;language=pl_PL" border="0" /></a></p>
<p>Inną, również polecaną przez wielu lekturą jest <a href="https://amzn.to/3qMiLaU">OCA Java SE 8 Programmer I Certification Guide by Mala Gupta</a>. Nie czytałem, więc nie mogę z czystym sercem polecić, ale patrząc na recenzje, uważam, że będzie równie wartościowa.</p>
<p><a href="https://www.amazon.de/-/pl/dp/1617293253?__mk_pl_PL=%C3%85M%C3%85%C5%BD%C3%95%C3%91&amp;dchild=1&amp;keywords=oca+java+se+8+programmer+i+certification+guide&amp;qid=1611416931&amp;sr=8-1&amp;linkCode=li3&amp;tag=dabek-21&amp;linkId=0e2212ea23e8ac57f5eb3bf63d964ccb&amp;language=pl_PL&amp;ref_=as_li_ss_il" target="_blank" rel="noopener"><img decoding="async" class="aligncenter" src="//ws-eu.amazon-adsystem.com/widgets/q?_encoding=UTF8&amp;ASIN=1617293253&amp;Format=_SL250_&amp;ID=AsinImage&amp;MarketPlace=DE&amp;ServiceVersion=20070822&amp;WS=1&amp;tag=dabek-21&amp;language=pl_PL" alt="" width="200" height="250" border="0" /></a><img decoding="async" style="border: none !important; margin: 0px !important;" src="https://ir-de.amazon-adsystem.com/e/ir?t=dabek-21&amp;language=pl_PL&amp;l=li3&amp;o=3&amp;a=1617293253" alt="" width="1" height="1" border="0" /></p>
<p><img decoding="async" style="border: none !important; margin: 0px !important;" src="https://ir-de.amazon-adsystem.com/e/ir?t=dabek-21&amp;language=pl_PL&amp;l=li3&amp;o=3&amp;a=1118957407" alt="" width="1" height="1" border="0" /></p>
<h3><span style="color: #ff6600;"><strong>Praktyka</strong></span></h3>
<p><span style="color: #ff6600;"><strong>Sekcja praktyczna</strong></span>, czyli rozwiązywanie zadań i przykładowych egzaminów próbnych.</p>
<p>Dzięki temu, że kupiłem wcześniej polecaną książkę (<a href="https://amzn.to/3oaWl1m">tą</a>), miałem dostęp do strony z testami. Są tam trzy próbne testy (60 pytań każdy), dodatkowo są tam też testy dla każdego z poszczególnych podrozdziałów książki.</p>
<p>Jednak to nie wydawało mi się to wystarczające i bałem się podchodzić do egzaminu wartego 1050 zł bez większej praktyki. W fazie analizy znalazłem kilka polecanych źródeł z przykładowymi testami. Najpopularniejszymi serwisami z pytaniami są:</p>
<ul>
<li><a href="https://enthuware.com/">Enthuware</a></li>
<li><a href="https://shrsl.com/2r6f2">Whizlabs</a>.</li>
</ul>
<p>Oba są relatywnie tanie — cena około 10$ za 400-500 różnorodnych pytań. Ja zdecydowałem się na <a href="https://shrsl.com/2r6f2">Whizlabs</a>. Testy na <a href="https://shrsl.com/2r6f2">Whizlabs</a> są ok. Nie mam niestety porównania z Enthuware. Na pewno plusem Whizlabs jest to, że korzystamy z przeglądarki internetowej + do każdego pytania są krótkie wyjaśnienia, dlaczego powinniśmy wybrać daną odpowiedź a inne odrzucić. Choć przyznam, że wyjaśnienia te czasami bywają bezwartościowe. Podam przykład, spolszczając co nieco i dodając szczyptę ironii: <em>odpowiedź A jest błędna, ponieważ nie można tak robić</em>. Mało wyjaśniający tekst, bo bardziej mnie interesowało, dlaczego tak nie można. Całe szczęście takich bezsensownych odpowiedzi nie jest wiele :). <span style="color: #ff6600;"><strong>Po przeczytaniu wcześniej polecanej książki i przerobieniu pytań na Whizlabs zaliczyłem egzamin na 95%</strong></span>, więc moim zdaniem były to wartościowe źródła.</p>
<p>Inne materiały, nad którymi się zastanawiałem, podaję poniżej. Jednak ze względu na ich cenę, postanowiłem, że wolę odpuścić.</p>
<ul>
<li><a href="https://www.certification-questions.com/practice-exam/java/1z0-808">certification-questions.com</a></li>
<li><a href="https://www.certleader.com/1z0-808-dumps.html">certleader.com</a></li>
</ul>
<hr id="Zapis na egzamin" />
<h2><span style="color: #ff6600;">Zapis na egzamin</span></h2>
<p><span style="color: #ff6600;"><strong>TL;DR</strong></span></p>
<p>Zapis na egzamin w styczniu 2021 w moim przypadku był uciążliwy. Pojawiło się kilka przeszkód, ale ostatecznie udało mi się zapisać&#8230; siedząc na słuchawce z konsultantem z UK (a po akcencie wnioskując to z Indii).</p>
<hr />
<p>Znane mi opcje do zapisu były dwie:</p>
<ol>
<li>kupuję voucher/egzamin na stronie Oracle, a następnie wykorzystuję w systemie certyfikującym (<a href="https://home.pearsonvue.com/oracle/onvue">pearson vue</a>)</li>
<li>kupuję egzamin bezpośrednio w systemie certyfikującym (<a href="https://home.pearsonvue.com/oracle/onvue">pearson vue</a>)</li>
</ol>
<p>Pomyślałem, że skoro to egzamin Oracle&#8217;owy, to kupię egzamin ze strony Oracle&#8217;a. Problemy zaczęły się już przy uzupełnianiu profilu&#8230; pola walidujące (imię, nazwisko, adres itp.) <span style="color: #ff6600;"><strong>to porażka</strong></span>. Masz wszystko uzupełnione, wciskasz <em>ok </em>i dostajesz błąd walidacji. Mało tego, pole walidujące numer telefonu posiada wejście na 10 cyfr (pomijając prefiks, który jest wykrywany automatycznie na podstawie wcześniej wprowadzonych pól) i jeżeli podamy mniej (a polskie numery są 9-cyfrowe), to co się dzieje? Oczywiście mamy błąd walidacji! Mocno mnie to zirytowało i aż napisałem do supportu Oracle&#8217;a, jak mam uzupełnić to dziadostwo. Rozwiązanie, jakie podali: <span style="color: #ff6600;"><strong>proszę wprowadzić 0 (zero) jako pierwszą cyfrę</strong></span>.</p>
<p>Przeszliśmy już przez wszystkie pola walidujące, mamy nasz voucher i kierujemy się do płatności. Na ten moment (przypominam, styczeń 2021) są tam 4 metody płatności — najwygodniejsza to oczywiście płatność kartą i tylko taką byłem zainteresowany, więc nie mogę opisać swoich wrażeń z pozostałymi. Wybrałem płatność kartą, uzupełniłem dane karty i aby móc przejść do samego zakupu, trzeba było potwierdzić kartę (lub to, że jest się jej właścicielem, nie wiem). Ogólnie to przenosi mnie na stronę banku, loguję się, widzę płatność dla Oracle&#8217;a na 1 zł (!), potwierdzam płatność na telefonie. Strona banku reaguje, że wszystko się udało i za chwilę powrócę do dalszych zakupów i&#8230; BAAAM, wywaliło mnie na pustą kartę. W pasku URL widzę tylko dziwny adres jakiegoś API i w zasadzie tyle.</p>
<p><span style="color: #ff6600;"><strong>Nic nie mogę zrobić</strong></span>. Na karcie widzę obciążenie na złotówkę (wisiało tak przez około tydzień) i tyle. Spróbowałem powtórzyć proces jeszcze 3x na innych przeglądarkach (nawet na wspaniałym IE!). Na żadnej się nie udało. Ale taki mały tip, że w zależności od przeglądarki, pola walidacyjne działały lepiej (tam, gdzie obsługa flasha była włączona, tam działało to trochę lepiej). O łał&#8230; Trochę ponarzekałem, a dopiero przechodzimy do samego systemu certyfikującego — perason vue. Postaram się bardziej streszczać.</p>
<p>W tym przypadku, pola walidacyjne, wprowadzanie numeru telefonu, itp. było o niebo prostsze! Niestety, był ten sam problem z płatnością. Potwierdzasz płatność i dostajesz przekierowanie na pustą stronę. Byłem już zirytowany tym wszystkim i napisałem maila do supportu, jak mam się zapisać na ten egzamin, <span style="color: #ff6600;"><strong>bo sam nie umiem</strong></span>. Powiedzieli, aby kontaktować się z ich obsługą, podali numer telefonu (numer w UK, bo nie mają wsparcia w Polsce) i godziny pracy. <span style="color: #ff6600;"><strong>Dzwonię</strong></span>&#8230; Standardowa infolinia, automat coś gada i wybieram odpowiednie przyciski. Po kilku wciśnięciach i kolejnych kilku minutach oczekiwania w kolejce w końcu łączy mnie z jednym z konsultantów wspierających sekcje Oracle.</p>
<p><span style="color: #ff6600;"><strong>Udało mi się zapisać na ten egzamin za 5 telefonem</strong></span>. Ogólnie całe flow polega na tym, że podajesz swoje dane i mówisz, co chcesz, dlaczego nie możesz sam tego zrobić i oni wprowadzają wszystkie dane za Ciebie. Ale dobra&#8230; dlaczego dopiero za 5 razem?? <span style="color: #ff6600;"><strong>Jeżeli coś im nie działało w systemie,</strong> <strong>to się rozłączali!</strong></span> Przykład: przeszedłem z gościem przez całe flow, doszliśmy do płatności. Gościu mi mówi, że system akurat im leży, żebym poczekał 4-5 minut i wtedy spróbujemy. Po 5 minutach odezwał się, że dalej nie działa i żebyśmy jeszcze chwilę poczekali. Czekam, czekam&#8230; cała rozmowa trwa już 20 minut i nagle słyszę <span style="color: #ff6600;"><strong>BIP</strong></span>, gościu się rozłączył. A tylko przypomnę, że to rozmowa z numerem z UK, która nie jest specjalnie za tania&#8230;</p>
<p><span style="color: #ff6600;"><b>Dobra rada </b></span>dla każdego, kto musi dzwonić za granicę. Używajcie Skype&#8217;a, wychodzi o wiele taniej (lub za darmo, jak się w dobrą promocję trafi).</p>
<hr id="Przebieg egzaminu" />
<h2><span style="color: #ff6600;">Przebieg egzaminu</span></h2>
<p>Ten artykuł i tak wyszedł spory, więc w tej sekcji postaram się pisać krótko i zwięźle. Ja podchodziłem do egzaminu online, więc naturalnie ten proces będę opisywać.</p>
<p>Wszystkie przydatne informacje co do samego egzaminu można było znaleźć na tej <a href="https://home.pearsonvue.com/oracle/onvue">stronie</a>. Mnie ciekawił bardziej proces weryfikacji przed przystąpieniem do egzaminu i jak to przebiega. Na oficjalnych stronach nie mogłem nic znaleźć, ale jest YouTube :). Poniżej podsyłam video, które przedstawia, jak wygląda proces weryfikacji.</p>
<p>W kwesti samego egzaminu nie było tu nic nadzwyczajnego. Dostajesz pytania i je rozwiązujesz. Egzamin posiada różne typy odpowiedzi — <strong><span style="color: #ff6600;">jednokrotnego</span> </strong>lub <strong><span style="color: #ff6600;">wielokrotnego</span> </strong>wyboru. Jeżeli pytania są wielokrotnego wyboru, to <span style="color: #ff6600;"><strong>w pytaniu jest jasno określona ilość poprawnych odpowiedzi</strong></span> (nie da się zaznaczyć większej ilości). <span style="color: #ff6600;"><strong>Wszystkie pytania są zamknięte</strong></span>.</p>
<p>Kończąc egzamin, nasz wynik (procent poprawnych odpowiedzi), jest przedstawiony zaraz po zakończeniu. A więc wciskasz <em>Finish</em> i za 10 sekund wiesz, czy egzamin jest zaliczony, czy nie.</p>
<div class="nv-iframe-embed"><iframe loading="lazy" title="EXAM DAY: Process of using onVUE App (Pearsonvue Online Exam Application) at Home or Office" width="1200" height="675" src="https://www.youtube.com/embed/otw3uO3KXpA?feature=oembed&#038;enablejsapi=1" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></div>
<hr />
<h2><span style="color: #ff6600;">Podsumowanie</span></h2>
<p><a href="https://www.bdabek.pl/spring-boot-i-logi-ustawienia-logbacka/lightbulb/" rel="attachment wp-att-976" data-slb-active="1" data-slb-asset="1379905354" data-slb-internal="976"><img decoding="async" class="aligncenter wp-image-976 size-thumbnail lazyloaded" src="https://cdn.shortpixel.ai/client/to_webp,q_glossy,ret_img,w_150,h_150/https://www.bdabek.pl/wp-content/uploads/2020/05/Lightbulb-150x150.jpg" alt="" width="150" height="150" data-src="https://cdn.shortpixel.ai/client/to_webp,q_glossy,ret_img,w_150,h_150/https://www.bdabek.pl/wp-content/uploads/2020/05/Lightbulb-150x150.jpg" /></a></p>
<p>Egzamin zaliczyłem z wynikiem 95% &#8211; myślę, że to jest całkiem ok. Czy warto było wydawać pieniądze na egzamin? W moim przypadku przenosiło się to bezpośrednio na wynagrodzenie, więc <span style="color: #ff6600;"><strong>dla mnie było warto</strong></span>. Oprócz tego bardzo często firmy oferują pokrycie kosztów, więc czemu by nie spróbować za pieniądze pracodawcy? Dodatkowo mam certyfikat, który dla ewentualnych, przyszłych klientów już coś mówi (co prawda samym OCA może lepiej się nie chwalić, ale lepszy rydz niż nic). Mogę też wpisać coś dodatkowego do CV (o ile potrzebuję). <span style="color: #ff6600;"><strong>Oprócz kwestii biznesowych</strong></span>, przygotowanie do egzaminu pozwoliło <span style="color: #ff6600;"><strong>powtórzyć i utrwalić podstawy</strong></span>.</p>
<p>Artykuł <a href="https://www.bdabek.pl/certyfikacja-z-javy/">Certyfikacja z Javy. Egzamin OCA i Moje Wnioski</a> pochodzi z serwisu <a href="https://www.bdabek.pl">bdabek.pl</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.bdabek.pl/certyfikacja-z-javy/feed/</wfw:commentRss>
			<slash:comments>20</slash:comments>
		
		
			</item>
		<item>
		<title>Czas w Javie ⏱️. Dobrze używasz?</title>
		<link>https://www.bdabek.pl/czas-w-javie/</link>
					<comments>https://www.bdabek.pl/czas-w-javie/#comments</comments>
		
		<dc:creator><![CDATA[Bartosz Dąbek]]></dc:creator>
		<pubDate>Sat, 25 Jul 2020 10:00:22 +0000</pubDate>
				<category><![CDATA[Programowanie]]></category>
		<category><![CDATA[Java]]></category>
		<guid isPermaLink="false">https://www.bdabek.pl/?p=1378</guid>

					<description><![CDATA[<p>Mądre zarządzanie czasem nie jest łatwe &#8211; w dużej mierze dotyczy się to życia prywatnego ale również ma swoje odniesienie w technologii. Każda operacja, która wplata czas w swoją domenę jest warta zastanowienia &#8211; jak, po co, dlaczego i dla kogo to ma służyć? Świat jest duży, istnieją różne strefy czasowe, przesilenia jesienne/wiosenne. To wszystko&#8230;&#160;<a href="https://www.bdabek.pl/czas-w-javie/" rel="bookmark">Dowiedz się więcej &#187;<span class="screen-reader-text">Czas w Javie ⏱️. Dobrze używasz?</span></a></p>
<p>Artykuł <a href="https://www.bdabek.pl/czas-w-javie/">Czas w Javie ⏱️. Dobrze używasz?</a> pochodzi z serwisu <a href="https://www.bdabek.pl">bdabek.pl</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Mądre zarządzanie czasem <strong>nie jest łatwe</strong> &#8211; w dużej mierze dotyczy się to życia prywatnego ale również ma swoje odniesienie w technologii. Każda operacja, która wplata czas w swoją domenę jest warta zastanowienia &#8211; <strong>jak, po co, dlaczego i dla kogo to ma służyć</strong>? Świat jest duży, istnieją różne strefy czasowe, przesilenia jesienne/wiosenne. To wszystko wpływa na czas i programy, które ten czas implementują. Raz błędnie zaimplementowana logika może ponieść za sobą olbrzymie konsekwencje.</p>
<hr />
<h4>Cześć <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /></h4>
<p><strong>Nie będzie</strong> to artykuł, który poprowadzi Cię szczegółowo po dokumentacji API. Chciałbym Ci przedstawić główne idee dotyczące czasu oraz abyś zrozumiał jak używać czasu. Dziwnie to brzmi <em>jak używać czasu</em>, ale taka jest koncepcja. Wiele osób nie zastanawia się nad tym, walą <em>LocalDateTime.now() </em>i <strong>wszystko gra bo u mnie działa</strong>. Świadomi programiści tak nie robią. Na początku penetrują API, później zastanawiają się jakie mogą być konsekwencje ich wyborów a następnie podejmują decyzje. Najlepiej takie decyzje, które mogą być odwracalne.</p>
<p>W dzisiejszym artykule:</p>
<ul>
<li><a href="#API Dawniej i Dziś"><strong>API Dawniej i Dziś</strong></a></li>
<li><strong><a href="#Moment a data wydarzenia">Moment a data wydarzenia</a></strong></li>
<li><a href="#Dobre zalecenia"><strong>Dobre zalecenia</strong></a></li>
</ul>
<hr id="API Dawniej i Dziś" />
<h3>API Dawniej i Dziś</h3>
<p>Bez zbędnego gadania &#8211; API do zarządzania datą przed Javą 8 było <strong>słabe </strong>&#8211; klasy były mutowalne i niebezpieczne dla środowisk wielowątkowych (<em>DateFormat</em>).  Jako, że API zostało zaprojektowane już dawno temu (java.util.Date &#8211; JDK 1 / java.util.Calendar &#8211; JDK 1.1) i było w użyciu przez wiele lat to jego wady zostały zauważone i podkreślane przez innych. Dzięki temu powstawały rozwiązania poza JDK, które ułatwiały pracę z czasem. Najpopularniejszą biblioteką jaka powstała jest <a href="https://www.joda.org/joda-time/" target="_blank" rel="noopener noreferrer"><strong>Joda-Time</strong></a> (<em>jeżeli utrzymujesz projekt posiadający wersję Javy niższą niż 8 i potrzebujesz zarządzać czasem, rozważ użycie tej biblioteki</em>).</p>
<p>Tak było kiedyś. Architekci Javy widząc problem i inspirując się API <strong><a href="https://www.joda.org/joda-time/" target="_blank" rel="noopener noreferrer">Joda-Time</a> </strong>doszli do wniosku, że aktualne rozwiązanie trzeba zaorać. I tak oto powstało nowe API, znajdujące się w JDK w pakiecie <strong>java.time</strong>. Uwagi projektowe zamieszczone w <strong><a href="https://docs.oracle.com/javase/8/docs/api/java/time/package-summary.html" target="_blank" rel="noopener noreferrer">dokumentacji</a> </strong>najlepiej opisują czym kierowali się twórcy projektując nowe API. Z <strong><a href="https://www.oracle.com/technical-resources/articles/java/jf14-date-time.html" target="_blank" rel="noopener noreferrer">notatek technicznych</a> </strong>można wskazać 3 główne cechy nowego API:</p>
<ol>
<li><strong>Niemutowalność</strong> &#8211; to była zmora dawnego API.</li>
<li><strong>Domain Driven Design</strong> &#8211; tworzone API ma być oparte na zachowaniach domeny &#8211; szczególnie istotne jest odróżnienie przypadków biznesowych dla Daty i Czasu.</li>
<li><strong>Separacja chronologii</strong> &#8211; umożliwienie pracy z kalendarzami innymi niż standardowe, np. japoński czy tajski.</li>
</ol>
<p>Pomimo, że pakiet <em>java.time</em>, może być początkowo dosyć przerażający biorąc pod uwagę ilość klas jakie posiada, to nawet dla osoby z niedużym doświadczeniem <strong>nie będzie to ciężkie do ogarnięcia podstawowych przypadków</strong>. Podstawowe przypadki to jest jakieś 90% albo i więcej czasu naszej pracy (<em>to już zależy jak trafisz</em>). Do uzupełnienia pozostałych 10% będziesz musiał poczytać dokumentację, doczytać źródła w Internecie i popróbować samemu &#8211; nie jest to ciężkie, ale wymaga pracy.</p>
<p>Warto też dodać, że musisz rozumieć czym jest czas. Ale ten punkt powinieneś zrozumieć czytając kolejną sekcję.</p>
<p>A teraz krótki cytat z <strong><a href="https://docs.oracle.com/javase/8/docs/api/java/time/package-summary.html" target="_blank" rel="noopener noreferrer">dokumentacji</a> </strong>API:</p>
<blockquote><p>This can seem like a lot of classes, but most applications can begin with just five date/time types.</p>
<ul>
<li><a title="class in java.time" href="https://docs.oracle.com/javase/8/docs/api/java/time/Instant.html"><code>Instant</code></a> &#8211; a timestamp</li>
<li><a title="class in java.time" href="https://docs.oracle.com/javase/8/docs/api/java/time/LocalDate.html"><code>LocalDate</code></a> &#8211; a date without a time, or any reference to an offset or time-zone</li>
<li><a title="class in java.time" href="https://docs.oracle.com/javase/8/docs/api/java/time/LocalTime.html"><code>LocalTime</code></a> &#8211; a time without a date, or any reference to an offset or time-zone</li>
<li><a title="class in java.time" href="https://docs.oracle.com/javase/8/docs/api/java/time/LocalDateTime.html"><code>LocalDateTime</code></a> &#8211; combines date and time, but still without any offset or time-zone</li>
<li><a title="class in java.time" href="https://docs.oracle.com/javase/8/docs/api/java/time/ZonedDateTime.html"><code>ZonedDateTime</code></a> &#8211; a &#8222;full&#8221; date-time with time-zone and resolved offset from UTC/Greenwich</li>
</ul>
<p><code>Instant</code> is the closest equivalent class to <code>java.util.Date</code>. <code>ZonedDateTime</code> is the closest equivalent class to <code>java.util.GregorianCalendar</code>.</p></blockquote>
<hr id="Moment a data wydarzenia" />
<h3>Moment a data wydarzenia</h3>
<p>Długo miałem problem żeby zrozumieć jaka jest różnica między <strong>momentem wydarzenia a datą wydarzenia</strong>. Mój mózg nie chciał tego <em>zwizualizować</em>. Jeżeli <strong>też masz problem ze zrozumieniem</strong> różnicy pomiędzy tym zagadnieniem, to proszę Cię o <strong>skupienie się</strong> przez najbliższą minutę.</p>
<p>Wyobraź sobie, że są Letnie Igrzyska Olimpijskie. Ludzie z całego świata walczą o jakieś tam tytuły <strong>w jednym konkretnym miejscu</strong> &#8211; akurat najbliższe będą w Tokyo. Inni ludzie &#8211; również z całego świata &#8211; będą te Igrzyska oglądać <strong>w różnych miejscach na świecie</strong>. Niech program Igrzysk trwa codziennie, pomiędzy 11 rano a 23 wieczorem czasu lokalnego (Tokyo).</p>
<p>Jestem Polakiem i chcę wiedzieć o której mam włączyć telewizor żeby móc to obejrzeć. Patrzę w reklamy w TV (<em>tak nawiasem, nie oglądam TV</em>) i mówią mi, że program Igrzysk trwa między 4 rano (dla niektórych to jeszcze noc) a 16. I właśnie tym jest moment. <strong>Konkretny czas wydarzenia w danym momencie na całej kuli ziemskiej</strong> (albo i we wszechświecie).</p>
<p>Kiedy stosować? Jeżeli Twoja aplikacja ma obsługiwać ludzi z całego świata (albo nawet z kilku stref czasowych) i chcesz żeby jakieś wydarzenie (cokolwiek co ma jakąś datę czy czas) <strong>było w danym momencie dostępne dla wszystkich</strong> o tej samej porze to użyj klas wspierających moment.</p>
<p><a href="https://www.bdabek.pl/czas-w-javie/moment-vs-datetime/" rel="attachment wp-att-1391"><img decoding="async" class="aligncenter size-full wp-image-1391" src="https://www.bdabek.pl/wp-content/uploads/2020/07/Moment-vs-DateTime.png" alt="" width="1120" height="728" srcset="https://www.bdabek.pl/wp-content/uploads/2020/07/Moment-vs-DateTime.png 1120w, https://www.bdabek.pl/wp-content/uploads/2020/07/Moment-vs-DateTime-300x195.png 300w, https://www.bdabek.pl/wp-content/uploads/2020/07/Moment-vs-DateTime-1024x666.png 1024w, https://www.bdabek.pl/wp-content/uploads/2020/07/Moment-vs-DateTime-768x499.png 768w" sizes="(max-width: 1120px) 100vw, 1120px" /></a></p>
<p>&nbsp;</p>
<p>A co z datą wydarzenia? Wydaje mi się, że tutaj nie ma aż tak wielkich problemów ze zrozumieniem. Data wydarzenia jest po prostu <strong>konkretnym punktem na osi czasu</strong>, np. urodziny babci 23 czerwca, start Igrzysk o godzinie 11, piłka z kolegami w piątek o 20. I teraz pytanie &#8211; czy jeżeli urodziny babci są 23 czerwca a ja jestem w Tokyo i przypomniałem sobie o nich o godzinie 20 to zdążę jeszcze złożyć życzenia? No i tu znów wchodzi w grę moment.</p>
<p>To czy będziesz wspierał strefę czasową czy nie, zależy od specyfikacji Twojej aplikacji. Warto jednak pamiętać, że nawet jeżeli nie decydujesz się ich wspierać to możesz wpaść w problemy. Większość państw ma coś takiego jak czas letni i czas zimowy, gdzie godzina na zegarku przeskakuje o godzinę w przód lub w tył. Jeżeli chcesz dowiedzieć się więcej na temat problemów w jakie możesz wpaść stosując wyłącznie klasy nie wspierające momentu, <strong><a href="https://youtu.be/VKvlOL19Itw?t=388" target="_blank" rel="noopener noreferrer">obejrzyj to krótkie wideo</a></strong>.</p>
<p><strong>Apropo stref czasowych</strong> i dlaczego sam nie powinieneś podejmować się ich implementacji. Polecam świetny 10-minutowy filmik przy którym można się nawet uśmiechnąć <strong><a href="https://youtu.be/-5wpm-gesOY" target="_blank" rel="noopener noreferrer">The Problem with Time &amp; Timezones &#8211; Computerphile</a></strong>.</p>
<hr id="Dobre zalecenia" />
<h3>Dobre zalecenia</h3>
<p>Niech ta sekcja będzie <strong>częścią wspólnych doświadczeń</strong> &#8211; jeżeli masz jakąś radę, coś, co widzisz, że jest problematyczne przy zarządzaniu czasem to <strong>daj o tym znać w komentarzu</strong>. Ja z chęcią zedytuję post i dodam Twoją radę.</p>
<h4><span style="color: #339966;"><strong>Jeden. Modeluj domenę przy użyciu klas <em>LocalDate</em>, <em>LocalTime</em> i <em>LocalDateTime</em>.</strong></span></h4>
<p>Cytat z <a href="https://docs.oracle.com/javase/8/docs/api/java/time/package-summary.html" target="_blank" rel="noopener noreferrer"><strong>dokumentacji</strong></a></p>
<blockquote><p><strong>Where possible, applications should use <code>LocalDate</code>, <code>LocalTime</code> and <code>LocalDateTime</code> to better model the domain</strong>. For example, a birthday should be stored in a code <code>LocalDate</code>. Bear in mind that any use of a <a title="class in java.time" href="https://docs.oracle.com/javase/8/docs/api/java/time/ZoneId.html">time-zone</a>, such as 'Europe/Paris&#8217;, adds considerable complexity to a calculation. Many applications can be written only using <code>LocalDate</code>, <code>LocalTime</code> and <code>Instant</code>, with the time-zone added at the user interface (UI) layer.</p></blockquote>
<p>&#8212;</p>
<h4><span style="color: #339966;"><strong>Dwa</strong>. Data i czas powinny być wymieniane/przechowywane w formacie UTC. Źródła [<strong><a style="color: #339966;" href="http://tutorials.jenkov.com/java-internationalization/time-zones.html" target="_blank" rel="noopener noreferrer">1</a></strong>][<a style="color: #339966;" href="https://stackoverflow.com/a/30177234/7252927" target="_blank" rel="noopener noreferrer"><strong>2</strong></a>]</span></h4>
<p><em>(<strong>Uwaga</strong>! Patrz również punkt 4)</em></p>
<p>Choć na pierwszy rzut oka można sobie pomyśleć, że gryzie się to z punktem pierwszym bo zaraz zaraz&#8230; będę używać np. <em>LocalDateTime</em>, który jest czasem lokalnym i jednocześnie czasu UTC? Tak <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p><pre class="crayon-plain-tag">LocalDateTime nowInUTCTimeWithClock = LocalDateTime.now(Clock.systemUTC());
LocalDateTime nowInUTCTime = LocalDateTime.now(ZoneOffset.UTC);</pre><p><a href="https://www.bdabek.pl/czas-w-javie/time-zones-storing/" rel="attachment wp-att-1398"><img decoding="async" class="aligncenter size-full wp-image-1398" src="https://www.bdabek.pl/wp-content/uploads/2020/07/time-zones-storing.png" alt="" width="366" height="167" srcset="https://www.bdabek.pl/wp-content/uploads/2020/07/time-zones-storing.png 366w, https://www.bdabek.pl/wp-content/uploads/2020/07/time-zones-storing-300x137.png 300w" sizes="(max-width: 366px) 100vw, 366px" /></a></p>
<p>&#8212;</p>
<h4><span style="color: #339966;"><strong>Trzy</strong>. <strong>Nie polegaj na strefie czasowej serwera</strong>! </span></h4>
<p>Unikaj czegoś takiego:</p><pre class="crayon-plain-tag">LocalDateTime.now();
LocalDateTime.now(Clock.systemDefaultZone());</pre><p>Poleganie na domyślnej strefie czasowej może zaskoczyć &#8211; pamiętaj, że strefa czasowa serwera jest poza Twoją kontrolą jako programisty. Co jeżeli Twój program będzie hostowany na 2 lub 3 serwerach &#8211; każdy w innej strefie czasowej.</p>
<p>Możesz sobie powiedzieć, nie no &#8211; wiem, że jest tylko jedna instancja serwera i to w moim mieście. Ok&#8230; niech będzie. Ale co jeżeli tą instancją zarządza jakiś admin, któremu nagle przyjdzie do głowy, żeby zmienić strefę czasową na serwerze bo taki miał kapryś tego dnia. (<strong><a href="https://stackoverflow.com/a/35635242/7252927" target="_blank" rel="noopener noreferrer">Ignore Server Time Zone</a></strong>)</p>
<p>&#8212;</p>
<h4><span style="color: #339966;"><strong>Cztery</strong>. UTC nie jest lekiem na wszystko!</span></h4>
<p>Użytkownik Cepewka w komentarzach do tego posta słusznie zauważył że <strong>przechowywanie czasu jako UTC nie jest złotym środkiem</strong>. Istnieją sytuacje kiedy czas, przechowywany w taki sposób może nie być odpowiedni dla naszego przypadku biznesowego. Nie będę poruszać tych kwestii w tym poście ale chcę żeby każdy czytający był świadomy.</p>
<p>Zachęcam do przeczytania komentarzy użytkownika <a href="https://www.bdabek.pl/czas-w-javie/#comment-47"><strong>Cepewka</strong> </a>(<em>dzięki za poruszenie tej kwestii!</em>). A jeżeli potrzebujesz więcej informacji to odsyłam do kilku linków:</p>
<ul>
<li><strong><a href="https://codeblog.jonskeet.uk/2019/03/27/storing-utc-is-not-a-silver-bullet/" target="_blank" rel="noopener noreferrer">STORING UTC IS NOT A SILVER BULLET</a></strong></li>
<li><strong><a href="https://stackoverflow.com/a/11590489/7252927" target="_blank" rel="noopener noreferrer">Is it always a good idea to store time in UTC or is this the case where storing in local time is better?</a></strong></li>
<li><strong><a href="https://stackoverflow.com/a/1130403/7252927" target="_blank" rel="noopener noreferrer">Is there ever a good reason to store time not in UTC?</a></strong></li>
</ul>
<hr />
<h3>Podsumowanie</h3>
<p><a href="https://www.bdabek.pl/spring-boot-i-logi-ustawienia-logbacka/lightbulb/" rel="attachment wp-att-976" data-slb-active="1" data-slb-asset="340876862" data-slb-internal="976"><img decoding="async" class="aligncenter wp-image-976 size-thumbnail lazyloaded" src="https://cdn.shortpixel.ai/client/to_webp,q_glossy,ret_img,w_150,h_150/https://www.bdabek.pl/wp-content/uploads/2020/05/Lightbulb-150x150.jpg" alt="" width="150" height="150" data-src="https://cdn.shortpixel.ai/client/to_webp,q_glossy,ret_img,w_150,h_150/https://www.bdabek.pl/wp-content/uploads/2020/05/Lightbulb-150x150.jpg" /></a></p>
<p>Zarządzanie czasem wydaje się łatwe ale nie jest proste. Lepiej spędź chwilę na rozmowach z klientem i podrąż temat jaki jest oczekiwany rezultat. Często okaże się, że plany długoterminowe biznesu są większe niż jest to przedstawiane na początku. Twórz takie API, które będzie łatwo przenaszalne pomiędzy różne serwery i na które <strong>strefa czasowa serwera nie wpływa. </strong>Mówi się, że <em>czas leczy rany</em>, w tym przypadku niekoniecznie <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f605.png" alt="😅" class="wp-smiley" style="height: 1em; max-height: 1em;" />. Może się okazać, że z czasem przyjdą zmiany a my będziemy zbierali żniwo naszej wcześniejszej implementacji. Życzę, żeby tak nie było.</p>
<p>Źródła:</p>
<ul>
<li><strong><a href="https://stackoverflow.com/a/39379431/7252927" target="_blank" rel="noopener noreferrer">How to get the current date/time in Java</a></strong></li>
<li><strong><a href="https://www.javabrahman.com/java-8/working-with-time-zones-in-java-8-zoneddatetime-zoneid-tutorial-with-examples/" target="_blank" rel="noopener noreferrer">Working with Time Zones in Java 8 | ZonedDateTime, ZoneId tutorial with examples</a></strong></li>
<li><strong><a href="https://programminghints.com/2017/05/still-using-java-util-date-dont/" target="_blank" rel="noopener noreferrer">Still using java.util.Date? Don’t!</a></strong></li>
<li><strong><a href="https://www.eversql.com/mysql-datetime-vs-timestamp-column-types-which-one-i-should-use/" target="_blank" rel="noopener noreferrer">MySQL Datetime vs Timestamp column types – which one I should use?</a></strong></li>
</ul>
<hr />
<h3>Za tydzień</h3>
<p>Porozmawiamy o <strong>architekturze warstwowej</strong>. Jest to architektura która pozwala na szybkie dostarczanie? A może zmora przez którą nie myślimy o tym co dostarczamy?</p>
<p>Artykuł <a href="https://www.bdabek.pl/czas-w-javie/">Czas w Javie ⏱️. Dobrze używasz?</a> pochodzi z serwisu <a href="https://www.bdabek.pl">bdabek.pl</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.bdabek.pl/czas-w-javie/feed/</wfw:commentRss>
			<slash:comments>6</slash:comments>
		
		
			</item>
	</channel>
</rss>
