<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[Solution Chaser]]></title><description><![CDATA[Blog o programowaniu]]></description><link>https://solutionchaser.com/</link><image><url>https://solutionchaser.com/favicon.png</url><title>Solution Chaser</title><link>https://solutionchaser.com/</link></image><generator>Ghost 3.15</generator><lastBuildDate>Fri, 17 Apr 2026 22:13:05 GMT</lastBuildDate><atom:link href="https://solutionchaser.com/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[CityJS London 2022 - online]]></title><description><![CDATA[<p>Dzień dobry! Ostatnio miałam okazję uczestniczyć w CityJS London 2022 i chciałabym podzielić się z Wami wrażeniami oraz wiedzą. Wpis jest lekko kontrowersyjny i nie ma na celu nikogo urazić, zawiera moje odczucia. </p><p>TL;DR: To była przeciętna konferencja, która miała wiele problemów zarówno z treścią jak i organizacyjnych.</p><p>Musimy</p>]]></description><link>https://solutionchaser.com/cityjs-london-2022/</link><guid isPermaLink="false">623d94ea56924dac7f40885e</guid><category><![CDATA[back-end]]></category><category><![CDATA[front-end]]></category><category><![CDATA[javascript]]></category><category><![CDATA[początkujący]]></category><category><![CDATA[średniozaawansowany]]></category><category><![CDATA[nodejs]]></category><dc:creator><![CDATA[Kamila]]></dc:creator><pubDate>Tue, 03 May 2022 13:52:33 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1551818255-e6e10975bc17?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDJ8fGNvbmZlcmVuY2V8ZW58MHx8fHwxNjUxNDk5OTUx&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=2000" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1551818255-e6e10975bc17?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwxMTc3M3wwfDF8c2VhcmNofDJ8fGNvbmZlcmVuY2V8ZW58MHx8fHwxNjUxNDk5OTUx&ixlib=rb-1.2.1&q=80&w=2000" alt="CityJS London 2022 - online"><p>Dzień dobry! Ostatnio miałam okazję uczestniczyć w CityJS London 2022 i chciałabym podzielić się z Wami wrażeniami oraz wiedzą. Wpis jest lekko kontrowersyjny i nie ma na celu nikogo urazić, zawiera moje odczucia. </p><p>TL;DR: To była przeciętna konferencja, która miała wiele problemów zarówno z treścią jak i organizacyjnych.</p><p>Musimy zacząć od tego, że<strong> lubię konferencje</strong>. Jest to magiczny czas, kiedy mam okazję na programistyczne wybudzenie się z zimowego snu i nadrobienie nowości. W tamtym roku część wykładowa CityJS trwała trzy dni a w tym tylko jeden. Nie miałam nic przeciwko, wprost przeciwnie: wydawało mi się, że poprawi to jakość.</p><p>Niestety całość była dla mnie bardzo męcząca:</p><ul><li>ogromna ilość powtarzających się reklam</li></ul><blockquote>Rozumiem, że konferencje nie są organizowane za darmo a sponsorzy wymagają sporej ekspozycji, ale połowa konferencji wydawała się jednym wielkim blokiem reklamowym.</blockquote><ul><li>dużo wykładów nietechnicznych</li></ul><blockquote>Liczyłam, że na CityJS będzie więcej o programowaniu. Tak po prostu.</blockquote><ul><li>krótkie wykłady, które były i tak za długie</li></ul><blockquote>Czas który mieli prelegenci był za krótki na dokładne wyjaśnienie technicznych detali, więc część zdecydowała się na prezentacje nietechniczne a druga przyśpieszała i pomijała slajdy. Często czułam spory niedostatek pomiędzy postawionymi problemami a przedstawionymi rozwiązaniami.</blockquote><h2 id="najciekawsze-prezentacje-i-wyk-ady">Najciekawsze prezentacje i wykłady</h2><p>Niemniej jednak kilka prezentacji mnie zainteresowało i chciałabym skrócić części, które uznałam za wartościowe :)</p><h3 id="pomys-maggie-appleton-komunikacja-przez-wizualizacje">Pomysł Maggie Appleton - komunikacja przez wizualizacje</h3><p>Maggie zawodowo zajmuje się designem i wyjaśniła, że skomplikowane pojęcia oraz koncepcje najłatwiej zrozumieć przez wizualizacje, obrazy oraz diagramy. <br><br>Najciekawszą częścią było wyjaśnienie metafor kognitywnych. Metafora często kojarzy nam się z literaturą i nie zauważamy jak podświadomie używamy jej w programowaniu. Czym innym jest 'kontener' jak nie metaforą zamknięcia i izolacji? Co mówią nam pojęcia 'zmienna' i 'stała'? Z czym kojarzy się nam 'front' (czyli pierwsze co widzimy) a z czym 'backend'?</p><p>Zupełnie pominę część o programowaniu wizualnym, bo mam mieszane uczucia wobec konceptu. Istnieją wizualizacje skryptów w Game Devie (na przykład w Unity), które pozwalają na programowanie poprzez interakcje z interfejsem graficznym i jest to sprawdzone rozwiązanie, jednak - jak zauważyła prelegentka - kod w formie wizualnej fatalnie się skaluje do dużych rozmiarów.</p><h3 id="web-monetization-api">Web Monetization API</h3><p>Jak można zarabiać na swojej twórczości? Jakie opcje mają twórcy internetowi? Alex Lakatos opowiadał o pracach nad Web Monetization API.<br><br>Koncepcja <a href="https://webmonetization.org/">Web Monetization API</a> jest prosta: bezpośredni, bezpieczny przepływ pieniędzy pomiędzy twórcą a odbiorcą.</p><p>Wydaje się to proste, ale po drodze istnieje wiele problemów.</p><p>Portale pośredniczące takie jak Patronite czy inne odpowiedniki pobierają procent od zarobków, banki pobierają prowizje za transakcje a paypal nie jest dostępny wszędzie. Obecny układ sił na rynku finansów sprawia, że drobne datki (na przykład jednodolarowe) są zupełnie nieopłacalne, gdyż koszt takiej transakcji to 30% darowizny.</p><p>Koncepcja w której każdy może wpłacić drobną kwotę bez opłat wydaje się idealna. </p><p>A teraz zobaczcie interfejs w... HTMLu!<br><br>Obecnie jest wspierany przez Chrome, Firefoxa, Edge oraz w przyszłości Safari.</p><pre><code>&lt;meta
  name="monetization"
  content="zewnetrznylinkdoportfela.com/kontokamili"&gt;</code></pre><p>Podejrzanie proste? Tak, płatności będą obsługiwały zewnętrzne firmy korzystające z protokołu stworzonego przez Alexa.</p><p>Trzymajcie kciuki!</p><h3 id="webxr-rozszerzona-rzeczywisto-dla-ka-dego">WebXR - rozszerzona rzeczywistość dla każdego</h3><p>Rozszerzona rzeczywistość (ang. augmented reality) to gorący temat, szczególnie jeśli podejrzewamy ile zainwestuje w to Facebook z powodu Metaverse. W prezentacji został przedstawiony bardzo przyjazny interfejs webowy, który pozwala tworzyć wirtualne światy mieszające się z naszym przy użyciu np. kamerki z telefonu komórkowego. Pomimo problemów technicznych prelegentce udało się pokazać część możliwości API.</p><p>Najbardziej zaskoczyły mnie dwie rzeczy:</p><ul><li>mnogość interfejsów - można tworzyć wirtualną rzeczywistość zarówno przez Javascript jak i... "HTML": <a href="https://aframe.io/">AFrame</a> niewiarygodnie łączy znaczniki i VR.</li><li>bardzo dobrze uproszczone koncepcje oświetlenia czy cieni: props tu, props tam i mamy światłocień :)</li></ul><p>Z resztą słowa tutaj nie wiele zdziałają, zobaczcie przykłady na oficjalnej stronie <a href="https://immersiveweb.dev/">WebXR</a> oraz <a href="https://experiments.withgoogle.com/collection/webxr">tutaj</a>. </p><h3 id="jak-wybiera-biblioteki-w-npm">Jak wybierać biblioteki w npm?</h3><p>Jeden z wykładów opowiadał o tym jak wybiera się biblioteki open source do użycia w większych firmach i do większych projektów. Dlaczego express.js a nie nest.js?</p><p>W wielkim skrócie jest to suma poniższych aspektów:</p><ul><li>wsparcie społeczności (dokumentacja, odpowiadanie na pytania)</li><li>ilość użytkowników (gwiazdki, pobrania)</li><li>rozwiązywalność bugów oraz aktualizacje (jak szybko, jak często)</li><li>ilość kontrybutorów (paczki posiadające jednego głównego kontrybutora są ryzykowane)</li><li>możliwość kontrybucji do biblioteki z zewnątrz</li></ul><h3 id="graphql-schema-stiching">GraphQL schema-stiching</h3><p>Było kilka wykładów o GraphQL. W pracy korzystam z federacji (Apollo Federation), która łączy serwisy różnych zespołów i jest powszechnie preferowanym rozwiązaniem. Niemniej jednak z ciekawością słuchałam o <a href="https://www.graphql-tools.com/docs/schema-stitching/stitch-combining-schemas">schema-stichingu</a>. Jest to opcja dla zespołu zajmującego się wieloma serwisami z małym budżetem, chcącego uniknąć zarządzania federacją.</p><h3 id="mateo-collina-graphql-caching-demystified">Mateo Collina - <strong>GraphQL caching demystified</strong></h3><p>Bezsprzecznie najlepsza prezentacja, którą widziałam na CityJS 2022 London. Wciąż jestem zafascynowana opowieścią Mateo Collina, który rozwija bibliotekę GraphQL do Fastify. Liczby świadczące o wydajności Fastify i <a href="https://www.npmjs.com/package/mercurius">Mercuriusa</a> względem konkurencji i natywnych rozwiązań powalają. <a href="https://github.com/mercurius-js/cache">Mercurius Cache</a> wyraźnie podnosi wydajność zapytań out-of-the-box, nie mówiąc o tym gdy jest dobrze połączony z Redisem. A to jak go dobrze połączyć z Redisem to najlepsza część wykładu, której nie chcę wam opowiadać: zobaczcie to w Internecie koniecznie.</p><p>Mateo polecił kilka tooli i bibliotek, którymi warto się zainteresować:</p><ul><li><a href="https://github.com/mcollina/autocannon">AutoCannon</a> - benchmark dla zapytań API</li><li><a href="https://clinicjs.org/flame/">Flame (ClinicJS)</a> - ułatwia analizę zapytań w twoim kodzie</li><li><a href="https://github.com/nodejs/undici">undici</a> - super szybka konkurencja dla axiosa</li></ul><p>Wybitny wykład i szkoda, że tak szybko się skończył.</p><h3 id="pwas-the-new-frontier-by-diego-gonzalez">PWAs: the new frontier by Diego Gonzalez</h3><p>PWA to genialna koncepcja - aplikacja webowa która działa również jako desktopowa czy mobilna. Jest to dosłownie marzenie web developera. Chociaż Google - moim zdaniem - przestało stawiać na to rozwiązanie, Microsoft wciąż inwestuje w rozwój PWA. I to nie bez przyczyny: duże korporacje takie jak Spotify z powodzeniem go stosują.</p><p>Jednak moja ekscytacja nie jest szczera, od dawna mam problem z prezentacjami Microsoftu. Prowadzą je świetni, inteligentni i zbyt spokojni ludzie, którzy zabijają mój entuzjazm. To jest pomysł, którego nie trzeba nawet sprzedawać - potrzebujemy PWA i absolutnie nie wiem skąd moje mieszane uczucia.</p><p>Zanim zaczniemy się rzucać na PWA patrząc tylko na pozytywny: szybkość developmentu, możliwość aktualizacji, działanie offline to musimy zdać sobie sprawę, że jest jeszcze wiele do zrobienia. </p><p>Głównie dotyczy to integracji z innymi platformami niż Microsoft. Chciałabym zakupić apkę PWA w Google Play tak jak w Microsoft Store, użyć funkcji mojego telefonu takich jak NFC czy czujniki, których PWA obecnie nie obsługuje. Rynek iOSa jest bardzo silnie chroniony przez producenta urządzeń, więc nie zapowiada się na jakąkolwiek integrację z ekosystemem Apple. Warto dodać, że PWA może wysyłać notyfikacje tylko desktopowo na windowsie oraz mobilnie na androidzie.</p><p>Musimy zadać sobie pytanie co jest potrzebne, spisać wymagania i sprawdzić na <a href="https://aka.ms/pwa">https://aka.ms/pwa</a>. </p><h3 id="inne-ciekawostki">Inne ciekawostki</h3><p>Powstał nowy, bardzo ciekawy logger <a href="https://www.npmjs.com/package/pino">Pino</a>. Jest kilkukrotnie szybszy niż konkurencja, twórcy mają na to dowody i radzą się mu przyjrzeć uważnie.</p><h1 id="podsumowanie">Podsumowanie</h1><p>Konferencja to też dzieło, może trafić na bardziej lub mniej dopasowanego odbiorcę. Tym razem byłam tym mniej dopasowanym. Nie oglądałam również wszystkich wykładów, więc najlepsze mogło mnie ominąć :) Sądzę, że moje i CityJS drogi na jakiś czas się rozstaną, ale nie zamykam się na konferencje i nie taki ma być wydźwięk tego wpisu.</p><p>Fakt, że mi coś nie odpowiadało nic nie znaczy.</p><p>Jeśli byliście na CityJS London 2022 i chcecie się podzielić wrażeniami to zapraszam. Kilku innych uczestników bardzo sobie ją chwaliło, szczególnie offline. Jeśli byliście na jakiś fajnych konferencjach to podzielcie się proszę, szukam wydarzenia które dobije do jakości SphereIT.</p><p>Pozdrawiam serdecznie i dziękuję za uwagę. Mam nadzieje, że dowiedzieliście się fajnych rzeczy :)</p>]]></content:encoded></item><item><title><![CDATA[Podstawy SQL - Select]]></title><description><![CDATA[<p>Dzień dobry! Dawno nie było nowego wpisu i miło mi tu wrócić :) Zakup nieruchomości zajął mi mnóstwo czasu, ale biuro już się urządza i przygotowałam dla was powitalny wpis. Będzie lekko i prosto, bo zaczniemy od podstaw SQL. Miło mi też widzieć, że czasami tu wracacie, a starsze wpisy są</p>]]></description><link>https://solutionchaser.com/podstawy-sql/</link><guid isPermaLink="false">61ea8f2832e0d53509bdefb6</guid><category><![CDATA[back-end]]></category><category><![CDATA[początkujący]]></category><category><![CDATA[database]]></category><dc:creator><![CDATA[Kamila]]></dc:creator><pubDate>Thu, 24 Feb 2022 20:00:18 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1483736762161-1d107f3c78e1?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDJ8fGRhdGFiYXNlfGVufDB8fHx8MTY0Mjc3OTI0Nw&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=2000" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1483736762161-1d107f3c78e1?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwxMTc3M3wwfDF8c2VhcmNofDJ8fGRhdGFiYXNlfGVufDB8fHx8MTY0Mjc3OTI0Nw&ixlib=rb-1.2.1&q=80&w=2000" alt="Podstawy SQL - Select"><p>Dzień dobry! Dawno nie było nowego wpisu i miło mi tu wrócić :) Zakup nieruchomości zajął mi mnóstwo czasu, ale biuro już się urządza i przygotowałam dla was powitalny wpis. Będzie lekko i prosto, bo zaczniemy od podstaw SQL. Miło mi też widzieć, że czasami tu wracacie, a starsze wpisy są nadal czytane! Dziękuję!<br><br>Tak więc, początkujący programiści, ruszajcie do czytania!</p><h3 id="co-to-jest-ten-sql">Co to jest ten SQL?</h3><p><br>SQL to język zapytań w którym porozumiewamy się z relacyjnymi bazami danych. Istnieją różne metody pośrednie takie jak przyjazne użytkownikowi programy z graficznym UI (gdzie wyklikujemy zapytanie SQL) czy ORMy, gdzie zapytania są generowane w czasie działania aplikacji. Niestety nie zawsze są optymalne. Dlatego warto poświęcić czas na naukę SQL :)</p><h2 id="baza-danych">Baza danych</h2><p>Żeby wykonać zapytanie musimy mieć bazę danych. Dzisiaj będzie wirtualna, nie potrzebujemy znać typów.</p><p><strong>Definicja bazy: posiada trzy tabele: user, address i łączącą je tabelę relacją wiele do wielu: user_adress.</strong></p><p>Tabela <code>user</code> ma pola: uuid, username, email, created_at, updated_at.</p><p>Tableta <code>address</code> ma pola: uuid, nip, street.</p><p>Tabela <code>user_address</code> ma pola user_uuid oraz address_uuid.</p><h2 id="zadania">Zadania</h2><p>Osobiście najlepiej uczę się przez zadania oraz wyzwania, więc prezentuję Wam zadania (dziękuję Aniołowi za pomoc w ich tworzeniu) na rozgrzewkę. Dzisiaj będziemy pobierać dane, użyjemy do tego operatora <code>SELECT</code>, który do tego służy.</p><h3 id="zadanie-1-sortowanie-i-wybieranie-kolumn">Zadanie 1: sortowanie i wybieranie kolumn</h3><p>Zacznijmy powoli :) Z naszej tabeli chcemy pobrać username i email wszystkich użytkowników i posortować od najdłużej istniejącego. Przejdziemy przez pierwsze zapytanie krokami :)</p><p>Najpierw pobierzmy wszystkich użytkowników:</p><pre><code>SELECT * FROM user;</code></pre><p>Jednak tabela user może mieć bardzo dużo kolumn i części tych danych nie potrzebujemy, więc wybierzmy konkretne:</p><pre><code>SELECT username, email FROM user;</code></pre><p>Na koniec możemy posortować użytkowników po dacie ich utworzenia, żeby w pierwszej kolejności mieć najdłużej istniejących użytkowników.</p><pre><code>SELECT username, email FROM user ORDER BY created_at;</code></pre><p>Proste, prawda?</p><h3 id="zadanie-2-filtrowanie-danych-poprzez-where">Zadanie 2:  Filtrowanie danych poprzez WHERE</h3><p>Teraz pobierzemy tylko tych użytkowników, którzy posiadają numer telefonu.</p><p>Do stawiania warunków w zapytaniu służy operator <code>WHERE</code> , wykorzystamy również <code>IS NOT</code> oraz <code>NULL</code> (zwykle nieobowiązkowe wartości są NULLami, jeśli ich nie wypełnimy).</p><pre><code>SELECT username, phone FROM user WHERE phone IS NOT NULL;</code></pre><p>W ramach ćwiczenia można również spróbować wylistować użytkowników, którzy nie podali swojego numeru telefonu żeby wysłać im przypomnienie:</p><pre><code>SELECT username, phone FROM user WHERE phone IS NULL;</code></pre><h3 id="zadanie-3-like">Zadanie 3: LIKE</h3><p>Bardzo przydatny jest operator <code>LIKE</code> które w przeciwieństwie do porównania pozwala szukać wyrażeń na początku, w środku i na końcu stringa, w różnych kombinacjach. Najczęściej używa do tego znaków <code>_</code> oraz <code>%</code>, gdzie <code>_</code> odpowiada za jeden znak a <code>%</code> za dowolny ciąg znaków (włączając pusty).</p><p>Teraz wybierzmy sobie użytkowników z mailami w domenie gmail.com: </p><pre><code>SELECT username, email FROM user WHERE email like '%@gmail.com';</code></pre><p>Można je dowolnie mieszać. Na przykład możemy szukać maili z dowolną końcówką. Google akurat nie oferuje takiej opcji, ale żeby kontynuować przykład:</p><pre><code>SELECT username, email FROM user WHERE email like '%@gmail.%';</code></pre><p>To wyrażenie niestety złapie także <code>imie.nazwisko@gmail.kotek</code> oraz <code>imie.nazwisko@gmail.</code> i w teorii możemy coś na to poradzić. </p><p>Jeśli mówimy o rozwiązaniach produkcyjnych to nie szłabym w tę stronę, ale istnieje w SQL narzędzie do budowania czegoś w stylu wyrażeń regularnych i wygląda to mniej więcej tak:</p><ol><li><code>[]</code> wyszukuje znaki znajdujące się w kwadratowych nawiasach np.: przez wyrażenie <code>k[o]t</code> przejdzie 'kot', ale już nie 'kat'. Przez wyrażenie <code>k[ao]t</code> przejdzie zarówno 'kot' jak i 'kat', ale nie 'kit'</li><li><code>[^]</code> wyszukuje znaki nie znajdujące się w kwadratowych nawiasach. Na przykład przez wyrażenie <code>k[^i]t</code> przejdzie 'kot', 'kat', ale ponownie nie 'kit'.</li><li><code>[a-c]</code> wyszukuje przedział znaków, np.: tutaj znaki od a do c włącznie. Przykładowo przez wyrażenie <code>k[a-i]t</code> przejdzie zarówno 'kat' jak i 'kit', ale już nie 'kot', bo literka 'o' jest poza przedziałem od 'a' do 'i'.</li></ol><pre><code>SELECT username, email from user where email like '%@gmail.__%';</code></pre><p>Nie wiem czy chcę dalej brnąć w koty, katów i kit, więc przejdźmy dalej :)</p><h3 id="zadanie-4-left-join">Zadanie 4: LEFT JOIN</h3><p>Teraz pobierzmy dane z dwóch tabel na raz, wyszukując użytkownika wraz z nipem jeśli istnieje w bazie.</p><p>Tego typu operacje robi się poprzez <code>JOIN</code>. Istnieje kilka rodzajów, troszkę się od siebie różnią, ale zaczniemy powolutku.</p><p><code>LEFT JOIN</code> wraca wszystkie wyniki z lewego zapytania i dopasowuje istniejące z prawego. Dlatego gdy wywołamy poniższe zapytanie dostaniemy wszystkich użytkowników i nipy ich firm jeśli istnieją. Jeśli nie istnieją to zapytanie zamiast nipu zwróci pustą wartość.</p><pre><code>SELECT user.username, address.nip FROM user LEFT JOIN user_address on user.uuid = user_address.user_uuid LEFT JOIN address ON user_address.address_uuid = address.uuid;</code></pre><h3 id="zadanie-5-inner-join">Zadanie 5: (INNER) JOIN</h3><p>Teraz pobierzmy użytkownika o NIPie <code>3398554396</code>.</p><p>Tutaj potrzebujemy tylko użytkowników, którzy mają zdefiniowane adresy, więc zastosujemy <code>JOIN</code> oraz dodamy operator <code>WHERE</code> który pozwoli wyfiltrować wartości.</p><pre><code>SELECT username, address.nip FROM user JOIN user_address ON user.uuid = user_address.user_uuid JOIN address ON user_address.address_uuid = address.uuid WHERE address.nip = '3398554396'</code></pre><h3 id="zadanie-6-limit">Zadanie 6: LIMIT</h3><p>Rzadko chcemy zwracać wszystkie rekordy z bazy, czasem potrzebujemy tylko kilku najważniejszych. Przykładowy przypadek: trzech najdłużej istniejących użytkowników dostanie rabat. Oto jak ich znaleźć:</p><pre><code>SELECT username, email FROM user ORDER BY created_at LIMIT 3;</code></pre><h1 id="podsumowanie"><br>Podsumowanie</h1><p>Cieszę się, że wytrwaliście do końca :) Potrzebowałam czegoś na rozruszanie, mam nadzieje, że wpis się przyda. Jak zwykle zapraszam do komentowania i poprawiania jeśli zauważycie błąd.</p><p>Trzymajcie się i nie przestawajcie uczyć!</p>]]></content:encoded></item><item><title><![CDATA[Język chmury - Terraform dla początkujących (HCL)]]></title><description><![CDATA[<p>Dzień dobry, mam nadzieje, że macie się dobrze i nie przestajecie się uczyć :)</p><p>Dzisiaj zapraszam Was na naukę terraforma, który pozwala tworzyć zasoby w chmurze. Jeśli początek Was przestraszył, nie martwcie się, zaczniemy od banałów.</p><h1 id="co-to-jest-ta-chmura">Co to jest ta chmura?</h1><h3 id="chmura">Chmura</h3><p>Ta mistyczna chmura to po prostu zasoby (serwery, dyski</p>]]></description><link>https://solutionchaser.com/jezyk-chmury-terraform-aws-hcl/</link><guid isPermaLink="false">601eaa8fb22cb13a2151267f</guid><category><![CDATA[back-end]]></category><category><![CDATA[DevOps]]></category><dc:creator><![CDATA[Kamila]]></dc:creator><pubDate>Mon, 01 Mar 2021 20:03:26 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1499346030926-9a72daac6c63?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MXwxMTc3M3wwfDF8c2VhcmNofDl8fGNsb3VkfGVufDB8fHw&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=2000" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1499346030926-9a72daac6c63?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MXwxMTc3M3wwfDF8c2VhcmNofDl8fGNsb3VkfGVufDB8fHw&ixlib=rb-1.2.1&q=80&w=2000" alt="Język chmury - Terraform dla początkujących (HCL)"><p>Dzień dobry, mam nadzieje, że macie się dobrze i nie przestajecie się uczyć :)</p><p>Dzisiaj zapraszam Was na naukę terraforma, który pozwala tworzyć zasoby w chmurze. Jeśli początek Was przestraszył, nie martwcie się, zaczniemy od banałów.</p><h1 id="co-to-jest-ta-chmura">Co to jest ta chmura?</h1><h3 id="chmura">Chmura</h3><p>Ta mistyczna chmura to po prostu zasoby (serwery, dyski twarde, wirtualne sieci itd.) które możesz dynamicznie <em>wypożyczać/tworzyć</em> w zależności od potrzeb. W większości przypadków płacisz dokładnie za tyle, ile używasz. Jeśli twoja aplikacja ma ruch zwiększony od 16:00 do 19:00 to na ten czas możesz zarezerwować więcej RAMU czy silniejsze CPU dla twojego serwera (co jest trudne w przypadku zwykłego hostingu).</p><p>Najpopularniejszymi rozwiązaniami tego typu są Amazon Web Services (AWS), Microsoft Azure oraz Google Cloud. Dzisiaj będziemy korzystać z AWSa, chociaż HCL - jako język - jest uniwersalnym medium.</p><h3 id="infrastructure-as-a-code">Infrastructure as a code</h3><p>Skoro można tak dynamicznie zmieniać zasoby i stawiać środowiska to pojawia się pytanie jak to zrobić. Kiedyś "goście od serwerów" instalowali systemy operacyjne/narzędzia/interpretery, obecnie przesuwa się tę pracę w stronę zespołu programistycznego. Dzięki temu jest w stanie stworzyć i udostępnić aplikację samodzielnie.</p><p><strong>Infrastructure as a code to nazwa podejścia w którym piszemy kod, który po wywołaniu tworzy zasoby w chmurze.</strong></p><p>A jeśli kod to w jakim języku? Większość dostawców udostępnia swoje narzędzia (API/CLI/etc.) w Javie, C#, JavaScriptcie, ale nie ma wsparcia dla każdego więc powstał unikalny język do tworzenia zasobów w chmurze, czyli HCL.</p><h3 id="hcl">HCL</h3><p>Przedmiotem dzisiejszego wpisu jest HCL, czyli HashiCorp Configuration Language na przykładzie użycia w chmurze AWS. Zapoznamy się z jego strukturą.</p><h2 id="hcl-1">HCL</h2><p>HCL posiada dwie podstawowe struktury danych: argumenty oraz bloki.</p><h3 id="argumenty">Argumenty</h3><p>Argumenty służą do przypisywania wartości do zmiennej.  Nazwa zmiennej może zawierać liczby, litery oraz znaki specjalne: <code>-</code> oraz <code>_</code>. </p><pre><code>name = "solutionchaser"
author_name = "kamila"</code></pre><h3 id="bloki">Bloki</h3><p>Bloki tworzą struktury danych za pomocą zagnieżdżonych klamer <code>{}</code>:</p><pre><code>resource "typStruktury" "nazwaWłasnaStruktury" {
  zmienna = "Hello World"

  struktura wewnętrzna {
    # ...
  }
  tablica = ["kot", "pies"]
}
</code></pre><h3 id="komentarze">Komentarze</h3><p>Z pewnością zauważyliście komentarz w powyższym przykładzie, więc udokumentujmy to jeszcze raz:</p><pre><code># komentarz jednolinijkowy, ten jedyny słuszny
// komentarz jednolinijkowy, nierekomendowany, stworzony żeby trudniej było utrzymać porządek w kodzie
/* komentarz
wielolinikowy */</code></pre><h2 id="terraform">Terraform</h2><p>Najpierw polecam zainstalowanie terraforma na naszym komputerze. Jeśli korzystasz Linuxa to będzie to:</p><pre><code>snap install terraform
</code></pre><p>Komendy na inne systemy operacyjne możesz znaleźć pod tym <a href="https://learn.hashicorp.com/tutorials/terraform/install-cli?in=terraform/aws-get-started">linkiem</a>. Ogólnie polecam zainstalować również <code>tfenv</code>, jeśli zamierzacie używać terraforma pracując w zespole. Pozwala on zmieniać obecnie używaną wersję terraforma.</p><p>Dobrze, już powinna zakończyć się instalacja. Poleceniem <code>terraform --help</code> zweryfikujesz czy działa poprawnie.</p><p>Terraform to akurat jedna z najprostszych technologii jakie znam. Musisz znać 4 komendy, żeby zacząć:</p><ul><li><code>terraform init</code> - inicjalizuje stan (zaraz powrócimy do tego ważnego słowa)</li><li><code>terraform plan</code> - porównuje obecny stan oraz ten który napisaliśmy przez nasz kod i generuje <em>plan zmian</em></li><li><code>terraform apply</code> - tworzyć/usuwa/edytuje zasoby w chmurze i zmienia stan</li><li><code>terraform destroy</code> - niszczy wszystkie zasoby w chmurze zapisanie w stanie</li><li><code>terraform fmt</code> - formatuje pliki z rozszerzeniem <code>tf</code></li></ul><h3 id="zmienne">Zmienne</h3><p>Są tworzone za pomocą bloku <code>variable</code> w którym pierwszy argument to nazwa zmiennej. Mogą mieć typ, opis oraz wartość (zadeklarowaną lub domyślną).</p><p>Standardowa deklaracja:</p><pre><code>variable "blog" {
  default = "solutionchaser"
}</code></pre><p>Zarówno wartość domyślną jak i brak wartości można nadpisać przy wywołaniu kodu, najczęściej przez plik <code>.tfvars</code>.</p><pre><code>variable "blog" {}</code></pre><pre><code>variable "blog" {
  type    = string
  default = "solutionchaser"
  description = "This variable describes blog's name"
}</code></pre><p>Powyższa deklaracja jest typowa: definiuje typ oraz dodaje opis przydatny przy czytaniu kodu oraz generowaniu dokumentacji. Poniżej mamy przykład zmiennej typu lista:</p><pre><code>variable "favourite_food_list" {
  type    = list(string)
  default = ["kefir", "borówki"]
}
</code></pre><p>HCL korzysta z typów prostych: <strong>string, boolean, numer </strong>oraz typów złożonych:<strong> list, map, set, turple oraz object,</strong> których nie będziemy dzisiaj szczegółowo omawiać.</p><h3 id="zmienne-lokalne-ang-locals-">Zmienne lokalne (ang. locals)</h3><p>Zmienne lokalne również mogą deklarować statyczne wartości, ale najczęściej używa się ich do tworzenia zmiennych z innych zmiennych. Spójrzmy na poniższy przykład:</p><pre><code>variable "blog" {
  default = "solutionchaser"
}

locals {
  blog   = var.blog #w starszych wersjach terraforma to będzie "${var.blog}"
  domain = "${var.blog}.com"
  author = "Kamila Brylewska"
}
</code></pre><h3 id="dostawcy-ang-providers-">Dostawcy (ang. Providers)</h3><p>Jak mówiłam wcześniej istnieje wielu dostawców chmury (Amazon, Microsoft etc.) i każdy ma swoje zasoby, strukturę i możliwości dlatego zwykle terraformowanie zaczynamy od zadeklarowania dostawcy.<br><br>Musimy także określić wersję <em>sterownika</em>, który zostanie pobrany na nasz komputer i będzie służył do komunikacji z chmurą.<br><br>Poniżej mamy przykład deklaracji Amazon Web Services jako dostawcy.</p><pre><code>terraform {
  required_providers {
    aws = "~&gt; 1.0"
  }
}
</code></pre><h3 id="zasoby-ang-resources-">Zasoby (ang. Resources)</h3><p>Zasoby to ładna nazwa na poszczególne usługi oferowane w chmurze takie jak - jeśli wybaczycie powtórzenia - wirtualna prywatna sieć, wirtualny dysk czy wirtualny serwer.</p><pre><code>resource "aws_instance" "NazwaZasobuNpMojSerwerInternetowy" {
  ami           = "ciągZnaków"
  instance_type = "t2.micro" # wartości które możesz tutaj wpisać są       zdefiniowane w dokumentacji AWS
}
</code></pre><h3 id="dane-wyj-ciowe-ang-output-">Dane wyjściowe (ang. output)</h3><p>Terraform po stworzeniu zasobu w chmurze zwróci nam szczegóły utworzonego komponentu np.: identyfikator. Możemy go wypisać w konsoli lub użyć do stworzenia innego zasobu.</p><h3 id="dane-ang-data-">Dane (ang. Data)</h3><p>Jeśli potrzebujemy informacji z chmury, na przykład identyfikatora czy nazwy jakiegoś zasobu, możemy je pobrać przy pomocy data i wykorzystać pobrane dane do stworzenia nowego elementu naszej infrastruktury.</p><h3 id="inne">Inne</h3><p>Terraform oferuje także wbudowane <a href="https://www.terraform.io/docs/language/functions/index.html">funkcje</a> oraz możliwość tworzenia/korzystania z gotowych modułów, ale opisanie tego nie jest sednem dzisiejszego wpisu.</p><h2 id="stw-rzmy-co-">Stwórzmy coś!</h2><p>Skoro już mniej więcej wiesz co jest co, to na sucho wytłumaczę jak tworzy się zasoby w chmurze.</p><h3 id="1-napiszmy-kod">1. Napiszmy kod</h3><p><em>Code as infrastructure</em> zakłada obecność kodu, więc napiszemy kod, który utworzy wirtualny dysk dla nas. Ten dysk jest o tym fajny, że płacimy tylko za GB które zajęliśmy i za transfer danych. W Amazonie ten zasób nazywa się wiaderkiem <code>s3</code> i - z pełną świadomościa jak zabawnie to brzmi - zamierzam go tak nazywać.</p><p>Mamy projekt, tworzymy folder <code>terraform</code> i plik <code>s3.tf</code>. </p><pre><code>// plik s3.tf
terraform {
  required_providers {
    aws = "~&gt; 1.0"
  }
}

resource "aws_s3_bucket" "MojeWiadro" {
  bucket = "moje-wiadro-solution-chaser" #unikalny identyfikator w chmurze. Jeśli go nie podasz to AWS wygeneruje nieczytelny ciąg znaków

  tags = { #tagi pomagają kategoryzować i grupować zasoby w chmurze
    Author      = "Kamila"
    Environment = "prod"
  }
}</code></pre><p>Teraz zainicjujemy lokalny stan wykonując w folderze <code>terraform</code> komendę:</p><pre><code>terraform init</code></pre><p>Po skończeniu inicjalizacji zauważycie, że powstał folder <code>.terraform</code> w którym znajduje się plik z sterownikami oraz plik terraform.tfstate.</p><p>Plik tfstate jest jedynym źródłem prawdy o zbudowanej przez nas infrastrukturze. W chwili obecnej mamy go w lokalnie, ale <strong>najczęściej korzystamy z pliku w chmurze, co nazywa się backendem</strong>.</p><p>Jeśli chcemy zobaczyć jakie zmiany zostaną wprowadzone to możemy wpisać:</p><pre><code>terraform plan</code></pre><p>Wykonanie tej komendy pokaże nam ile zasobów zostanie stworzonych, zmienionych i usuniętych oraz dokładne zmiany.</p><p>Dobrze, to utwórzmy wirtualny dysk:</p><pre><code>terraform apply</code></pre><p>To jest moment w którym zostają utworzone zasoby w chmurze, aktualizuje się stan i zaczynamy ponosić koszta.</p><p>Dlatego, szczególnie w przypadku droższych zasobów, powinniście teraz wykonać:</p><pre><code>terraform destroy</code></pre><p>Komenda ta usunie zasoby z chmury, zaktualizuje stan oraz zakończy naukę na dzień dzisiejszy. Samą historię jak skorzystać z tego wirtualnego dysku zostawiam na inny dzień :)</p><h1 id="podsumowanie">Podsumowanie</h1><p>Ostatnio spędzam w chmurach... znaczy w chmurze mnóstwo czasu i <strong>świetnie się bawię</strong>. To magia, że jako developer mogę utworzyć sobie środowisko swoich marzeń w kilkanaście sekund i równie szybko je usunąć.</p><p>Bardzo przepraszam za uogólnienia i zapraszam do komentowania. To niestety ułamek wiedzy z terraforma, który jest potrzebny do stworzenia infrastruktury aplikacji internetowej, nie mówiąc o doświadczeniu serwerowo-sieciowym czy projektowaniu. Niemniej jednak to dobry początek!</p><p>Mam nadzieje, że się podobało i bardzo dziękuję za uwagę. Ostatnio dostaję od Was sporo fajnego feedbacku i chciałam bardzo podziękować. Prowadzenie bloga to sama przyjemność, ale posiadanie czytelników dodaje temu uroku.<br><br>Powodzenia!</p>]]></content:encoded></item><item><title><![CDATA[Back-end w Node.js z Nest.js (REST API #1)]]></title><description><![CDATA[<p>Dzień dobry! Mam nadzieje, że wszystko u was w porządku, 2020 był ciężki, trzymajcie się!</p><p>Dzisiaj zabiorę Was na przygodę z Nest.js - biblioteką która wprowadza poważne wzorce i architekturę do aplikacjach opartych na Express.js. Uczciwie przyznam, że od dawna spoglądam tam w poszukiwaniu inspiracji i rozwiązań, więc</p>]]></description><link>https://solutionchaser.com/back-end-w-node-js-z-nest-js1-rest-api/</link><guid isPermaLink="false">5ff999db5bff26417a8f3f8c</guid><category><![CDATA[back-end]]></category><category><![CDATA[nodejs]]></category><category><![CDATA[początkujący]]></category><category><![CDATA[typescript]]></category><dc:creator><![CDATA[Kamila]]></dc:creator><pubDate>Thu, 21 Jan 2021 16:14:58 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1486025402772-bc179c8dfb0e?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MXwxMTc3M3wwfDF8c2VhcmNofDh8fHJlZHxlbnwwfHx8&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=2000" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1486025402772-bc179c8dfb0e?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MXwxMTc3M3wwfDF8c2VhcmNofDh8fHJlZHxlbnwwfHx8&ixlib=rb-1.2.1&q=80&w=2000" alt="Back-end w Node.js z Nest.js (REST API #1)"><p>Dzień dobry! Mam nadzieje, że wszystko u was w porządku, 2020 był ciężki, trzymajcie się!</p><p>Dzisiaj zabiorę Was na przygodę z Nest.js - biblioteką która wprowadza poważne wzorce i architekturę do aplikacjach opartych na Express.js. Uczciwie przyznam, że od dawna spoglądam tam w poszukiwaniu inspiracji i rozwiązań, więc ten tutorial musiał powstać :)</p><p>Z powodu dużej popularności poprzednich wpisów o Node.js zadecydowałam, że będzie to tutorial <strong>dla kompletnie zielonych</strong>. Nie było to łatwe, gdyż Nest.js wykorzystuje kilka popularnych wzorców, których wytłumaczenie uczyniłoby ten wpis trudniejszym.</p><p>Dzisiaj będziemy dodawali, usuwali, edytowali i odczytywali opowiadania za pomocą REST API.</p><p>Aby ukończyć ten tutorial powinieneś:</p><ul><li>umieć otworzyć konsolę</li><li>znać podstawy TypeScripta</li></ul><h2 id="instalacja">Instalacja</h2><p>Zakładam, że macie Node.js w wersji minimum 12. Można to sprawdzić wpisując <code>node -v</code>.</p><p>Zainstalujmy <em>Nest.js CLI, </em>która pozwoli na automatyzację niektórych czynności takich jak wygenerowanie podstaw projektu. Linuksiarze, pamiętajcie o uprawieniach przy instalacji globalnej paczki :)</p><pre><code>npm i -g @nestjs/cli
// nest new &lt;nazwa_projektu&gt;
nest new tutek</code></pre><p>Powyżej mamy wygenerowany projekt o nazwie <code>tutek</code>.  Sprawdźmy czy aplikacja wygenerowała się poprawnie wpisując w folderze <code>tutek</code> komendę:</p><pre><code>npm run start</code></pre><p>Poczekajmy chwilę aż transpilator skończy pracę, skrypt uruchomi aplikację i wejdźmy na <a href="http://localhost:3000/">http://localhost:3000/</a>.</p><p>Powinniśmy zobaczyć napis <em>Hello World! </em>będący naszym pierwszym sukcesem! Gratulacje!</p><h2 id="teoria-nest-js-dla-pocz-tkuj-cych-programist-w">Teoria Nest.js dla początkujących programistów</h2><p>Jeśli znasz Nest.js lub przeczytałeś dokumentację to ten podpunkt możesz pominąć. Może być tymczasowym zamiennikiem dla dokumentacji, szczególnie że wybiera kluczowe dla tutoriala kwestie i upraszcza/trywializuje je. Są to <strong>uogólnienia skierowane do początkującego programisty</strong> i nie powinny być odnośnikiem do żadnych rozważań.</p><p>Dzisiaj będziemy używać trzech podstawowych koncepcji z Nest.js: modułów, kontrolerów oraz providerów:</p><ul><li><strong>moduł</strong> to klasa grupująca kontrolery i providery. Nie jest jednak obiektem abstrakcyjnym, nastawionym jednie na<em> wrapowanie</em>. Pozwala definiować zależności z innymi modułami (przez importy i eksporty) oraz nakładać globalne właściwości na obiekty które zawiera.</li><li>kontrolery to klasy odpowiedzialne za zapytania i odpowiedzi naszego API. Najprościej mówiąc to dzięki nim mamy dostęp do danych pod adresem URL.</li><li>providery to ogólna nazwa dla pomocniczych klas. Logika/dostęp do danych/generowanie obiektów itd. nie powinna być kodowana w kontrolerze, a w osobnych klasach, gdyż może być tak, że będziemy chcieli z niej korzystać w innym kontrolerze, a kod powinien być reużywalny (w granicach rozsądku).</li></ul><h1 id="modu-story">Moduł <em>Story</em></h1><p>Zanim zaczniemy kodowanie wyłączmy poprzedni serwer Node.js zamykając konsolę i otwórzmy nową aby wywołać: <code>npm run start:dev</code>. Ta komenda nie tylko transpiluje aplikację z TypeScripta na JavaScript i uruchamia ją, ale restartuje serwer po każdej zmianie w kodzie.</p><p>Po wygenerowaniu projektu powinniśmy mieć wygenerowany folder<em> src: </em></p><ul><li>usuńmy wszystkie pliki ts poza plikami<em>: </em>app.module.ts i main.ts.</li><li>stwórzmy folder story</li></ul><p>W folderze <em>story</em> utwórzmy plik <code>story.module.ts</code>. Prosta aplikacja Nest.js będzie składała się z połączonych ze sobą modułów których struktura znajdzie odzwierciedlenie w logice.</p><pre><code>// /src/story/story.module.ts
import { Module } from '@nestjs/common';
import { StoryController } from './story.controller';
import { StoryService } from './story.service';

@Module({
  controllers: [StoryController],
  providers: [StoryService],
})
export class StoryModule {}
</code></pre><p>Moduł jest miejscem w którym importujemy (czyli czynimy nasz moduł Story zależnym od tego zasobu) oraz eksportujemy (czyli pozwalamy innym modułom korzystać z naszego moduł Story). Moduł może zawierać dużo więcej, nasz będzie jednak pustą definicją klasy, w której - za pomocą dekoratora - importujemy kontroler StoryController w który będzie zdefiniowane nasze API oraz serwis StoryService z którego będziemy pobierać dane.</p><h3 id="struktura-danych">Struktura danych</h3><p>W naszej aplikacji będziemy wykorzystywać dwa typy (zalecane przez developerów Nest.js):</p><ul><li>interfejs <code>Story</code></li><li>klasę <code>createStoryDTO</code></li><li>powinny jeszcze istnieć analogiczne klasy DTO, na razie popełnijmy świadomy błąd żeby wszystko uprosić</li></ul><p>Mam nadzieje, że wiecie co to jest interfejs, z DTO sprawa wymaga wytłumaczenia. DTO to typ obiektów które będziemy przesyłać po HTTP. Na przykład - jak zobaczcie w przykładzie - tworząc Story nie potrzebne jest przesyłanie całego obiektu. Ba! Jest to niemożliwe, bo <strong>nie znamy jego id PRZED utworzeniem</strong>. </p><pre><code>export interface Story {
    id: string;
    name: string
}</code></pre><pre><code>src/story/dto/createStory.dto.ts
import { Story } from "../interfaces/story.interface";

export class createStoryDto {
    public name: string
}</code></pre><p>Nie zaszalałam, prawda? Prosto i klarowanie :)</p><h3 id="serwis-storyservice">Serwis StoryService</h3><p>StoryService jest punktem z którego w całej aplikacji będziemy pobierać dane o Story. Zwykle serwis odwołuje się do jakiegoś źródła, <strong>na przykład bazy danych</strong>. Dzisiaj jednak - na potrzeby tutoriala - będziemy <strong>trzymać dane w pamięci</strong> co oznacza, że będą istnieć tak długo jak instancja serwera: od uruchomienia node.js do jego zamknięcia/przeładowania.</p><pre><code>// src/story/story.service.ts

import { Injectable } from '@nestjs/common';
import { Story } from './interfaces/story.interface';

@Injectable()
export class StoryService {
  private stories: Story[] = [];

  constructor() {
    // możecie to odkomentować jeśli chcecie mieć jakieś dane na początku
    // this.stories.push({ id: '2', name: 'ExampleStoryName'});
  }

  getStories(): Story[] {
    return this.stories;
  }

  getStory(id: string): Story {
    return this.stories.find((story: Story) =&gt; story.id === id);
  }

  create(newStory: Story): void {
    this.stories.push(newStory);
  }

  remove(id: string): void {
    const index = this.stories.findIndex((story: Story) =&gt; story.id === id);
    if (index &gt; -1) {
      this.stories.splice(index, 1);
    }
  }

  update(newStory: Story): void {
    this.stories = this.stories.map((story: Story) =&gt; story.id === newStory.id ? newStory : story);
  }
}
</code></pre><p>Klasa <code>StoryService</code> posiada dekorator o nazwie <code>@Injectable</code>. Jeśli chcecie się w to zagłębić to warto poczytać o wzorcu <em>Dependency Injection</em>, dzisiaj wystarczy Wam informacja, że jest konieczny aby przekazać w module <em>StoryModule</em> klasę do  <code>providers</code>.<br><br>Następnie inicjalizujemy prywatną właściwość (property) <em>stories</em>, które będzie naszym źródłem danych :).</p><p>Mam nadzieje, że metody są jasne, ale podsumujmy:</p><ul><li>metoda getStories zwraca wszystkie story w pamięci</li><li>metoda getStory(id) zwraca story o id równym parametrowi.</li><li>metoda create(story) tworzy nowe story</li><li>metoda remove(id) usuwa story o danym id</li><li>metoda update(story) uaktulnia story o danym id</li></ul><h3 id="kontroler-storycontroller">Kontroler StoryController</h3><p>Kontroler - jeśli chodzi o back-end w Nest.js - jest klasą odpowiadającą za endpointy (czyli dostępne w API ścieżki takie jak http://mojastrona.pl/story). Kontrolery w Nest.js są ograne za pomocą biblioteki routing-controllers o których możecie przeczytać w moim poprzednim wpisie: <a href="https://solutionchaser.com/piszemy-kontrolery-w-nodejs-latwiej-i-szybciej/">tutaj</a>.</p><pre><code>// src/story/story.controller.

import { Controller, Get, Put, Delete, Param, Body, Post } from '@nestjs/common';
import { createStoryDto } from './dto/createStory.dto';
import { Story } from './interfaces/story.interface';
import { StoryService } from './story.service';

@Controller('/story')
export class StoryController {
  constructor(private readonly storyService: StoryService) {}

  @Get()
  getStories(): Story[] {
    return this.storyService.getStories();
  }

  @Get(':id')
  getStory(@Param('id') id: string): Story {
    return this.storyService.getStory(id);
  }

  @Post()
  createStory(@Body() updateCatDto: createStoryDto) {
    // proszę tak nie robić, to powinno zostać utworzone inaczej
    // przez generowanie UUID;
    // często id tworzy za nas baza danych przez autoinkrementację
    const id = `${Math.floor(Math.random() * 1000)}`;
    this.storyService.create({...updateCatDto, id });
  }

  @Put(':id')
  updateStory(@Param('id') id: string, @Body() updateCatDto: createStoryDto) {
    this.storyService.update({ ...updateCatDto, id });
  }

  @Delete(':id')
  removeStory(@Param('id') id: string) {
    this.storyService.remove(id);
  }
}
</code></pre><p>Klasa StoryController jest oznaczona dekoratorem <code>@Controller</code>. Przyjmuje on jako parametr string, który jest ścieżką bazową dla całego kontrolera. Warto wspomnieć, że ten dekorator zmienia odpowiedź (jak to dekorator) i domyślnie wszystkie obiekty zostaną zwrócone jako JSON. Nie trzeba nic robić, wszystko dzieje się pod spodem dzięki mocy Nest.js.</p><p>W powyższym kontrolerze stworzone są metody udostępniające poniższe ścieżki:</p><ul><li>GET <code>http://localhost:3000/story/</code> zwracająca tablicę obiektów Story</li><li>GET <code>http://localhost:3000/story/{id}</code> zwracająca pojedynczy obiekt Story</li><li>PUT <code>http://localhost:3000/story/{id}</code> zmieniająca obiekt o id 2 na podstawie przesyłanych danych</li><li>DELETE <code>http://localhost:3000/story/{id}</code> usuwający obiekt o id równym 2</li><li>POST <code>http://localhost:3000/story/</code> tworzący nowy obiekt na podstawie przesłanych danych</li></ul><h3 id="pod-czenie-modu-u-story-do-app">Podłączenie modułu Story do App</h3><p>Jeśli usunęliście niepotrzebne pliki z modułu App jak napisałam wcześniej to powinniście mieć <code>app.module.ts</code> i <code>main.ts</code>. Ten pierwszy musimy lekko zmodyfikować.</p><pre><code>// src/app.module.ts
import { Module } from '@nestjs/common';
import { StoryModule } from './story/story.module';

@Module({
  imports: [StoryModule],
})
export class AppModule {}
</code></pre><h2 id="uruchomienie-i-testowanie">Uruchomienie i testowanie</h2><p>Jeśli uruchomiliście aplikację za pomocą <code>npm run start:dev</code> i odkomentowaliście linijkę w contructorze StoryService to przy tworzeniu tego obiektu powinno dodać się jedno Story i możemy je zobaczyć wpisując w przeglądarkę <code>http://localhost:3000/story</code>.<br><br>Gratulacje! Twoje API zwraca dane.</p><p>Teraz pewnie zastanawiasz się jak przetestować resztę. Masz wiele wyjść, ale ja proponuję dwa narzędzia:</p><ul><li>biblioteka <em>curl</em> korzysta z terminala/konsoli żeby wysłać zapytanie i zwraca odpowiedź</li><li>Postman to program w którym można <em>wyklikać</em>, pobierać, zapisywać, katalogować zapytania, ustawiać zmienne itd. Można też wyklikać tylko proste zapytanie i wysłać.</li></ul><p>Osobiście używam Postmana w którym wybieram typ zapytania z dropdowna, wpisuję ścieżkę i potem Body -&gt; Raw i wybieram Content-Type jako JSON z dropdowna.<br><br>Używając curl w ten sposób będziecie dodawać nowe story: <em>curl -v -X POST -H "Content-Type: application/json" -d '{"name":"Testowa nazwa"}' <a href="http://localhost:3000/story">http://localhost:3000/story</a></em>.</p><p>Teraz po odświeżeniu strony powinniście zobaczyć nowe story pod adresem <a href="http://localhost:3000/story">http://localhost:3000/story</a>.</p><h1 id="podsumowanie">Podsumowanie</h1><p>Mam nadzieje, że dzisiaj w godzinę albo dwie napisaliście ze mną swoje pierwsze API przy użyciu Nest.js.<strong> Czeka nas jeszcze dużo pracy</strong> związanej z walidacją danych, podłączeniem bazy, autoryzacją i obsługą błędów, jednak mam nadzieje, że widzicie jak prosto można stworzyć szkielet.<br><br>Pozdrawiam Was serdecznie i dziękuję za poświęcony czas. Jeśli się spodobało, skorzystaliście lub znaleźliście błędy to zapraszam do komentowania i dyskusji.</p><h3 id="materia-y-do-uzupe-nienia-wiedzy">Materiały do uzupełnienia wiedzy</h3><p>Ten wpis miał być krótki i treściwy, a wręcz dowodzić jak można pozwolić komuś na naukę, której mi jest najbliżej: modyfikację gotowych rozwiązań i naukę poprzez czytanie kodu. Mam jednak wielkie parcie na szerzenie wiedzy, więc dla ciekawskich zostawiłam kilka linków:</p><ul><li>co to jest ten dekorator (oznaczony <code>@</code>)? FSGeek dobrze to tłumaczy w tym <a href="https://fsgeek.pl/post/dekoratory-w-typescript/">artykule</a>.</li><li>co to jest <em>Dependency Injection</em>? O tym opowie Wam Michał z TypeOfWeb w <a href="https://typeofweb.com/tworzymy-wlasne-dependency-injection-w-typescript/">tutaj</a>.</li><li>Trochę teorii o tworzeniu API oraz HTTP opowiedzą dwaj Grzegorze: Grzesiek z <em>DevMobile.pl</em> w tym <a href="https://www.devmobile.pl/rest-api-od-podstaw/">wpisie</a> i Grzesiek z <em>gregkaqa.pl</em> <a href="https://gregkaqa.pl/index.php/2020/08/31/postman01-czym-jest-restapi-czym-jest-postman-pobranie-omowienie-przyklady/">tutaj</a> przy okazji pokazując Wam Postmana (bardzo polecam).</li></ul>]]></content:encoded></item><item><title><![CDATA[Docker Compose dla początkujących]]></title><description><![CDATA[<p>Dzień dobry!<br>Mam nadzieje, że jesteście zdrowi i chętni do nauki, bowiem ruszamy z kolejną częścią serii o konteneryzacji. Pierwszą możecie przeczytać <a href="https://solutionchaser.com/pierwsza-przygoda-z-dockerem/">tutaj</a> gdzie wyjaśniam podstawy dockera :)</p><p>Oczywiście polecam mojego <a href="https://www.instagram.com/kbrylewska/">instagrama</a> oraz staram się wrócić na <a href="https://twitter.com/SolutionChaser">Twittera</a> ze śmieszną poezją developerską. Serio.</p><p>Segment reklamowy zakończony, więc kodujmy:<br>Zastanawiałam się jak</p>]]></description><link>https://solutionchaser.com/docker-compose-dla-poczatkujacych/</link><guid isPermaLink="false">5f86f869ee5eda2b9414bdf4</guid><category><![CDATA[back-end]]></category><category><![CDATA[nodejs]]></category><category><![CDATA[średniozaawansowany]]></category><dc:creator><![CDATA[Kamila]]></dc:creator><pubDate>Wed, 11 Nov 2020 15:52:31 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1516788875874-c5912cae7b43?ixlib=rb-1.2.1&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=2000&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjExNzczfQ" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1516788875874-c5912cae7b43?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=2000&fit=max&ixid=eyJhcHBfaWQiOjExNzczfQ" alt="Docker Compose dla początkujących"><p>Dzień dobry!<br>Mam nadzieje, że jesteście zdrowi i chętni do nauki, bowiem ruszamy z kolejną częścią serii o konteneryzacji. Pierwszą możecie przeczytać <a href="https://solutionchaser.com/pierwsza-przygoda-z-dockerem/">tutaj</a> gdzie wyjaśniam podstawy dockera :)</p><p>Oczywiście polecam mojego <a href="https://www.instagram.com/kbrylewska/">instagrama</a> oraz staram się wrócić na <a href="https://twitter.com/SolutionChaser">Twittera</a> ze śmieszną poezją developerską. Serio.</p><p>Segment reklamowy zakończony, więc kodujmy:<br>Zastanawiałam się jak ugryźć temat, żeby nie zasypać Was setką informacji i nie zrobić z tego wpisu książki. Szczególnie że ostatni wpis się udał. Inspiracja przyszła z pracy tak więc zaczynamy!</p><h3 id="dzisiejszy-przypadek">Dzisiejszy przypadek</h3><p>Dzisiejszy <em>use case</em> będzie polegał na skomunikowaniu dwóch kontenerów. W jednym odpalimy aplikację nodejsową, a w drugim pobierzemy zwróconą informację z homepage'a :)</p><h2 id="jeden-yml-by-rz-dzi-wszystkimi">Jeden (yml) by rządzić wszystkimi</h2><p>Skoro mamy dockera to możemy tworzyć dowolną ilość obrazów i kontenerów, więc po co nam dodatkowe narzędzie? Odpowiedź jest prosta: żeby było łatwiej.</p><p>Docker-compose to narzędzie, które pozwala nam na zarządzenie wieloma kontenerami włączając dzielenie zasobów. Wszystko dzieje się poprzez plik yml oraz proste komendy.</p><p>Dzisiejszy przykład w którym mamy dwa kontenery z pewnością nie byłoby dużym problemem, ale pomyślmy jaki chaos wprowadziłoby pięć czy siedem. Dlatego powstała usługa docker-compose.</p><p>Zacznijmy od instalacji dockera oraz docker-compose. Osobiście korzystam z snapów na Ubuntu:</p><pre><code>sudo snap install docker</code></pre><p>Można się też posiłkować dokumentacją dla apt-get <a href="https://docs.docker.com/engine/install/ubuntu/">tutaj</a>, ale wymaga to trochę więcej pracy. Polecam snapy, więcej możecie przeczytać o nich w moim artykule na <a href="https://devenv.pl/zakochaj-sie-w-ubuntu-najpopularniejszy-linuks/">devenv.pl</a>.</p><p>Zacznijmy od napisania pliku yml. Tradycyjnie nazywa się docker-compose.yml, ale nie musimy mieć tylko jednego, więc pewnie spotkacie docker-compose.tests.yml czy docker-compose.local.yml.</p><h2 id="konstrukcja-pliku-docker-compose-yml">Konstrukcja pliku docker-compose.yml</h2><p>Pierwsza linijka jest wersją formatu pliku konfiguracyjnego docker-compose.yml, która powinna się zgadzać z zainstalowaną wersją dockera (nie docker-compose). </p><p>Można to sprawdzić za pomocą poniższych komend:</p><pre><code>docker-compose -v 
// docker-compose version 1.25.5 &lt;- nie chodzi o tę wersję
docker -v
// Docker version 19.03.11, build dd360c7 &lt;- tak</code></pre><p>Jak widzicie powyżej w chwili pisania tego posta mam wersję 19 i mogę korzystać z wersji pliku 3.8 lub mniejszej <a href="https://docs.docker.com/compose/compose-file/">wg tabelki w dokumentacji</a>.</p><p>Prawdę mówiąc zwykle to nie ma znaczenia, szczególnie w tak prostym tutorialu, ale powinniście mieć tego świadomość.</p><p>Następnie wylistujemy dwa serwisy, które - wyjątkowo - nazwiemy po polsku: <em>aplikacja</em> i <em>szperacz, </em>odpowiadające za dwa kontenery. <em>Aplikacja</em> będzie typowym serwisem webowym, a <strong>szperacz</strong> może być dosłownie wszystkim co powinno mieć dostęp do aplikacji (jakiś crawler, skrypt wykonujący testy e2e, czy jakiś health check).<br><br>Przykładowy plik YML:</p><pre><code>version: "3.8"
services:
  aplikacja:
    tty: true
    build:
      context: .
      dockerfile: ./Dockerfile.aplikacja
    volumes:
      - .:/usr/app/
      - /usr/app/node_modules
  szperacz:
    tty: true
    build:
      context: .
      dockerfile: ./Dockerfile.szperacz
    depends_on:
      - aplikacja

</code></pre><h3 id="build">build</h3><p>Sekcja odpowiedzialna za budowanie kontenera. Można ją opisać skrótowo umieszczając w niej sam kontekst (ścieżkę, której kontekst będzie dostępny w kontenerze) albo jako obiekt z ścieżką do kontekstu oraz ścieżkę do dockerfile'a.</p><h3 id="ports">ports</h3><p>To sekcja w której możemy mapować i udostępniać porty z wewnątrz kontenera na zewnętrz w formacie: <em>zewnętrzny_port:wewnętrzny_port</em> np.: <code>5001:5002</code>. Jeśli chcemy zmapować ten sam port to możemy skorzystać z skrótu: <em>5000</em> (zamiast <em>5000:5000).</em></p><h3 id="environment">environment</h3><p>Lista zmiennych środowiskowych (environment) jest odpowiedzialna za zmienne które z powłoki (np.: będziemy mogli je przekazać przy uruchomieniu) trafią do kontenera. Często wykorzystuje się je do przekazywania sekretów.</p><h3 id="depends_on">depends_on</h3><p>Pozwala uruchamiać kontener w określonej kolejności. Jeśli serwis A jest zależy od serwisu B, to może kontener serwisu B powinien się uruchomić pierwszy? Zwrócę szczególną uwagę, że dotyczy to uruchamiania kontenerów, a nie aplikacji w kontenerze.</p><h3 id="tty">tty</h3><p>Ten parametr odpowiada za wyświetlanie z którego kontenera pochodzi informacja w konsoli. Przydatne do nauki :)</p><h2 id="uruchamianie">Uruchamianie</h2><p>Żeby nie przedobrzyć na początek musicie wiedzieć, że kontenery się tworzy i uruchamia. Tworzy się poprzez komendę <code>docker-compose build</code> a uruchamia poprzez <code>docker-compose up</code>. Nie wykańcza to tematu ale na razie to wystarczy.</p><p>Czego potrzebujemy aby zbudować naszą aplikację:</p><ul><li>docker-compose.yml - plik który pozwoli utworzyć i skomunikować dwa kontenery</li><li>Dockerfile.aplikacja - plik odpowiadający za szczegóły kontenera naszej aplikacji</li><li>Dockerfile.szperacz - plik odpowiadający za szczegóły naszego szperacza</li><li>package.json - plik który skopiujemy do kontera, żeby prosto zainstalować zależności naszej aplikacji</li><li>server.js - nasza wielce skomplikowana aplikacja z poprzedniego tutoriala</li></ul><h3 id="server-js">server.js</h3><p>To prosty plik, który korzystając z frameworka express zwraca wiadomość <code>Hello guys! Kamila is here</code> i słucha na portcie 8080.</p><pre><code>// server.js
const express = require('express');
const app = express();

app.get('/', function (req, res) {
  res.send('Hello guys! Kamila is here');
});

// 8080 to przykładowy port
app.listen(8080, function () {
  console.log('Example app listening on port 8080!');
});</code></pre><h3 id="package-json">package.json</h3><p>To prosty plik z jedną dependencją.</p><pre><code>{
  "name": "solutionchaser",
  "version": "1.0.0",
  "description": "Blog post",
  "main": "server.js",
  "author": "Kamila",
  "license": "OhPlease",
  "dependencies": {
    "express": "^4.15.3"
  }
}
</code></pre><h2 id="dockerfile">Dockerfile</h2><p>Dockerfile służy do zdefiniowania obrazu. Można zainstalować wszystko samemu, ale istnieją również gotowe rozwiązania. Możemy również używać gotowych rozwiązań i rozszerzyć je.</p><h3 id="from">FROM</h3><p>Komenda <code>FROM</code> służy do rozszerzania obraz z innego. Działa to w prosty sposób: najpierw wykonuje się Dockerfile z polecenia <code>FROM</code>. Obrazy mogą pochodzić z naszego repozytorium, z prywatnych plików lub - najczęściej - <a href="https://hub.docker.com/">dockerhuba</a> (taka biblioteka dockerowych obrazów).</p><h3 id="workdir">WORKDIR</h3><p>Zmienia katalog w którym pracuje/wykonujemy komendy/etc. To jest dosłownie work dir - katalog w którym pracujesz.</p><h3 id="run">RUN</h3><p>Odpala komendy podczas <code>build</code>a, czyli tworzenia się kontenera (nazwanie tego <em>instalacją to przesada, ale w czasie tworzenia kontenera zwykle instalujemy potrzebne rzeczy)</em>.</p><h3 id="cmd">CMD</h3><p>Odpala komendy podczas <code>up</code>, czyli uruchamiania kontenera.</p><h3 id="copy">COPY</h3><p>Kopiuje podany plik lub folder do katalogu w kontenerze. Składania jest prosta: pomiędzy jednym a drugim argumentem jest spacja. Na poniższym przykładzie mamy: skopiuj plik server.js z dostępnego kontekstu (context w docker-compose.yml) do katalogu w którym obecnie jestem w kontenerze.</p><pre><code>COPY ./server.js .</code></pre><h2 id="dockerfile-aplikacja">Dockerfile.aplikacja</h2><p>Podobnie jak w poprzednim tutorialu uruchomimy nasz serwer. Korzystamy z obrazu <code>node:12-apline</code>, który zawiera bardzo mały system alpine i nodejs w wersji 12 :)</p><pre><code>FROM node:12-alpine 

WORKDIR /app

COPY ./server.js .
COPY ./package.json .

RUN npm i

CMD [ "node", "server.js"]</code></pre><p>Potem zmieniamy katalog, kopiujemy dwa niezbędne pliki do głównego katalogu (wyznaczonego przez WORKDIR), instalujemy zależności, które utworzą node_modules, a potem odpalamy aplikację.</p><h2 id="dockerfile-szperacz">Dockerfile.szperacz</h2><p>W tym Dockerfilu użyjemy obrazu nodejs z strechem, ponieważ zawiera curla, który potrafi odpytywać serwery HTTP. Nie jest to dobre wyjście, ale myślę, że ten tutorial na tym nie ucierpi. </p><p>Ciekawe jest to, że <strong>aby połączyć się do innego kontenera możemy użyć nazwy serwisu z docker-compose.yml.</strong></p><pre><code>FROM node:12-stretch

WORKDIR /app

CMD curl http://aplikacja:8080</code></pre><h2 id="docker-compose-yml">docker-compose.yml</h2><p>Oto nasz docker-compose.yml, gdzie można zobaczyć wszystkie opisane wcześniej rzeczy.</p><pre><code>version: "3.8"
services:
  aplikacja:
    tty: true
    build:
      context: .
      dockerfile: ./Dockerfile.aplikacja
  szperacz:
    tty: true
    build:
      context: .
      dockerfile: ./Dockerfile.szperacz
    depends_on:
      - aplikacja
</code></pre><h2 id="wywo-anie">Wywołanie</h2><p>Teraz wystarczy tylko:</p><pre><code>sudo docker-compose build
sudo docker-compose up</code></pre><p>Dlaczego z podwyższeniem uprawień? Na potrzeby tutoriala, taka jest natywna polityka dockera. Poprawnym wyjściem byłoby dodanie naszego użytkownika do grupy docker z odpowiednimi uprawieniami, ale nie chcę komplikować zbyt bardzo.</p><p>No i czekamy :)</p><pre><code>aplikacja_1  | Example app listening on port 8080!
szperacz_1   | Hello guys! Kamila is here
dockersample_szperacz_1 exited with code 0</code></pre><p><strong>Co się stało?</strong><br>Najpierw poprawnie zbudowały się oba kontenery, uruchomił serwis <em>aplikacja,</em> a potem <em>szperacz</em>. <em>Aplikacja</em> zwróciła informację o tym, że apka nodejs już działa, a potem <em>szperacz</em> zapytał naszą apkę o dane z głównego endpointa.</p><p>Na końcu szperacz się wyłączył (bowiem zakończył swoją pracę wykonując wszystkie komendy), a aplikacja wciąż działa (nieskończenie czeka na zapytania, bo komenda <code>node server.js</code> nic nie zwróci).</p><p>Pełen sukces!</p><p>Warto jednak zauważyć, że<strong> przypadkiem jest, że serwer nodejs był gotowy gdy szperacz wywołał curl'a</strong>. Parametr <code>depends_on</code> czeka na uruchomienie kontenera, a nie wszystkich wykonywanych w nim poleceń. Pozostaje więc pytanie: jak to bezpiecznie synchronizować? Zagadnienie opisuję kilka akapitów niżej :)</p><h2 id="problemy-i-ciekawe-zagadnienia">Problemy i ciekawe zagadnienia</h2><p>Nie starczy mi czasu i miejsca - a Wam cierpliwości - żeby opisać wszystkie potencjalne problemy i rozwiązania. Nawet nie zakończyłam podstaw docker-compose i niestety w tym wpisie nie starczy mi czasu na pozostałe zagadnienia.</p><p>Kilka słów o debugowaniu: gdy coś nie działa, a informacja w konsoli nie wyjaśnia zbyt wiele warto dodać <code>--verbose</code> do zapytania. Wtedy zobaczymy więcej szczegółów, na przykład: <code>docker-compose --verbose up</code>.</p><h3 id="za-ma-o-miejsca">Za mało miejsca</h3><p>Prawdopodobnie podczas swojej nauki doświadczysz informacji o skończonym miejscu na dysku, chociaż twój komputer może mieć jeszcze pełnego miejsca. Chodzi tutaj konkretnie o miejsce przeznaczone na obrazy i kontenery</p><p>Docker ma ciekawą politykę, ponieważ nie usuwa sam nieużywanych kontenerów. Jeśli często robisz buildy (np.: przy nauce) to miejsce na dysku może się szybko skończyć. Jak temu zaradzić? Usunąć starocie :)</p><p>Ten błąd można wykryć komendą: <code>docker system df</code>. Jeśli w wierszu <code>Images</code> będzie bardzo duży rozmiar oraz wysoki procent pamięci do odzyskania (<code>Reclaimable</code>) to w środowisku developerskim  pomoże <code>docker image prune -a</code>. </p><h3 id="zale-no-pomi-dzy-serwisami-w-kontenerach">Zależność pomiędzy serwisami w kontenerach</h3><p>Jak wspomniałam parametr <code>depends_on</code> czeka na uruchomienie kontenera, a nie serwera nodejs. Szczególnie gdy aplikacja będzie większa to instalacja dependencji może chwilę czekać i <code>curl</code> w drugim kontenerze odpali się przed uruchomieniem aplikacji. Zwróci wtedy błąd.</p><p>Jak to zrobić poprawnie? W poprzednich wersji dockera istniała opcja wbudowanego healthchecku podłączonego z depend_on, ale obecnie dokumentacja sugeruje ręczne sprawdzanie dostępności serwisu.</p><p>Bardzo popularnym rozwiązaniem jest skrypt <a href="https://github.com/vishnubob/wait-for-it">wait-for-it.sh</a>. Można go pobrać z repozytorium do projektu i skopiować do kontenera lub ściągnąć w kontenerze.<br><br>Potem zmienić uprawnienia i wywołać. W naszej aplikacji będzie to wyglądało tak:</p><pre><code>RUN chmod +x ./wait-for-it.sh
CMD ["/bin/sh", "-c", "wait-for-it.sh aplikacja:8080 --timeout=120 --strict -- curl aplikacja:8080"]</code></pre><p>W tej chwili wydaje się to absurdalne (bo trochę jest), ale curl jest tutaj tylko placeholderem.<br><br>Co się stało? Nadaliśmy plikowi pozwolenia na wykonywania, a potem wykonaliśmy skrypt wait-for-it.sh. Wykorzystaliśmy dwa parametry: timeout który mówi po ilu sekundach skrypt ma przestać czekać i <code>strict</code>, który mówi o tym, że gdy serwis się nie odnajdzie to ma zwrócić błąd.</p><h1 id="podsumowanie">Podsumowanie</h1><p>Mam nadzieje, że się podobało i z chęcią wybraliście się ze mną w dockerową podróż. Miałam z tego ogromną przyjemność i z radością wrócę do tematu (szczególnie zasobów; gdzie <code>network</code> i <code>volumes</code>?).</p><p>Jak zwykle zapraszam do komentowania, zostawiania reakcji i komentarzy, jeśli gdzieś źle się wyraziłam lub popełniłam błąd!</p>]]></content:encoded></item><item><title><![CDATA[Vue Router i TypeScript - jak zrobić frontowy routing?]]></title><description><![CDATA[<p>Dzień dobry! Mam nadzieje, że macie się dobrze, wakacje minęły pogodnie i jesteście głodni wiedzy. Dzisiaj powrócimy do Vue zaliczając kolejny, niezbędny element z stacku Vue: Vue Router. Zaczniemy prosto dlatego zapraszam wszystkich początkujących do nauki!</p><p>Krótki blok reklamowy: <a href="https://www.facebook.com/solutionchaser">Facebook</a>, <a href="https://www.instagram.com/kbrylewska/">Instagram</a>. Implementacja - jak zawsze - w TypeScriptcie.</p><p><a href="https://solutionchaser.com/typescript-pierwsze-kroki-konfiguracja/">Konfiguracja Typescripta</a></p>]]></description><link>https://solutionchaser.com/vue-router-i-typescript-jak-zrobic-frontowy-routing/</link><guid isPermaLink="false">5f108da483e45678e1167b56</guid><category><![CDATA[front-end]]></category><category><![CDATA[początkujący]]></category><category><![CDATA[typescript]]></category><category><![CDATA[Vue.js]]></category><dc:creator><![CDATA[Kamila]]></dc:creator><pubDate>Tue, 06 Oct 2020 18:30:16 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1465447142348-e9952c393450?ixlib=rb-1.2.1&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=2000&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjExNzczfQ" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1465447142348-e9952c393450?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=2000&fit=max&ixid=eyJhcHBfaWQiOjExNzczfQ" alt="Vue Router i TypeScript - jak zrobić frontowy routing?"><p>Dzień dobry! Mam nadzieje, że macie się dobrze, wakacje minęły pogodnie i jesteście głodni wiedzy. Dzisiaj powrócimy do Vue zaliczając kolejny, niezbędny element z stacku Vue: Vue Router. Zaczniemy prosto dlatego zapraszam wszystkich początkujących do nauki!</p><p>Krótki blok reklamowy: <a href="https://www.facebook.com/solutionchaser">Facebook</a>, <a href="https://www.instagram.com/kbrylewska/">Instagram</a>. Implementacja - jak zawsze - w TypeScriptcie.</p><p><a href="https://solutionchaser.com/typescript-pierwsze-kroki-konfiguracja/">Konfiguracja Typescripta jest w tym poście. </a></p><h2 id="instalacja">Instalacja</h2><p>Instalacja Vue Routera polega na pobraniu paczki <code>vue-router</code>:</p><pre><code>npm install vue-router
</code></pre><p>Możemy zacząć od przekazania Vue Routera w konstruktorze Vue, za chwilę go stworzymy:</p><pre><code>// front.ts
import Vue from 'vue';
import App from 'Front/components/app.vue';
import { router } from 'Front/routing/router';

const v: Vue = new Vue({
    router,
    el: '#app',
    template: '&lt;App/&gt;',
    components: {
        App,
    },
});
</code></pre><p>To czas na konfigurację VueRoutera, która na początku będzie polegała na zmapowaniu komponentów i ścieżek. Musimy wiedzieć pod którym adresem wyświetli się jaki komponent.</p><pre><code>// Front/routing/router/index.ts
import VueRouter, { RouteConfig } from "vue-router";
Vue.use(VueRouter);

const routes: Array&lt;RouteConfig&gt; = [
    { path: 'login', component: Login},
    { path: '/', component: StoryList},
]
    
export const router = new VueRouter({
    routes
});
</code></pre><p>Musimy także znaleźć miejsce w aplikacji w którym wyświetlimy komponent z wskazanej ścieżki. Może być to w głównym komponencie, gdy będziemy mieli każdą podstronę inną albo pomiędzy nagłówkiem a stopką, gdy zdecydujemy się na proste SPA. <br><br>W perfekcyjne miejsce wkleimy komponent, który<strong> pełni rolę slota</strong>:</p><pre><code>// part of front/components/app.vue   
&lt;template&gt;
    &lt;div class="layout"&gt;
        &lt;div class="layout_content"&gt;
            &lt;HeaderNavigation&gt;&lt;/HeaderNavigation&gt;
            &lt;router-view&gt;&lt;/router-view&gt;
        &lt;/div&gt;

        &lt;Footer&gt;&lt;/Footer&gt;
    &lt;/div&gt;
&lt;/template&gt;</code></pre><p>Ok, to jak sprawdzić czy działa? Najlepiej stworzyć linka i nacisnąć w niego.</p><h3 id="kotwice-router-link">Kotwice <code>&lt;router-link&gt;</code></h3><p>Zapewne za chwilę zaczniecie się zastanawiać dlaczego nie stworzyć zwykłej kotwicy <code>&lt;a&gt;</code>? Po synchronizacji z paskiem adresu wszystko powinno działać.<br>Tak, będzie działać, lecz stracimy część funkcjonalności.</p><p>Skąd to wynika? Z tego, że gdy linki obsługuje Vue Router to stara się maksymalnie zminimalizować przeładowania. Na przykład gdy będąc na podstronie <code>https://twojastrona.com/#/boo</code> klikniesz w link przekierowujący na tę samą podstronę, nie załaduje się żaden nowy komponent.</p><p>To jest jeden z wielu powodów dlaczego warto używać komponentu Vue Routera <code>&lt;router-link&gt;</code> do wewnętrznych linków. </p><pre><code>&lt;router-link :to="{ name: ROUTINGS.MAIN }"&gt;Nazwa linka&lt;/router-link&gt;</code></pre><p>Jeśli chcemy wykonać przekierowanie w kodzie wystarczy wykonać metodę <code>push</code> z odpowiednio zbudowanym obiektem.</p><pre><code>router.push({ path: '/' });</code></pre><p>Proste? To dobrze, podstawy mamy już za sobą!</p><h3 id="parametry-w-url">Parametry w URL</h3><p>Kolejnym częstym przypadkiem jest parametr w URL. Pokażę Wam jak zaimplementować taki URL: <code>https://twojastrona.com/#/story/5</code> który otwiera opowiadanie o id równym pięć. Będzie on mapowany z stringa <code>https://twojastrona.com/#/story/:id</code> gdzie <code>:id</code> będzie miejscem wstawienia parametru. </p><p>Aby to uzyskać najlepiej aby nasze routingi miały zdefiniowaną unikalną nazwę. Osobiście stosuję enumy, chociaż gdy macie potrzebę iterowania po wszystkich routingach - na przykład w celu stworzenia menu - to równie dobre będą obiekty.</p><pre><code>// Front/routing/router/routings.ts
export const ROUTING_URLS = {
    MAIN: '/',
    LOGIN: '/login',
    STORIES: '/stories',
    STORY: '/story/:id',
    ERROR404: '/404'
}</code></pre><p>Możemy zaimplementować różną logikę:</p><ul><li>parametr może być wymagany, a jego brak skutkuje przeniesieniem do innej podstrony np.: podstrony z błędem. Przykładem jest na przykład podstrona z opowiadaniem, gdzie gdy nie wiemy jakie opowiadanie mamy wyświetlić, to nie wyświetlamy żadnego.</li><li>parametr może być opcjonalny i jego brak skutkuje np.: nie pojawieniem się jakiegoś elementu</li><li>parametr może być opcjonalny i posiadać wartość domyślną np.: jeśli wyświetlając listę opowiadań nie podamy wartości paginacji to zakładamy, że chodzi o pierwszą stronę. Tak więc <code>https://twojastrona.com/#/stories</code> i <code>https://twojastrona.com/#/stories/1/</code> będą wyświetlały to samo.</li></ul><p>Wszystkie obecne parametry są podstępne w globalnym obiekcie <code>this.$route.params</code>, jeśli ustawimy opcję <code>props: true</code>. W innych przypadkach możemy przypisać obiekt, jeśli chcemy podać stałą wartość lub... funkcję, jeśli chcemy stworzyć parametr wyliczanych z innych :)</p><pre><code>import Vue from 'vue';
import VueRouter, { RouteConfig } from "vue-router";
import DisplayStory from 'Front/components/story/DisplayStory.vue';
import { ROUTING_URLS } from 'Front/routing/routings';

Vue.use(VueRouter);

const routes: Array&lt;RouteConfig&gt; = [
    { path: ROUTING_URLS.STORY, component: DisplayStory, name: ROUTING_URLS.STORY, props: true },
    { path: ROUTING_URLS.STORY2, component: DisplayStory, name: ROUTING_URLS.STORY, props: { id: 1 },
        { path: ROUTING_URLS.STORY3, component: DisplayStory, name: ROUTING_URLS.STORY, props: props: route =&gt; ({ query: route.query.id }),
]
    
export const router = new VueRouter({
    routes
});
</code></pre><h2 id="wi-cej-dynamicznych-slot-w">Więcej dynamicznych slotów</h2><p>Przyjrzyjmy się temu co tej pory zrobiliśmy: w naszej testowej aplikacji mamy nagłówek, stopkę i treść. Nagłówek i stopka są stałe, a treść jest zależna od routingu i wyświetlana w komponencie <code>&lt;router-view&gt;</code>.</p><p>Tylko co z sytuacja kiedy na różnych podstronach chcemy wyświetlać nie tylko inną treść ale także inny nagłówek?</p><p>Jak pewnie się domyślacie, Vue oferuje rozwiązanie tego problemu, bowiem slot z którego korzystaliśmy to jedynie slot domyślny i można ich napisać nieskończenie wiele. Także z:</p><pre><code>&lt;Header /&gt;
&lt;router-view&gt;&lt;/router-view&gt;
&lt;Footer /&gt;</code></pre><p>Można zrobić:</p><pre><code>&lt;router-view name="myheader"&gt;&lt;/router-view&gt;
&lt;router-view&gt;&lt;/router-view&gt;
&lt;Footer /&gt;</code></pre><p>i uzyskać możliwość zmiany nagłówka w zależności od podstrony. Jedyną różnicą jest rozróżnienie slota atrybutem <code>name</code>. Musimy tylko jeszcze zadeklarować jaki widok ma się wyświetlać po jakim atrybutem:</p><pre><code>const router = new VueRouter({
  routes: [{
    path: '/story/',
    components: {
        default: DisplayStory,
        myheader: StoryHeader
    },
  }]
});</code></pre><h2 id="zagnie-d-one-widoki">Zagnieżdżone widoki</h2><p>Skoro już wiemy, że da się spokojnie używać więcej niż jednego slotu <code>router-view</code> to pewnie przyszło Wam do głowy, że dobrze byłoby je zagnieżdżać.</p><p>Otóż da się i wcale nie jest to takie trudne! Wystarczy - poza dodaniem komponentu <code>&lt;router-view&gt;</code>  w innym komponencie wyświetlanym za pomocą <code>&lt;router-view&gt;</code> - zdefiniować potomków w konfiguracji Vue Routera za pomocą klucza <code>children</code>.</p><pre><code>const router = new VueRouter({
  routes: [
    { path: '/author/:id', component: Author,
      children: [
        {
          // /author/:id/profile
          path: 'profile',
          component: AuthorProfile
        },
        {
          // /author/:id/stories
          path: 'stories',
          component: AuthorPosts
        }
      ]
    }
  ]
})
</code></pre><h1 id="podsumowanie">Podsumowanie</h1><p>Mam nadzieje, że się podobało i początkujący programiści Vue.js już lecą zaimplementować swój pierwszy Vue Router :) Niestety temat nie dość, że nie został wyczerpany to jeszcze ledwo co zaczęty, gdyż Vue Router - i w ogóle frontowy routing - kryje dużo więcej: middleware, lazy-loading, sprawdzanie ścieżek to tylko przykłady. Na razie nie jest to jeszcze wersja, która mogłaby się pojawić na produkcji w standardowej aplikacji. Będę kontynuować temat w następnych wpisach, więc wyczekujcie cierpliwie :)</p><p>Zapraszam do zadawania pytań i komentowania, w szczególności jeśli coś jest niejasne :)</p><p>Trzymajcie się!</p><p>Polecam też inne wpisy o Vue na moim blogu:</p><ul><li><a href="https://solutionchaser.com/implementacja-vuex-z-typescriptem/">Implementacja Vuex</a></li><li><a href="https://solutionchaser.com/vuejs-typescript-ui-frameworks-przeglad/">Implementacja frameworka UI</a> (Vue + TypeScript)</li></ul>]]></content:encoded></item><item><title><![CDATA[Podstawy Continuous Integration&Delivery na przykładzie Github Actions]]></title><description><![CDATA[<p><strong>Continuous Integration</strong> i<strong> Continous Delivery</strong> to terminy, które powinny być znane każdemu programiście. <strong>Continuous Integration</strong> to praktyka regularnego mergowania kodu dzięki której powstało mnóstwo świetnych praktyk i narzędzi. Jest związana z pojęciem <strong>Continous Delivery</strong>, które odnosi się do regularnego wydawania na produkcję małych funkcjonalności. Dzisiaj spróbuję początkującym wyjaśnić z czym</p>]]></description><link>https://solutionchaser.com/podstawy-continuous-integration-na-przykladzie-github-actions/</link><guid isPermaLink="false">5ec7b5e44b38eaf9a2a33eb1</guid><category><![CDATA[back-end]]></category><category><![CDATA[front-end]]></category><category><![CDATA[początkujący]]></category><category><![CDATA[open source]]></category><category><![CDATA[ghost]]></category><dc:creator><![CDATA[Kamila]]></dc:creator><pubDate>Mon, 15 Jun 2020 22:13:35 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1496247749665-49cf5b1022e9?ixlib=rb-1.2.1&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=2000&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjExNzczfQ" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1496247749665-49cf5b1022e9?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=2000&fit=max&ixid=eyJhcHBfaWQiOjExNzczfQ" alt="Podstawy Continuous Integration&Delivery na przykładzie Github Actions"><p><strong>Continuous Integration</strong> i<strong> Continous Delivery</strong> to terminy, które powinny być znane każdemu programiście. <strong>Continuous Integration</strong> to praktyka regularnego mergowania kodu dzięki której powstało mnóstwo świetnych praktyk i narzędzi. Jest związana z pojęciem <strong>Continous Delivery</strong>, które odnosi się do regularnego wydawania na produkcję małych funkcjonalności. Dzisiaj spróbuję początkującym wyjaśnić z czym to się je :)</p><p>Jeszcze blok reklamowy przed wpisem i jedziemy!</p><p>Po pierwsze: <a href="https://www.instagram.com/kbrylewska/">mój Instagram</a> (można tam znaleźć zapowiedzi wpisów, dodać jakieś sugestie i przywitać się :) Jestem również na <a href="https://devenv.pl">devenv.pl</a>, szczególnie zapraszam na mój artykuł o <a href="https://devenv.pl/mechanizmy-typescripta-ktore-musisz-znac/">tej trudniejszej części TypeScripta</a>.<br><br>Wystartowałam tez w wersji alpha z newsletterem :) Jeśli chcecie dostawać ciekawe linki i zadania z programowania to zapraszam do zapisania się :)</p><h2 id="troch-teorii-dla-pocz-tkuj-cych">Trochę teorii dla początkujących</h2><p>Zacznijmy od podstaw. Chociaż CI w każdym projekcie wygląda inaczej, jeśli chodzi o web development można wyodrębnić popularne praktyki takie jak:</p><ul><li>używanie repozytorium kodu z systemem kontroli wersji - najpopularniejszym jest git</li><li>testy (zwykle jednostkowe) których poprawne przejście jest warunkiem koniecznym do pushowania kodu</li><li>automatyzacja budowania aplikacji - push na konkretnego brancha powinien wywołać proces budowania się aplikacji</li><li>zbudowana aplikacja podlega automatycznym testom - push na konkretnego brancha powinien uruchamiać testy na serwerze</li><li>po wykonaniu testów oraz builda, aplikacji powinna zostać zreleasowana na odpowiednie środowisko (albo na staging skąd w przyszłości pójdzie <em>promote</em> - czyli wierna kopia - na produkcję)</li></ul><h3 id="prosty-przyk-ad-dobrze-zaimplementowanego-ci-cd-">Prosty przykład dobrze zaimplementowanego CI/CD:</h3><ol><li>Push uruchamia prepush który puszcza testy jednostkowe. Testy zakończone sukcesem umożliwiają push kodu do repozytorium.</li><li>Push uruchamia testy jednostkowe na zewnętrznej maszynie (może to być serwer, chmura albo komputer leżący dwa biurka dalej)</li><li>Po przejściu testów uruchamia się build, który buduje z kodu źródłowego aplikację</li><li>Często po buildzie na środowisku testowym/stagingowym uruchamiają się testy automatyczne E2E</li><li>Aplikacja zostaje zreleasowana (udostępniona publicznie)</li></ol><p>Dla początkującego programisty, który zna podstawy gita z pewnością pojawi się pytanie: Jak to się stało, że git push uruchomił akcję na serwerze?</p><p>Na to pytanie odpowiem dzisiaj :)</p><h2 id="github-actions">Github Actions</h2><p>Trochę zastanawiałam się nad idealnym przykładem. W pracy używam Drone'a jednak nie jest on open source'owym rozwiązaniem ani nawet - od jakiegoś czas - darmowym. Okazja nadarzyła się sama:<strong> Ghost w wersji 3.0 obsługuje customowe integracje!</strong></p><p>W końcu się udało i nie będę musiała już budować szablonu lokalnie oraz wysyłać do na serwer. <strong>Wspólnie zautomatyzujemy ten proces :)</strong></p><p>Po pierwsze potrzebujemy projektu do zbudowania na githubie. Moim będzie szablon bloga o nazwie <em>technozaur</em>.</p><p>Maszyną która wykona dla nas builta będzie serwer githuba, a dokładnie usługa Github Action. Istnieją alternatywne CI takie jak Drone, Jenkins, CircleCI, Buddy i wiele innych, jednak ta - ze względu na brak kosztów - będzie idealnym wyjściem. Dodatkowo autentykację mamy załatwioną, bo Github Actions jest częścią Githuba.</p><p>We wszystkich popularniejszych rozwiązaniach zadania dla usługi CI tworzy się poprzez plik w formacie <code>yml</code> (lub <code>yaml</code>) który umieszczamy w repozytorium kodu. Będzie on źródłem informacji o tym co i jak powinien zrobić serwer.</p><p>Nasz będzie wyglądał następująco:</p><pre><code>name: Deploy Theme
on:
  push:	
    branches:	
      - master
jobs:
  deploy:
    runs-on: ubuntu-18.04
    steps:
      - uses: actions/checkout@master
      - uses: TryGhost/action-deploy-theme@v1.0.0
        with:
          api-url: https://solutionchaser.com 
          api-key: ${{ secrets.CHASER_PROD_API_KEY }}
</code></pre><p>Dokładne formaty znajdziesz w dokumentacji poszczególnych narzędzi, ale zasada działania będzie podobna.</p><p>W pierwszej linijce podajemy <code>name</code> czyli nazwę joba (akcji do wykonania), czuj się swobodnie puścić wodze fantazji, to jest nazwa własna i nie ma znaczenia :) </p><p>Druga linijka jest bardzo ważna, bowiem triggerem (czyli elementem wywołującym joba) może być mnóstwo rzeczy: zmiana labelki, stworzenie Pull Requesta czy zgłoszenie buga. <strong>W tym przypadku będzie to push do brancha master.</strong></p><p>Następnie pod kluczem <code>jobs</code> definiujemy akcje będą składowymi joba, w tym przypadku jest to tylko<em> deploy </em>(to też nazwa własna w yml) na produkcję, który wykonamy na obrazie ubuntu-18.04. Github Actions udostępnia kilka typów maszyn z różnymi systemami operacyjnymi. Jeśli zastanawia cię co to obraz (czy kontener) to zapraszam do przeczytania <a href="https://solutionchaser.com/pierwsza-przygoda-z-dockerem/">wpisu o Dockerze</a>. </p><p>Warto wiedzieć, że jest w pełni wyizolowane, postawione na chwilę (dosłownie na wywołanie tego joba) środowisko, które zostanie usunięte wraz z zakończeniem pracy.</p><p>Następnie podajemy kroki, które chcemy wykonać (pod kluczem <code>steps</code>). Tutaj mamy dwa:</p><ul><li>pobierz najnowszą wersję szablonu z mastera</li><li>zbuduj szablon Ghosta i umieść na produkcji</li></ul><pre><code>      // fragment yml
      - uses: actions/checkout@master
      - uses: TryGhost/action-deploy-theme@v1.0.0</code></pre><p>Pierwsze jest łatwe, bo przecież znamy gita i wystarczy tylko użyć pluginu z Github Actions. Drugie już mniej a to po prostu napisany skrypt w js i wrzucony do repozytorium <a href="https://github.com/TryGhost/action-deploy-theme/">https://github.com/TryGhost/action-deploy-theme/</a>.</p><p>Szczegóły można zobaczyć tutaj: <a href="https://github.com/TryGhost/action-deploy-theme/blob/master/index.js">https://github.com/TryGhost/action-deploy-theme/blob/master/index.js</a>.</p><p>Pisanie takich skryptów jest monotonne: Normalnie użylibyśmy kontenera z nodejs, potem zrobili <code>npm install</code>, a następnie <code>npm build</code> (pod którym w przypadku szablonu ghosta byłby <code>gulp zip</code>), aż w końcu skopiowali otrzymany plik do katalogu na serwerze poleceniem <code>cp</code>. </p><p>Jednak w większości przypadków będziecie używać gotowych rozwiązań, które robią to za nas :)</p><h2 id="zmienne-rodowiskowe-i-sekrety">Zmienne środowiskowe i sekrety</h2><p>Skoro już wiemy jak wywołać kolejne akcje to teraz objaśnijmy sobie klucz <code>with</code>. Odpowiada on za zmienne środowiskowe, które będą dostępne w czasie przetwarzania kroku. Zwykle są to zewnętrzne dane takie jak środowisko, ścieżki, rodzaj builda albo hasła.</p><p>W naszym przykładzie podaliśmy tam URL mojego bloga. Akurat ten plugin wymaga takich danych do poprawnego działania.</p><p>Pewnie zastanawia was kolejna zmienna środowiskowa <code>${{ secrets.GHOST_ADMIN_API_KEY }}</code>. To całkiem proste: klamerki poprzedzone dolarem to oznaczanie zmiennej, a w środku mamy jej nazwę.</p><p>Tylko skąd się wzięła zmienna secrets? I co to w ogóle jest?</p><h3 id="co-to-sekrety">Co to sekrety?</h3><p>Sekretami w programowaniu nazywamy informacje, które nie powinny być dostępne publicznie: takie jak hasła i - jak w tym przypadku - klucze dostępu. Lokalnie przechowywane są w powłokach lub plikach, których nie pushuje się do repozytorium a serwery korzystają z narzędzi przechowujących klucze pod postacią klucz-wartość. Rzadko jest to zwykła baza, powstało wiele dedykowanych ku temu narzędzi.<br><br>Na szczęście Github ma swoje, dostępne w Settingsach każdego repozytorium. Najprościej go znaleźć przez klienta webowego Githuba czyli github.com. Wejdź do repozytorium swojego szablonu, przyciśnij <em>Settings</em> i z pionowego menu po lewej wybierz <em>Secrets</em>. Ścieżka powinna być mniej więcej taka <a href="https://github.com/KamilaBrylewska/technozaur/settings/secrets/">https://github.com/KamilaBrylewska/technozaur/settings/secrets/</a>.</p><p>Umieściłam tam klucz który pobrałam po tworzeniu customowej integracji w panelu ghosta: Ghost Admin -&gt; Settings -&gt; Inegrations -&gt; Add Custom Integration. Klucz który cię interesuje to <strong>Admin API Key</strong> i to właśnie jego wartość dodałam po kluczem<strong> </strong><code>CHASER_PROD_API_KEY</code> na githubie.</p><p>Gotowe!</p><p>Teraz udostępnijmy <code>yml</code> serwerowi pushując plik do repozytorium:</p><pre><code>git add .github/workflows/deploy-theme.yml
git commit -m "Github Actions - Deploy"
git push</code></pre><blockquote>Jeśli autoryzujecie się do githuba przez customowe integracje np.: OAuth to możecie napotkać błąd <em>'refusing to allow an OAuth App to create or update workflow <code>.github/workflows/main.yml</code> without <code>workflow</code> scope'. </em>Jest to celowe działanie, które ma zapobiegać aktualizacji workflow poprzez zewnętrzne aplikacje. Więc przygotujcie klucze do działania!</blockquote><p>Teraz musicie wejść na <a href="https://github.com/KamilaBrylewska/technozaur/actions">https://github.com/TwojaNazwa/NazwaTwojeRepozytorium/actions</a> i zobaczyć swój pierwszy deploy :)</p><figure class="kg-card kg-image-card"><img src="https://solutionchaser.com/content/images/2020/06/image.png" class="kg-image" alt="Podstawy Continuous Integration&Delivery na przykładzie Github Actions"></figure><p>Po kliknięciu na szczegóły będziecie mogli podejrzeć jakie dokładnie kroki się wykonały.</p><h2 id="fajne-linki-do-dokumentacji">Fajne linki do dokumentacji</h2><p>Ten wpis jest coraz dłuższy, a informacji wciąż sporo do przekazania, więc dla dociekliwych przygotowałam kilka ciekawych linków. Jeśli chcecie wiedzieć co można wpisać w <code>runs-on</code>, co oznaczają poszczególne klucze w YAML oraz jakie zmienne środowiskowe są dostępne, zapraszam do odwiedzenia poniższych linków:</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://help.github.com/en/actions/language-and-framework-guides/using-nodejs-with-github-actions"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Using Node.js with GitHub Actions - GitHub Help</div><div class="kg-bookmark-description">You can create a continuous integration (CI) workflow to build and test your Node.js project.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://help.github.com/assets/images/site/favicon.ico" alt="Podstawy Continuous Integration&Delivery na przykładzie Github Actions"><span class="kg-bookmark-publisher">GitHub Help</span></div></div></a></figure><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://help.github.com/en/actions/configuring-and-managing-workflows/using-environment-variables"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Using environment variables - GitHub Help</div><div class="kg-bookmark-description">GitHub sets default environment variables for each GitHub Actions workflow run. You can also set custom environment variables in your workflow file.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://help.github.com/assets/images/site/favicon.ico" alt="Podstawy Continuous Integration&Delivery na przykładzie Github Actions"><span class="kg-bookmark-publisher">GitHub Help</span></div></div></a></figure><p>Dodatkowo jeśli nie chcecie korzystać z gotowego plugina, można poczytać dokładną instrukcję jak samemu napisać podobny workflow:</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://help.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idruns-on"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Workflow syntax for GitHub Actions - GitHub Help</div><div class="kg-bookmark-description">A workflow is a configurable automated process made up of one or more jobs. You must create a YAML file to define your workflow configuration.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://help.github.com/assets/images/site/favicon.ico" alt="Podstawy Continuous Integration&Delivery na przykładzie Github Actions"><span class="kg-bookmark-publisher">GitHub Help</span></div></div></a></figure><h1 id="podsumowanie">Podsumowanie</h1><p>Mam nadzieje, że się podobało :) Obecnie automatyzacja jest niezbędna do zwinnej produkcji oprogramowania i obecnie nie wyobrażam sobie pracy bez niej. Pomijając wyniosłe idee <strong>tak naprawdę to po prostu szereg powtarzalnych zadań, których nie muszę robić</strong>. A to tygryski lubią najbardziej :)</p><p>A wy z jakich CI korzystacie? Możecie coś polecić w rozsądnej cenie dla developera-hobbysty?</p>]]></content:encoded></item><item><title><![CDATA[Czy jesteś gotowy na pierwszą pracę? - zadania dla początkującego front-end developera]]></title><description><![CDATA[<p>W ramach mentoringu tworzę zadania dla mojego mentee i postanowiłam się z Wami nimi podzielić :) <strong>Ten wpis jest dla osób początkujących po kursach. </strong>Tych którzy czują się gotowi na podjęcie pierwszej pracy lub chcą sprawdzić się w prawdziwym zadaniu. </p><p><strong>Jak wiadomo od słuchania i oglądania nikt programistą nie został, więc</strong></p>]]></description><link>https://solutionchaser.com/zadania-dla-poczatkujacego-front-end-developera/</link><guid isPermaLink="false">5ea2c55fcb5cbe060d180cb7</guid><category><![CDATA[front-end]]></category><category><![CDATA[początkujący]]></category><dc:creator><![CDATA[Kamila]]></dc:creator><pubDate>Sat, 25 Apr 2020 18:04:00 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1568598035424-7070b67317d2?ixlib=rb-1.2.1&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=2000&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjExNzczfQ" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1568598035424-7070b67317d2?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=2000&fit=max&ixid=eyJhcHBfaWQiOjExNzczfQ" alt="Czy jesteś gotowy na pierwszą pracę? - zadania dla początkującego front-end developera"><p>W ramach mentoringu tworzę zadania dla mojego mentee i postanowiłam się z Wami nimi podzielić :) <strong>Ten wpis jest dla osób początkujących po kursach. </strong>Tych którzy czują się gotowi na podjęcie pierwszej pracy lub chcą sprawdzić się w prawdziwym zadaniu. </p><p><strong>Jak wiadomo od słuchania i oglądania nikt programistą nie został, więc do roboty.</strong> Dobrze zrobione zadania tego typu to fajny wpis do pierwszego CV front-end developera :)</p><h2 id="s-owniczek">Słowniczek</h2><p>Zanim przejdziemy do zadań musimy wyjaśnić sobie kilka słów:</p><ul><li>AC (Acceptance Criteria) - lista biznesowych (czyli nietechnicznych), wymagań, które trzeba spełnić aby zadanie zostało zakończone. Czym dokładniejsze tym lepsze :) A dzisiaj to ja będe je przygotowała.</li><li>standardy kodowania - każdy team ma swoje, uczymy się ich kodując i współpracując z innymi programistami. Jeśli nie masz swoich to polecam te od Google'a. Dla mnie podstawą dla juniora będzie: ES6, modularność i reużywalność kodu (na takim poziomie jak dacie radę), logicznie ponazywane zmienne, czytelny kod.</li><li>CTA - skrót marketingowców od Call To Action; zwykle interaktywny komponent, kluczowy w kontekście danego widoku strony. Powinien się wizualnie wyróżniać.</li></ul><h2 id="formularz-kontaktowy">Formularz kontaktowy</h2><p>Poziom trudności dla początkującego: wysoki.</p><p>Zaczęłam od najtrudniejszego zadania, ale front-end developer powinien umieć stworzyć dobry formularz. Moim zdaniem perfekcyjne zadanie dla kogoś kto opanował podstawy HTML, CSS oraz JavaScript i szuka wyzwania.</p><p>AC:</p><ul><li>podstawą formularza jest prosty landing page z białym tłem</li><li>formularz jest wycentrowany zarówno w poziomie jak i w pionie</li><li>formularz posiada tytuł "Skontaktuj się ze mną" oraz podtytuł "Zawsze chętnie się dowiemy się co Ci chodzi po głowie"</li><li>Formularz posiada trzy pola (imię, adres e-mail oraz treść wiadomości) oraz przycisk "Wyślij"</li><li>wszystkie pola w formularzu są walidowane: w polu imię da się wpisać tylko imię a w polu email tylko email. Błędna walidacja pola jest sygnalizowana czerwonym kolorem.</li><li>pole "Treść wiadomości" pozwala na wpisanie maksymalnie 120 znaków</li><li>przycisk "Wyślij" jest CTA (więc jest wystylowany jako taki)</li><li>przycisk "Wyślij" jest nieaktywny gdy formularz jest niepoprawnie wypełniony</li><li>design ma być elegancki, czytelny i klarowny, a obsługa intuicyjna i zgodna z nawykami użytkowników</li></ul><p>To wbrew pozorom trudne zadanie, które wymaga zainteresowania jak wyglądają formularze i interakcje z nimi. Dla początkującego front-end developera jest to wiedza wręcz niezbędna, więc zostawiam Was z wyszukiwarką.</p><h2 id="stopka">Stopka</h2><p>Poziom trudności dla początkującego: średni. </p><p>Kolejnym zadaniem jest klasyczna stopka w której zwykle umieszczane są linki do najważniejszych podstron. Niezbędna część strony.</p><p>AC:</p><ul><li>stopka znajduje się na dole strony, jest to rozciągnięta na całą szerokość</li><li>tło stopki jest w kolorze #383B44, tekst (linki oraz tekst) w #EBECF0</li><li>Stopka zawiera trzy kolumny ułożone obok siebie, a w każdej z nich tytuł oraz pięć Twoich ulubionych linków dotyczących web developmentu</li><li>Każda kolumna ma taką samą szerokość</li><li>W wersji mobilnej kolumny zamieniają się w rozwijaną listę składającą się z tytułów.</li><li>Listę rozwijasz klikając na tytuł, dzięki czemu ukazują się linki. Liste zwijasz klikają na tytuł, linki się chowają. Jak w poniższym przykładzie można użyć jakieś ikonki pokazującej stan (plus/minus albo strzałki góra/dół).</li></ul><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://solutionchaser.com/content/images/2020/04/obraz.png" class="kg-image" alt="Czy jesteś gotowy na pierwszą pracę? - zadania dla początkującego front-end developera"><figcaption>https://stackoverflow.com/questions/35349802/bootstrap-list-group-for-desktop-accordion-for-mobile</figcaption></figure><p>Da się to zrobić w samym CSS i jest to wersja preferowana ze względu na wydajność, ale zostawiam to Wam :)</p><h2 id="menu-typu-hamburger">Menu typu hamburger</h2><p>Poziom trudności dla początkującego: niski. </p><p>Jest to typowy komponent stworzony pod mobilne wersje, ale wiele stron - w tym YouTube - korzysta z niego na wszystkich rozdzielczościach. Możecie je kojarzyć jako charakterystyczne trzy poziom kreski po naciśnięciu których pojawia się menu tak jak na zdjęciu poniżej:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://solutionchaser.com/content/images/2020/04/obraz-1.png" class="kg-image" alt="Czy jesteś gotowy na pierwszą pracę? - zadania dla początkującego front-end developera"><figcaption>youtube.com</figcaption></figure><p>AC:</p><ul><li>strona posiada klikalną ikonkę hamburgera w lewym górym rogu strony</li><li>ikona zawsze (niezależnie od skrolowania) jest u góry strony</li><li>po naciśnięciu ikonki pojawia się menu o szerokości 200px którego wysokość jest równa wysokości strony</li><li>w menu są klikalne bloki z linkami</li><li>menu posiada wewnętrzny scroll na wypadek gdyby pozycji menu było więcej niż pozwala na to wysokość strony</li><li>menu chowa się po ponownym naciśnięciu na ikonkę hamburgera</li><li>dodatkowym atutem będzie animacja pojawiania się i chowania menu, ale nie jest konieczna</li></ul><p>Hamburger jest obecnie nielubiany przez UXowców, ale to w miarę proste zadanie, idealne na rozgrzewkę lub mniej śmiałego adepta frontu :) Protip: To również można wykonać samym CSS.</p><h1 id="podsumowanie">Podsumowanie</h1><p>Udostępniłam 3 zadania o różnym (wg mnie) poziomie trudności, które sprawdzają wiedzę i - przede wszystkim - umiejętność zdobywania informacji. Możecie zauważyć, że zadania nie kolidują ze sobą, więc szaleńcy mogą wykonać je w jednym pliku.</p><p>Piszcie jeśli coś jest niejasne i chwalcie się wynikami Waszej pracy :)</p><p>Zapraszam do kodowania :)</p>]]></content:encoded></item><item><title><![CDATA[Pierwsza przygoda z Dockerem]]></title><description><![CDATA[<p>Docker. Kontenery. Wirtualizacja. Środowisko programistyczne. Jeśli zastanawialiście się jak rozpocząć zabawę z konteneryzacją to jest wpis dla Was :) Krok po kroczku postawicie swojego pierwszego dockera.</p><p>Dzisiejszy przykład będzie bardzo prosty, postawimy serwer node.js w kontenerze, który będzie zwracał miłą wiadomość. Proszę nie robić tak na produkcji :)</p><h2 id="stop-co-to-s-te-kontenery">Stop. Co to</h2>]]></description><link>https://solutionchaser.com/pierwsza-przygoda-z-dockerem/</link><guid isPermaLink="false">5e4d8065dc71cb4c1e332e36</guid><category><![CDATA[back-end]]></category><category><![CDATA[front-end]]></category><category><![CDATA[nodejs]]></category><category><![CDATA[początkujący]]></category><category><![CDATA[javascript]]></category><dc:creator><![CDATA[Kamila]]></dc:creator><pubDate>Sun, 23 Feb 2020 11:59:24 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1568430462989-44163eb1752f?ixlib=rb-1.2.1&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=1080&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjExNzczfQ" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1568430462989-44163eb1752f?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=1080&fit=max&ixid=eyJhcHBfaWQiOjExNzczfQ" alt="Pierwsza przygoda z Dockerem"><p>Docker. Kontenery. Wirtualizacja. Środowisko programistyczne. Jeśli zastanawialiście się jak rozpocząć zabawę z konteneryzacją to jest wpis dla Was :) Krok po kroczku postawicie swojego pierwszego dockera.</p><p>Dzisiejszy przykład będzie bardzo prosty, postawimy serwer node.js w kontenerze, który będzie zwracał miłą wiadomość. Proszę nie robić tak na produkcji :)</p><h2 id="stop-co-to-s-te-kontenery">Stop. Co to są te kontenery?</h2><p>Jeśli takie pytanie przeszło ci przez głowę to najlepsza odpowiedź brzmi mniej tak: to taki wirtualny komputer na twoim fizycznym: kompletnie odseparowany i niezależny (oczywiście oprócz zasobów fizycznych). Można go postawić na dowolnym, innym komputerze i wszędzie będzie działał tak samo. Dlatego developerzy używają go do stawiania środowisk programistycznych/produkcyjnych.</p><p>To jak? Gotowi na pierwszą przygodę z Dockerem?</p><h2 id="rozpocz-cie">Rozpoczęcie</h2><p>Pierwsze co musicie zrobić to zainstalować Dockera, najbezpieczniej pobrać go z oficjalnej strony.</p><p>Stwórzmy folder <em>kreda</em> w którym będziemy trzymali nasz projekt, a w środku:</p><ul><li>plik <em>server.js </em>w którym będzie kod aplikacji opartej na express.js</li><li>plik <em>package.json</em> w którym dodamy zależności aplikacji</li><li>plik <em>Dockerfile</em> w którym będą polecenia do zbudowania środowiska i aplikacji</li><li>plik <em>.dockerignore</em> w którym dodamy ścieżki które chcemy w dockerze ignorować</li></ul><p>Zacznijmy od serwera:</p><pre><code>// server.js
const express = require('express');
const app = express();

app.get('/', function (req, res) {
  res.send('Hello guys! Kamila is here');
});

// 8080 to przykładowy port
app.listen(8080, function () {
  console.log('Example app listening on port 8080!');
});</code></pre><p>A teraz package.json:</p><pre><code>// package.json
{
    "name": "solutionchaser",
    "version": "1.0.0",
    "description": "Blog post",
    "main": "index.js",
    "scripts": {
      "start": "node server.js"
    },
    "author": "Kamila",
    "license": "OhPlease",
    "dependencies": {
      "express": "^4.15.3"
    }
  }</code></pre><p>Testowo odpalmy server.js w konsoli (będąc oczywiście w folderze <em>kreda</em>):</p><pre><code>// w konsoli
npm i
node sever.js</code></pre><p>Jeśli nie pojawił się żaden błąd, to spróbujmy otworzyć stronę w przeglądarce pod adresem <code>http://127.0.0.1:8080</code>. Jeśli wyświetli się ekran powitalny to odnieśliśmy pierwszy sukces. Niezwiązany z dockerem, ale jednak!</p><p>Teraz zabijmy proces i <strong>zamknijmy konsolę, </strong>jest to szczególnie ważne bowiem czasem system nie zwalnia portu.</p><h2 id="definicje-dockerowe">Definicje dockerowe</h2><p>Korzystając z Dockera najczęściej korzysta się z gotowych obrazów zawierających system z zainstalowanymi <em>komponentami</em>. Jako, że chcemy postawić prostą aplikację node.js przydałby się nam node. </p><p>Pod tym <a href="https://hub.docker.com/">linkiem DockerHub</a> można zobaczyć listę oficjalnie dostępnych obrazów do uruchomienia w dockerze i chyba jest to najprostszy sposób na start :) Wybrałam node'a w wersji 10.</p><p>W pliku Dockerfile wykonujemy kroki służące do zbudowania kontenera. Robimy to za pomocą krótkich (zwykle pisanych wielkimi literami) komend takich jak COPY albo CMD.</p><pre><code>// wykorzystanie obrazu zawierającego node w wersji 10
FROM node:10

// skopiowanie wszystkich plików z obecnego katalogu do kontenera
COPY . .

// wykonanie komendy: npm install która pobierze paczkę express.js
CMD npm install

// wystaw na zewnątrz port 8080, żeby można było się z nim połączyć
EXPOSE 8080

// wykonanie komendy node server.js
CMD node server.js</code></pre><p>A teraz .dockerignore, bowiem nie chcemy, żeby z naszego lokalnego środowiska kopiowały się niepotrzebne pliki:</p><pre><code>node_modules
npm-debug.log
</code></pre><h2 id="ty-ja-i-docker-let-s-run-it-">Ty, ja i Docker - let's run it!</h2><p>Po pierwsze musimy zbudować środowisko:</p><pre><code>docker build -t twoja-nazwa-kontenera .</code></pre><p>Nie ma żadnych błędów? Mam nadzieję :)</p><p>To teraz uruchomimy go, żebyśmy mogli korzystać z aplikacji. W parametrze <code>p</code> podajemy mapowanie portu (tego samego co w EXPOSE do tego który chcemy wpisywać w przeglądarce). Tutaj oczywiście mapowanie jest trochę bez sensu, ale gdy macie port 8080 zajęty na fizycznej maszynie to oto trick :)</p><pre><code>docker run -p 8080:8080 -d twoja-nazwa-kontenera</code></pre><p>Mam nadzieje, że zwrócił długi ciąg znaków w konsoli, teraz skopiujmy go i wklejmy:</p><pre><code>docker logs dhdbahjdbahjdbadjhabdbdahdbahwid</code></pre><p>Tutaj powinniśmy dostać informację: Example app listening on port 8080!</p><p>Ostatni etap to odpalenie serwera w przeglądarce: <code>http://127.0.0.1:8080</code>.</p><p>SUKCES :)</p><p>Niestety nie jest to perfekcyjne rozwiązanie ze względu na mnogość środowisk fizycznych, gdzie najbardziej ograniczają nas systemy operacyjne. Prawda jest taka, że większość serwerów na świecie stoi na Linuxach i jest to najlepsze środowisko programistyczne również pod względem wirtualizacji.</p><p><br>Apple nie wspiera natywnie wirtualizacji, więc większe środowiska mogą chodzić dużo wolniej bez paru tricków i hasków. Na Windowsie w wersji Home (brak obsługi wirtualizacji Hyper-V) podobno trudno uruchomić Dockera bez dodatkowego oprogramowania. Są jeszcze rozważania na temat ogólnej wydajności, ale to zdecydowanie nie jest wpis aby się w to zagłębiać.</p><h1 id="podsumowanie">Podsumowanie</h1><p>Mam nadzieje, że się podobało i udało się Wam w 30 minut zbudować swój pierwszy kontener. To oczywiście jest tylko zalążek możliwości dockera i jeden serwis wiosny nie czyni, ale mam nadzieje, że przekonałam jak łatwa i przyjemna jest konteneryzacja :)</p><p></p><p></p>]]></content:encoded></item><item><title><![CDATA[Przerywanie pobierania danych - Quiz z AbortControllerem - #funWithJavascript]]></title><description><![CDATA[<p>Dzień dobry! Jak się macie? U mnie wspaniale, chociaż dosyć pracowicie, mam nadzieje, że ten rok będzie pełen sukcesów.</p><p>Bardzo mi miło, że ze mną tutaj jesteście! Coraz więcej osób mnie czyta, dziękuję za ten czas, mam nadzieje, że nie jest zmarnowany!</p><p>Dzisiaj przychodzę do Was z bardzo ciekawym tematem,</p>]]></description><link>https://solutionchaser.com/przerywanie-pobierania-danych-abortcontroller-quiz/</link><guid isPermaLink="false">5df7ae839edf607b675bb2dc</guid><category><![CDATA[front-end]]></category><category><![CDATA[javascript]]></category><category><![CDATA[średniozaawansowany]]></category><dc:creator><![CDATA[Kamila]]></dc:creator><pubDate>Thu, 30 Jan 2020 19:38:56 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1518387534167-27adccbb255d?ixlib=rb-1.2.1&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=1080&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjExNzczfQ" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1518387534167-27adccbb255d?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=1080&fit=max&ixid=eyJhcHBfaWQiOjExNzczfQ" alt="Przerywanie pobierania danych - Quiz z AbortControllerem - #funWithJavascript"><p>Dzień dobry! Jak się macie? U mnie wspaniale, chociaż dosyć pracowicie, mam nadzieje, że ten rok będzie pełen sukcesów.</p><p>Bardzo mi miło, że ze mną tutaj jesteście! Coraz więcej osób mnie czyta, dziękuję za ten czas, mam nadzieje, że nie jest zmarnowany!</p><p>Dzisiaj przychodzę do Was z bardzo ciekawym tematem, który postanowiłam ogarnąć w weekend.</p><h2 id="fetch">Fetch</h2><pre><code>// implementacja syntax-sugar
const response = await fetch('https://pokeapi.co/api/v2/pokemon');
const json = await response.json();
console.log(json));

// implementacja sugar-free
fetch('https://pokeapi.co/api/v2/pokemon')
.then((response) =&gt; response.json())
    .then((json) =&gt;  {
        console.log(json); 
    }); </code></pre><p><em>Fetch</em> to natywna funkcja umożliwiająca asynchroniczne pobieranie danych, swojego rodzaju alternatywa dla <a href="https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest"><code>XMLHttpRequest</code></a>. Istnieje pomiędzy nimi kilka różnic w które polecam się zagłębić, jednak kluczową informacją jest, że fetch zwraca Promise'a.</p><p><strong>Co oznacza, że los fetch'a nie jest przekreślony, tym bardziej jeśli skorzystamy z AbortAPI.</strong></p><h2 id="abortapi">AbortAPI</h2><p>Sprawa jest prosta: przeglądarka udostępnia narzędzia, które umożliwiają przerwanie dowolnego requestu z DOM, a ja pokażę wam się tego używa.</p><p><strong>Przykład będzie bardzo życiowy: chcemy pobrać dane, które są tak dynamiczne że czekanie na nie powyżej sekundy mija się z celem, a nawet szkodzi naszej aplikacji.</strong></p><p>To co? Ruszamy do kodowania!</p><p>Przykładowe wywołanie poniżej, oszczędziłam Wam catch'a, ale nie powinnam!</p><pre><code>const response = SolutionFetch.fetch('https://pokeapi.co/api/v2/pokemon', 6000)
    .then((response) =&gt; response.json())
    .then((json) =&gt; {
        console.log(json);
        // pokaż tylko wartościowe dane
    })
    .catch(() =&gt; {});</code></pre><p>A teraz wrapper na natywnego fetcha:</p><pre><code>class SolutionFetch {
    static fetch(url, timeout, configObj = {}) {
        const controller = new AbortController();
        const signal = controller.signal;
        let timeoutReference = null;
        
        return new Promise((resolve, reject) =&gt; {
        
            // rejestrujemy timeouta
            timeoutReference = setTimeout(() =&gt; {
                console.log('ABORT');
                controller.abort();
                return reject();
            }, timeout);

            // fetchujemy prawdziwe dane
            fetch(url, { signal }).then((response) =&gt; {
                clearTimeout(timeoutReference);
                console.log('OK');
                return resolve(response);
            }).catch((error) =&gt; {
                console.log('NOPE');
                clearTimeout(timeoutReference);
                return reject(error);
            });
        });
    }
}
</code></pre><p>Jak to działa? Gdy utworzymy controller i podamy jego sygnał do fetcha, możemy go przerwać w dowolnym momencie! Kluczowe jest tutaj <code>controller.abort()</code>.</p><h2 id="to-teraz-szybki-quiz-">To teraz szybki quiz:<br></h2><p>1) Co będzie w konsoli jeśli wywołamy te funkcję z dużym timeoutem (czyli wartością po której chcemy zrezygnować z fetcha, w tym przykładzie 6000ms)?</p><p>2) A co jeśli timeout będzie równy 1ms? Spójrzcie do góry na kod i zastanówcie się. </p><p>3) Co się zmieni jeśli wykomentujemy 12 linijkę ( <code>controller.abort();</code> ) i czas będzie równy 1ms ?</p><p>4) Co się stanie jeśli nie <em>wyclearujemy SetTimeout'a, </em>gdy czas będzie długi (na przykład 1000ms)?</p><p><strong>I jak? Proste pytania czy wymagają nieco zastanowienia?</strong></p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://images.unsplash.com/photo-1456406644174-8ddd4cd52a06?ixlib=rb-1.2.1&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=1080&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjExNzczfQ" class="kg-image" alt="Przerywanie pobierania danych - Quiz z AbortControllerem - #funWithJavascript"><figcaption>Photo by <a href="https://unsplash.com/@punttim?utm_source=ghost&utm_medium=referral&utm_campaign=api-credit">Tim Gouw</a> / <a href="https://unsplash.com/?utm_source=ghost&utm_medium=referral&utm_campaign=api-credit">Unsplash</a></figcaption></figure><h2 id="jeste-cie-pewni-e-chcecie-zna-odpowiedzi-je-li-tak-to-scrollujcie-dalej-"><strong>Jesteście pewni, że chcecie znać odpowiedzi? Jeśli tak to scrollujcie dalej!</strong></h2><p></p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://images.unsplash.com/photo-1566770050648-8fb922f3f977?ixlib=rb-1.2.1&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=1080&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjExNzczfQ" class="kg-image" alt="Przerywanie pobierania danych - Quiz z AbortControllerem - #funWithJavascript"><figcaption>Photo by <a href="https://unsplash.com/@jentheodore?utm_source=ghost&utm_medium=referral&utm_campaign=api-credit">Jen Theodore</a> / <a href="https://unsplash.com/?utm_source=ghost&utm_medium=referral&utm_campaign=api-credit">Unsplash</a></figcaption></figure><h2 id="a-teraz-wyniki-">A teraz wyniki:</h2><p></p><p>1) Wyświetli się zarówno "OK" jak i odpowiedź z serwera z listą pokemonów.</p><p>2) Wyświetli się "ABORT" i "NOPE", a request nie zostanie wysłany. Można to zobaczyć w zakładce "Sieć"/"Network"</p><p>3) Wyświetli się "ABORT" i "OK", request zostanie wysłany.</p><p>4) Wyświetli się "OK", potem pojawi się odpowiedź z serwera, a po chwili "ABORT". Raz zresolvowanego promise'a nie da się rejectować, więc reject w setTimeoutcie nie będzie miał znaczenia.<br></p><h1 id="podsumowanie">Podsumowanie</h1><p>Mam nadzieje, że się podobało :) Staram się cały czas na nowo odkrywać Javascript, a pisanie #funWithJavascript to najlepsza okazja!</p><p>Pochwalcie się wynikami? Udało Wam się rozwiązać mój mini quiz czy gdzieś się pomyliliście?<br><br>Pozdrawiam serdecznie i bardzo dziękuję za wszystkie polubienia, udostępnienia oraz miłe słowa!</p>]]></content:encoded></item><item><title><![CDATA[Specjaliści w IT dużo pracują i niewystarczająco zarabiają - Finalne wyniki badania na temat jakości pracy na B2B]]></title><description><![CDATA[<p>Dzień dobry!</p><p>Niestety wszystko co dobre kiedyś się kończy i przed nami <strong>finalne wyniki badań</strong>! Jeśli chcecie pozazdrościć specjalistom z Podlasia to zapraszam do czytania!</p><p>Warto dodać, że ostatnie wpisy są całkiem popularne (także te techniczne), a dzięki wykopowi (<a href="https://www.wykop.pl/wpis/46198145/unknownews-to-prawdopodobnie-ostatnie-wydanie-zest/">wykop.pl</a>) zaliczyłam ogromny skok popularności właśnie dzięki wstępnym wynikom badań.</p>]]></description><link>https://solutionchaser.com/zarobki-specjalistow-w-it/</link><guid isPermaLink="false">5e2c3d5c851014c430c06e83</guid><category><![CDATA[Weekend bez komputera]]></category><category><![CDATA[maintenance]]></category><category><![CDATA[crazy]]></category><dc:creator><![CDATA[Kamila]]></dc:creator><pubDate>Sat, 25 Jan 2020 14:45:19 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1518458028785-8fbcd101ebb9?ixlib=rb-1.2.1&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=1080&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjExNzczfQ" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1518458028785-8fbcd101ebb9?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=1080&fit=max&ixid=eyJhcHBfaWQiOjExNzczfQ" alt="Specjaliści w IT dużo pracują i niewystarczająco zarabiają - Finalne wyniki badania na temat jakości pracy na B2B"><p>Dzień dobry!</p><p>Niestety wszystko co dobre kiedyś się kończy i przed nami <strong>finalne wyniki badań</strong>! Jeśli chcecie pozazdrościć specjalistom z Podlasia to zapraszam do czytania!</p><p>Warto dodać, że ostatnie wpisy są całkiem popularne (także te techniczne), a dzięki wykopowi (<a href="https://www.wykop.pl/wpis/46198145/unknownews-to-prawdopodobnie-ostatnie-wydanie-zest/">wykop.pl</a>) zaliczyłam ogromny skok popularności właśnie dzięki wstępnym wynikom badań. Dziękuję za wszystkie lajki, reakcje! </p><p>Dzisiaj będzie równie interesująco. Jeśli boicie się zapytać kto, gdzie i ile zarabia, ten wpis odpowie na wiele pytań!</p><h2 id="tl-dr">TL;DR</h2><ul><li>Aż 66% specjalistów pracuje ponad etat miesięcznie i podczas gdy za standardową liczbę godzin (160h w miesiącu) zarabiają średnio 10,5 tys. miesięcznie netto. </li><li>Większość z ankietowanych uważa, że zarobki są nieadekwatne do wykonywanej pracy.</li><li>Statystycznie kobiety w IT zarabiają mniej niż mężczyźni, za to odczuwają większy komfort pracy i rozwoju.</li><li>2,6% ankietowanych kobiet i 11,8% mężczyzn zarabia ponad 150zł/h netto.</li><li>Zadowolonych z wynagrodzenia jest tylko 47% badanych</li><li>Najniższy komfort finansowy odczuwają respondenci z <strong>województwa lubelskiego</strong>: 48%, a najwyższy <strong>z... </strong></li></ul><h2 id="podzi-kowania">Podziękowania</h2><p>Bardzo chciałabym podziękować grupie <a href="https://eworkgroup.com/pl">EWork</a> za inicjatywę, która ma na celu poprawę warunków pracy specjalistów w IT. Według badań nie jest tak różowo jak mówią w mediach, ale już dokładanie wiemy co trzeba zmienić :)</p><p>Ework Group to niezależna agencja konsultingowa notowana na giełdzie Nasdaq Stockholm, zrzeszająca specjalistów IT, reprezentująca pochodzący ze Skandynawii model biznesowy powstały w 2000 roku w Szwecji. Obecnie funkcjonuje również w Danii, Norwegii, Finlandii i w Polsce. Ework Group działa w Polsce od 2015 r., z biurami w Warszawie, Wrocławiu i Gdyni.</p><p>Największe - bo osobiste - podziękowania chciałabym skierować ku agencji reklamowej, która powoli przeprowadziła mnie przez moją pierwszą komercyjną współpracę! Naprawdę cudowne osoby pomogły mi przekazać Wam tę całą wiedzę!</p><p>Agencja Biuro Podróży Reklamy to eksperci w kampaniach łączących social, web, mobile, search marketing, video, blog i content marketing z ambientem technologicznym, marketingiem partyzanckim oraz innymi działaniami niestandardowymi i innowacyjnymi technologiami. Twórcy nowatorskich stron i aplikacji mobilnych. Agencja posiada dwa tytuły agencji roku: Agency of the Year 2014 in Poland – Epica Awards, Agencja Marketingu Zintegrowanego Roku – Impactor (2015) oraz w sumie 33 nagrody i wyróżnienia branżowe: Epica Awards, Kreatura, Impactor, Mixx Awards, AME Award, Webstar Creative, Golden Arrow, Innovation Award, Pióro Roku, Złoty i Srebrny Spinacz, Kampania Społeczna Roku.</p><h2 id="wyniki-badania">Wyniki badania</h2><p>Po długim wstępie nadszedł czas na wyniki badania!</p><p>W badaniu oceniliście są takie obszary jak „Komfort finansowy”, „Komfort pracy”, „Komfort czasu pracy”, „Styl pracy”, „Komfort współpracy” czy „Komfort rozwoju”. Okazuje się, że w swojej pracy specjaliści IT najgorzej oceniają „komfort finansowy”, na który wpływają m.in. zarobki i systemy podwyżek – został oceniony średnio na 62% (w skali satysfakcji 0-100%). </p><figure class="kg-card kg-image-card"><img src="https://solutionchaser.com/content/images/2020/01/eWORK_infographic_1.jpg" class="kg-image" alt="Specjaliści w IT dużo pracują i niewystarczająco zarabiają - Finalne wyniki badania na temat jakości pracy na B2B"></figure><p>I to mimo faktu, iż ponad 60% kobiet i ponad 70% mężczyzn pracujących jako specjaliści IT w oparciu o kontrakt B2B zarabia w Polsce powyżej 65 zł na godzinę (netto), czyli co najmniej 10,5 tys. zł netto miesięcznie (przy przyjęciu puli godzin w miesiącu jak na etacie).</p><figure class="kg-card kg-image-card"><img src="https://solutionchaser.com/content/images/2020/01/eWORK_infographic_2.jpg" class="kg-image" alt="Specjaliści w IT dużo pracują i niewystarczająco zarabiają - Finalne wyniki badania na temat jakości pracy na B2B"></figure><p>Zarobki do 65 zł (netto) za godzinę deklaruje 36,8% kobiet i 27,8% mężczyzn, od 66 do 95 zł za godzinę – 23,7% kobiet i 24,4% mężczyzn, od 96 zł do 125 zł za godzinę – 19,7% i 25% mężczyzn, od 126 do 150 zł za godzinę – 17,1% kobiet i 11% mężczyzn oraz powyżej 150 zł za godzinę – 2,6% kobiet i 11,8% mężczyzn.</p><figure class="kg-card kg-image-card"><img src="https://solutionchaser.com/content/images/2020/01/eWORK_infographic_3.jpg" class="kg-image" alt="Specjaliści w IT dużo pracują i niewystarczająco zarabiają - Finalne wyniki badania na temat jakości pracy na B2B"></figure><p>Dla 43% ankietowanych najważniejszym benefitem stażu pracy jest właśnie wyższe wynagrodzenie, 29% ankietowanych uznała, że najważniejsze są ciekawe projekty. Aż 53% badanych uważa, że ich zarobki mogłyby być lub wręcz powinny być lepsze. Ogólne zadowolenie z zarobków wynosi 47% - tyle procent badanych uważa, że ich zarobki są „stabilne” lub „adekwatne do projektu”.</p><figure class="kg-card kg-image-card"><img src="https://solutionchaser.com/content/images/2020/01/eWORK_infographic_4.jpg" class="kg-image" alt="Specjaliści w IT dużo pracują i niewystarczająco zarabiają - Finalne wyniki badania na temat jakości pracy na B2B"></figure><p>Najbardziej zadowoloną ze swoich zarobków grupą są osoby, które mają mniej niż 2 lata doświadczenia. 55% z nich uznało, że wynagrodzenie jest adekwatne lub stabilne. Jednak im dłuższy staż pracy, tym więcej wskazań „mogłoby być lepiej”.</p><p>Wraz z doświadczeniem rosną stawki. Pośród osób biorących udział w badaniu, ponad 70% osób z doświadczeniem poniżej 2 lat zarabia poniżej 65 zł za godzinę, z kolei prawie 20% osób z doświadczeniem ponad 9 lat zarabia powyżej 150 zł za<br>godzinę.</p><figure class="kg-card kg-image-card"><img src="https://solutionchaser.com/content/images/2020/01/eWORK_infographic_5.jpg" class="kg-image" alt="Specjaliści w IT dużo pracują i niewystarczająco zarabiają - Finalne wyniki badania na temat jakości pracy na B2B"></figure><p>Z kolei w podziale na specjalności zawodowe kwestie zarobków i satysfakcji kształtują się tak, że spośród badanych, najwyższe zarobki deklarują specjaliści pracujący w obszarze zarządzania IT i systemów ERP, a najmniejsze – specjaliści w<br>obszarze bezpieczeństwa.</p><p>Jednocześnie specjaliści w obszarze bezpieczeństwa deklarują największe zadowolenie z zarobków, a specjaliści z obszaru zarządzania IT - najmniejsze.</p><figure class="kg-card kg-image-card"><img src="https://solutionchaser.com/content/images/2020/01/eWORK_infographic_6.jpg" class="kg-image" alt="Specjaliści w IT dużo pracują i niewystarczająco zarabiają - Finalne wyniki badania na temat jakości pracy na B2B"></figure><p>Zarobki to jednak nie wszystko. Specjaliści w branży IT (pracujący na kontraktach B2B) najwyżej oceniają „komfort rozwoju” (m.in. możliwości podnoszenia kwalifikacji, szkolenia, premie i nagrody) – kategorię tę oceniono średnio<br>na 86% (w skali 0-100%).</p><p>Wysoko oceniano także „komfort czasu” pracy (m.in. liczba godzin w miesiącu oraz możliwość pracy zdalnej) – 80% oraz komfort współpracy (m.in. pozyskiwanie nowych projektów, ich atrakcyjność czy atmosfera pracy) - 75%.</p><p>Gorzej oceniane są kategorie takie jak „styl pracy” (m.in. trudność w prowadzeniu biznesu, elastyczność czasu pracy, wybór projektu) - 65%; oraz komfort pracy (m.in. podróże służbowe czy lokalizacja biura) - 67%.<br>Kobiety notują wyższy średni komfort pracy, komfort czasu pracy, komfort współpracy oraz komfort rozwoju. Mężczyźni mają wyższy średni komfort finansowy, jak również oceniają wyżej styl pracy.</p><figure class="kg-card kg-image-card"><img src="https://solutionchaser.com/content/images/2020/01/eWORK_infographic_7.jpg" class="kg-image" alt="Specjaliści w IT dużo pracują i niewystarczająco zarabiają - Finalne wyniki badania na temat jakości pracy na B2B"></figure><p>W skali ogólnopolskiej, średni komfort we wszystkich kategoriach jest wysoki – wynosi 72,5%. Najniższy średni komfort jest notowany w województwie opolskim – wynosi 64%. Najwyżej plasują się specjaliści IT z województwa świętokrzyskiego, których średni komfort wynosi aż 76%. Najniższy komfort finansowy odczuwają respondenci z województwa lubelskiego: 48%, a najwyższy – z podlaskiego – 73%.</p><h2 id="podsumowanie">Podsumowanie</h2><p>Ta współpraca to była sama przyjemność, sporo nauczyłam się o branży i mogłam posłuchać Waszych opinii. Statystyka jest zwodniczą nauką, ale bez zadawania pytań i kategoryzowania problemów nigdzie nie zaszlibyśmy jako ludzkość i cieszę się, że mogę w tym uczestniczyć.</p><p>A jak tam u Was? Zszkokowani? Czekacie na przelew 10k czy kujecie po nocach, żeby dostac lepszą pracę?</p><p><strong>Pozdrawiam i serdecznie dziękuję za wszystkie polecenia, linki oraz reakcje &lt;3 </strong></p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://images.unsplash.com/photo-1554830072-52d78d0d4c18?ixlib=rb-1.2.1&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=1080&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjExNzczfQ" class="kg-image" alt="Specjaliści w IT dużo pracują i niewystarczająco zarabiają - Finalne wyniki badania na temat jakości pracy na B2B"><figcaption>Photo by <a href="https://unsplash.com/@howier?utm_source=ghost&utm_medium=referral&utm_campaign=api-credit">Howard Riminton</a> / <a href="https://unsplash.com/?utm_source=ghost&utm_medium=referral&utm_campaign=api-credit">Unsplash</a></figcaption></figure>]]></content:encoded></item><item><title><![CDATA[Podstawy TypeScript #2 - typowanie dla zielonych]]></title><description><![CDATA[<p>Szczęśliwego Nowego Roku! Mam nadzieje, że przerwa świąteczno-noworoczna była okazją do odpoczynku. Wróciłam z zdwojoną siła i entuzjazmem!</p><p>Serdecznie zapraszam do czytania drugiej części tego cyklu. Dzisiaj będziemy kontynuować podstawy i zjemy duży kawałek TypeScriptowego tortu. Największą zaletą TypeScripta jest... typowanie, więc bez tego trudno ruszyć dalej.</p><p>Do przeczytania tego</p>]]></description><link>https://solutionchaser.com/podstawy-typescript-2-typy-podstawowe/</link><guid isPermaLink="false">5e03d2b688a6dcf451ccb7bf</guid><category><![CDATA[front-end]]></category><category><![CDATA[typescript]]></category><category><![CDATA[średniozaawansowany]]></category><category><![CDATA[początkujący]]></category><dc:creator><![CDATA[Kamila]]></dc:creator><pubDate>Fri, 03 Jan 2020 06:02:00 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1458067380247-41000a5397cb?ixlib=rb-1.2.1&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=1080&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjExNzczfQ" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1458067380247-41000a5397cb?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=1080&fit=max&ixid=eyJhcHBfaWQiOjExNzczfQ" alt="Podstawy TypeScript #2 - typowanie dla zielonych"><p>Szczęśliwego Nowego Roku! Mam nadzieje, że przerwa świąteczno-noworoczna była okazją do odpoczynku. Wróciłam z zdwojoną siła i entuzjazmem!</p><p>Serdecznie zapraszam do czytania drugiej części tego cyklu. Dzisiaj będziemy kontynuować podstawy i zjemy duży kawałek TypeScriptowego tortu. Największą zaletą TypeScripta jest... typowanie, więc bez tego trudno ruszyć dalej.</p><p>Do przeczytania tego artykuły wymagana jest podstawowa znajomość JavaScript. <strong>Nie omówiłam wszystkich typów ani niuansów związanych z typowaniem. Żeby nie było zbyt słodko :)</strong></p><h2 id="typy-zmiennych">Typy zmiennych</h2><p>Na początek drobna uwaga: w TypeScripcie typy natywne zapisujemy z małej litery. Trzeba pamiętać, że <code>number</code> to typ, a <code>Number</code> to obiekt.</p><p>Tutaj wylistowałam <strong>niekompletną</strong> liczbę typów. Dlaczego niekompletną? Bowiem trudno mi było jednoznacznie oddzielić wiedzę podstawową od tej bardziej zaawansowanej i zrobiłam to według własnego uznania.</p><ul><li><code>string</code> to powszechnie znany łańcuch znakowy, przechowuje tekst</li><li><code>number</code> trzyma w sobie liczby</li><li><code>array</code> lub <code>[]</code> to  tablica, można również deklarować tablice konkretnego typu np.:  <code>string[]</code> lub <code>Cat[]</code></li><li><code>object</code> to powszechnie znany obiekt, wrócimy do niego za kilka akapitów</li><li><code>unknown</code> - to typ nieznany</li><li><code>any</code> - to dowolny typ</li><li><code>[key | string]</code> - typy indexów</li><li> <code>&lt;T&gt;</code> - typy generyczne zostawiam na inny wpis</li><li><code>never</code></li><li><code>void</code> </li><li><code>enum</code> - zapraszam do czytania specjalnego wpisu o <a href="https://solutionchaser.com/typescript-enum/">Enumach w TypeScripcie</a> <a href="https://solutionchaser.com/typescript-enum/">https://solutionchaser.com/typescript-enum/</a></li><li>inne: typy mieszane i zaawansowane</li></ul><h2 id="any-i-unknown">Any i unknown</h2><p>Z pewnością ten akapit wzbudzi wiele kontrowersji, bowiem samo istnienie typu - nazwijmy to tymczasowo - nieokreślonego wydaje się kontrowersyjne. TypeScript jest po to, żeby typować, więc o co chodzi? Używać czy nie używać? A jeśli tak to kiedy?</p><p>Sama koncepcja pochodzi z języków obiektowych, gdzie istnieje bazowy `Object` z którego dziedziczy wszystko. Jak nie ma na co rzutować to zawsze można na <code>Object</code>.</p><p>W JavaScripcie <code>any</code>/ <code>unknown</code>  pełni podobną rolę dodatkowo ułatwiając przetwarzanie danych, szczególnie tych pobranych z zewnętrznych źródeł. Jeśli jednak uważnie przeczytacie ten post możecie znaleźć lepsze alternatywy.</p><p>Moim zdaniem powszechnym błędem jest stosowanie <code>any</code> oraz <code>unknown</code> zamiennie lub stosowanie tylko <code>any</code>. </p><p><code>Any</code> ma większy zakres, zmienną tego typu można zawołać, może być także konstruktorem. Wszystko można przypisać do zmiennej typu <code>any</code> i zmienna typu <code>any</code> może być przypisana do wszystkiego (z drobnym wyjątkiem: <code>never</code>).</p><p><code>Unknown</code> został wprowadzony jako poprawka do <code>any</code>. Do tego typu zmiennej można przypisać wszystko, ale zmiennej typu <code>unknown</code> nie można przypisać do innego typu niż <code>any</code> or <code>unknown</code>. Nie można jej wywołać.</p><p>To jakby powiedzieć: <em>"Ok, rozumiem, że w tamtej chwili nie było możliwości, żeby znać strukturę danych, ale żeby ich użyć bezpiecznie musisz rzutować na odpowiedni typ."</em></p><pre><code>// data to dane z nieznanego nam API
let jakakolwiek: any = data;
let nieznana: unknown = data;

let numerek: string = jakakolwiek; // OK
let numerek2: string = nieznana; // ERROR</code></pre><p>Ok, to jak to zrobić? Trzeba rzutować, a co za tym idzie: dokładnie wiedzieć co się robi.</p><pre><code>let numerek2: string = nieznana as string; // OK</code></pre><h2 id="object-typy-index-w-i-index-signatures">Object, typy indexów i index signatures</h2><p>Podczas gdy w Javascriptcie obiekty są wolnym duchem, TypeScript lubi trzymać je pod kontrolą.</p><pre><code>let obj: { kot: string };

obj = {
	kot: 'franek"
}</code></pre><p>Dlatego powyższy zapis jest poprawny, ale poniższy wyrzuci błąd:</p><pre><code>let obj: { kot: string };

obj = {
	kot: 'franek',
	pies: 'łapka' // ERROR
}</code></pre><p>Czy straciliśmy całą elastyczność związaną z obiektami? Niekoniecznie!<br><br>Mamy dwa wyjścia:</p><ul><li>właściwość nieobowiązkowa oznaczona znakiem zapytania</li></ul><p>W poniższym przykładzie mamy definicję typu, który jest obiektem z obowiązkową właściwością <code>kot</code> i dodatkową <code>pies</code>. Dzięki temu możemy elastyczniej przypisywać obiekty. </p><pre><code>let obj: { kot: string, pies?: string };

obj = { // OK
	kot: 'franek',
	pies: 'łapka'
}

obj = { // OK
	kot: 'franek',
}

obj = { // ERROR
	pies: 'łapka'
}</code></pre><p>Nie będę dzisiaj tego omawiać, ale tutaj również rozwiązaniem mogą być typy zaawansowane/mieszane.</p><ul><li>zdefiniować klucz obiektu</li></ul><p>Tutaj mamy mnóstwo władzy, której łatwo naużyć, ale tak: mamy możliwość zdefiniować typu klucza oraz umieszczonych pod nim danych.</p><pre><code>let obj: {
    [key: string] : string
}


obj = {
    piesek: 'łapka',
    kotek: 'mruczek',
    papuzka: 'swiergotka'
    wiek: 3 // ERROR
}</code></pre><p>Świetne, ale co z sytuacją gdy chcemy przypisać cokolwiek?</p><pre><code>let obj: {
    [key: string] : any
}

obj = {
    piesek: 'łapka',
    kotek: 'mruczek',
    papuzka: 'swiergotka',
    wiek: 3 // OK
}</code></pre><p>Jeśli już potrzebujemy sporej elastyczności, powyższe rozwiązanie jest dobre.  Oczywiście klucz może być także <code>number</code>.</p><h2 id="never-void">Never &amp; Void</h2><p>Te typy nie są powiązane, ale bardzo łatwo można je zmylić. </p><p><code>Void</code> jest typem, który często zwracamy w metodach, bowiem jest <strong>on oznaczeniem, że ta funkcja nic nie zwróci</strong>. Podczas wykorzystywania tak oznaczonej funkcji linter przypilnuje, żeby nic nie zwracała oraz żebyśmy nie przypisywali wyniku do jakieś zmiennej.</p><p><code>Never</code> to informacja o tym, że ta <strong>funkcja nigdy się nie zakończy</strong>. Istnieje kilka takich funkcji np.: niekończący się while.</p><pre><code>const immortality = (): never =&gt; {
    while(1) {
        breath();
    }
}</code></pre><p>Albo funkcja, która zawsze zwróci wyjątek. Są to często funkcje pomocnicze, gdy aplikacja wymaga bardziej skomplikowanej obsługi błędów:</p><pre><code>function error(message: string): never {
    throw new Error(message);
}</code></pre><h1 id="podsumowanie">Podsumowanie</h1><p>Podobało się? To tylko zalążek tego co można zrobić z typami w TypeScriptcie! Wrócimy jeszcze do typów generycznych oraz bardziej zaawansowanego typowania, ale na dzisiaj odpocznijcie. Ten rok będzie szalony!</p><p> Zapraszam do komentowania, pewnie kilka niuansów przeoczyłam!</p>]]></content:encoded></item><item><title><![CDATA[Ile zarabiają i jak pracują specjaliści w IT? - Wstępne wyniki badania na temat jakości pracy na B2B]]></title><description><![CDATA[<p>Dzień dobry! Dzisiaj mam dla Was szalenie ciekawe wyniki z ankiety na temat jakości pracy na B2B. Jeśli interesuje Was komfort pracy, zarobki oraz motywacje w świecie IT to serdecznie zapraszam do czytania!</p><h2 id="s-owem-wst-pu">Słowem wstępu</h2><p>Od początku października Grupa Ework organizuje „Wielkie badanie specjalistów IT na B2B” . Badanie ma na</p>]]></description><link>https://solutionchaser.com/wyniki-badania-na-temat-jakosci-pracy-na-b2b/</link><guid isPermaLink="false">5de416b435f4a59645860313</guid><category><![CDATA[Weekend bez komputera]]></category><dc:creator><![CDATA[Kamila]]></dc:creator><pubDate>Tue, 03 Dec 2019 04:36:37 GMT</pubDate><media:content url="https://solutionchaser.com/content/images/2019/12/1080x1080_fb_SC.png" medium="image"/><content:encoded><![CDATA[<img src="https://solutionchaser.com/content/images/2019/12/1080x1080_fb_SC.png" alt="Ile zarabiają i jak pracują specjaliści w IT? - Wstępne wyniki badania na temat jakości pracy na B2B"><p>Dzień dobry! Dzisiaj mam dla Was szalenie ciekawe wyniki z ankiety na temat jakości pracy na B2B. Jeśli interesuje Was komfort pracy, zarobki oraz motywacje w świecie IT to serdecznie zapraszam do czytania!</p><h2 id="s-owem-wst-pu">Słowem wstępu</h2><p>Od początku października Grupa Ework organizuje „Wielkie badanie specjalistów IT na B2B” . Badanie ma na celu określenie trendów w pracy na rynku IT z perspektywy specjalistów pracujących na B2B, określenie jakie są ich potrzeby, co wymaga zmian oraz określenie jak obszar <em>biznes-to-biznes</em> będzie rozwijał się w przyszłości. Jest to pierwsze takie badanie na polskim rynku.</p><p><strong>Badanie nie jest jeszcze zakończone</strong> i nadal można wziąć w nim udział (do końca stycznia) na stronie internetowej: <a href="https://badanieb2b.eworkgroup.com/?utm_source=artykul2">badanieB2B.eworkgroup.com</a>.</p><h2 id="tl-dr">TL;DR</h2><p>Jeśli przeraża cię statystyka (nawet w formie obrazków) to uogólniając: specjaliści na B2B uważają, że zarabiają za mało, kiepsko również oceniają podwyżki (zarówno ilość jak i częstotliwość). Bardzo chwalą się sobie jednak komfort rozwoju oraz ciekawe projekty. Prowadzenie firmy uważają za niepotrzebnie skomplikowane.</p><h2 id="wyniki-badania">Wyniki badania</h2><p>W badaniu oceniane są m.in. takie obszary jak „Komfort finansowy”, „Komfort pracy”, „Komfort czasu pracy”, „Styl pracy”, „Komfort współpracy” czy „Komfort rozwoju”. Są to określenia uogólniające szereg pytań o zadowolenie z każdego obszaru.</p><figure class="kg-card kg-image-card"><img src="https://solutionchaser.com/content/images/2019/12/eWORK_infographic_1.jpg" class="kg-image" alt="Ile zarabiają i jak pracują specjaliści w IT? - Wstępne wyniki badania na temat jakości pracy na B2B"></figure><p> Okazuje się, że najgorzej specjaliści IT w swojej pracy oceniają „komfort finansowy” (na który wpływają m.in. zarobki i podwyżki) – został on oceniony średnio na 61% (w skali satysfakcji 0-100%). </p><figure class="kg-card kg-image-card"><img src="https://solutionchaser.com/content/images/2019/12/eWORK_infographic_2.jpg" class="kg-image" alt="Ile zarabiają i jak pracują specjaliści w IT? - Wstępne wyniki badania na temat jakości pracy na B2B"></figure><p>Kobiety notują wyższy średni komfort pracy, komfort czasu pracy, komfort współpracy oraz komfort rozwoju. Mężczyźni mają wyższy średni komfort finansowy, jak również oceniają wyżej styl pracy.</p><figure class="kg-card kg-image-card"><img src="https://solutionchaser.com/content/images/2019/12/eWORK_infographic_3.jpg" class="kg-image" alt="Ile zarabiają i jak pracują specjaliści w IT? - Wstępne wyniki badania na temat jakości pracy na B2B"></figure><p>Specjaliści w branży IT (pracujący na kontraktach B2B) najwyżej oceniają natomiast „komfort rozwoju” (m.in. możliwości podnoszenia kwalifikacji, szkolenia, premie i<br>nagrody) – kategorię tę oceniono średnio na 85% (w skali 0-100%).</p><p>Wysoko oceniano także „komfort czasu” pracy (m.in. liczba godzin w miesiącu oraz możliwość pracy zdalnej) - 79% oraz komfort współpracy (m.in. pozyskiwanie nowych projektów, ich atrakcyjność czy atmosfera pracy) - 75%.</p><figure class="kg-card kg-image-card"><img src="https://solutionchaser.com/content/images/2019/12/eWORK_infographic_4.jpg" class="kg-image" alt="Ile zarabiają i jak pracują specjaliści w IT? - Wstępne wyniki badania na temat jakości pracy na B2B"></figure><p></p><figure class="kg-card kg-image-card"><img src="https://solutionchaser.com/content/images/2019/12/eWORK_infographic_5.jpg" class="kg-image" alt="Ile zarabiają i jak pracują specjaliści w IT? - Wstępne wyniki badania na temat jakości pracy na B2B"></figure><p>Analizując powyższe dane liczbowe o zarobkach trzeba zwrócić uwagę na dwie rzeczy: po pierwsze są to wartości netto, a po drugie B2B jest opłacalne dopiero od pewnego pułapu finansowego. Najczęściej po zdobyciu doświadczenia i przekroczeniu pewnej kwoty wynagrodzenia specjaliści decydują się na założenie firmy.</p><figure class="kg-card kg-image-card"><img src="https://solutionchaser.com/content/images/2019/12/eWORK_infographic_6.jpg" class="kg-image" alt="Ile zarabiają i jak pracują specjaliści w IT? - Wstępne wyniki badania na temat jakości pracy na B2B"></figure><p>Dla prawie 40% ankietowanych najważniejszym benefitem stażu pracy jest właśnie wyższe wynagrodzenie, mniej niż 1/3 ankietowanych uznała, że najważniejsze są ciekawe projekty. Aż 56,5% badanych uważa, że ich zarobki mogłyby być lub wręcz powinny być lepsze.</p><figure class="kg-card kg-image-card"><img src="https://solutionchaser.com/content/images/2019/12/eWORK_infographic_7.jpg" class="kg-image" alt="Ile zarabiają i jak pracują specjaliści w IT? - Wstępne wyniki badania na temat jakości pracy na B2B"></figure><p>To chyba najciekawszy element ankiety :) Głęboko utożsamiam się z potrzebą dobrych zaróbków, ciekawych projektów oraz partnerstwa. Co o tym myślicie?</p><h2 id="podsumowanie-potencja-badania">Podsumowanie - potencjał badania</h2><p>Wyniki nie są szokujące, ale zdecydowanie jednoznaczenie nakierowują na konkretne obszary w których można poprawić sytuację:</p><ul><li>wyższe wynagrodzenia</li><li>regularne, adekwatne do umiejętności i zaangażowania podwyżki</li><li>ciekawe projekty</li><li>partnerstwo biznesowe - dobre relacje, szacunek, elastyczność ze strony pracodawcy oraz zaufanie</li></ul><p><br><br>Pamiętajcie jednak, że <strong>badanie nie jest zakończone i każdy z was może wziąć w nim udział :) </strong>Zapraszam tutaj: <a href="https://badanieb2b.eworkgroup.com/?utm_source=artykul2">badanieB2B.eworkgroup.com</a>.<br><br>A jakie jest Wasze zdanie? Coś was zszokowało, z czymś się nie zgadzacie?</p>]]></content:encoded></item><item><title><![CDATA[Wprowadzanie do testów jednostkowych w JEST (Javascript + Typescript) #1]]></title><description><![CDATA[<blockquote>Nie zna swojego kodu ten, kto testów nie pisze!</blockquote><p>Dzisiaj rozpoczniemy zabawę z testami jednostkowymi. Już trochę doświadczenia z JESTem mam, ale zaczniemy zgodnie z naturalnym biegiem spraw... Od początku! </p><p>Test jednostkowe (tzw. unit testy) są to testy sprawdzające malutkie części kodu: najczęściej funkcje lub/i metody. Każdy test jest</p>]]></description><link>https://solutionchaser.com/unit-testy-w-jest-testy-jednostkowe/</link><guid isPermaLink="false">5d9c460202ed71d6805dcfb5</guid><category><![CDATA[front-end]]></category><category><![CDATA[javascript]]></category><category><![CDATA[początkujący]]></category><category><![CDATA[typescript]]></category><dc:creator><![CDATA[Kamila]]></dc:creator><pubDate>Sat, 09 Nov 2019 22:52:36 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1532264523420-881a47db012d?ixlib=rb-1.2.1&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=1080&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjExNzczfQ" medium="image"/><content:encoded><![CDATA[<blockquote>Nie zna swojego kodu ten, kto testów nie pisze!</blockquote><img src="https://images.unsplash.com/photo-1532264523420-881a47db012d?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=1080&fit=max&ixid=eyJhcHBfaWQiOjExNzczfQ" alt="Wprowadzanie do testów jednostkowych w JEST (Javascript + Typescript) #1"><p>Dzisiaj rozpoczniemy zabawę z testami jednostkowymi. Już trochę doświadczenia z JESTem mam, ale zaczniemy zgodnie z naturalnym biegiem spraw... Od początku! </p><p>Test jednostkowe (tzw. unit testy) są to testy sprawdzające malutkie części kodu: najczęściej funkcje lub/i metody. Każdy test jest niezależny od poprzedniego oraz w jak najmniejszym stopniu opiera się na zewnętrznych zależnościach (wręcz nie powinno ich być!). Test może zakończyć się sukcesem lub porażką (ang. fail).</p><p><code>npm i --save-dev jest</code> to dobry początek, potem w package.json można podpiąć <code>npm test</code> do polecenia <code>jest</code>, którym uruchamiamy testy.</p><p>Tworzymy folder <code>tests</code>, a potem plik mytest.test.js.</p><p><strong>Nazewnictwo jest tutaj kluczowe, bowiem domyślnie JEST szuka testów w wszystkich plikach w projekcie o rozszerzeniu *.test.js.</strong> Jest to szalenie wygodne.</p><h2 id="odpalamy-">Odpalamy!</h2><p>Teraz sprawdźmy czy wszystko działa :)</p><p>W pliku mytest.test.js utwórzmy sobie test, który zawsze będzie przechodził. W JEST testy definiuje się bardzo prosto: funkcją <code>test</code>.</p><p>Jej pierwszym argumentem jest opis testu, kolejnym funkcja w której wywołujemy <code>expect</code> sprawdzającą poprawność wartości. W tej chwili pominiemy wszystkie inne aspekty.</p><pre><code>test('3 is equal to 3', () =&gt; {
    expect(3).toBe(3);
});</code></pre><p>Powyższy test sprawcza czy <code>3 === 3</code>.</p><p>Teraz w konsoli puszczamy komendę <code>jest</code> lub `npm test`, jeśli wpisaliśmy polecenie do package.jsona. Wynik?<br></p><pre><code>&gt; storyportal@1.0.0 test /home/kamila/Dokumenty/StoryPortal
&gt; jest

 PASS  tests/first.test.js
  ✓ adds 1 + 2 to equal 3 (6ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        2.332s
Ran all test suites.</code></pre><p>Pełen sukces!</p><p>Chociaż przyznam, że <em>programistyczny instynkt</em> podpowiedział mi, że 3 jest równie 3 :)</p><h2 id="typescript">Typescript</h2><p>Niestety dobrze wiecie, że to nie koniec konfiguracji bowiem moja miłość do TypeScripta nie pozwoliłaby mi spać. Musicie wiedzieć, że są dwa sposoby na integrację JESTa z Typescriptem<strong>, jeden sprawdza typy, drugi korzysta z wygenerowanych plików js</strong>. My oczywiście chcemy sprawdzać typy, więc użyjemy ts-jest!</p><p>Najpierw instalacja:</p><pre><code>npm i --save-dev jest typescript
npm i --save-dev ts-jest @types/jest
npx ts-jest config:init</code></pre><p>Teraz stworzymy plik <code>typetest.test.ts</code> i wklejamy dokładnie to co mieliśmy w poprzednim teście.</p><p>I puszczamy <code>npm test</code>. Wynik?</p><pre><code>&gt; storyportal@1.0.0 test /home/kamila/Dokumenty/StoryPortal
&gt; jest

 PASS  tests/first.test.js
 PASS  tests/typetest.test.ts

Test Suites: 2 passed, 2 total
Tests:       2 passed, 2 total
Snapshots:   0 total
Time:        1.643s, estimated 5s
Ran all test suites.</code></pre><p>Znowu dziki, programistyczny instynkt zadziałał i byłam niemal pewna, że cztery jest równe cztery. Niemal :)</p><p>No ale w końcu musimy coś przetestować i dlatego wybrałam pusty controller. </p><pre><code>import { JsonController } from "routing-controllers";

@JsonController()
export class StoryController {
  constructor() {
    console.log('Wywołany!');
  }
}
</code></pre><p>Stwórzmy plik storyController.test.ts i wypełnijmy go szalenie nudnym testem. Sprawdzimy czy zmienna do której przypisaliśmy nową instancję klasy na pewno jest instancji tej klasy. W prostych aplikacjach jest to oczywiście kompletna bzdura.</p><pre><code>import { StoryController } from './../src/controllers/StoryController';

test('StoryController constructor allows creating story', () =&gt; {
    const storyController = new StoryController();
    expect(storyController).toBeInstanceOf(StoryController);
});</code></pre><p>Puszczamy <code>npm test</code> i co? Błąd. Okazuje się, że JEST nie radzi sobie z czytaniem relatywnych ścieżek z aplikacji, które są zdefiniowane w tsconfig.json. </p><p>Problem jest powszechnie znany i powstał fix naprawiający go w pewnym stopniu: <a href="https://github.com/kulshekhar/ts-jest/issues/414">link</a>, jednak nie wystarczająco dobry jak na moją aplikację, gdzie trochę podmieniam nazwy ścieżek. </p><p>Istnieją dwa wyjścia:</p><ul><li>ręczne wpisywanie mapperów do jest.config.js</li><li>zastosowanie jakieś funkcji/biblioteki np.: <a href="https://www.npmjs.com/package/jest-module-name-mapper">https://www.npmjs.com/package/jest-module-name-mapper</a></li></ul><p>Ręczne wpisywanie jest prostsze, ale wymaga duplikacji danych co zawsze wiąże się z ryzykiem starty spójności. Dlatego zainstalujemy i użyjemy <code>jest-module-name-mapper</code> :)</p><pre><code>npm i --save-dev jest-module-name-mapper</code></pre><p>A w jest.config.js:</p><pre><code>module.exports = {
  preset: 'ts-jest',
  testEnvironment: 'node',
  moduleNameMapper: require('jest-module-name-mapper')(),
};</code></pre><p>Puszczamy... I działa! Ale zaszaleliśmy!</p><h2 id="expect">Expect</h2><p>Czeka nas jeszcze długa droga poprzez mockowanie, fake'owanie, strukturę JESTa i wiele innych przygód.</p><p>Na żadną z nich nie wyruszymy bez przybliżenia się funkcji <code>expect</code>.<br><br>Zwraca ona obiekt z metodami, które umożliwiają wybranie wygodnego operatora logicznego oraz tego co dokładnie będziemy porównywać. </p><p>W poprzednich przykładach poznaliśmy dwie z tych metod: <code>toBe</code> (która jest jednym z kilku odpowiedników równości w JEST) oraz beInstanceOf (która sprawdza klasę zmiennej).</p><p>Teraz napiszemy kilka oczywistych testów, żeby poznać bliżej JESTa. Wszystkie testy poniżej <em>przechodzą</em>.</p><pre><code>test('if 3 is equal to 3', () =&gt; {
    expect(5).not.toBe('5');
});

test('if 3 is equal to 3', () =&gt; {
    expect(0).toBeFalsy();
});

test('if 3 is equal to 3', () =&gt; {
    expect(5).toBeLessThan(6);
});

test('if 3 is equal to 3', () =&gt; {
    expect(5).toBeGreaterThanOrEqual(5);
});

test('if 3 is equal to 3', () =&gt; {
    // strict checking 
    expect(['cat', 5]).toContain('cat');
});

test('if 3 is equal to 3', () =&gt; {
    expect(4).not.toBe(3);
});
</code></pre><p>Z powyższych przykładów powinniście zapamiętać:</p><ul><li>funkcję <code>not</code> będącą zaprzeczeniem</li><li>niektóre funkcje sprawdzają typy strictly (z porównaniem typów, podobnie jak <code>===</code>). Dlatego <code>5</code> nie jest równe <code>'5'</code>.</li><li>funkcje takie jak toBeFalsy rzutują na bool'a. Jest to szczególnie przydatne przy sprawdzaniu warunków.</li></ul><p>Podsumowanie</p><p>I jak podobało się Wam? Gotowi na więcej? Jeśli ktoś chce się podzielić uwagami na temat pisania testów w JEST lub ma inny ulubiony framework to zapraszam do sekcji komentarzy.</p><p>W następnej części przygotujcie się na testowanie funkcji oraz klas, w tym także tych asynchronicznych!</p>]]></content:encoded></item><item><title><![CDATA[Badanie na temat jakości pracy na B2B]]></title><description><![CDATA[<p>Dzisiaj specjalny post na moim blogu! Skontaktowała się ze mną Ework Group, która chce dotrzeć do Was z kwestionariuszem. Interesuje ich współpraca oparta na B2B i bardzo chcą poznać Wasze zdanie na ten temat.</p><p>Jeśli bez dodatkowych chcesz się wypowiedzieć to zapraszam do wzięcia udziału w ankiecie od razu: <a href="https://badanieb2b.eworkgroup.com?solutionchaser=artykul">https:</a></p>]]></description><link>https://solutionchaser.com/badanie-jakosci-pracy-na-b2b/</link><guid isPermaLink="false">5dae0f72b50ea1cf009262ee</guid><category><![CDATA[Weekend bez komputera]]></category><dc:creator><![CDATA[Kamila]]></dc:creator><pubDate>Mon, 21 Oct 2019 20:28:45 GMT</pubDate><media:content url="https://solutionchaser.com/content/images/2019/10/x800-solution.png" medium="image"/><content:encoded><![CDATA[<img src="https://solutionchaser.com/content/images/2019/10/x800-solution.png" alt="Badanie na temat jakości pracy na B2B"><p>Dzisiaj specjalny post na moim blogu! Skontaktowała się ze mną Ework Group, która chce dotrzeć do Was z kwestionariuszem. Interesuje ich współpraca oparta na B2B i bardzo chcą poznać Wasze zdanie na ten temat.</p><p>Jeśli bez dodatkowych chcesz się wypowiedzieć to zapraszam do wzięcia udziału w ankiecie od razu: <a href="https://badanieb2b.eworkgroup.com?solutionchaser=artykul">https://badanieb2b.eworkgroup.com/</a>.</p><p>Jeśli jednak interesuje Was o co dokładnie chodzi to zapraszam do czytania dalej :)</p><h2 id="co-si-dzieje">Co się dzieje?</h2><p>W okresie od października do grudnia 2019 na stronie internetowej <a href="https://badanieb2b.eworkgroup.com?solutionchaser=artykul">https://badanieb2b.eworkgroup.com/</a> przeprowadzone zostanie badanie pt. „<em>Wielkie badanie specjalistów IT na B2B</em>”. W ramach badania przeprowadzany jest również konkurs (można wygrać IPHONE XS, szczegóły na stronie). <strong>Badanie ma na celu znalezienie odpowiedzi na pytania jakie są trendy na rynku IT</strong>, jak ma się ta branża z perspektywy freelancerów,<strong> jakie są ich potrzeby i co wymaga zmian</strong>, a w konsekwencji ocena jak ten obszar będzie rozwijał się w przyszłości. Będzie to pierwsze takie badanie na polskim rynku.</p><p>Badanie zostanie przeprowadzone przy użyciu specjalnie przygotowanej strony internetowej z kwestionariuszem online, w którym znajdą się m.in. pytania dotyczące modelu i komfortu pracy, komfortu finansowego, możliwości rozwoju. Pytania demograficzne z kolei umożliwią scharakteryzowanie grupy zawodowej jaką są specjaliści IT współpracujący na B2B.</p><p>Jak wziąć udział w badaniu i konkursie? Wystarczy wejść na stronę internetową <a href="https://badanieb2b.eworkgroup.com?solutionchaser=artykul">https://badanieb2b.eworkgroup.com/</a> przejść przez cztery proste kroki: odpowiedzieć na pytania, wykonać krótkie zadanie konkursowe, podać swój adres e-mail (jeśli chcecie wziąć udział w konkursie) i dzięki wygenerowanemu wynikowi dowiedzieć się o poziomie komfortu swojej pracy.</p><h2 id="kto-to-organizuje">Kto to organizuje?</h2><p>Organizatorem badania i konkursu jest <strong>Ework Group </strong>- niezależna agencja konsultingowa zrzeszająca specjalistów IT, działająca w pochodzącym ze Skandynawii modelu biznesowym powstałym w Szwecji. Obecnie funkcjonuje również w Danii, Norwegii, Finlandii i Polsce. Główna siedziba Ework Group znajduje się w Sztokholmie, a od 2008 roku akcje firmy notowane są na giełdzie NASDAQ Stockholm. Od 2015 Ework Group działa w Polsce: w Warszawie, Wrocławiu i Gdyni. Wspiera rozwój działalności biznesowej dopasowując kompetencje do standardów projektu. Współpracuje z ponad 170 największymi firmami w większości branż, zapewniając kontrakty B2B ponad 10 000 specjalistom IT.<br><br><strong>Chcesz mieć wpływ na komfort swojej pracy? Weź udział w „Wielkim badaniu specjalistów IT na B2B”!</strong><br><br><a href="https://badanieb2b.eworkgroup.com?solutionchaser=artykul">https://badanieb2b.eworkgroup.com</a></p><p><br>Po zakończeniu badania opublikę i omówię wyniki. Chciałabym zacząć serię artykułów o podobnej tematyce dotykające pracy programisty: od HR, po managmentu, organizację pracy i rozwiązywanie konfliktów.</p>]]></content:encoded></item></channel></rss>