Sprawny Programista

Nauka programowania czas

Nauka programowania – jak się uczyć programowania, mimo braku czasu i motywacji

Czy Ty też nie masz czasu na naukę programowania? I mi się kiedyś tak wydawało…  Teraz jednak już wiem, w jak wielkim byłem błędzie.
Przed sobą masz materiał, w którym zdradzam moje sprawdzone sposoby na efektywną naukę programowania – każdego roku dzięki nim uczę się wielu nowych technologii i frameworków. Nie wierzysz? – przeczytaj i sam wypróbuj.

Nauka programowania – jak znaleźć na nią czas?

Prawda jest taka, że wszystko w życiu to kwestia  wyboru i to od nas zależy, na co poświęcimy swój czas, a z czego zrezygnujemy.

Niezależnie od tego, kim jesteś: studentem dopiero zaczynającym swoją naukę, prezydentem, czy może profesorem na emeryturze, doba dla każdego z nas trwa tyle samo – 24h i nie zmienisz tego.

Nauka programowania – streszczenie

TL;DR: Dla osób, które chcą uczyć się programowania – ale nie mają kiedy

Skoro mówimy o braku czasu i Ty właśnie należysz do osób, które nawet nie mają czasu, żeby przeczytać tekst o tym, jak poradzić sobie z brakiem czasu… To poniżej masz streszczenie najważniejszych informacji z tego wpisu:

  • znajdź swoją motywację – bez tego szybko odpuścisz, gdy tylko pojawią się pierwsze kłopoty;
  • poświęć chwilę na ułożenie planu – tak, żebyś wiedział, co dokładnie chcesz osiągnąć. Bez tego będziesz się rozpraszał i pracował nad rzeczami mało ważnymi;
  • skup się na celu – czasem kosztem innych, chwilowo mniej ważnych rzeczy;
  • dociskaj i szukaj każdej chwili wolnego czasu – mniej śpij, mniej pracuj, zrezygnuj z telewizji, z facebooka itp.
[SprawnyProgramista_intro /]

Nauka programowania – lista moich 12 sprawdzonych sposobów
na dodatkowy czas na naukę programowania

Poniższe sposoby wypróbowałem już wielokrotnie na sobie i zawsze byłem zadowolony z efektów. Faktem jest jednak to, że do wszystkiego trzeba podchodzić z głową i z umiarem. Nie staraj się teraz na siłę wprowadzać każdego z tych sposobów. Niektóre z nich sprawdzają się tylko doraźnie, a na dłuższą metę mogą być wyniszczające dla człowieka. Każdy też ma inne predyspozycje i preferencje. To, co dobrze sprawdzało się w moim przypadku, nie musi sprawdzić się u Ciebie. Dlatego czytaj, wybieraj i przede wszystkim samodzielnie podejmuj decyzje.

Sposób #1. Znajdź swoje dlaczego

Zacznij od tego prostego pytania:

Po co uczysz się programowania?

Zanim przejdziesz dalej KONIECZNIE odpowiedz sobie na to pytanie. Najlepiej, jeżeli zrobisz to na kartce. Weź zwykłą kartkę papieru i zapisz swoje motywacje.

Dlaczego to jest takie ważne?

Ponieważ programowanie nie jest łatwe! To nie jest coś, czego możesz nauczyć się w weekend w przerwie między jednym a drugim filmem. Jeżeli zdecydujesz się uczyć programowania, to gwarantuję Ci, że nie raz będziesz miał wątpliwości i nie raz będziesz chciał rzucić to wszystko w diabły i zająć się czymś innym, czymś dużo prostszym…

I właśnie po to jest Ci potrzebna ta kartka. W takich momentach będziesz mógł do niej wrócić  i przypomnieć sobie, po co to wszystko robisz.

Tak wygląda moja motywacja – teraz Twoja kolej.

Chcę się uczyć programowania, ponieważ:

  • lubię rozwiązywać problemy;
  • lubię wyzwania;
  • czerpię przyjemność z ciągłej nauki;
  • mam możliwość kontaktu z wieloma interesującymi osobami;
  • taka praca zapewnia godny byt mnie i mojej rodzinie.

Nie masz odpowiedniej motywacji?

Poważnie zastanów się nad tym, czy programowanie jest rzeczywiście dla Ciebie. Jest wiele różnych innych zawodów – może znajdziesz dla siebie coś lepszego.

Simon Sinek – dlaczego?

Simon Sinek – dlaczego? (Motywacja do nauki programowania)

Simon Sinek – dlaczego?

W tym miejscu po prostu nie można wspomnieć o słynnym wystąpieniu TED, które wygłosił Simon Sinek. Jeżeli jeszcze nie miałeś okazji go przesłuchać, to zdecydowanie warto. Simon mówi w nim między innymi o tym, jak ważne są nasze motywacje i dlaczego tylko nielicznym firmom i ludziom udaje się odnieść tak spektakularne sukcesy, jak Apple, czy Martin Luther King.

Większość ludzi i firm wie, co trzeba zrobić, niektórzy z nich nawet wiedzą jak to zrobić – jednak mało kto wie, dlaczego powinno się to robić.

Dlaczego

Dlaczego?

Natomiast jeżeli chciałbyś dowiedzieć się, co programowanie może Ci zaoferować, to przeczytaj poniższy wpis.

Czy warto uczyć się programowania?

Czy warto uczyć się programowania?

➡ ZOBACZ 👉: Czy warto być programistą?

Sposób #2. Ucz się rano

Lubisz sobie dłużej pospać?

Ja też 🙂 Ba, kto nie lubi?…

🦉 Sowa vs skowronek 🐦

Nauka programowania – sowa vs skowronek

Nauka programowania – sowa vs skowronek

Podobno ludzie dzielą się na:

  • 🦉 sowy, którym lepiej pracuje się wieczorami oraz w nocy i na
  • 🐦 skowronki, którym lepiej pracuje się rano.

Kim Ty jesteś?

Zaobserwowałem, że w moim przypadku zmieniało się to w czasie. Miałem okresy, gdzie pracowałem dosłownie całymi nocami i potrafiłem zachować świeżość umysłu na kolejny dzień. Najbardziej niezniszczalny pod tym względem czułem  się podczas studiów, niestety z biegiem czasu utraciłem tę zdolność. Teraz po takim maratonie zwyczajnie byłbym nieprzytomny, a czas, który chwilowo oszczędziłbym, pracując w nocy, straciłbym w kolejnych dniach z nawiązką.

Od momentu, gdy w moim życiu pojawiły się dzieci, nauczyłem się też doceniać i szanować przespane noce. Niewiele życiowych sytuacji tak zmienia perspektywę, jak pojawienie się potomstwa. Od tego momentu zwyczajnie wiedziałem, że jak nie wykorzystam chwili na odpoczynek w nocy, to nie będę miał kiedy tego odespać.

Choćbyś nie wiem, jak się starał, to nie wytłumaczysz niemowlakowi, że chcesz jeszcze chwilę pospać, bo miałeś ciężką noc i właściwie dopiero co się położyłeś…
Mam też wrażenie, że dzieci mają jakiś dodatkowy zmysł i w takich sytuacjach z nieznanych mi jeszcze powodów wstają zwyczajnie jeszcze wcześniej.

Miałem też okresy, że wstawałem o drugiej w nocy i uczyłem się do białego rana, by potem na chwilę się jeszcze zdrzemnąć. Akurat wtedy taki model najlepiej się u mnie sprawdzał.
Czasem to może być jedyna możliwość, gdy ma się inne zobowiązania, takie jak rodzina, studia, czy praca zawodowa.

Nawet jeżeli uważasz się za typową sowę, to zachęcam, żebyś przynajmniej spróbował pracy lub nauki rano.

⏩ Miracle morning

Niektóre osoby, w tym również ja, potrafią nawet doświadczyć tak zwanego fenomenu poranka.

Zwrot cudowny poranek lub fenomen poranka (ang. miracle morning) pochodzi z książki „Miracle Morning”, której autorem jest Hal Elrod.

Autor książki zwraca uwagę na to, jak dobrze odbyty poranek może wpłynąć na Twój cały dzień, a długofalowo nawet na całe Twoje życie. Z własnego doświadczenia wiem, jak dobry poranek może dać zastrzyk energii na cały, nawet bardzo trudny, dzień. Osobiście staram się planować na poranki trudne zadania, ale też takie, które sprawiają mi dużo przyjemności i dają satysfakcję – czyli np. pisanie artykułów na bloga lub naukę programowania.

Fenomen poranka - Hal Elrod

Fenomen poranka – Hal Elrod

➡ ZOBACZ 👉: Link do książki: Fenomen poranka – Hal Elrod

Jest to o tyle ważne, że zanim cały świat obudzi się do życia, czyli zanim pójdziesz do pracy, czy zanim obudzi się reszta Twojej rodziny, to Ty już masz zrobione coś dla siebie. Wiesz, że choćby nie wiadomo co miało się wydarzyć tego dnia, to Ty już to zrobiłeś.

Autor książki „Miracle morning” idzie nawet o krok dalej i sugeruje strukturę takiego idealnego poranka pod postacią akronimu:

Life S.A.V.E.R.S

co można przetłumaczyć jako „uratować życie.

Poszczególne litery można rozszyfrować jako:

  • cisza (ang. Silence) – modlitwa, medytacja itp.
  • afirmacja (ang. Affirmation) – przekonanie samego siebie w myślach, że to, co robisz, jest rzeczywiście tym, co chcesz robić i prowadzi Cię tam, gdzie chcesz;
  • wizualizacja (ang. Visualisation) – wyobrażenie sobie swojego sukcesu – tego, co chcemy osiągnąć oraz drogi, jaką do tego doszliśmy;
  • ćwiczenia (ang. Exercise) – poranne ćwiczenia, pompki, przysiady, siłownia, bieganie itp.
  • czytanie (ang. Read) – czytanie książek, artykułów itp.
  • pisanie (ang. Scribe) – prowadzenie dziennika, bloga itp.

Te rzeczy tylko z pozoru muszą zająć dużo czasu. To od Ciebie zależy, ile chcesz na nie przeznaczyć. Jeżeli danego dnia bardzo się spieszysz, to możesz wyrobić się dosłownie w 10-15 minut. Jeżeli jednak masz więcej czasu, to może to być godzina i więcej.

OK Nawet jeżeli będzie to tylko chwila, to właśnie spędziłeś tę chwilę na rozwoju siebie samego i jesteś o tę chwilę bliżej swojego celu.

Nie oszukujmy się jednak, że nagle uda Ci się wprowadzić wszystkie te zwyczaje równocześnie, a od jutra będziesz wstawał o 3:30 po to, by godzinę poćwiczyć na siłowni, przeczytać kilka rozdziałów książki, zrobić kilka zadań z programowania i jeszcze zdążyć na 7 do pracy 🙂
Najlepiej zacząć od czegoś małego. Może będą to poranne ćwiczenia, może czytanie, a może nauka programowania? 🙂

Sposób #3. Ucz się wieczorem

Nauka programowania wieczorem

Nauka programowania wieczorem

Nauka wieczorem z natury obarczona jest bardzo dużym ryzykiem. Czasem trzeba naprawdę ogromnego samozaparcia, by po ciężkim dniu jeszcze zmotywować się, czy wręcz zmusić do kolejnego wysiłku i chociaż przez chwilę popracować. W takich warunkach naprawdę trudno o produktywną naukę.

Czasem nauka wieczorami jest też zwyczajnie niemożliwa, gdy akurat trzeba zająć się innymi sprawami. Niestety po kilku takich nieudanych podejściach, człowiekowi zazwyczaj bardzo spada motywacja do dalszych prób. Między innymi właśnie dlatego jestem zwolennikiem pracy nad najważniejszymi dla nas tematami z samego rana.

Jeżeli jednak masz czas, siły i chęci, żeby dokształcać się wieczorami, to potencjalnie można tu zyskać bardzo dużo cennego czasu.

Gdy głowa nie chce już współpracować

Nauka programowania ból głowy

Nauka programowania ból głowy

Gdy jesteś naprawdę zmęczony, ale mimo wszystko chcesz zrobić coś produktywnego, warto rozważyć zmianę podejścia.

Jeżeli jestem w takiej sytuacji i widzę, że zwyczajnie nie mam już sił na bardziej wymagające zadania, to po prostu przełączam się na mniej angażujące zajęcia – takie jak czytanie, oglądanie tutoriali, czy inne domowe obowiązki.

Takie prace też są bardzo ważne. Nie tylko pozwalają czegoś się dowiedzieć, ale też uwalniają czas na przyszłość. Przez co później, gdy mamy więcej energii, można skupić się już tylko na tych bardziej wymagających pracach.

Nie zapominaj jednak, że każdemu należy się też przerwa. Czasem warto zwyczajnie odpuścić i odpocząć.
Jutro też jest dzień i może akurat uda Ci się wstać rano 🙂

Sposób #4. Zrezygnuj ze swojego wolnego czasu 💀☠

Niektóre rzeczy wymagają poświęceń – nikt nie mówił, że będzie łatwo.

Zrezygnowaliśmy już z wieczorów na rzecz nauki programowania, a co z weekendami? – a co z urlopem?…

Człowiek nie jest maszyną, żeby pracował 24h na dobę, siedem dni w tygodniu – nie możesz o tym zapomnieć – każdy ma swoje ograniczenia. Jeżeli jednak dalej szukasz możliwości, by jeszcze więcej czasu poświęcić na naukę, pomyśl o weekendach i przynajmniej częściowej rezygnacji z urlopu.

Nie uważam, żeby całkowita rezygnacja z wolnego czasu była dobrym pomysłem – można jednak trochę go zredukować. Przykładowo w sobotę i niedzielę można popracować do 12:00 lub zamiast dwutygodniowego urlopu, tydzień spędzić na nauce, a drugi tydzień na wymarzonym wolnym. Przez wiele lat nie miałem urlopów praktycznie wcale, dopiero teraz staram się nadrabiać zaległości – dlatego wiem, jak może być to trudne.

Przede wszystkim pamiętaj, by nie przesadzić. Wielokrotnie miałem okazję obserwować, jak zachowują się ludzie na kursach wieczorowych, czy weekendowych. Osiem godzin pracy plus dojazdy, wieczorem nauka programowania, niedospana noc, a w weekend kolejne zajęcia. Pierwsze tygodnie kursu zazwyczaj nie stanowią problemu, ale po około dwóch miesiącach takiej pracy, bez wieczorów, bez weekendów i czasu na odpoczynek większość osób jest tak zmęczona, że z trudem kojarzy nowe fakty.

Info Pamiętaj, nie tędy droga – wszystko z umiarem.

Sposób #5. Mniej pracuj

Nauka programowania – redukcja etatu

Nauka programowania – redukcja etatu

Jeżeli jeszcze nie pracujesz jako programista i uczysz się programowania, żeby zmienić branżę, to rozważ redukcję obecnego etatu – lub zamiast robić nadgodziny, przeznacz ten czas na doszkolenie się.

W życiu nie można mieć wszystkiego, a przynajmniej nie w tym samym momencie 🙂 – dlatego zazwyczaj trzeba z czegoś zrezygnować.

Nie każdy pracodawca zgodzi się na redukcję etatu np. do 4 dni w tygodniu lub 6–7 godzin dziennie, warto jednak spróbować i zwyczajnie go spytać.
Jeżeli nie, jednoznaczna redukcja etatu, to może urlop lub urlop bezpłatny? – możliwości jest naprawdę sporo. To w Twoim interesie leży, żeby to sprawdzić.

Programowanie jako inwestycja w przyszłość

Takie działania z pewnością chwilowo nie poprawią Twojej sytuacji finansowej, jednak programowanie można traktować jako inwestycję w swoją przyszłość. Przy odrobinie samozaparcia i szczęścia, taka decyzja może zwrócić się w przyszłości z nawiązką.

Sposób #6. Popraw swoją wydajność, czyli ucz się szybciej – lepsza organizacja nauki

Skoro skończyły nam się już sposoby na wyciśnięcie więcej czasu na naukę, to czas skupić się na tym, jak jeszcze efektywniej wykorzystać ten czas.

Jest wiele sposobów na poprawę swojej wydajności:

  • Technika Pomodoro;
  • praca w tematycznych blokach czasu;
  • praca głęboka;
  • nauka na kursach lub z mentorem itp.

Wszystkie one skupiają się na poprawie Twojej wydajności i lepszej organizacji czasu, który już posiadasz. Przyjrzyjmy się teraz bliżej kilku wybranych sposobom.

Sposób #7. Rob jedną rzecz jednocześnie – siła skupienia  🎯

Nauka programowania – siła skupienia

Nauka programowania – siła skupienia

Nasze mózgi można by porównać do jedno-rdzeniowych procesorów. Są tak skonstruowane, że najlepiej, najwydajniej radzą sobie z pracą nad jednym zadaniem w tym samym czasie. Nasz mózg podobnie jak tego typu procesory może co prawda emulować wielowątkowość, jednak jest to dla niego na tyle nienaturalne, że taka praca jest bardzo niewydajna. Żeby zmienić kontekst pracy, trzeba załadować wszystkie nowe informacje do pamięci podręcznej i tak za każdym razem przy przełączaniu się między zadaniami, czy wątkami.

Programistyczny FLOW

Słyszałeś kiedyś o takim pojęciu o jak programistyczny flow?

To prawie mityczny stan, w którym programista jest tak skupiony na swoim zadaniu, że cały świat przestaje dla niego istnieć. W głowie jest już ułożony plan rozwiązania problemu, zostało tylko przenieść pomysł na kod. W tym momencie dzwoni telefon lub ktoś wchodzi do pokoju, żeby spytać, czy nie idziesz na kawę… 🗣I wszystko przepadło 💥– nie możesz już przypomnieć sobie rozwiązania, a w głowie jest tylko jedna wielka pustka…

Ciągła zmiana kontekstu 📉

Nauka programowania zmiana kontekstu

Nauka programowania zmiana kontekstu

Nasz umysł potrzebuje chwili czasu, żeby nastawić się na realizację danego zadania. Potrzebujemy „złapać kontekst”, czyli przypomnieć sobie wszystkie poboczne zagadnienia. Dopiero wtedy możemy przejść do realizacji głównego zadania. Bez takiego rozruchu nie możemy zwyczajnie wydajnie pracować.

Właśnie dlatego, tak ważne jest, żeby nie skakać ciągle między różnymi zadaniami i skupić się na jednym, konkretnym celu. Poświęcić całą swoją uwagę na ten jeden temat, rozwiązać go i dopiero wtedy zająć się czymś innym.

Info Jeżeli w Twoim projekcie manager co chwilę wrzuca Ci jakieś dodatkowe zadania do realizacji „na szybko”, postaraj się z nim porozmawiać i wytłumaczyć, że zwyczajnie takie podejście ma swój koszt. Jeżeli natomiast sam planujesz sobie zadania, to warto pracować lub uczyć się w blokach tematycznych. Jeżeli mam jakieś mniejsze zadania np. odpisanie na kilka maili, to staram się to zrobić jednym ciągiem, tak by potem nie zaprzątało mi to już głowy.

Deep work 📈

Przeciwieństwem do ciągłej zmiany kontekstu jest tak zwana „praca głęboka”, czyli po angielsku deep work.

Ta koncepcja dosyć szczegółowo została opisana w książce Cal’a Newport’a o tym samym tytule: „Deep work”. Autor książki skupia się na założeniu, że praca głęboka – czyli praca w maksymalnym skupieniu jest swego rodzaju super mocą, która może pomóc w osiągnięciu przewagi nad innymi ludźmi.

To learn is an act of deep work
(Uczenie się jest czynnością wymagającą skupienia).
Cal Newport

Nie ulega wątpliwości, że do nauki potrzebne jest skupienie, a nauka nowych rzeczy jest nieodłącznym elementem pracy jako programista. W świecie IT, który tak często się zmienia, zdolność do opanowania skomplikowanych rzeczy w krótkim czasie jest po prostu nieoceniona.

Cal Newport pokusił się nawet o zapisanie tej koncepcji w formie wzoru:

High Quality Work Produced = (Time Spent) x (Intensity of Focus)
Praca Wysokiej Jakości = (Spędzony Czas) x (Intensywności Skupienia)

W skrócie możemy to odczytywać, że im uda nam się osiągnąć lepsze skupienie, tym zapewnimy sobie lepsze rezultaty nauki.

Tylko jak to osiągnąć? ❓❓❓

4 zasady, aby pracować w skupieniu – czyli, jak się skupić❓

Autor przygotował 4 zasady, które mają nam pomóc w osiągnięciu stanu skupienia.

✔ Zasada 1 – skup się na pracy

Powinniśmy tak zorganizować sobie pracę, by wspomagało to nasze skupienie. Można to zrobić np. przez wybór jednej z filozofii pracy i nauki opisanych w książce:

  • Monastyczna – cały Twój dostępny czas poświęcony jest realizacji danego zagadnienia. Jeżeli już zabierasz się za zadanie, to poświęcasz mu tyle czasu, ile będzie na to potrzeba – dzień, tydzień, miesiąc, a może rok. Dopiero po jego realizacji możesz zająć się czymś innym;
  • Bimodalna – podczas „normalnej”, codziennej pracy, co jakiś czas przeznaczasz jeden cały dzień na pracę w skupieniu nad wybranym zadaniem. Taki cykl powtarzasz co pewien czas, np. 2-3 dni w tygodniu przeznaczasz tylko na naukę programowania, a przez resztę czasu chodzisz normalnie do pracy lub na uczelnię;
  • Rytmiczna – każdego dnia przeznaczasz na pracę w skupieniu określony/wybrany czas np. codziennie rano godzina. Ważne jest to, żeby było to codziennie i o tej samej porze;
  • Dziennikarska – pracujesz nad swoim zadaniem/projektem w każdej wolnej chwili: czekając na spotkanie, w przerwie na obiad, rano, przed snem itp.
Nauka programowania – rytm

Nauka programowania – rytm

Rytm pracy i nauki

Pomocne może okazać się też wypracowanie rytuałów, czyli np.:

  • praca w tym samym miejscu;
  • o tej samej porze dnia;
  • oraz w analogicznych warunkach: muzyka, szklanka wody pod ręką itp.
Nauka jak biznes

Kolejną rzeczą, na którą autor zwraca uwagę, jest analogia nauki do prowadzenia biznesu. Według tej teorii powinniśmy:

  • skupić się na tym, co dla nas najważniejsze i co przynosi największy zysk;
  • mierzyć swoją efektywność i na podstawie tych pomiarów podejmować dalsze decyzje, na czym się skupić, a z czego zrezygnować;
  • zobowiązać się, że dowieziemy konkretny wynik – najlepiej, jeżeli będziemy mieli kogoś, kto później zweryfikuje, czy rzeczywiście to zrobiliśmy.
Bądź leniwy
Nauka programowania – nuda

Nauka programowania – nuda

Ostatnia rzecz, na którą warto zwrócić uwagę w tym punkcie to hasło: „Be lazy” – czyli bądź leniwy. Oczywiście chodzi o bycie leniwym w ten roztropny sposób – to właśnie podczas przerw w nauce najczęściej wpadamy na ciekawe pomysły, ponieważ mamy wtedy chwilę na zastanowienie się nad tym, co robimy.

Odpoczynek jest też niezbędny do późniejszej pracy w głębokim skupieniu. Praca głęboka jest bardzo męcząca i wymaga ogromnych pokładów energii, zarówno fizycznej, jak i emocjonalnej. Nie zrażaj się, jeżeli na początku nie jesteś w stanie zbyt długo tak pracować – tego też trzeba się nauczyć.

✔ Zasada 2 – Zaprzyjaźnij się z nudą (ang. Embrace Boredom)

W tym punkcie Cal Newport dodatkowo zwraca uwagę, by nauczyć się dobrze wykorzystywać czas wolny bez nauki i pracy.

W naszym zawodzie paradoksalnie zazwyczaj największym problemem jest sam Internet, czyli dostęp do Facebooka, czy innych social mediów. Jeżeli pracujesz przy komputerze, to bardzo złym odpoczynkiem będzie przeglądanie wiadomości w sieci, czy scrollowanie facebookowego walla. W ten sposób tak naprawdę nie odpoczywasz, a jedynie odwlekasz moment powrotu do nauki.

Wiele razy sam łapałem się na tym, że pisząc artykuł, chciałem coś sprawdzić i dlatego uruchamiałem Google i szukałem informacji – pół godziny później orientowałem się, że przeglądam wpisy na FB lub oglądam jakiś film na YouTube… – słabo.

Info Dlatego teraz, w takiej sytuacji, staram się zostawić sobie jakieś TODO np. „poszukaj informacji o XYZ” i pisać dalej. Po sesji pracy głębokiej będę miał kilka takich TODO i wtedy poszukam wszystkich informacji w jednym bloku.

Nauka programowania – facebook

Nauka programowania – facebook

✔ Zasada 3 – Porzuć social media

Może nie chodzi o całkowite odinstalowanie Facebooka, Instagrama i Twittera, ale o zastanowienie się jak, i po co się z nich korzysta – tak, by robić to bardziej świadomie.

Czasem wystarczy samo policzenie ile czasu każdego dnia, czy tygodnia te aplikacje są uruchomione, by zmienić swoje podejście.

✔ Zasada 4 – Eliminuj czas bez skupienia

Niestety zazwyczaj jesteśmy przyzwyczajeni do ciągłego braku skupienia i rozpraszania się – a wtedy czas dosłownie ucieka nam między palcami. Jeżeli na koniec dnia jesteś zmęczony i jednocześnie nie wiesz, na co właściwie poświęciłeś ten dzień – to najprawdopodobniej jest to również Twój problem.

Dlatego postaraj się:

  • zaplanować swój dzień – nawet najsłabszy plan jest lepszy niż totalna samowolka;
  • oceniaj jakość tego, co robisz i wyciągaj wnioski;
  • bądź trudno dostępny – tutaj chodzi przede wszystkim o rezygnację z ciągłej komunikacji i np. odpowiadanie na maile tylko w określonych porach dnia.

Jeżeli spodobały Ci się opisane tu zasady, to warto sięgnąć do źródła i przeczytać książkę Deep work – Cal Newport (link znajdziesz poniżej).

Deep work – Cal Newport

Deep work – Cal Newport

➡ ZOBACZ 👉: Link do książki: Deep work – Cal Newport

Sposób #8. Zrezygnuj z rozpraszaczy 👥

Ten temat był już wałkowany tak wiele razy, że nie będę się nad nim rozwodził. Jednocześnie jednak jest on na tyle powszechnym problemem, że zasłużył na osobny punkt.

Prawda jest taka, że Facebook, Slack, telefon i inne automatyczne powiadomienia zabijają naszą produktywność.

Pamiętasz, co mówiłem o tym, jak ważne jest skupienie się na jednej rzeczy?

Fail A niby jakim cudem to zrobić, jak co chwilę wyskakują jakieś powiadomienia na telefonie, czy komputerze. Teoretycznie to tylko ułamek sekundy, ale takie chwilowe przerwy potrafią całkowicie wybić człowieka z rytmu pracy i skupienia.

Dlatego następnym razem, zanim zaczniesz pracę:

  • wyłącz telefon (albo przynajmniej go wycisz i odłącz od Internetu);
  • wyłącz wszelkie możliwe komunikatory i automatyczne synchronizacje maila (Slack, Gmail, Outlook itp.);
  • warto też na pewien czas całkowicie zablokować dostęp do social mediów 🙂 – możesz np. wykorzystać aplikację SelfControl.

Zapewniam Cię, że wystarczy pół godziny nauki w takich warunkach i poczujesz różnicę.

Myślisz, że w Twoim przypadku to się nie sprawdzi i Twój zespół albo przełożony zaprotestuje⁉

Info Też tak myślałem – jednak nic takiego się nie stało. Wystarczy wysłać wcześniej krótka wiadomość, że teraz pracujesz i potrzebujesz chwili skupienia, a wszelkie wiadomości będziesz sprawdzał np. co 30 minut. Jeżeli dalej ktoś będzie miał wątpliwości, to warto uzmysłowić mu, jak nierobienie czegoś takiego wpływa negatywnie na produktywność i że bez tego możesz nawet nie dostarczyć swoich zadań. Z takimi argumentami mało kto polemizuje.

Nauka programowania – równocześnie

Nauka programowania – równocześnie

Sposób #9. Rób wiele rzeczy jednocześnie 🔁

Kolejny sposób na naukę i poprawę naszej wydajności to robienie wielu rzeczy jednocześnie.

Możesz spytać: ale jak to? Dopiero co pisałem, żeby skupić się na jednej rzeczy

Tutaj niestety muszę zacytować słynne programistyczne powiedzenie: to zależy 🙂

Rzeczywiście skupienie się na jednej wybranej rzeczy jest bardzo ważne, mimo wszystko są takie zadania, które nie pasują do tej reguły i możemy je zrównoleglić.

Robienie kilku rzeczy jednocześnie siłą rzeczy przyspieszy naszą naukę.

Podcasty 🎧

Sprawny Programista podcast

Sprawny Programista podcast

Jednym z moich ulubionych zajęć, które lubię wplatać w inne aktywności, jest słuchanie podcastów. Staram się to robić za każdym razem, gdy wykonuję jakieś umysłowo mniej angażujące rzeczy – takie jak bieganie, różnego rodzaju prace fizyczne, czy domowe obowiązki.

Do tego stopnia lubię tę formę konsumowania wiedzy, że zdecydowałem się samodzielnie nagrywać podcast. Do którego słuchania oczywiście gorąco zachęcam.

➡ ZOBACZ 👉: Podcast Sprawny Programista

Mądra praca zawodowa

Jest takie powiedzenie, że nie chodzi o to, żeby pracować ciężko, ale mądrze. Przekładając to na naszą sytuację – jeżeli już pracujesz jako programista i chcesz się rozwijać, chcesz dalej uczyć się nowych rzeczy, to najlepszym wyjściem dla Ciebie będzie robienie tego w ramach obecnej pracy.

Czy jest coś lepszego niż możliwość uczenia się nowych i ciekawych rzeczy, w momencie, kiedy Ci jeszcze za to płacą?

Jak to zrobić?

Info Zwyczajnie poproś swojego przełożonego o ciekawsze, trudniejsze zadania i powiedz, że chcesz się rozwijać. W wielu projektach brakuje ochotników, którzy chcą dać z siebie coś więcej i dobrowolnie zająć się trudniejszym zadaniem.

Sposób #10. Wypracuj  zwyczaje i nawyki ⚒

Siła nawyku – Charles Duhigg

Siła nawyku – Charles Duhigg

W tym miejscu posłużę się kolejną już książką i będzie to:  Charles Duhigg – Siła nawyku. Myślę, że domyślasz się już, jak bardzo lubię czytać. 🙂

Charles Duhigg – Siła nawyku

Autor stara się nas przekonać, że odpowiednie pokierowanie wyrobieniem nowych lub zmianą dotychczasowych nawyków może diametralnie odmienić czyjeś życie. A przekładając to na większą skalę nawet funkcjonowanie społeczeństw, przedsiębiorstw, czy całych państw…

Charles na łamach swojej książki przedstawia teorię „pętli nawyków”, która ma pomóc osiągać wymarzone cele.
W ramach tej teorii nawyki i zwyczaje rozłożone są na czynniki pierwsze, a my dowiadujemy się jak:

  • powstaje taki nawyk;
  • jak funkcjonuje
  • i co bardzo ważne: co należy zrobić, żeby wyrobić w sobie taki nawyk lub zmienić już istniejący.

W tej książce nie znajdziemy jednak prostych przepisów, według których moglibyśmy zadziałać . Znajdziemy za to liczne przykłady i historie, na których możemy się wzorować i samodzielnie wyciągać wnioski.

Fail Przykładem złego nawyku może być codzienne siadanie przed telewizorem, otwieranie piwa, czy palenie papierosów. O ile jednorazowo takie czynności nie mają większego wpływu na nasze życie – to jeżeli przerodzą się w nawyk i każde popołudnie będzie tak wyglądało – może prowadzić to do problemów.

OK  Odwracając sytuację – jednorazowe wyjście na siłownię, czy sięgnięcie po książkę niewiele zmieni w naszym życiu. Jednak jeżeli zrobimy z tego codzienny nawyk, to po miesiącu, czy roku można już oczekiwać całkiem niezłych efektów.

Tylko jak się zmotywować, żeby wyrobić w sobie takie nawyki?

Nawet jeżeli wiemy, jak dobrze by to nam zrobiło, nie jest to takie proste – i tutaj właśnie przychodzą nam z pomocą zimne prysznice. 🙂

Joel Runyon zimny prysznic (ang. cold shower)

Joel Runyon zimny prysznic (ang. cold shower

Joel Runyon zimny prysznic (ang. cold shower

Joel Runyon podczas swojego wystąpienia na TED opowiada o tym, jak codzienny zwyczaj brania lodowatych pryszniców wpłynął na jego życie. Na pierwszy rzut oka dosyć ciężko znaleźć związek między zimną wodą a nauką programowania – jednak jak to mówią: w tym szaleństwie jest metoda. 🙂

Joel mówi, że tak naprawdę to w większości wypadków my sami dobrze wiemy, co należy zrobić, żeby osiągnąć nasz cel.

  • Chcesz znaleźć pracę jako programista? => ucz się programowania.
  • Chcesz być wysportowany i dobrze wyglądać? => dobrze się odżywiaj i zacznij ćwiczyć itp.

Skoro to jest takie proste, to czemu tak mało osób to robi?

Zazwyczaj ograniczają nas i blokują nasze własne obawy – mało osób świadomie jest w stanie wprowadzić się w niekomfortowy stan. Dużo łatwiej jest powiedzieć, że chce się pracować jako programista, niż zrezygnować z wolnego weekendu, czy serialu wieczorem, żeby poświęcić ten czas na naukę programowania.
Niby wiesz, co trzeba zrobić, a mimo to nie robisz tego.

Info Idąc tym tropem, można dojść do wniosku, że to nie nauka programowania jest problemem, a brak umiejętności radzenia sobie z niekomfortowymi sytuacjami.

Na takie problemy Joel proponuje wyzwanie – przez kolejne 30 dni codziennie rano brać zimny, a nawet lodowaty prysznic.

Na samą myśl o takiej  propozycji mam w głowie same wątpliwości i budzi się totalny sprzeciw.

  • ale rano? Może jednak wieczorem, później;
  • czemu zimny?
  • przecież to głupie;
  • i co to ma mi niby dać?

Taki sprzeciw, a nawet nie poszedłem jeszcze do łazienki 🙂 – tam zapewne byłoby jeszcze trudniej.

I dokładnie o to chodzi! W analogiczny sposób nasz mózg broni się, jeżeli mamy zacząć naukę programowania lub jakąkolwiek inną czynność, która nie jest dla nas komfortowa – lub jak to się teraz ładnie mówi, która wykracza poza naszą strefę komfortu.

Skoro nie możesz poradzić sobie z taką małą trudnością, która będzie trwała tylko kilka minut i nikt tego nie będzie widział – to dlaczego myślisz, że poradzisz sobie z czymś dużo trudniejszym, co będzie trwało zdecydowanie dłużej?

Nie wiem jak Ty, ale ja po obejrzeniu tego video zacząłem się przekonywać, że skoro on już to zrobił za mnie i wyciągnął wnioski, to ja wcale nie muszę tego robić…

Link do wystąpienia.

Sposób #11. Zapłać za naukę 💰💸💲

Zapłać za naukę programowania

Na niektórych ludzi nic nie działa tak motywująco, jak świadomość potencjalnej utraty gotówki. Osobiście bardzo nie lubię TRACIĆ pieniędzy.

Jak się nad tym dłużej zastanowić, to bardziej boli mnie utracone 100 PLN, niż zrezygnowanie z możliwości zarobienia kolejnych 100 PLN.
W efekcie zdarza mi się złapać samego siebie na sytuacji, że poświęcam bardzo dużo wysiłku, żeby zaoszczędzić pewną kwotę, zamiast poświęcić ten sam wysiłek i w tym czasie skupić się na zarabianiu i np. zarobić dwa razy tyle.

Info Od kiedy uświadomiłem sobie bezsens takiego rozumowania, dużo chętniej np. kupuję różnego rodzaju kursy lub konsultacje. Potrafię nawet zapłacić za kurs 1000 PLN i więcej, co może wydawać się dużo, zważywszy, że większość podanych w nim informacji równie dobrze mógłbym znaleźć za darmo w Internecie. Jednak ktoś poświęcił swój czas i zebrał za mnie te informacje. Zweryfikował je i przygotował w takiej formie, że ucząc się z tego opracowania, mogę zrobić to znacząco szybciej.

OK Kolejny plus jest taki, że łatwiej odpuścić sobie realizację kursu, za który nic się nie zapłaciło, niż takiego, który coś nas kosztował. 😉

Sposób #12. Nie ucz się w pojedynkę 👩‍👩‍👧‍👦

Ludzie są z natury stworzeniami stadnymi. 😉
Zazwyczaj przyjemniej pokonuje się nam różne trudności, gdy możemy wesprzeć się w ciężkich momentach na drugiej osobie.
Przyjemniej jest też, gdy mamy możliwość podzielenia się swoimi sukcesami.

Bardzo długo nie doceniałem tego aspektu społecznego związanego z programowaniem. W efekcie moje początki nie były zbyt łatwe. Możliwe, że gdybym szybciej wyszedł ze swoimi problemami do ludzi nie popełniłbym tak wielu błędów początkującej osoby i nie zajęłoby mi to tak wiele czasu.

Mentor programowania

Jedną z rzeczy, którą teraz zalecam młodym programistom jest znalezienie swojego mentora programowania. Pojęcie mentoringu niestety przez wielu jest odbierane negatywnie. Kojarzy się ono nam często z pseudomotywacyjnymi mówcami w stylu „Jesteś zwycięzcą”.

Z moich doświadczeń wynika, że na dobrze prowadzonym mentoringu mogą zyskać obie strony. Dlatego staram się zachęcać początkujące osoby, by szukały wsparcia u bardziej doświadczonych kolegów po fachu. Może na tym jednak skorzystać również druga strona, czyli osoba dzieląca się swoim doświadczeniem. Dzieje się tak między innymi dlatego, ponieważ tłumaczenie innym to jednocześnie najlepszy sposób na własną naukę. Żeby to zrobić sam musisz bardzo dobrze zrozumieć dane zagadnienie i spojrzeć na nie z punktu widzenia drugiej osoby.

Gdy przygotowuję się do zajęć na bootcampie, to staram się rozłożyć dany temat dosłownie na czynniki pierwsze. Wiem, że na sali będzie kilkanaście osób z których przynajmniej kilka napotka takie problemy, na które ja przy normalnej pracy raczej się nie natkę. Dlatego zawsze po takich zajęciach wychodzę bogatszy o nową wiedzę i doświadczenia.

Jak wybrać dobrego mentora?

Z mentoringiem niestety związane są też ryzyka. Co jeżeli mój mentor się myli? Co jeżeli ma złe intencje?

Osobiście zawsze trzymam się poniższej zasady.

Podpatruj inne osoby i ucz się od nich,  ale ZAWSZE myśl samodzielnie i dopiero wtedy podejmuj decyzje. Ponieważ to Ty ostatecznie za nie odpowiadasz.

Dodatkowo staram się szukać osób, które przeszły już przez jakiś proces, przez który sam chcę przejść. Przykładowo, gdy zaczynałem nagrywać podcast szukałem ludzi, którzy już to robią, a nie tylko osób, które słyszały jak to się robi. Dzięki temu mogłem z nimi porozmawiać i podpytać jak wyglądała ich droga, jakie mieli problemy, jak sobie z nimi poradzili i co zrobić by ich uniknąć.

Społeczność programistów

A co gdybym Ci powiedział, że nie musisz wybierać jednego mentora, a możesz ich mieć kilku? Albo nawet kilkudziesięciu, lub kilkuset?…

Tak właśnie działają społeczności. Programiści też maja swoje społeczności i warto z nich korzystać.
Do dyspozycji mamy różnego rodzaju meetupy, grupy w social media itp.

➡ ZOBACZ 👉: Zachęcam do dołączenia do naszej grupy zebranej wokół bloga.

Nauka programowania – podsumowanie sposobów na więcej czasu

Odpowiadając krótko na tytułowe pytanie: „Jak się uczyć programowania, mimo braku czasu i motywacji?” – moim zdaniem trzeba przede wszystkim chcieć. Jeżeli są szczere chęci, to możliwości zawsze się znajdą. Wtedy na drugi plan schodzą wszelkie wymówki i potencjalne przeszkody. Te kwestie nie dotyczą tylko i wyłącznie nauki programowania, ale odnoszą się również do wszystkich innych aspektów naszego życia.

Na koniec mam jeszcze ogłoszenie.
Właśnie wystartowała przedsprzedaż mojego kursu – KierunekProgramista, gdzie pokazuję więcej tego typu przykładów, tak by ułatwić Ci zostanie programistą i wejście do świata IT.

>>> KierunekProgramista.pl <<<

Jeżeli podobał Ci się ten materiał, proszę podziel się nim choćby z jedna osobą, która może go potrzebować. Dzięki temu pomożesz mi w dotarciu z tym przekazem do większego grona zainteresowanych.

A Ty Jak radzisz sobie z ciągłym brakiem czasu?

 

3 komentarze
Share:
Urlop programisty

Jak profesjonalnie podejść do przerwy w pracy, by uniknąć niepotrzebnych kłopotów – urlop programisty, programista na wakacjach 🌴🎒🍹

Wakacje programisty – Tomek wybrał się na swój długo wyczekiwany urlop. Przez ostatnie dwa lata nie miał tyle szczęścia i brał tylko pojedyncze dni wolne na podreperowanie zdrowia – w tym roku miało być inaczej. Tym razem to aż dwa tygodnie urlopu jednym ciągiem! Wspólnie z żoną postanowili, że zabiorą dzieci i spędzą ten czas razem w domku nad jeziorem koło Iławy. Wymarzona sytuacja: dwa tygodnie urlopu, rodzina, woda, las – nic, tylko cieszyć się życiem i wypoczywać.

Niestety dość szybko przekonali się, że tak łatwo to nie będzie. Już drugiego dnia wyjazdu Tomek dostał telefon z pracy. Niby nic wielkiego – tylko 5 minut rozmowy i w dodatku z kolegą. To jednak wystarczyło, żeby ruszyć lawinę zmian. Kolega Łukasz, który zadzwonił, był odpowiedzialny za wsparcie testów u dość ważnego klienta. Klient właśnie zaczął sprawdzać nową funkcjonalność, za którą Tomek był odpowiedzialny przed wyjazdem. Niestety Łukasz nie wiedział, jak ją włączyć. Nie znalazł również nic na ten temat w dokumentacji. Ponieważ nie chciał sam narazić się klientowi oraz swoim przełożonym, pozwolił sobie zadzwonić do Tomka.

Później było już tylko gorzej… Okazało się, że moduł, który Tomek pisał kilka dni przez urlopem, zawierał sporo błędów i niedoróbek. Zwyczajnie ciężko było w pełni skupić się na pracy, gdy myślami wypoczywał już na urlopie. Na domiar złego klient bardzo mocno nalegał na szybką poprawę usterek. Dlatego przełożony Tomka poprosił go o wsparcie: „Usiądziesz sobie na chwilę na plaży z lapkiem na kolanach. No wiesz, nogi w wodzie, piwko obok – będzie dobrze. Przecież to tylko chwila”.

Programista na wakacjach

Po kolejnych trzech dniach takiego „urlopowania” dość mocno wkurzona już żona postawiła sprawę jasno: „Albo urlop, albo praca”.  Tomek nie chciał walki z przełożonym, ponieważ tak naprawdę lubił swoją pracę. Nie chciał też podpaść małżonce. Tym razem jednak sprawy zawodowe wygrały…

Wakacje skończyły się tydzień szybciej, niż to było zaplanowane. Nasz bohater z motywacją na poziomie podłogi wrócił do swoich zadań, a o relacjach z małżonką i dziećmi lepiej wcale nie wspominać…

A wszystko przez to, że Tomek zapomniał przygotować się do swojego urlopu…
Nie bądź jak Tomek. Wyciągnij wnioski z jego porażki i ciesz się swoim wypoczynkiem. 

5 rzeczy, które każdy programista powinien zrobić przed urlopem, jeżeli chce uniknąć nieprzyjemności

Wydanie nowej wersji w piątek

Jeżeli nie chcesz być jak Tomek, to zanim udasz się na wymarzony urlop, by oddać się błogiemu wypoczynkowi – poświęć jeszcze chwilę na bardziej przyziemne sprawy. Wystarczy, że zastanowisz się, co zostawiasz za sobą na czas Twojej nieobecności.

Poniższa lista powinna Ci w tym pomóc. Jest to moja lista spraw, o których zawsze staram się pamiętać, zanim opuszczę pracę na dłużej.

1. Dokończ i zamknij najważniejsze zadania

Info Nie będzie Cię przez tydzień, dwa, a nawet i dłużej. W tym czasie ktoś – niewykluczone, że Twój ważny klient – może czekać na Twoje zadanie. A Ciebie przecież nie ma…

Dobrze by było uniknąć takiej sytuacji – dlatego jeszcze przed swoim urlopem dokończ, co tylko można. W skrajnych sytuacjach warto wyraźnie zakomunikować swojemu przełożonemu, że zwyczajnie jest za mało czasu, żeby dowieźć dane zadanie. Wtedy wspólnie można się zastanowić nad jakimś wsparciem lub zwyczajnie przełożeniem zadania na potem.

Deployment nowej wersji w piątek o 17:00

Nie zapomnij jednak o jakości tego, co za sobą zostawiasz. Nie jest sztuką wydać nową wersję aplikacji bez jej wcześniejszej weryfikacji i zwyczajnie wyjść z biura. Ktoś później z tego będzie korzystał, może ktoś będzie musiał to naprawić lub wytłumaczyć klientowi, dlaczego coś nie działa tak, jak powinno.

Dobrą praktyką jest nie brać sobie na głowę niczego dużego przed samym urlopem. Lepiej podopinać wszystkie obecne tematy, niż rozgrzebać na szybko jakieś nowe. Po powrocie prawdopodobnie i tak niewiele z tego będziesz pamiętać. Czasem po dłuższym urlopie mam problemy z przypomnieniem sobie podstawowych haseł, a co dopiero funkcjonalności, nad którymi pracowałem 🙂

Deployment nowej wersji w piątek o 17:00 – 2

Deployment nowej wersji w piątek o 17:00 – 3Deployment nowej wersji w piątek o 17:00 – 1

2. Przekaż obowiązki swojemu zastępcy – czyli szukamy sobie proxy

Bycie osobą niezastąpioną w projekcie na pierwszy rzut oka może wydawać się kuszące – wszyscy liczą się z Twoim zdaniem, przychodzą do Ciebie po radę i nie ma tematu, którego nie musiałbyś zaakceptować, zanim zostanie wdrożony.

Niestety niesie to za sobą duże ryzyko – osoby niezastąpione bardzo rzadko chodzą na urlopy 🙂

Zrobiłem ten błąd w jednym z projektów. Na początku było to nawet dość przyjemne. Jednak w kulminacyjnym momencie to od tego, jak szybko odblokuję dany serwer, zależały relacje z niezwykle ważnym klientem. Dodatkowo takie blokady, które zdarzały się nad wyraz często, wstrzymywały pracę niemal 50-osobowego zespołu.

W tamtym okresie prawie nie rozstawałem się z telefonem. Na powrót z biura do domu potrzebowałem około 30 minut – zazwyczaj w tym czasie był już telefon z pracy, a kolejnych kilka po południu. Zdarzały się też połączenia po północy. Taki support, tylko 24 h na dobę, 7 dni w tygodniu…

Dlatego wiem z własnego doświadczenia, jak ważne jest to, by zawczasu poszukać sobie ludzi, którzy przynajmniej w niektórych tematach będą mogli nas zastąpić. Takich osób może być oczywiście kilka. Dzięki nim prace będą kontynuowane podczas Twojej nieobecności. Zastępcy mogą również stanowić Twoje wsparcie – w przypadku wątpliwości będziesz mógł się ich poradzić.

Przed urlopem zostawiamy takim osobom:

  • informacje o wszystkich obecnie realizowanych zadaniach;
  • kontakty do zainteresowanych klientów lub współpracowników;
  • wszelkie inne informacje, jakie w tym czasie mogą im być potrzebne.

Programista proxy

Spisane ustalenia

Ustalenia najlepiej pozostawić w formie pisanej. Pamięć jest bardzo ulotna, więc warto zadbać o to, by nasz zastępca miał się do czego odwołać. Wszelkie wytyczne staram się spisać na wiki lub ewentualnie wysłać mailem.

Jeżeli ktoś nie znajdzie jakiejś ważnej informacji w Twoich notatkach, a będzie wiedział, że Ty ją masz, może chcieć się z Tobą skontaktować, a nie ma lepszego przerywnika podczas urlopu, jak telefon z pracy 🙂

3. Zapisz, co możesz, i zrób backup

Backup danych

Wypadek losowy – to zgodnie z definicją coś nieszczęśliwego, coś, czego się nie spodziewaliśmy. I właśnie na takie nieszczęśliwe wypadki robimy kopie zapasowe.

Szkoda by było zaczynać pracę po urlopie od informacji, że projekt, nad którym pracowałeś lokalnie, przepadł, bo coś stało się z Twoim dyskiem.

Dlatego:

  • git commit; git push!!! – zawsze trzymaj swoje zmiany przynajmniej w dwóch miejscach. To może Cię uratować nie tylko w przypadku awarii dysku, ale i w dużo częstszych sytuacjach – kiedy np. sam zepsujesz lub usuniesz swoje pliki…
  • i backup reszty rzeczy – kod źródłowy to nie wszystko. Pamiętaj też o dokumentacji, notatkach, skryptach itp.
Zdarzyło Ci się kiedyś płakać po utracie danych? To teraz wyobraź sobie, że tracisz ten dwuterabajtowy dysk, na którym trzymasz swoją skończoną w 3/4 pracę magisterską i kolekcję zdjęć z ostatnich 3 lat. Boli, prawda?

Backup danych 2

Gdzie backupować dane?

  • zewnętrzny dysk;
  • chmura (Dropbox, Google Drive, OneDrive, IDrive) – możliwości jest bardzo dużo – najważniejsze jest, żeby to robić.

4. Ustaw autoresponder i status na komunikatorze

Mało rzeczy tak potrafi zirytować człowieka, jak notoryczny brak odpowiedzi na pytania – szczególnie wtedy, gdy w Twoim mniemaniu są one bardzo ważne.

To teraz wyobraź sobie, że ktoś z Twoich współpracowników lub – co gorsza – jakiś ważny klient przez cały Twój urlop wysyła Ci na maila ważne wiadomości.

Po co kusić los i niepotrzebnie denerwować ludzi?

Wystarczy ustawić odpowiedni status na komunikatorze i autoresponder na mailu z informacją, że jesteśmy na urlopie. Warto też dodać, kto Cię zastępuje i kiedy znowu będziesz dostępny.

Po powrocie nie zapomnij tylko usunąć autorespondera 🙂

Slack urlop status

Slack urlop status

Gmail. Wiadomości o nieobecności – autoresponder

Takie automatyczne odpowiedzi można skonfigurować w większości popularnych klientów pocztowych – poniżej przykład, jak zrobić to przy pomocy Gmail.

Przejdź do ustawień i zakładki „Ogólne”, a następnie wprowadź informacje o swojej nieobecności.

Gmail wiadomości o nieobecności – autoresponder

Przykładowe automatyczne wiadomości o nieobecności


Autoresponder – 1

5. Przygotuj współpracowników na swoją nieobecność

Urlop to przyjemny moment dla osoby, która na niego idzie, ale już dla jej współpracowników niekoniecznie.
To oni tracą kolegę z pracy, a czasem i przełożonego.
To oni często są obarczani dodatkowymi obowiązkami.
I to właśnie od nich nierzadko zależy, co zastaniemy po naszym powrocie 🙂

Przed wypoczynkiem warto ich przynajmniej poinformować i pożegnać się.

Wypoczęty programista – dlaczego nie potrafimy odpocząć nawet na urlopie?

Programista na wakacjach – 2

Chciałbym poruszyć jeszcze jeden temat, a mianowicie zagadnienie braku umiejętności odpoczywania.

Niby fizycznie wyszedłeś już pracy, ale myślami dalej w niej jesteś – dalej pracujesz.

Znasz to?

Stosunkowo mało osób potrafi całkowicie odciąć się od swoich obowiązków zawodowych w czasie wolnym. Szczególnie pracownicy IT – programiści – borykają się z tym problemem. Bez tego jednak ciężko o efektywny odpoczynek, a bez odpoczynku bardzo szybko spadnie nasza wydajność i motywacja do dalszej pracy.

Jeden dzień można docisnąć i popracować dłużej, dwa dni – OK, zdarza się. Niemniej na dłuższą metę takie podejście i tak odbije się czkawką. O długotrwałej pracy pod presją pisałem trochę tutaj: Crunch. Zadziwiające jest to, jak wielu z nas boryka się z tym w branży, w której cały czas mamy rynek pracownika.

Programista na wakacjach – opalenizna

Jak programista spędza urlop?

Jak spędzamy nasze urlopy? Niestety bardzo często właśnie tak, jak na podlinkowanym wideo.

Programista i analityk na urlopie

Programista i analityk na urlopie

Programista na urlopie – podsumowanie

Jako podsumowanie tego tematu chciałbym zostawić Cię z kilkoma pytaniami. Mnie dały całkiem sporo do myślenia – może i Tobie się przydadzą.

  • Jak często chodzisz na urlop?
  • Jak spędzasz swoje wolne – czy rzeczywiście odpoczywasz?
  • Czy zabierasz pracę ze sobą?
  • Czy Twoi współpracownicy mogą się wtedy z Tobą skontaktować?
  • Czy projekt, który za sobą zostawiasz, jest w takim stanie, w jakim sam chciałbyś go otrzymać?

Na koniec pozostaje mi już tylko życzyć Wam jak najczęstszych i jak najbardziej udanych urlopów.
Powodzenia!

3 komentarze
Share:
Projekt OpenSource DevAdventCalendar

Projekt Open source #DevAdventCalendar: zespół, technologie, finanse – Michał Gellert

Czy wiesz, jak wygląda prowadzenie projektu Open source od środka? Czego można się przy tym nauczyć oraz jak można na tym zarobić!?
Teraz masz świetną okazję, żeby to sprawdzić – zapraszam do nowego odcinka podcastu: „Projekt Open source #DevAdventCalendar: zespół, technologie, finanse”.

Do rozmowy zaprosiłem jednego z organizatorów: Michała Gellert.

[SprawnyProgramista_intro][/SprawnyProgramista_intro]

Z tego odcinka dowiesz się:

  • co to jest DevAdventCalendar i na czym polega ten konkurs;
  • kto należy do zespołu odpowiedzialnego za jego realizację i czy można jeszcze do nich dołączyć, by pomóc w pracach;
  • jak można reklamować i komercjalizować projekt OpenSource;
  • jak wewnętrznie wyglądają prace nad tego typu projektem.

Nie przedłużając już – zapraszam do wysłuchania naszej rozmowy.

Cześć Michał. Miło mi tutaj Ciebie widzieć. Proszę, powiedz kilka słów o sobie. 

Z tego, co wiem, jesteś naprawdę wyjątkowo aktywną osobą, ponieważ prowadzisz swojego bloga, masz swój kanał na YouTube. Dodatkowo pracujesz jako programista, a teraz zajmujesz się jeszcze organizacją DevAdventCalendar. To jest naprawdę bardzo dużo jak na jedną osobę. Jak mógłbyś coś więcej powiedzieć…

Cześć. Po pierwsze, to dzięki za zaproszenie. Bardzo się cieszę z tego powodu – zwłaszcza że aktualnie, jak wspomniałeś, jesteśmy przed wystartowaniem z projektem DevAdventCalendar. Ponieważ sam ten projekt będzie w założeniach trwał od 1 do 24 grudnia, więc tak generalnie idealny moment na rozmowę.

Coś więcej o sobie mogę powiedzieć. Tak mnie przedstawiłeś dosyć aktywnie, a tak szczerze mówiąc, to na tym blogu już na przykład dosyć mało się dzieje w sumie od paru miesięcy. Tak samo z pozostałymi tematami, ale generalnie – tak, staram się robić zawsze coś dodatkowego poza swoim aktualnym zajęciem, za które płacą – poza aktualnym kontraktem.

Myślę, że jest to zdecydowanie bardzo ważne, ponieważ wiele osób zapomina o tym, jak istotne są dodatkowe aktywności w wolnym czasie. I prawda też jest taka, że pracodawcy bardzo często zwracają na to uwagę.

Jak zostać programistą

Myślę, że wielu naszych słuchaczy to osoby, które dopiero zaczynają swoją karierę, jeżeli chodzi o programowanie, lub jeszcze o tym myślą. Mógłbyś troszeczkę powiedzieć o tym, jak Ty zaczynałeś – w ogóle dlaczego zacząłeś interesować się programowaniem.

To jest generalnie dosyć długa historia. Jak miałem 18–19 lat, czyli kiedy zdawałem maturę, to nie bardzo wiedziałem, co chcę zrobić ze sobą. Miałem w planie zostanie nauczycielem matematyki i poszedłem nawet na studia matematyczne, które zacząłem, ale przerwałem w trakcie. Jednak uznałem, że matematyka nie jest dla mnie. I dopiero potem zacząłem tak właściwie uczyć się programowania. Przez jakiś czas byłem na studiach zaocznych, bo pracowałem, już w tym momencie miałem żonę i rodzinę do utrzymania. Mieszkałem też w małej wiosce, jakieś 80 kilometrów od Wrocławia, więc musiałem spędzać sporo godzin w pracy, a dopiero potem mogłem siadać i tak naprawdę się uczyć czy coś ze sobą robić.

Pierwszą pracę dostałem, jak miałem 25 lat dopiero, czyli generalnie dosyć późno, bo jak gadałem z innymi, to mówią, że to już nawet tak trochę brzmi jak przebranżowienie się w tym wieku. No ale od około czterech i pół, no już blisko pięciu lat, pracuję jako programista. Więc tak wyglądały moje początki

➡ ZOBACZ 👉: Jak zostać programistą – historia prawdziwa

Rzeczywiście ja troszeczkę szybciej zaczynałem, ponieważ zacząłem pracę zawodową już po drugim roku studiów. Ja też od razu jakby trafiłem na informatykę, stąd o tyle było mi łatwiej. Rzeczywiście, jak wspomniałeś o tym przebranżowieniu, to mogło to tak wyglądać.

Jak znaleźć czas na naukę programowania

To powiedz mi w takim razie, jak udało Ci się wtedy znaleźć czas na naukę programowania i jak uczyłeś się na samym początku. Ponieważ z tego, co wiem, ludziom bardzo ciężko jest znaleźć na początku motywację i czas na naukę. Bardzo często w ogóle nie wiedzą, od czego zacząć.

Nie wiem, czy moje porady będą tutaj pedagogiczne, chodzi po prostu o to, że w momencie, w którym uczyłem się, to byłem w to maksymalnie zaangażowany. Do tego stopnia, że nawet, powiedzmy, momentami cierpiała na tym moja żona – w tym sensie, że po prostu zamiast poświęcać czas jej, ja poświęcałem czas na rozwiązywanie jakichś zadań programistycznych czy uczenie się kolejnych przedmiotów.

➡ ZOBACZ 👉: Pierwsza praca – jak ją znaleźć? Jak wygląda proces rekrutacji?

I też faktem jest, że pięć lat temu było zdecydowanie łatwiej wystartować niż teraz. Wiem, że gdybym w tym momencie podchodził do szukania pracy, to też podszedłbym zupełnie inaczej, niż te kilka lat temu, i wiem też, że gdybym w tym momencie chciał zacząć z wiedzą, jaką posiadałem w momencie, w którym zaczynałem, to nie dałbym rady – po prostu ten próg wejścia cały czas się zwiększa, technologia się cały czas rozwija.

➡ ZOBACZ 👉: Od czego zacząć naukę programowania? Jakich języków się uczyć?

Generalnie osób, które chcą zacząć, jest całkiem sporo. I, mówiąc szczerze, nie mają tak prostej sytuacji, jak ja miałem te kilka lat temu. Ale wracając do pytania, co bym poradził. To jest tak, że jeżeli jest Ci w życiu wygodnie, np. masz jakąś pracę, niekoniecznie jako programista, ale chcesz być programistą, to jednak to twoje „wygodnie” będzie Cię cały czas ciągnęło w dół. W tym sensie, że no bo po co zmieniać, skoro któraś część ciebie jest wypoczęta, ma wszystko, czego potrzebuje, więc po co tak naprawdę z tym walczyć. I wydaje mi się, że to jest tak naprawdę główna blokada, to jest też później blokada na kolejnych etapach. Kiedy np. pracujesz już jako programista, to żeby zacząć jakiś dodatkowy projekt, pojawia się generalnie to samo – „no cóż, pracuję jako programista świetnie zarabiam, więc po co będę się jeszcze dodatkowo starał. Przecież pracuję te 8 godzin, odbębnie swoje i tyle”. No i wydaje mi się, że to jest główna przyczyna – taka codzienna wygoda, którą mamy, nie będąc programistą, przeważa nad chęcią, by nim zostać.

Doskonale Ciebie rozumiem. To prawda, że te technologie cały czas się zmieniają, coraz więcej wymaga się od programistów. Ostatnio jest taki boom na to, żeby wejść do IT. Coraz więcej osób myśli o tym. Pamiętam też, jak mnie wiele wysiłku kosztowała ta nauka na samym początku czy chociażby skończenie studiów. Jak kończyłem studia na ostatnim roku i jak pisałem swoją pracę magisterską, to miałem już córkę. Pamiętam, jak pomagała mi w trakcie pisania tej pracy magisterskiej – siedziała mi na kolanach w trakcie robienia projektu. Naprawdę trzeba bardzo dużo samozaparcia, żeby w takim momencie po prostu nie odpuścić. Zwłaszcza że wiele osób, które już zaczną pracę w IT, dostają tę swoją pierwszą pracę i ta praca często jest całkiem fajnie płatna i wtedy nie ma już takiej motywacji, żeby właśnie wrócić na te studia i dokończyć. Efekt był taki, że u nas, na moim roku, bardzo dużo osób rzuciło studia pod sam koniec i po prostu poszli już do pracy.

Tak, dokładnie, bardzo dobrze to rozumiem, bo też mam teraz małą córkę i czasem jest po prostu szkoda poświęcić czas, który mógłbym spędzić z nią, bawiąc się w jakieś dodatkowe projekty. Ale niestety życie to sztuka wyboru, więc coś coś za coś.

Co to jest DevAdventCalendar?

Dokładnie. Spotkaliśmy się tutaj dzisiaj, żeby głównie porozmawiać o DevAdventCalendar. Proszę, przybliż nam trochę tę inicjatywę. Co to w ogóle jest? Skąd to się wzięło?

Generalnie na sam pomysł wpadła Weronika Tobor dwa lata temu, kiedy to zorganizowała pierwszą edycję. To była taka dosyć prosta edycja. Bardzo szybko postawili stronę, udało im się zebrać kilkadziesiąt chętnych osób, które odpowiadały na pytania. I taki był początek. Ja dołączyłem w drugiej edycji, kiedy ta ekipa już zdecydowanie rozrosła, bo wtedy organizowało ją 10 osób. I w drugiej edycji pojawił się projekt Open Source, taki, który jest, powiedzmy, większy. Tam już stoi za tym jakiś backend, jakaś logika. Udało nam się namówić przede wszystkim o wiele więcej osób do wystartowania w tym konkursie, bo w tamtym roku udział brało około półtora tysiąca osób. Generalnie, po samym skończeniu konkursu dostaliśmy feedback na temat tego, jak to przebiegało, więc w tym roku wzięliśmy go pod uwagę i po prostu rozwijamy się w ten sposób, że wdrażamy pomysły, które podsunęli nam uczestnicy. Dlatego w tym roku mamy też przygotowanych więcej nagród, ponieważ udało nam się pozyskać większą ilość sponsorów, no i generalnie mamy też kilka poprawek co do samej mechaniki.

Nagrody

Mógłbyś rozwinąć temat nagród? Na co mogą liczyć uczestnicy tego konkursu?

W tym momencie jeszcze nie wszystko mamy zaplanowane, ale podzieliliśmy to sobie, ponieważ w tamtym roku mieliśmy sporo uczestników, którzy dołączyli do nas np. w drugim tygodniu wydarzenia. W tamtym roku działało to w ten sposób, że jeżeli ktoś odpowiadał na pytania każdego dnia, miał szansę na wygranie nagrody. Finalnie było chyba pięćdziesiąt kilka osób, które odpowiedziały na wszystkie pytania, więc osoba, która, powiedzmy, dołączyła po dwóch tygodniach, już nie miała takiej możliwości, bo już wtedy zamykaliśmy – wtedy pytanie było dostępne przez określoną ilość czasu, bardzo krótko, chyba 12 godzin, więc trzeba było regularnie codziennie wchodzić na stronę i odpowiadać, i generalnie w tym roku postanowiliśmy to zmienić. Po pierwsze, w ten sposób, że nie będziemy zamykali okienek po tych 12 godzinach, czyli jeżeli użytkownik dołączy, powiedzmy, 10 grudnia, to w dalszym ciągu może odpowiedzieć na wszystkie pytania, zebrać komplet punktów, ale niestety wtedy też sumarycznie czas jego odpowiedzi będzie dłuższy niż pozostałych uczestników. Ale mimo wszystko znaleźliśmy sposób, żeby nagradzać również takie osoby. I dodatkowo podzieliliśmy ten okres kalendarza na trzy oddzielne tygodnie, czyli od pierwszego do siódmego/ósmego grudnia. To jest generalnie od niedzieli do soboty; od niedzieli do soboty; od niedzieli do soboty. Takie trzy tygodnie. Jeżeli ktoś np. dołączy w środku wydarzenia, to jeśli będzie się starał, to dalej ma szansę na nagrody za ten ostatni tydzień. To znaczy w tym momencie będziemy nagradzali uczestników każdego tygodnia oraz na samym końcu do najwytrwalszych trafią nagrody kalendarza.

Taka fajna analogia do tego kalendarza z czekoladkami. Też możesz później zacząć i zjeść po prostu więcej czekoladek jednego dnia.

Tak, stąd się wziął pomysł. Jak Fornalika opisuje, to była nasza inspiracja, że jak byliśmy mali, dostawaliśmy kalendarze z czekoladkami. Teraz jesteśmy starsi i w kalendarzu czekają na nas zagadki i nagrody, jeśli się wykażemy.

Muszę przyznać, że cały czas bardzo miło wspominam te kalendarze. Teraz, jak patrzę na moje dzieci, które też je mają, to wspomnienia wracają. Jak mógłbyś powiedzieć, do kogo naprawdę jest adresowany ten konkurs? Co taka osoba, która chciałaby wziąć udział w tym konkursie, powinna umieć? To jest raczej adresowane do jakichś osób z większym doświadczeniem programistycznym, czy każdy może wziąć w nim udział?

Każdy może wziąć udział. Jeżeli nie znasz odpowiedzi na dane pytanie, to po prostu musisz poszukać. Generalnie nie oszukujmy się, tak wygląda nasza praca na co dzień, cały czas trafiamy na problemy, z którymi nie mieliśmy wcześniej do czynienia, więc musimy się dowiedzieć czegoś nowego czy poszukać informacji, jak ten problem go rozwiązać. Więc generalnie nie chcemy dawać jakichś supertrudnych zagadek, ale też takich superłatwych też, chyba że, powiedzmy, na mikołajki taka edycja specjalna – okienka, gdzie zadanie będzie naprawdę proste.

Jak dołączyć do konkursu?

A co trzeba zrobić, żeby dołączyć do tego konkursu? Czy muszę brać udział we wszystkich tych codziennych zadaniach, czy mogę tylko w wybranych?

Generalnie działa to w ten sposób, że – żeby dołączyć – trzeba przejść na stronę DevAdventCalendar i zarejestrować się jako uczestnik. Później każdego dnia – wydaje nam się, że okienko będziemy otwierali o dwudziestej, ponieważ przeprowadziliśmy ankietę wśród uczestników i najczęściej podawaną/proponowaną godziną otwarcia okienka była dwudziesta, czyli dla nas taka trochę późna pora. No ale OK. Lud zdecydował – użytkownicy zdecydowali.

Wiele osób wraca po pracy, zajmuje się swoimi dziećmi, swoimi własnymi sprawami i wtedy dopiero mają czas na takie aktywności.

Tak, tak, to też dobrze rozumiem. Dlatego się zdzwaniamy tak późno generalnie. Ale jeżeli użytkownik dołączy, to wtedy każdego dnia o godzinie 20.00 będzie otwierane kolejne okienko. I im szybciej od momentu otwarcia okienka odpowie na pytanie, tym generalnie będzie miał krótszy czas odpowiedzi, bo finalnie i tak będą się liczyły punkty, czyli ważniejsze jest to, żeby odpowiedzieć poprawnie, niż to, żeby odpowiedzieć szybko, ale w momencie, w którym będziemy mieli kilku użytkowników z tą samą liczbą punktów, ponieważ tam, powiedzmy, przez tydzień będzie grupa użytkowników, która nie popełni żadnego błędu, no to wtedy będziemy musieli jakoś zdecydować, kto wygrał, więc uznaliśmy, że wtedy będziemy po prostu liczyli czas odpowiedzi.

Czyli przede wszystkim odpowiadać poprawnie, a jak już znamy odpowiedź, to w miarę szybko. Jak najbardziej uzasadnione.

Oczywiście można też wziąć udział, rezygnując z nagród, dla własnej satysfakcji, to jest powód. Generalnie dlatego właśnie, dla takich osób, postanowiliśmy, że te okienka zostaną otwarte na dłużej, do samego końca kalendarza. Dla osób, które chciałyby po prostu sprawdzić swoją wiedzę i tak rekreacyjnie odpowiadać na pytania, sprawdzić, ile zyskają punktów.

Nie oszukujmy się, te nagrody nie muszą być głównym celem. Sama frajda z uczestnictwa w zabawie i możliwość dowiedzenia się nowych rzeczy też niewątpliwie jest plusem. Ja już się zarejestrowałem i stąd liczę na ciekawe zadania.

Będą, obiecuję.

Trzymam za słowo. Dobrze, troszeczkę już o tym powiedziałeś, ale chciałbym jeszcze do tego wrócić. Cofnijmy się teraz troszeczkę w czasie. Jak mógłbyś powiedzieć coś więcej o tym, jak powstał ten konkurs, kto wpadł na ten pomysł, jak udało się zebrać całą tę ekipę i jak ciebie przekonali, żebyś dołączył.

Generalnie na pomysł wpadła Weronika Tobor dwa lata temu, to ona zorganizowała pierwszą edycję i w momencie, w którym ja spotkałem się z tą edycją, bo generalnie wtedy byłem uczestnikiem, też odpowiadałem na pytania, dowiedziałem się dopiero jakoś pod koniec konkursu. Stwierdziłem, że jeśli chce tworzyć, chce zrobić to samo w tym roku, to ja chętnie dołączę. Nie znam się na C#, ale powiedzmy, że ciut się interesuję marketingiem, więc mógłbym wspomóc z tej strony. I wydaje mi się, że to nam się udało w poprzednim roku, to znaczy mieliśmy dziesięciokrotny przyrost użytkowników. Czyli w pierwszej edycji brało udział około stu pięćdziesięciu osób, druga edycja to już było półtora tysiąca. Nie wiem, czy w trzeciej edycji dociągniemy do piętnastu tysięcy, bo byłoby super, ale zobaczymy. No i tak, i głównie tym zajmuję się w tym projekcie, czyli dbam o stronę marketingową, kontaktuję się ze sponsorami czy tego typu rzeczy.

Do sponsorów jeszcze wrócimy. Chciałbym teraz skupić się troszeczkę na tych poprzednich edycjach. Powiedziałeś już, ile osób było, jakie były nagrody, a czy można wrócić do poprzednich edycji i np. podejrzeć pytania, które były tam zadane.

Dobre pytanie. Wydaje mi się, że w tym momencie są pozamykane już tamte tamte okienka i nie ma w tym momencie możliwości podejrzenia pytań z zeszłego roku, ale możliwe, że udostępnimy te pytania.

Błędy podczas realizacji projektu

Jak mógłbyś podzielić się jakimiś wypadkami albo takimi ciekawostkami, które były w trakcie poprzednich edycji. Wiadomo, że ludzie najchętniej słuchają o tym, jak coś komuś nie wyszło. Może macie jakieś takie smaczki, które były w trakcie ostatniej edycji.

Smaczki. Mogę Ci powiedzieć np. o tym, że godzinę przed startem, bo w tamtym roku start był w sobotę 1 grudnia, ustaliliśmy godzinę otwarcia okienka na dziesiątą, a o dziewiątej był jakiś problem techniczny i w ogóle aplikacja nie chciała wstać. Ale na szczęście udało się go załatać dosyć szybko, więc wystartowaliśmy o czasie. No ale to był dosyć stresujący moment dla wszystkich, żeby się po prostu nie okazało, że cała praca poszła na marne, ale udało nam się finalnie. No i generalnie takich sytuacji było całkiem sporo. To znaczy, to też jest ciekawa kwestia, bo dla mnie jako programisty rozmowa czy kontaktowanie się, powiedzmy, z firmą i przekazanie informacji, że organizujemy konkurs, chcielibyśmy od Was pieniądze na nagrody, no to też jest dosyć taki ciekawy temat. Dlatego możliwe, że z tego tytułu też popełniliśmy kilka wpadek, kiedy mogliśmy np. zyskać jakiegoś sponsora, ale przez złe przedstawienie oferty albo przez złe przygotowanie oferty – no niestety, sponsor nie był zainteresowany, dlatego w tym roku postawiliśmy na ofertę przygotowaną profesjonalnie przez grafika. No i to już mogę powiedzieć, że w tym momencie dała nam takie rezultaty, że mamy więcej pieniędzy na nagrody niż w tamtym roku. Ale niestety z grafikiem się skontaktowaliśmy zbyt późno, więc finalnie zdobywamy sponsorów tak naprawdę dopiero od połowy listopada, może od 7 listopada, więc mamy teraz super dopracowaną ofertę, ale zbyt mało czasu, żeby zyskać tych sponsorów, więc generalnie zawsze coś się dzieje i zawsze się uczymy czegoś ciekawego. Lekcja na przyszłość, żeby z grafikiem kontaktować się już dużo, dużo wcześniej.

Jak to się mówi, nie popełnia błędów ten, kto nie próbuje. Rzeczywiście troszeczkę tego czasu już mało zostało, aczkolwiek myślę i mam taką nadzieję że uda się to wszystko z waszej strony załatwić.

Projekt Open source DevAdventCalendar – technologie

Sam DevAdventCalendar to jest coś więcej niż tylko inicjatywa, to jest również projekt informatyczny. Chciałem troszeczkę nawiązać do tego, jak mógłbyś zdradzić nam, jakie technologie na przykład wykorzystaliście. Wspomniałeś coś wcześniej, że jest to realizowane w ramach Open Source. Czy każdy mógłby dołączyć obecnie do tego projektu?

Tak. Projekt jest zrealizowany w C#. Powiem szczerze, że jestem programistą Java, więc zupełnie tam nie dotykam kodu. Ciężko mi się wypowiedzieć, jakkolwiek technicznie wiem tylko tyle, że tam jest C#. Ale jeżeli znasz tę technologię i chcesz rozwiązać jakiś problem, to mamy cały czas dostępne to na Github issue. Można nawet bez znajomości całego kontekstu podejść i rozwiązać jakiś problem. A jeżeli chcesz się zaangażować bardziej, to wtedy można się skontaktować z Weroniką i ona tam już spokojnie prace nada. Tak że tak, jeżeli ktoś jest chętny, to zapraszamy, zresztą informowaliśmy też o tym w mailach, że projekt Open Source, jeżeli jesteś chętny, to dołącz do nas.

Czyli takie dodatkowe zadania poza tymi standardowymi, które codziennie będą rozdawane. Ale z tego, co zdążyłem się już zorientować, macie też taki corowy zespół, który pracuje nad tym projektem. Na ile ta struktura w tym zespole jest u was sztywno zorganizowana? Czy macie może jakieś cykliczne spotkania, na których dzielicie się zadaniami, czy to jest raczej taka bardziej luźna inicjatywa?

Generalnie mamy, powiedzmy, tygodniowe podsumowania tego, co udało się zrobić, plany na kolejne miesiące, a jeśli chodzi o samo wdrażanie i pisanie funkcjonalności, to w tych tematach również kontaktujemy się i po prostu rozmawiamy, co chcielibyśmy poprawić w tej edycji, co trzeba dodatkowo zaimplementować, co ma jaki priorytet, więc nie ma jakiejś super zorganizowanej struktury, to są raczej luźne struktury, w których po prostu określa się, jaka jest twoja dyspozycja i ile czasu możesz poświęcić na ten projekt, co możesz zaimplementować, jak możesz pomóc.

Wy się spotykacie fizycznie czy to jest typowo zdalna współpraca?

To zależy. Czasem się uda fizycznie, czasem po prostu się zdzwaniamy.

Fajnie, fajnie to wygląda.

Chciałbym teraz zmienić troszeczkę temat i wcielić się w rolę takiej osoby, która samodzielnie chciałaby zrealizować taką inicjatywę. Myślisz, że jest jeszcze miejsce na rynku dla nowych tego typu przedsięwzięć? Nie chodzi mi tutaj koniecznie o konkurs, który byłby kopią waszego rozwiązania, raczej o coś podobnego. Czy w ogóle warto jeszcze interesować się tym tematem?

Zdecydowanie. To znaczy nasz konkurs jest już organizowany, ale mamy bardzo określone widełki czasowe, bo jest organizowany w okresie adwentu przez 24 dni w roku, ale są jeszcze pozostałe dni, w których można zorganizować coś podobnego i do czego też zachęcamy, bo dobrze byłoby mieć jakąś konkurencję, zawsze wtedy można by się było porównać czy nawzajem od siebie czegoś ciekawego nauczyć. No i generalnie mamy mnóstwo problemów, które są jeszcze niezaadresowane i które mogą być początkiem naprawdę ciekawych informatycznych projektów. Więc jeśli ktoś chce robić coś dodatkowo, pewnie, to jest zawsze dobry pomysł, nawet jeżeli nie uda nam się tego skomercjalizować. W tym momencie też DevAdventCalendar to jest inicjatywa, na której my nie zarabiamy. Tam pieniądze, jeśli jakieś trafiają do nas, to te pieniądze są przeznaczane na nagrody, na, powiedzmy, domeny, na hosting. A w tym roku też na przygotowanie tej oferty. Ale pomimo tego, nawet jeśli nie uda się na tym w żaden sposób zarobić, to osoba, która coś tworzy, zawsze zyskuje jakieś doświadczenie. To będzie z jednej strony doświadczenie IT, jeśli będzie to jakiś projekt informatyczny, a z drugiej strony naprawdę ciekawie zaczyna się robić, kiedy taka osoba, która zajmuje się IT, próbuje coś komuś sprzedać. To jest zupełnie nowy obszar, który też warto eksplorować, bo nawet jeżeli te sukcesy sprzedażowe nie będą jakieś spektakularne, to nauczymy się czegoś nowego i później choćby coś takiego jak negocjacje własnej stawki z pracodawcą będzie już dla nas czymś, co znamy, przychodzimy z konkretnym ofertami i z grubsza wiemy to, co chcemy załatwić i jak.

Tak, te wasze doświadczenia dosyć mocno pokrywają się z moimi doświadczeniami, które ja mam na blogu i obecnie też bezpośrednio nie zarabiam na blogu. Natomiast wszystkie te dodatkowe inicjatywy, które podejmowałem, pozwoliły mi się rozwinąć nie tylko w wielu kwestiach programistycznych, jak przygotowanie chociażby czasami materiałów na wpisy, ale właśnie te wszystkie takie zagadnienia, które wiążą się dookoła tego, jak kontakt z innymi ludźmi, jak kontakty z firmami, które potencjalnie byłyby zainteresowane na przykład reklamą. Jeszcze raz podkreślam to, że warto robić coś poza standardowym etatem.

No tak, tutaj pełna zgoda, zdecydowanie warto robić coś więcej, chociaż rozumiemy, że jest ciężko i nie zawsze się chce.

A jeżeli chodzi o to ciężko. Jak udawało wam się łączyć te dodatkowe aktywności z codziennym życiem? Jednak przygotowanie takiego konkursu niewątpliwie zajęło bardzo dużo czasu, a życie się nie zatrzyma. Są dzieci, jest praca. Jak  zdobywaliście ten czas?

Generalnie, z mojej perspektywy, jeżeli podejmuję jakąś współpracę z kimś, to bardzo ważna jest dla mnie elastyczność, w takim sensie, żeby, powiedzmy, godziny nie były aż tak sztywno ustalone. I jeżeli mam taką elastyczność, mogę np. pewnego dnia zacząć o dwunastej, nic się nie stanie, no to wtedy odpowiednio do tego dopasowuję sobie kalendarz i – tak jak mówisz – życie się nie zatrzyma, więc trzeba też pamiętać o tym, żeby dziecko z przedszkola odebrać czy nakarmić je, bo też nie chce przestać jeść na czas projektu.

Tak, to też ważne. <śmiech>

Tak, dokładnie. Więc, no cóż, podstawą z mojej perspektywy jest zarządzanie czasem i tworzenie sobie kalendarza. Druga sprawa to wybieranie rzeczy, które są istotne, bo też, nie oszukujmy się, gdybym mógł poświęcić na kalendarz więcej godzin, wtedy przeprowadziłbym więcej działań marketingowych i byłoby więcej pomysłów itd. A w tym momencie, już mając jakąś tam odrobinę doświadczenia, staram się wybrać te, które albo dały mi najwięcej frajdy, albo przełożyły się po prostu na najlepsze wyniki w zeszłym roku. Więc warto sobie wyznaczyć czas i warto sobie ten czas wyznaczyć, patrząc po prostu w kalendarz, żeby też zdawać sobie sprawę, że nie wszystko, co planujemy, uda się zrobić, zwłaszcza jeżeli mamy jakiś sztywny deadline, i dlatego warto skupić się na tym, co daje nam najlepsze efekty.

Promocja projektu Open source

Pełna zgodność. Jeszcze raz. Przejdźmy do kolejnego tematu. Wspomniałeś, że zajmowałeś się marketingiem w tym projekcie. Jak mógłbyś rozwinąć ten temat i powiedzieć, w jaki sposób starałeś się dotrzeć do potencjalnych użytkowników, jak po prostu reklamowaliście ten projekt?

To jest dosyć złożona sprawa, w tym sensie, że nie mieliśmy jakiegoś superprzekazu. Nasz przekaz brzmi tak, jak generalnie ten kalendarz działa, czyli to jest konkurs dla programistów, którzy chcą sprawdzić swoją wiedzę oraz dodatkowo zgarnąć jakieś nagrody, jeśli jeśli będą najszybsi. Więc z takim przekazem, powiedzmy sobie szczerze, też nie jest jakoś szczególnie trudno, bo jesteśmy z reguły ludźmi ciekawymi, których – mówiąc kolokwialnie – jarają takie rzeczy, jeżeli ktoś słyszy, że jest jakiś konkurs IT, no to choćby z ciekawości się zarejestruje, choćby nawet nie wziął udziału, to jednak jakaś część jego będzie chciała się sprawdzić albo przynajmniej sprawdzić, co to jest. Więc wydaje mi się, że konkurs już tak sam w sobie wzbudza jakieś zainteresowanie.

Poza tym staraliśmy się docierać do miejsc, w których programistów jest dużo, czyli np. wszelkie grupy IT ze wsparciem, czy tego typu miejsca, powiedzmy, w Internecie oraz dodatkowo wykupiliśmy sobie jeszcze reklamę na Facebooku. Ponieważ Facebook tnie zasięgi, czyli jeżeli mamy jakąś tam grupę lajków, powiedzmy sobie szczerze, nasze lajki na Facebooku nie powalają. Nie wiem, ile ich jest w tym momencie, ale one nie mają aż tak dużego znaczenia, kiedy mamy dużą grupę mailową, bo w momencie, w którym mamy dużą grupę, tak jak wspomniałem, to było półtora tysiąca osób, to też gdy wysyłamy te wiadomości, te osoby je po prostu otwierają. Nie dojdzie do sytuacji, że ktoś podejmie decyzję, że to my teraz dostarczymy tylko 5% wiadomości, tylko ty wysyłasz te wiadomości do wszystkich, jeżeli są interesujące. Jeżeli osoby są zaangażowane, to po prostu będą otwierały te maile. Więc też kontaktując się, też pisząc swoją ofertę. Staraliśmy się zwrócić na to uwagę że te sociale nie są aż tak napompowane jak gdziekolwiek indziej, ale mamy sporą grupę osób, które po prostu czytają nasze maile i te osoby biorą udział w konkursie.

DevAdventCalendar – plany na przyszłość

Czyli ci najbardziej zaangażowani użytkownicy, którzy już do was przyszli. Może, tak powoli już przechodząc do końca, chciałbym dowiedzieć się, jakie macie plany na przyszłość. Czy w kolejnym roku można spodziewać się nowej edycji? Czy może coś więcej planujecie? Rozbudować projekt lub może planujecie zamknąć go?

W tym momencie nie wiem. Ciężko mi mówić o jakichś planach. W tym momencie jesteśmy skupieni w całości na tej aktualnej edycji, ale raczej nie będziemy go zamykać. Podejrzewam, że pojawi się kolejna edycja, w której będziemy wdrażać kolejne rzeczy, ponieważ znowu będziemy mieli kolejne informacje od uczestników, co można by poprawić. No oraz próbować zyskać kolejne pieniądze, znowu miejmy nadzieję, żeby były jeszcze większe, żeby konkurs dotarł do większej ilości osób, żebyśmy mogli większą ilość osób nagrodzić. Wydaje mi się, że tak wyglądają nasze plany. A czy zrobimy z tym coś więcej, ma jakieś dodatkowe pomysły. Ale w tym momencie to jeszcze chyba nie czas, nie miejsce, żeby o tym opowiadać.

Miejmy nadzieję, że nie będziecie projektu zamykać i że projekt będzie trwał, jak to się mówi, sto lat i jeszcze trochę. Zdecydowanie trzymamy kciuki za kolejne edycje. Chciałbym, żebyś jeszcze na koniec przypomniał nam, gdzie można znaleźć więcej informacji o tym konkursie i co trzeba zrobić, żeby się do niego zapisać.

Generalnie informacje są dostępne na stronie DevAdventCalendar.pl. Tam jest możliwość zapisania się, dołączenia po prostu do grupy subskrybentów naszego mailingu, gdzie opisujemy najwięcej, oraz jest tam możliwość założenia konta, które pozwoli brać udział w konkursie. Dodatkowo mamy też oczywiście konto na Facebooku, gdzie staramy się co jakiś czas publikować jakieś informacje. Do tego konto na Twitterze, można być na Twitterze chyba nawet w elitarnej grupie pierwszych stu, ponieważ tam jest chyba tylko 60 followersów, czy coś takiego.

Wszystkie linki umieścimy pod artykułem.

Dokładnie tak, że zapraszamy. Można śledzić. Można się z nami kontaktować.

Super, Michał, dzięki wielkie za tę rozmowę, naprawdę bardzo miło spędziłem czas i myślę, że to wszystko, co powiedziałeś, będzie naprawdę bardzo interesujące dla naszych słuchaczy. Jeszcze raz wielkie dzięki.

Dziękuję bardzo za zaproszenie.

Zakończenie – DevAdventCalendar Open source

I jak podobało się Wam?
Świetna inicjatywa i świetni ludzie – bardzo lubię rozmawiać z osobami, które prawdziwie lubią, to co robią i chcą dzielić się swoją wiedzą.
Na koniec życzę Ci jeszcze, żeby ten okres przygotowań do świąt był owocny nie tylko pod kątem zadań programistycznych – dla mnie zazwyczaj jest to moment większych przemyśleń i planów na przyszłość.
Pozdrawiam i do usłyszenia już niedługo.

Linki  – DevAdventCalendar Open source

Michał

No comments
Share:
FizzBuzz

Co to jest gra FizzBuzz i jak wykorzystać ją podczas rozmowy kwalifikacyjnej

Gra FizzBuzz wykorzystywana jest na wielu rozmowach kwalifikacyjnych na programistę.
Sprawdź, czy zdasz taki test.
Wystarczy 10 minut, żeby się zapoznać z tą metodą i zwiększyć swoje szanse przy kolejnej rozmowie.

FizzBuzz to jedno z popularniejszych praktycznych zadań podczas technicznej rekrutacji na programistę. Test FizzBuzz jest zazwyczaj wykorzystywany do wstępnego odfiltrowania osób, które zwyczajnie nie potrafią programować – może wydać się to dość dziwne, ale na wstępnych rozmowach kwalifikacyjnych pojawia się zadziwiająco dużo osób, które mają problemy z rozwiązaniem nawet wyjątkowo prostych problemów programistycznych.

No dobrze, ale jaki to ma związek z dziećmi?

[SprawnyProgramista_intro /]

Dziecięca gra FizzBuzz

FizzBuzz gra dziecięca

Gra dziecięca FizzBuzz

Pierwotnie test FizzBuzz zyskał popularność jako gra przeznaczona dla dzieci, mająca na celu nauczenie ich dzielenia.

Dzieci siadały w kółeczku i kolejno musiały wymieniać liczby całkowite:

  • pierwsze dziecko – jeden;
  • drugie dziecko – dwa;
  • trzecie – trzy;
  • i tak dalej…

Cała zabawa polegała na tym, że jeżeli liczba była podzielna przez trzy, to – zamiast podania samej liczby – trzeba było krzyknąć Fizz, jeżeli była podzielna przez pięć, to Buzz, a jeżeli przez trzy i pięć, to FizzBuzz.

Świetny i wyjątkowo prosty sposób na zabawę, a jednocześnie skuteczna zachęta do nauki matematyki.

Zabawa stała się na tyle popularna, że zyskała wiele różnych odsłon, np. w formie zadań programistycznych.

Zasady gry FizzBuzz dla programistów

W podstawowej wersji dla programistów zadanie zazwyczaj przyjmuje następującą formę.

Wypisz wszystkie liczby od 1 do 100, jednak jeżeli liczba jest podzielna przez:

  • trzy – wypisz „Fizz”,
  • pięć – wypisz „Buzz”,
  • trzy i pięć wypisz „FizzBuzz”.

Niby nic trudnego – trzy „ify”, kilka linijek kodu i problem rozwiązany. Interview zaliczone.

Ale, ale…

Nie tak szybko 🙂 Wbrew pozorom nawet na podstawie tak prostego zadania można bardzo dużo dowiedzieć się o kandydacie.
Jak się za chwilę przekonasz, w zadaniu jest ukrytych kilka pułapek programistycznych i można je rozwiązać na naprawdę wiele – w tym również błędnych – sposobów.

Pierwsze rozwiązanie problemu FizzBuzz

Zacznijmy od podstawowej implementacji, która jest jednocześnie najczęściej udzielaną odpowiedzią.

for (int i = 1; i <= 100; i++) {
	if (i % 3 == 0) {
		if (i % 5 == 0) {
			System.out.println("FizzBuzz");
		} else {
			System.out.println("Fizz");
		}
	} else if (i % 5 == 0) {
		System.out.println("Buzz");
	} else {
		System.out.println(String.valueOf(i));
	}
}

Zadanie zostało rozwiązane, udało nam się udowodnić, że znamy podstawową składnię Javy.
Jeżeli to Ci wystarczy, możesz skończyć czytać ten tekst już w tym momencie.
Jeżeli jednak masz odrobinę większe ambicje i chciałbyś dowiedzieć się, w jaki sposób można wykazać się przed rekruterem czymś więcej, niż tylko podstawową składnią języka, to zapraszam do dalszej lektury.

Co jest nie tak z moim rozwiązaniem?

Powyższy kod zwraca poprawne wyniki – czyli robi to, co najważniejsze – działa. Jeżeli jednak chcesz pokazać się z jak najlepszej strony podczas rozmowy rekrutacyjnej – a zakładam, że tak właśnie jest – to rozłóżmy teraz wspólnie to zadanie na czynniki pierwsze i zastanówmy się, co możemy jeszcze poprawić.

Pamiętaj – nie ma czegoś takiego jak uniwersalnie idealne rozwiązanie.

Może co najwyżej istnieć bardzo dobre rozwiązanie w ramach naszych konkretnych założeń.

Przykładowo:

  • inaczej będzie wyglądał kod napisany z myślą o minimalnym zużyciu pamięci;
  • inaczej, jeżeli naszym głównym celem będzie czytelność rozwiązania;
  • a jeszcze inaczej, gdy naszym głównym celem jest napisanie kodu, który w przyszłości będzie możliwie łatwy do rozbudowy o nowe funkcjonalności.

Dlatego, zanim pochwalimy się, że zadanie jest skończone, warto jasno zadeklarować przy jakich założeniach powstała ta implementacja i dopytać, czy nie ma potrzeby, żebyśmy dostosowali ją do specyficznych wymagań.

Pokażesz się wtedy jako osoba, która zwraca uwagę na coś więcej niż tylko jej kilka linijek kodu i umie dostosować swoje zadanie do większej całości.

My jednak musimy coś założyć, żeby móc pójść dalej. Dlatego przyjmiemy w miarę możliwości ogólne założenie, że chcemy przygotować uniwersalne rozwiązanie oraz dodatkowo pochwalić się podstawową znajomością dobrych praktyk programistycznych, przy jednoczesnym zachowaniu czytelności kodu – czyli wszystko po trochu, bez przesadnej optymalizacji pod żadnym kątem.

Poprawiona wersja implementacji testu FizzBuzz

Jeżeli przyjrzymy się bliżej temu rozwiązaniu, to dojdziemy do wniosku, że struktura „if’ów” jest źle dobrana, przez co mamy powielone sprawdzenie tych samych warunków. Wpływa to również na pogorszenie czytelności całego rozwiązania.

Jednym ze sposobów na poprawienie implementacji jest spłaszczenie struktury warunków do jednego poziomu zagnieżdżenia. Jednak, żeby to zrobić, trzeba zauważyć, że napis FizzBuzz będzie wyświetlony tylko w przypadku, gdy liczba jest podzielna przez 15.

Poprawiona implementacja mogłaby wyglądać tak:

for (int i = 1; i <= 100; i++) {
	if (i % 15 == 0) {
		System.out.println("FizzBuzz");

	} else if (i % 3 == 0) {
		System.out.println("Fizz");

	} else if (i % 5 == 0) {
		System.out.println("Buzz");

	} else {
		System.out.println(i);
	}
}

Sprawdzenie najpierw podzielności przez 15 poprawia czytelność i dodatkowo unikamy duplikacji kodu.
Jednak ten warunek nie wynika bezpośrednio z treści zadania i trzeba zauważyć poniższą zależność.

i%3==0 && i%5==0
=> i%15==0

Nie jest to jednak jedyny sposób na rozwiązanie tego problemu. Prześledźmy teraz najczęściej występujące błędy oraz kilka alternatywnych rozwiązań.

Na co uważać i czego unikać – główne błędy?

  • źle dobrana struktura „ifów” – omówiliśmy sobie to szczegółowo w poprzednich punktach;
  • nie pchaj wszystkiego na siłę do jednego wora – nie staraj się za wszelką cenę wykorzystać całej swojej wiedzy w tym jednym zadaniu. Przekolorowane rozwiązania, w których na siłę upychasz różne możliwości, wcale nie wyglądają dobrze. Pamiętaj o jednej z ważniejszych zasadach programistycznych: KISS (ang. keep it simple, stupid),
  • egzotyczne rozwiązania – staraj się zachować standardy i raczej unikaj nad wyraz twórczych rozwiązań. Przykładowo, resztę z dzielenia modulo w Javie można obliczyć, skorzystać z operatora modulo: x % y, ale jak ktoś się postara, to można poradzić sobie również bez niego: x-x/y*y.

Alternatywna implementacja FizzBuzz #1. – konkatenacja stringów

W tym rozwiązaniu, zamiast co chwilę wyświetlać wyniki po małym kawałku na standardowe wyjście, zbieramy wyniki i dopiero na samym końcu jedną komendą je wyświetlamy.

Standardowa konkatenacja stringów może być zastąpiona klasą StringBuilder – więcej na temat samej klasy StringBuilder oraz jej zalet w porównaniu do ręcznego łączenia stringów przeczytasz w podlinkowanym artykule.

for (int i = 1; i &lt;= 100; i++) {
	String result = "";
	if (i % 3 == 0) {
		result = "Fizz";
	}
	if (i % 5 == 0) {
		result += "Buzz";
	}
	if (result.isEmpty()) {
		result += i;
	}

	System.out.println(result);
}

Alternatywna implementacja FizzBuzz #2. – dodatkowa flaga boolean

Wykorzystanie pomocniczej zmiennej jest alternatywą do sprawdzania warunku na modulo 15.

for (int i = 1; i &lt;= 100; i++) {
	boolean fizzOrBuzz = false;
	if (i % 3 == 0) {
		System.out.print("Fizz");
		fizzOrBuzz = true;
	}
	if (i % 5 == 0) {
		System.out.print("Buzz");
		fizzOrBuzz = true;
	}

	if (fizzOrBuzz) {
		System.out.println();
	} else {
		System.out.println(String.valueOf(i));
	}
}

Alternatywna implementacja FizzBuzz #3. – switch

W tej wersji implementacji całkowicie rezygnujemy z instrukcji warunkowej if i zastępujemy ją instrukcją switch.

Moim zdaniem takie rozwiązanie jest już trochę przekombinowane i powoli zaczynamy tracić na czytelności.

for (int i = 1; i &lt;= 100; i++) {
	String value;
	switch (i % 15) {
		case 3:
		case 6:
		case 9:
		case 12:  // podzielne przez 3
			value = "Fizz";
			break;
		case 5:
		case 10:  // podzielne przez 5
			value = "Buzz";
			break;
		case 0:  // podzielne przez 3 i 5
			value = "FizzBuzz";
			break;
		default:
			value = Integer.toString(i);
	}
	
	System.out.println(value);
}

Alternatywna implementacja FizzBuzz #4. – potrójny operator warunkowy (ang. ternary operator)

Korzystając z potrójnego operatora warunkowego (ang. ternary operator), moglibyśmy nasze rozwiązanie zmieścić nawet w jednej linijce kodu.
Tylko czy warto? – tu już sami musicie sobie odpowiedzieć.

for (int i = 1; i &lt;= 100; i++) {
	System.out.println(i % 15 != 0 ? i % 5 != 0 ? i % 3 != 0 ? String.valueOf(i) : "Fizz" : "Buzz" : "FizzBuzz");
}

Alternatywna implementacja FizzBuzz #5. – rekurencja

Rekurencja jest potężnym orężem w ręku doświadczonego programisty. Dzięki niej można w stosunkowo prosty sposób rozwiązać nawet bardzo skomplikowane problemy. Mimo wszystko nie jest to uniwersalne rozwiązanie, które rozwiąże za nas wszystkie nasze problemy.

Pamiętaj o zasadzie złotego młotka (ang. golden hammer) i z rozwagą dobieraj rozwiązania do Twojego problemu.

System.out.println(fizzBuzz(100));

String fizzBuzz(int n) {
	String s = "";
	if (n == 0) {
		return s;
	}
	if ((n % 5) == 0) {
		s = "Buzz" + s;
	}
	if ((n % 3) == 0) {
		s = "Fizz" + s;
	}
	if (s.equals("")) {
		s = n + "";
	}
	return fizzBuzz(n - 1) + s + "\n";
}

Alternatywna implementacja FizzBuzz #6. – tablica

W tej wersji rozwiązania problemu FizzBuzz posłużymy się tablicą.

for (int i = 1; i &lt;= 100; i++) {
	String[] array = new String[]{i + "", "Fizz", "Buzz", "FizzBuzz"};
	int index = (i % 3 == 0 ? 1 : 0) + (i % 5 == 0 ? 2 : 0);

	System.out.println(array[index]);
}

Alternatywna implementacja FizzBuzz #7. – wyrażenia lambda i tablica

Gdybyś chciał popisać się znajomością wyrażeń lambda, to do zadania FizzBuzz mógłbyś wykorzystać takie rozwiązanie.

int[] x = new int[101];
Arrays.setAll(x, j -&gt; j++);
Arrays.stream(x).forEach(i -&gt; {
	if (i == 0) return;
	String output = "";
	if (i % 3 == 0) output += "Fizz";
	if (i % 5 == 0) output += "Buzz";
	if (output.equals("")) output += i;

	System.out.println(output);
});

Alternatywna implementacja FizzBuzz #8. – wyrażenia lambda i strumienie

Poniższe rozwiązanie wykorzystuje wyrażenia lambda oraz strumienie java (ang. java stream).

IntStream.rangeClosed(1, 100)
		.mapToObj(i -&gt; {
			if (i % (3 * 5) == 0) {
				return "FizzBuzz";
			} else if (i % 3 == 0) {
				return "Fizz";
			} else if (i % 5 == 0) {
				return "Buzz";
			} else {
				return Integer.toString(i);
			}
		})
		.forEach(System.out::println);

Alternatywna implementacja FizzBuzz #9. – programowanie obiektowe

Na sam koniec zostawiłem implementację w stylu OOP, gdzie wykorzystujemy programowanie obiektowe do zamodelowania rozwiązania.

Zobacz, że dzięki takiej implementacji, nie ograniczamy się na sztywno do liczb 3 i 5 oraz napisów Fizz i Buzz. Wydzielenie logiki do osobnej klasy pozwoliło przygotować bardziej uniwersalne rozwiązanie.

Sound sound = new Sound(3, "Fizz", new Sound(5, "Buzz"));
for (int i = 1; i &lt;= 100; i++) {
	System.out.println(sound.generate(i));
}

oraz klasa Sound.

class Sound {
	private final int trigger;
	private final String sound;
	private final Sound next;

	public Sound(int trigger, String sound, Sound next) {
		this.trigger = trigger;
		this.sound = sound;
		this.next = next;
	}

	public Sound(int trigger, String sound) {
		this(trigger, sound, null);
	}

	public String generate(int n) {
		StringBuilder sb = new StringBuilder();
		generate(sb, n);
		return sb.length() == 0 ? String.valueOf(n) : sb.toString();
	}

	private void generate(StringBuilder sb, int n) {
		if (n % trigger == 0) {
			sb.append(sound);
		}
		if (next != null) {
			next.generate(sb, n);
		}
	}
}

Alternatywna implementacja FizzBuzz #10. – wersja korporacyjna

Jeżeli chociaż raz miałeś okazję pracować z wielkim i „ciężkim” projektem korporacyjnym, to doskonale wiesz, czego można się spodziewać po tego typu implementacji.
FizzBuzz w wersji korporacyjnej ma wykorzystane chyba wszystkie możliwe interfejsy i wzorce projektowe.
Tylko konia z rzędem temu, kto byłby w stanie napisać taki kod podczas rozmowy kwalifikacyjnej lub chociaż zrozumieć go w tym czasie 😉

Tutaj link do GitHub – FizzBuzz EnterpriseEdition.

TDD i testy jednostkowe

A co Ty na to, żeby dodatkowo przetestować swoje rozwiązanie?

Jeżeli podczas rozmowy kwalifikacyjnej dodatkowo wykażesz się znajomością dobrych praktyk i dbałością o jakość Twojego rozwiązania, może to stanowić duży plus na Twoją korzyść.
Problem FizzBuzz idealnie nadaje się do rozwiązania z wykorzystaniem testów jednostkowych i TDD (ang. test driven development).

➡ ZOBACZ 👉: Testowanie oprogramowania

Czy to już wszystko? – różne wariacje gry FizzBuzz

FizzBuzz jest na tyle popularnym problemem, że doczekał się wielu różnych modyfikacji i rozszerzeń – zaczynając od dość prostych, a kończąc na prawdziwych programistycznych wyzwaniach.
Poniżej kilka przykładowych wariacji:

  • zmiana zakresu z 1–100 do np. 100–1000 itp;
  • zmiana lub dodanie liczb, na podstawie których sprawdzamy podzielność, np. słowo Zazz dla każdej liczby podzielnej przez 10;
  • zmiana systemu liczbowego, na którym operujemy, np. z dziesiętnego na ósemkowy;
  • 3, 5, 7 Fizz Buzz Woof – gdzie jeżeli w sprawdzanej liczbie wystąpi nasza szukana, wyświetlamy odpowiadające jej słowo klucz – przykładowo liczba 3307 powinna być zamieniona na FizzFizzWoof .

Teraz Twoja kolej

Ja już rozwiązałem FizzBuzz – teraz Twoja kolej.
Zachęcam, żebyś spróbował zmierzyć się z tym zadaniem i podzielił się swoją implementacją. Szczególnie przydatne mogą okazać się inne niż Java języki programowania  – takie jak: C/C++, C#, Python, PHP itd.

Rozwiązaniem możesz podzielić się w komentarzu poniżej lub na grupie.

Teraz Ty!

Teraz Ty!

Podsumowanie FizzBuzz i co dalej?

FizzBuzz jest już swego rodzaju klasykiem technicznych rozmów kwalifikacyjnych. Dzięki temu szybkiemu ćwiczeniu w mig można sprawdzić, jak kandydat porusza się w IDE oraz jakie stosuje podejście przy programowaniu. Zadanie jest na tyle uniwersalne, że niezależnie od technologii, w której pracujesz, warto się z nim zmierzyć.

Nie twierdzę jednak, że dzięki FizzBuzz uda się potwierdzić, że ktoś jest świetnym developerem, jednak z łatwością zidentyfikujemy tych słabych. A to już coś na początek procesu rekrutacji.

Jakie Ty miałeś pytania na rozmowie kwalifikacyjnej? Podeślij mi je, to wspólnie je rozwiążemy.

Jeżeli natomiast szukasz więcej przykładowych pytań rekrutacyjnych, to dołącz do newslettera i odbierz przykładową listę z zadaniami.

 

Chcesz przygotować fantastyczne CV i zabłysnąć na rozmowie kwalifikacyjnej? Sprawdź  najnowsze e-booki:

CV Programisty oraz Rozmowa kwalifikacyjna Programisty

15 komentarzy
12 błędów przez które nie dostałem pierwszej pracy

12 błędów przez które nie dostałem pierwszej pracy

Mało kto lubi mówić o swoich porażkach – ja nie jestem w tej kwestii wyjątkiem. Jednak zdecydowałem się wrócić myślami do tego niezbyt miłego doświadczenia i podzielić się z Tobą moimi błędami, które popełniłem podczas szukania pierwszej pracy i w czasie pierwszej rozmowy kwalifikacyjnej.

Mimo iż było to kilkanaście lat temu, gdy to wspominam, jeszcze czuję to niemiłe uczucie zażenowania, rozczarowania i wstydu…
Sam nie wiem, co bardziej bolało? – urażona duma czy to, że czułem się totalnie bezsilny i nie wiedziałem, co dalej zrobić.

Jak to!? Jak oni śmieli mi to zrobić? Nie przyjąć mnie!? PROGRAMISTY? Studenta informatyki?

Cóż miałem robić? Zabrałem swoje zabawki i z podkulonym ogonem wróciłem do domu…

Na moje szczęście nie należę do ludzi, którzy zbyt długo płaczą nad takimi sprawami. Gdy tylko trochę otrzeźwiałem i powoli zacząłem łapać kontakt z rzeczywistością, zacząłem zastanawiać się, co właściwie się stało. I co ważniejsze: dlaczego to się stało.

Przed sobą masz listę 12 głównych błędów, które wtedy popełniłem. Lista ma tylko 12 pozycji, ponieważ nie chciałem Cię zbytnio przytłoczyć i je pogrupowałem…

[SprawnyProgramista_intro][/SprawnyProgramista_intro]

Błąd #1. Nie miałem planu

Pierwszy i podstawowy błąd był taki, że nie miałem żadnego planu na znalezienie pracy.
Byłem do tego stopnia pewny siebie, że uważałem, że zwyczajnie go nie potrzebuję.

Po co? Skoro wszystkie argumenty są po mojej stronie.

  • uczę się już CAŁE dwa lata programowania;
  • studiuję na renomowanej i poważanej uczelni;
  • jestem PROGRAMISTĄ! A świat przecież chce programistów, prawda?

Także bez większego zastanowienia na szybko przygotowałem JAKIEŚ CV.
Następnie, również bez większego zastanowienia, wybrałem JAKIEŚ firmy i wysłałem tam swoje dokumenty.

Może miałem trochę szczęścia, a może zwyczajnie ktoś zaprosił mnie na rozmowę z ciekawości – fakt, że dość szybko umówiłem się na swoją PIERWSZĄ w życiu rozmowę kwalifikacyjną.

Mój plan na tę rozmowę?
A po co mi jakiś plan…

Pierwsza praca – jak ją znaleźć? Jak wygląda proces rekrutacji?

Błąd #2. Nie wiedziałem, do jakiej firmy właściwie aplikuję

Wspomniałem już, że rozesłałem CV do jakichś firm. O ile na etapie wysyłania CV jest to, delikatnie mówiąc, słabe podejście, to już na etapie rozmowy kwalifikacyjnej jest to podejście… jeszcze słabsze.

Z samego ogłoszenia o pracę wywnioskowałem, że firma ma swoją siedzibę „gdzieś” w Gdańsku oraz że szukają programistów PHP.

Po co mi właściwie więcej informacji? 🙂

Niestety nie sprawdziłem nawet podstawowych informacji o tej firmie w Internecie.
Może dowiedziałbym się wtedy:

  • jak pracują;
  • jakie mają projekty;
  • jakie są opinie o tej firmie jako o pracodawcy itp.

Tego typu informacje pomogłyby mi podjąć decyzję, czy w ogóle chcę z nimi współpracować.
Może też uniknąłbym lekko żenujących pytań w stylu: co Wy właściwie robicie?

Poza podstawowymi informacjami, które firma umieszcza na stronie i które można znaleźć w Google, zawsze można poszukać ludzi, którzy już tam pracują. Chwila rozmowy z takimi osobami może okazać się nieoceniona podczas podejmowania decyzji, którą firmę wybrać.

Jak dotrzeć do takich osób?

Mamy chociażby LinkedIn – przy odrobinie chęci w dzisiejszych czasach takie rzeczy nie stanowią już problemu.

Błąd #3. Nie sprawdziłem wymagań na stanowisko, na które aplikowałem

Ogłoszenie o pracę zazwyczaj zawiera opis kandydata idealnego. Nie ma co się zrażać, jeżeli nie pasuje się idealnie do tego wzorca. Mimo wszystko warto jednak do niego dążyć.

Jeszcze przed wysłaniem CV warto je odpowiednio spersonalizować pod takie ogłoszenie. Skoro firma w wymaganiach wymieniła daną technologię lub umiejętność, to możemy założyć, że jest to dla nich ważne. Skoro jest ważne, to podkreślmy to w swoim CV.

Taki prosty zabieg, a można bardzo wiele zyskać. Bardzo często o zaproszeniu na rozmowę decyduje fakt dopasowania CV do tego wyidealizowanego wzorca.

Po zaproszeniu na rozmowę możemy też spodziewać się pytań właśnie o rzeczy wymienione w ogłoszeniu. Proste, prawda? 🙂

Błąd #4. Miałem słabe CV i go nie znałem

Podstawowym zadaniem CV jest oczywiście nakłonienie potencjalnego pracodawcy do zaproszenia Cię na rozmowę kwalifikacyjną.
Jednak DOBRE CV potrafi dużo więcej! Może bardzo Ci pomóc podczas samej rozmowy kwalifikacyjnej.

Wiele rozmów kwalifikacyjnych przeprowadzanych jest zgodnie ze scenariuszem – scenariuszem podyktowanym CV kandydata.
Rekruter chce dowiedzieć się czegoś więcej o Tobie i o Twoim doświadczeniu. Może wymyślać wszystkie pytania od zera lub skorzystać z Twojego CV i poprosić Cię o dopowiedzenie niektórych rzeczy.

Przykładowo:

O widzę, że miałeś praktyki w firmie XYZ. Kojarzysz może Marka? Znam go ze studiów.

Albo:

Widzę, że w projekcie, który realizowałeś, wykorzystywaliście Apache Maven do budowania aplikacji. Jak Ci się podoba to rozwiązanie? Znasz może jakieś warte uwagi alternatywy?

Dzięki takiemu podejściu nie tylko osobie zadającej pytania jest łatwiej, ale i kandydatowi.

O czym jak o czym, ale o własnym doświadczeniu i umiejętnościach powinno Ci się mówić najłatwiej. Dlatego właśnie takie rzeczy trzeba wykuć i wielokrotnie przećwiczyć. Nie ma nic gorszego na rozmowie kwalifikacyjnej niż wyłożyć się na pytaniu o własne doświadczenie…

Ciekawe i dobrze przygotowane CV może być również pretekstem do ciekawej rozmowy i odciągnięcia uwagi od Twoich słabych stron.

Pamiętaj też, że im dłużej odpowiadasz na pytania, na które dobrze znasz odpowiedź, tym mniej czasu zostaje na zadanie pytań, na które możesz nie znać odpowiedzi.

Niestety moje CV było zwyczajnie słabe… niespersonalizowane pod tę konkretną firmę i na pierwszy rzut oka było widać, że to pierwsze CV, jakie przygotowałem w życiu.

CV Programisty

Błąd #5. Nie zadawałem pytań

Właściwie to nie czułem takiej potrzeby i nawet nie wiedziałbym, o co miałbym spytać. To oczywiście jest ogromnym błędem!

Dzięki dobrze przemyślanym pytaniom nie tylko można poprowadzić rozmowę w dogodnym dla siebie kierunku, ale też dowiedzieć się bardzo wielu ciekawych informacji o samej firmie, o projekcie i procesie rekrutacji.
Osoba zadająca odpowiednie pytania w oczach rozmówcy sprawia też wrażenie bardziej kompetentnej i zaangażowanej. Tyle plusów, że aż szkoda rezygnować z tej możliwości.

Trzeba jednak wiedzieć, jakie pytania zadawać.

W tym miejscu przede wszystkim uważałbym na pytania o oczywistości, czyli wszystko to, co w kilka chwil można znaleźć na stronie firmy. Swoją drogą przed rozmową warto zobaczyć, jak wygląda taka strona i zapoznać się z informacjami na niej.

Jeżeli odrobiliśmy wcześniej pracę domową i zdobyliśmy trochę informacji na temat rozmowy, na którą się wybieramy, i dowiedzieliśmy się, kto będzie w niej uczestniczył, to też będzie nam łatwiej.

Jak zdobyć takie informacje?
Zwyczajnie o nie zapytać.

Zazwyczaj nikt nie robi tajemnicy z tego, kto będzie uczestniczył w rozmowie rekrutacyjnej, ani z tego, jakiego typu pytań można się spodziewać (pytania techniczne, HR, o doświadczenie, rozmowa po angielsku itp.).

Jeżeli już wiesz, z kim będziesz rozmawiał, to warto poszukać informacji o takiej osobie. Zawsze lepiej jest poznać swojego wroga przed walką 🙂
Może uda się znaleźć coś ciekawego o tym człowieku. Bardzo często osoby techniczne występują na różnego rodzaju konferencjach lub mają swojego technologicznego konika. Jeżeli znajdziesz takie coś, nawiąż do tego podczas rozmowy, może akurat uda się wywiązać ciekawą rozmowę i zyskać kilka dodatkowych punktów.

Osobiście bardzo lubię zadawać pytania o:

  • firmę, o jej misję – zazwyczaj rekruterzy lubią o tym opowiadać;
  • zespół;
  • wykorzystywane technologie;
  • jak pracują, w jakich metodologiach;
  • z kim ja będę pracował, jeżeli zostanę zatrudniony;
  • jak będą wyglądały moje przykładowe zadania;
  • czy w firmie są nadgodziny, a jeżeli tak, to, jak są rozliczane;
  • czy są wyjazdy służbowe, jeżeli tak, to, jak często, gdzie i na jak długo.

Zadaj przede wszystkim pytania o rzeczy ważne dla Ciebie.

Na koniec rozmowy, szczególnie jeżeli widzę, że dobrze mi poszło, lubię spytać: jakie są kolejne kroki w rekrutacji i kiedy dostanę odpowiedź.
Jeżeli udało się też nawiązać dobrą relację podczas rozmowy, to zdarza mi się spytać bezpośrednio, jak wypadłem w ich oczach.

Błąd #6. Nie sprawdziłem najczęściej występujących pytań rekrutacyjnych

Wiedziałeś, że pytania na większości rozmów kwalifikacyjnych się powtarzają?

Ja nie wiedziałem…

Oczywiście nie wszystkie, bo czasem ludzie starają się być oryginalni, jednak w zdecydowanej większości przypadków znaczną część pytań można przewidzieć już przed samą rozmową.
To nie same pytania są problemem, ale to, jak dobrze na nie odpowiedzieć 🙂

Zazwyczaj rozmowy zaczynają się od spokojnego wprowadzenia, żeby lekko rozluźnić kandydata i wprowadzić go w odpowiedni nastrój.

Czyli coś w stylu:

opowiedz nam trochę o sobie, o swoim doświadczeniu, o projektach, w których pracowałeś itp.

Po takim wprowadzeniu czas na danie główne, czyli pytania weryfikujące Twoje umiejętności techniczne. Często są one połączone z pytaniami o Twoje doświadczenie, czyli np. skoro w projekcie wykorzystywałeś Spring Framework, to rekruter może do tego nawiązać i spytać np. jak zarządzałeś transakcjami lub z jakich typów beanów korzystałeś.

Na koniec zazwyczaj są pytania o Twoje preferencje, o to, w którym kierunku chcesz się rozwijać, o warunki umowy, pensję itp. Jest to również bardzo dobre miejsce na Twoje pytania.
[box]

Jeżeli chcesz zobaczyć więcej przykładowych pytań rekrutacyjnych, dołącz na naszego newslettera i

[/box]

Błąd #7. Nie przećwiczyłem rozmowy

Niestety nikt mi nie powiedział i sam na to nie wpadłem, że umiejętność dobrego pokazania się na rozmowie kwalifikacyjnej to umiejętność jak każda i inna i zwyczajnie można się tego nauczyć.

Jak się tego nauczyć? Przez praktykę!

Rozmowa kwalifikacyjna po angielsku

Większość rzeczy można oczywiście przećwiczyć „na sucho” – do czego swoją drogą gorąco zachęcam. Jednak nic tak nie pobudza człowieka do działania, jak odrobina stresu i możliwość zmierzenia się z prawdziwym przeciwnikiem 🙂

Dlatego po kilku próbnych rozmowach, czy to przed lustrem, czy przed „zaprzyjaźnionym” słuchaczem, warto umówić się na kilka prawdziwych rozmów kwalifikacyjnych.

Nawet jeżeli nie jesteś przekonany, czy chcesz pracować konkretnie w tej firmie, to mimo wszystko warto rozważyć pójście na rozmowę i wykorzystać fakt, że firma chciała zaprosić Cię do siebie i poświęcić swój czas na rozmowę z Tobą. Może akurat dowiesz się tam czegoś na tyle ciekawego, że zmienisz zdanie i podejmiecie współpracę. A może zwyczajnie zdobędziesz jeszcze jedno doświadczenie, dzięki któremu będzie Ci łatwiej w przyszłości.

Teraz, nawet jak nie planuję zmiany pracy, to lubię od czasu do czasu przejść się na taką rozmowę. Jest to świetny sposób, żeby zwyczajnie nie „zardzewieć”. Można też rozeznać się w rynku, w tym, czego oczekują firmy, ale też w tym, co potencjalnie mogą zaoferować. Uważam, że uczestniczenie w rozmowach kwalifikacyjnych jest ważnym elementem bycia etatowcem i nie ma co tego unikać.

Może gdybym wtedy o tym wiedział, nie byłbym tak zdenerwowany, gdy sprawy zaczęły wymykać mi się spod kontroli.

Pierwszy raz mało komu udaje się tak, jakby tego chciał, ale prawda jest taka, że nikt nie powiedział, że Twoja pierwsza rozmowa kwalifikacyjna musi się odbyć w Twojej wymarzonej firmie 🙂

Błąd #8. Brakowało mi umiejętności twardych

Poza tymi wszystkimi brakami, które już opisałem, brakowało mi też tak zwanych umiejętności twardych, czyli zwyczajnie byłem kiepskim programistą.

Ale czego się właściwie spodziewać po kimś, kto dopiero ubiega się o swoją pierwszą pracę jako Junior Developer?

Firmy doskonale zdają sobie z tego sprawę i naprawdę w zdecydowanej większości przypadków, jak już decydują się na zatrudnienie Juniora, to liczą się z tym, że taką osobą będzie się trzeba trochę zaopiekować i pokazać jej co i jak.

Sprawa jednak rozchodzi się często o to, „jak bardzo ktoś jest Juniorem”.

Ja niestety byłem bardzo 🙂

Poniżej znajdziesz wpis, gdzie opowiadam trochę więcej na temat minimalnych umiejętności, jakie trzeba zdobyć, żeby myśleć o pracy jako programista.

➡ ZOBACZ 👉: Co trzeba umieć, żeby dostać pierwszą pracę jako programista?

Błąd #9. Brakowało mi umiejętności miękkich

Brakowało mi nie tylko umiejętności technicznych, ale i umiejętności miękkich.

Nawet jak znasz wszystkie tajniki danej technologii, a zwyczajnie nie można się z Tobą dogadać, to Twoja kandydatura może zostać odrzucona. Zwyczajnie nikt nie lubi pracować z gburami i osobami zadufanymi w sobie.
Programowanie to gra zespołowa!

Może gdybym więcej wtedy wiedział na ten temat i przećwiczył to w praktyce, to zrobiłbym lepsze pierwsze wrażenie. Może też nie przybrałbym postawy przegranego, gdy grunt zaczął palić mi się pod nogami.

Nie wszystkie rzeczy jesteśmy w stanie zmienić. Mało komu udaje się zmienić swój charakter. Dlatego właśnie firmy przywiązują tak dużą wagę do kompetencji miękkich danej osoby.
Wychodzą z dość słusznego założenia, że łatwiej będzie nauczyć kogoś nowej technologii, niż sprawić, by zmienił swoje podejście do życia i do pracy.

Całe szczęście nie jesteśmy tutaj na całkowicie straconej pozycji i na wiele rzeczy mamy wpływ.
Jeżeli chcesz zobaczyć, na co jeszcze zwracają uwagę firmy, to przeczytaj ten wpis:

Umiejętności i kompetencje miękkie – soft skills

Błąd #10. Nie miałem planu B

Wspomniałem już, że nie miałem planu A. Niestety planu B tym bardziej.

Umówiłem się tylko na jedną rozmowę i założyłem, że jakoś to będzie. No i było jakoś – zostałem odrzucony.

O ile jestem zdania, że na bardzo wiele spraw mamy wpływ, to niestety nie na wszystko. W życiu wiele rzeczy może się zdarzyć, wiele może się nie udać i to niekoniecznie z naszej winy. Nawet gdybym był wtedy najlepiej przygotowany do tej rozmowy, to przecież mogliby wybrać innego kandydata lub sama firma czy projekt mógłby okazać się totalną klapą i ja nie chciałbym z nimi współpracować.

Dzisiaj w tak ważnych dla mnie i dla mojej rodziny sprawach staram się mieć nie nie tylko plan B, ale również C, a czasem i D.

Czy to przesada? Niekoniecznie.
To normalne, że bierze się udział w kilku rekrutacjach jednocześnie. Nie ma w tym nic złego ani dziwnego.
Firmy też na rozmowę kwalifikacyjną zapraszają więcej kandydatów, a nie tylko Ciebie.

Każdy musi zadbać o swoje interesy. Jeżeli Ty sam tego nie zrobisz, to nie licz, że ktoś zrobi to za Ciebie.

Błąd #11. Szukałem pracy pod presją czasu

Praca pod presją czasu

Był to dość ciekawy okres w moim życiu – pełen licznych niespodzianek 🙂
Po drugim roku studiów wziąłem roczny urlop dziekański, żeby wyjechać do pracy za granicę. Wyjazd ostatecznie nie doszedł do skutku, a ja za to zostałem: bez pracy, bez kasy i bez pomysłu na życie, ale za to z dużą ilością wolnego czasu.

Taka sytuacja nie była dla mnie zbyt komfortowa. Dużo przyjemniej szuka się pracy, gdy mamy zapewnioną ciepłą i pewną posadę. Wtedy, gdy coś pójdzie nie tak, zawsze możemy wrócić w bezpieczne miejsce i nic nie zmieniać.

Dlatego gorąco zachęcam do szukania pracy, gdy jest na to jeszcze czas, a nie gdy musisz zrobić to już teraz! Wtedy to Ty dyktujesz warunki, a nie godzisz się na to, co akurat wpadło i ktoś łaskawie Ci to zaoferował.

Błąd #12. Nie byłem na miejscu

Może nie jest  to decydujący czynnik, ale z pewnością nie ułatwił mi podjęcia pracy.

Cały proces rekrutacji chciałem załatwić zdalnie i przyjechać tylko na samą rozmowę kwalifikacyjną. Było to o tyle problematyczne, że na dojazd na miejsce potrzebowałem 5-6 godzin lub więcej, jeżeli nie było akurat autobusu. W takiej sytuacji trudniej o umówienie się na większą ilość rozmów i o dynamiczne decyzje, np. o zmianie godziny rozmowy. Szczególnie że już przed samą rozmową kwalifikacyjną miałem kupiony bilet powrotny.

Co teraz?

Skąd wziął się pomysł, by zostać programistą?

Jeżeli zastanawiasz się, co teraz,
to przede wszystkim nie popełniaj tych samych błędów co ja! Niestety nie mogę cofnąć się w czasie, palnąć się w łeb i kazać się bardziej ogarnąć. To, co jednak mogę, to wyciągnąć wnioski na przyszłość i więcej nie popełniać tych samych błędów.

Od mojej pierwszej rozmowy kwalifikacyjnej minęło już sporo czasu i wiele się zmieniło w moich umiejętnościach i w moim podejściu do wielu spraw.

Dziś częściej zdarza mi się być po drugiej stronie stołu i samemu zadawać pytania, niż uczestniczyć w rekrutacji jako kandydat. Zdecydowanie otwiera to oczy na wiele różnych spraw.

Jeżeli jesteś w podobnej sytuacji, jak ja byłem, to na koniec mam dla Ciebie jeszcze pozytywną wiadomość.
Dosyć szybko, bo już niecałe cztery miesiące po tych wydarzeniach, dostałem swoją pierwszą pracę!
Jeszcze nie umiałem WSZYSTKIEGO, ale umiałem już zdecydowanie więcej i – co bardzo ważne – nie popełniałem drugi raz tak wielu podstawowych błędów.

Ze swojej strony życzę Ci powodzenia  i wytrwałości przy szukaniu pierwszej pracy – obie te cechy mogą się bardzo przydać 🙂

Jeżeli natomiast uważasz, że dużo tego wszystkiego i nie warto tak się starać, to zastanów się, o co toczy się ta gra. Dla niektórych nagrodą może być dostanie pierwszej pracy, która pozwoli się utrzymać, dla kogoś innego zmiana pracy i przejście do dużo ciekawszego projektu za dużo lepsze pieniądze.
Sam musisz sobie odpowiedzieć, czy warto jest się o to tak starać. Decyzja należy do Ciebie.

Ze swojej strony jeszcze raz życzę Ci powodzenia i jeżeli uznasz, że to, co napisałem, było dla Ciebie wartościowe, to, proszę, podziel się tym wpisem ze znajomymi, może im też to pomoże. Jeżeli masz jeszcze jakieś pytania lub zwyczajnie chcesz pochwalić się swoją pierwszą pracą, daj mi o tym znać.

Dodatkowe materiały:

 

Chcesz przygotować fantastyczne CV i zabłysnąć na rozmowie kwalifikacyjnej? Sprawdź  najnowsze e-booki:

CV Programisty oraz Rozmowa kwalifikacyjna Programisty

No comments
Share:
Kolejka –¸FIFO

Kolejka (Queue) – samouczek, FIFO krok po kroku

Wiesz, że kolejka (Queue) jest jedną z częściej wykorzystywanych struktur danych w Javie? – I co kryje się pod akronimem FIFO? Dzięki temu materiałowi dowiesz się jak krok po kroku wykorzystać kolejkę do budowania własnej aplikacji oraz jak samodzielnie zaimplementować FIFO.

Witaj w drugiej części wpisu na temat struktur danych: FIFO oraz LIFO. W dzisiejszej odcinku zajmiemy się szczegółowo kolejką (ang. queue) oraz akronimem FIFO.
Jeżeli jednak nie czytałeś jeszcze pierwszej części, to gorąco zachęcam do zapoznania się z nią w pierwszej kolejności: ➡ Stos (Stack) – 7+ tajników implementacji LIFO.

Zapraszam do lektury.

[SprawnyProgramista_intro]

Z tej serii dowiesz się:

  • co to jest LIFO, FIFO, HIFO, FEFO, FINO oraz FISH; 🙂
  • co to jest i jak działa stos (ang. stack);
  • jak działa kolejka (ang. queue) oraz kolejka priorytetowa (ang. priority queue);
  • jak samodzielnie zaimplementować takie struktury danych;
  • oraz jak korzystać z gotowych rozwiązań.

Kolejka (ang. queue)

Gdy myślę o kolejce, nasuwa mi się przede wszystkim skojarzenie z kolejką ludzi czekających do kasy w sklepie lub też ze sznurem samochodów stojących w korku na drodze jednopasmowej.

W kontekście informatyki jest to jak najbardziej trafna analogia. Kolejkę danych rozumiemy jako ciąg elementów ułożonych jeden za drugim, który charakteryzuje się przede wszystkim tym, że zachowana jest konkretna kolejność przechowywania tych elementów.

Kolejka zazwyczaj porządkuje elementy zgodnie z zasadą FIFO. Wyjątek od tej reguły stanowi kolejka priorytetowa, ale do tego jeszcze wrócimy.

Kolejka, queue, fifo

FIFO (ang. First In, First Out)

Wszystkie elementy w kolejce – czy to w kolejce danych, czy w kolejce osób w sklepie zwyczajowo zachowują się zgodnie z FIFO (ang. First In, First Out) – czyli w dosłownym tłumaczeniu: pierwszy na wejściu, pierwszy na wyjściu. Pomijamy na chwilę przypadek z przepychankami kolejkowymi, zakładamy, że każdy będzie grzecznie stał i czekał na swoją kolej.

Dzięki takiemu przechowywaniu elementów mamy pewność, że natłok nowych elementów nie spowoduje niejako zagłodzenia elementów już znajdujących się w kolejce od pewnego czasu, jak mogłoby to mieć miejsce w przypadku stosu. Musimy się jednak liczyć z możliwością, że w procesie dodawania bardzo wielu elementów do kolejki i wolnego ich przetwarzania, czyli zdejmowania ich z kolejki, czas oczekiwania w naszej kolejce bardzo się wydłuży.

LIFO vs FIFO

Stos – LIFO

Stos – LIFO

Przeciwieństwem omawianej tu kolejki i organizacji elementów zgodnie z FIFO
jest stos z elementami ułożonymi wg zasady LIFO (ang. Last In, First Out) – czyli ostatni na wejściu, pierwszy na wyjściu.

Więcej na ten temat będziesz mógł przeczytać w pierwszej części wpisu:
Stos (Stack) – 7+ tajników implementacji LIFO

FIFO i kolejka w informatyce

Kolejka Queue – FIFO

Struktury danych oparte o FIFO bardzo chętnie wykorzystywane są w informatyce przede wszystkim do przechowywania danych lub jako systemy planowania zadań.

Omówimy sobie teraz główne koncepcje związane z wykorzystywaniem kolejki.

Głowa kolejki (ang. queue head or front)

Zacznijmy od pojęcia głowy (ang. head) kolejki – jest to wskaźnik określający, w którym miejscu znajduje się najstarszy/pierwszy element kolejki.

Niektóre z operacji wykonywanych na kolejce, takie jak np. pobranie pierwszego elementu (ang. poll) czy podejrzenie pierwszego elementu (ang. peek), będą właśnie korzystały z tego wskaźnika.

Ogon kolejki (ang. queue tail)

Ogonem kolejki (ang. queue tail) zwyczajowo nazywamy wskaźnik wskazujący na ostatni element w kolejce. Operacja korzystająca z tego wskaźnika to dodanie nowego elementu na końcu kolejki (ang. queue offer or insert).

Dodanie elementu do kolejki (ang. queue offer or insert)

Korzystając z metody offer, nowo dodane elementy domyślnie lądują na końcu kolejki i wskazuje na nie wskaźnik tail. W przypadku, gdy w kolejce będzie tylko jeden element, oba wskaźniki head i tail będą wskazywały na ten sam obiekt.

Wyjście z kolejki (ang. queue poll or remove)

Metoda poll pobiera pierwszy element z kolejki i go z niej zdejmuje. Wskaźnik head będzie teraz wskazywał na element, który był drugi lub na wartość pustą NULL, jeżeli nie ma więcej elementów.

Podejrzenie pierwszego elementu kolejki (ang. queue peek or element)

Metoda peek zwraca pierwszy element z kolejki, czyli ten wskazywany przez head, ale – w przeciwieństwie do metody poll – jej nie modyfikuje.

Kolejka w Javie (ang. Queue Java)

Przyjrzyjmy się teraz bliżej, co Java oferuje nam w kontekście kolejek.

Zamieszczone poniżej fragmenty kodu napisano w Javie, jednak przykłady są na tyle uniwersalne, że nie powinno być problemu z odniesieniem ich do innych języków programowania.

Do dyspozycji mamy przede wszystkim interfejs: java.util.Queue oraz rozszerzające go subinterfejsy: java.util.concurrent.BlockingDeque, java.util.concurrent.TransferQueue i java.util.Deque.

Wszystkie te interfejsy i ich różne implementacje wykorzystywane są do obsługi większości kolejek w Javie. Przyjrzyjmy się teraz im trochę dokładniej.

AbstractQueue

java.util.AbstractQueue to najprostsza dostępna implementacja. Nie jest to jeszcze pełnoprawna kolejka i stanowi jedynie szkielet dla konkretnych implementacji.

Kolejki blokujące (ang. blocking queues)

java.util.concurrent.BlockingQueue obsługuje dodatkowe metody wspierające blokowanie operacji, np. poczekanie i przytrzymanie logiki pobierania elementu z kolejki, jeżeli jeszcze nic w niej nie ma.

Jeżeli chodzi o implementacje, to możemy skorzystać z java.util.concurrent.LinkedBlockingQueue, java.util.concurrent.SynchronousQueue i java.util.concurrent.ArrayBlockingQueue.

BlockingQueue

BlockingQueue

Prześledźmy to na przykładzie poniższego kodu:

BlockingQueue<String> blockingQueue = new ArrayBlockingQueue<>(10);

try {
	new Thread(() -> {
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

		blockingQueue.offer("Hello from another thread.");
	}).start();

	System.out.println(blockingQueue.poll());

	System.out.println(blockingQueue.poll(5, TimeUnit.SECONDS));
} catch (InterruptedException e) {
	e.printStackTrace();
}
  • tworzymy blokującą kolejkę o pojemności 10 elementów: BlockingQueue blockingQueue = new ArrayBlockingQueue<>(10);
  • tworzymy i uruchamiamy nowy wątek, który czeka sekundę i dodaje nowy element do kolejki;
  • wywołujemy standardową metodę: blockingQueue.poll(), która zwraca NULL, ponieważ kolejka jest jeszcze pusta;
  • natomiast wywołanie metody: blockingQueue.poll(5, TimeUnit.SECONDS) poczeka maksymalnie 5 sekund, aż coś pojawi się w kolejce i pobierze ten element – w naszym wypadku po około jednej sekundzie drugi wątek uzupełni kolejkę, przez co metoda poll będzie mogła go pobrać.

Kolejki a wielowątkowość (ang. Thread Safety)

W przypadku aplikacji wielowątkowych warto zainteresować się dedykowanymi implementacjami, takimi jak: java.util.concurrent.ConcurrentLinkedDeque, java.util.concurrent.ConcurrentLinkedQueue, czy java.util.concurrent.ArrayBlockingQueue.

Deque

Deque to skrót od ang. Double-Ended Queue – czyli podwójnie zakończona kolejka. W tym wypadku możemy dodawać i usuwać elementy zarówno z początku, jak i z końca takiej kolejki.

W Javie do obsługi Deque mamy interfejs java.util.Deque oraz między innymi implementacje: java.util.ArrayDeque i java.util.LinkedList.

Kolejka priorytetowa (ang. priority queue)

Kolejka priorytetowa łamie już zasady FIFO. W tym wypadku o tym, który element zostanie pobrany jako pierwszy, nie decyduje już to, kiedy został dodany, ale jego waga – ważność.

Możesz to sobie wyobrazić jako standardową kolejkę np. przy wsiadaniu do samolotu – wszyscy czekają, jeden za drugim, aż tu nagle przychodzi VIP z wykupionym specjalnym pakietem członkowskim i ładuje się na sam początek kolejki.

Sprawa trochę bardziej się komplikuje, gdy mamy więcej osób/elementów w kolejce z różnymi wagami – wtedy poszczególne elementy w kolejce są układane właśnie według ich wagi.

HIFO (ang. Highest In, First Out)

Kolejka priorytetowa bywa nazywana również HIFO (ang. Highest In, First Out) – czyli najwyższe/najdroższe elementy będą przetwarzane jako pierwsze.

Elementy dodawane do java.util.PriorityQueue domyślne układane są według ich naturalnej kolejności, czyli np. dla liczb całkowitych zostaną one posortowane wg wielkości. Natomiast dla ciągów znaków byłaby to kolejność alfabetyczna.

// given
PriorityQueue<Integer> queue = new PriorityQueue<>();

queue.offer(1);
queue.offer(10);
queue.offer(2);
queue.offer(20);
queue.offer(3);
queue.offer(30);

// when
List<Integer> list = new ArrayList<>();

while (!queue.isEmpty()) {
	list.add(queue.poll());
}

// then
assertThat(list).containsExactly(1, 2, 3, 10, 20, 30);

Comparator i Comparable

Na to domyślne zachowanie też możemy wpłynąć. Jeżeli elementy przechowywane w kolejce będą implementowały interfejs: java.lang.Comparable, jak ma to miejsce w przypadku klas String i Integer, to zostaną one ułożone zgodnie z implementacją metody: java.lang.Comparable#compareTo.

Możemy jednak nadpisać to zachowanie i – tworząc kolejkę – jako argument przekazać komparator (obiekt implementujacy: java.util.Comparator), który zdecyduje, w jakiej kolejności mają zostać ułożone elementy.

// given
Comparator<String> comparator = (o1, o2) -> {
	int length1 = o1.length();
	int length2 = o2.length();

	if (length1 == length2) {
		return o1.compareTo(o2);
	}

	return length1 - length2;
};

PriorityQueue<String> queue = new PriorityQueue<>(comparator);

queue.offer("a");
queue.offer("c");
queue.offer("cc");
queue.offer("ccc");
queue.offer("C");
queue.offer("aa");

// when
List<String> list = new ArrayList<>();

while (!queue.isEmpty()) {
	list.add(queue.poll());
}

// then
assertThat(list).containsExactly("C", "a", "c", "aa", "cc", "ccc");

W naszym przykładzie elementy w kolejce przechowującej ciągi znaków zostaną ułożone według ich długości.

Kolejki Java – przykłady (ang. examples)

1. Utworzenie kolejki

Queue<Integer> queue = new ArrayDeque<>();

2. Dodanie nowego elementu do kolejki (ang. queue offer)

queue.offer(1);
queue.add(2);

Obie metody różnią się tylko raportowaniem ewentualnych problemów podczas dodawania nowego elementu:

  • offer – w przypadku niewystarczającej ilości miejsca zwróci false, natomiast:
  • add – zwróci wyjątek: IllegalStateException.

3. Zdjęcie z kolejki pierwszego elementu (ang. queue poll)

Integer poll1 = queue.poll();
Integer remove1 = queue.remove();

Te dwie metody też różnią się tylko raportowaniem błędów:

  • poll – zwróci wartość pustą NULL, jeżeli kolejka będzie pusta, natomiast:
  • remove – zwróci wyjątek: NoSuchElementException.

4. Pobranie pierwszego elementu bez modyfikacji kolejki (ang. queue peek)

Integer peek1 = queue.peek();
Integer element1 = queue.element();

I w przypadku tej operacji mamy do dyspozycji dwie metody różniące się tylko nieznacznie:

  • peek – zwróci NULL w przypadku pustej kolejki, natomiast:
  • element – zwróci wyjątek: NoSuchElementException.

5. Przeglądanie kolejki i wyświetlenie elementów (ang. queue iterate)

Elementy w kolejce możemy przeglądać na kilka różnych sposobów, np. korzystając ze wbudowanego iteratora: queue.iterator().

Iterator<Integer> it = queue.iterator();
while (it.hasNext()) {
	Integer item = it.next();
	System.out.println(item);
}

Alternatywnie można skorzystać z pętli while oraz metody poll – jak w drugim przykładzie.

while (!queue.isEmpty()) {
	Integer item = queue.poll();
	System.out.println(item);
}

6. Korzystanie z kolejki przy pomocy strumieni i wyrażeń lambda (ang. queue java stream)

Nic nie stoi na przeszkodzie, żeby z kolejki korzystać przy pomocy strumieni i wyrażeń lambda.
Najpierw pobieramy strumień, korzystając z metody: stream(), i wykonujemy niezbędne operacje.

Poniżej kilka przykładów.

  • Wyświetlenie wszystkich elementów na standardowe wyjście.
Queue<Integer> queue = new ArrayDeque<>();
queue.offer(1);
queue.offer(2);
queue.offer(3);
queue.offer(4);

queue.stream().forEach(System.out::print);
  • Zamiana kolejki na listę.
List<Integer> list = queue.stream().collect(Collectors.toList());
System.out.println(list);
  • Usunięcie wybranych elementów.
queue.removeIf(element -> element > 3);
  • Zamiana kolejki na tablicę.
int[] intArray = queue.stream()
		.mapToInt(element -> element)
		.toArray();

System.out.println(Arrays.toString(intArray));

Kolejka w innych językach programowania (PHP, Python, C++)

PHP

Ds\Queue implements Ds\Collection {
/* Constants */
const int MIN_CAPACITY = 8 ;
/* Methods */
public allocate ( int $capacity ) : void
public capacity ( void ) : int
public clear ( void ) : void
public copy ( void ) : Ds\Queue
public isEmpty ( void ) : bool
public peek ( void ) : mixed
public pop ( void ) : mixed
public push ([ mixed $...values ] ) : void
public toArray ( void ) : array
}

Źródło: The Queue class

Python

https://docs.python.org/3/library/queue.html

tw@tw:~$ python
Python 2.7.15+ (default, Oct  7 2019, 17:39:04) 
[GCC 7.4.0] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import Queue
>>> 
>>> queue = Queue.Queue()
>>> 
>>> for i in range(3):
...     queue.put(i)
... 
>>> while not queue.empty():
...     print queue.get()
... 
0
1
2
>>> 

C/C++

// queue::push/pop
#include <iostream>       // std::cin, std::cout
#include <queue>          // std::queue

int main ()
{
  std::queue<int> myqueue;
  int myint;

  std::cout << "Please enter some integers (enter 0 to end):\n";

  do {
    std::cin >> myint;
    myqueue.push (myint);
  } while (myint);

  std::cout << "myqueue contains: ";
  while (!myqueue.empty())
  {
    std::cout << ' ' << myqueue.front();
    myqueue.pop();
  }
  std::cout << '\n';

  return 0;
}

Źródło

Samodzielna implementacja FIFO (ang. Queue)

W celu utrwalenia omawianych tu zagadnień spróbujemy teraz samodzielnie zaimplementować standardową kolejkę typu FIFO.

Najczęściej możemy spotkać się z dwiema różnymi implementacjami kolejki:

  • Array queue – bazującej na tablicy oraz
  • Linked queue – wykorzystującej listę wskaźnikową.

W naszych rozważaniach zaimplementujemy kolejkę opartą na tablicy.

Przerobienie tych przykładów nie jest konieczne do zrozumienia omawianych tu pojęć i w zdecydowanej większości przypadków dużo lepszym wyjściem jest skorzystanie z gotowych już klas implementujących kolejkę, takich jak java.util.ArrayDeque czy java.util.LinkedList.
Mimo wszystko zachęcam do ich przejrzenia i samodzielnej próby implementacji – jest to świetny sposób na utrwalenie wiedzy w praktyce i pełniejsze zrozumienie tematu.

Interfejs stosu i główne wymagania

Nasza kolejka powinna implementować wszystkie podstawowe metody, takie jak: peekpulloffer i size. Zanim jednak przejdziemy do samej implementacji, zacznijmy od zdefiniowania interfejsu – czyli określmy, co właściwie będzie robiła nasza kolejka.

Na tym etapie jeszcze nie określamy, jak będzie to realizowane – tym zajmiemy się podczas implementacji.

public interface Queue<T> {

	void offer(T element);

	T poll();

	T peek();

	int size();
}

Wewnętrzna tablica przechowująca elementy

Elementy w naszej kolejce przechowamy w tablicy, dzięki czemu będziemy mieć prawie za darmo zapewnioną ich kolejność.

Nie musimy też przejmować się takimi wskaźnikami, jak head czy tail, jak miałoby to miejsce w przypadku implementacji z listą wskaźnikową.

public class ArrayQueue<T> implements Queue<T> {

	private Object[] array = new Object[MAX_SIZE];

Ponieważ tablice mają stały rozmiar, musimy określić maksymalną ilość przechowywanych elementów.

Tablica będzie przechowywała referencje typu Object, jednak później będziemy je rzutować na konkretne klasy.

Rozmiar (ang. queue size) i pojemność (ang. queue capacity) kolejki 

private final int MAX_SIZE = 10; 
private int size = 0;

Żeby za każdym razem nie liczyć wszystkich elementów, które są w kolejce, do przechowania rozmiaru wykorzystamy wewnętrzną zmienną.

Natomiast maksymalna pojemność kolejki została pobrana ze stałej.

Dodanie elementu do kolejki (ang. offer)

Dodawanie nowego elementu do kolejki musimy zacząć od sprawdzenia, czy mamy jeszcze wolne miejsce. Jeżeli nie ma już miejsca, to odpowiednio to komunikujemy wyjątkiem, jak w przykładzie lub np. zwracając z metody FALSE.
Następnie wstawiamy element na ostatnim miejscu w tablicy i inkrementujemy licznik, który jest jednocześnie ilością przechowywanych elementów w tablicy.

@Override
public void offer(T value) {
	if (size == MAX_SIZE) {
		throw new IllegalArgumentException(String.format("Maximum stack size: %s has been reached.", MAX_SIZE));
	}

	array[size++] = value;
}

Zdjęcie elementu z kolejki (ang. poll)

W metodzie poll zaczynamy od sprawdzenia, czy są już jakieś elementy w kolejce i jeżeli ich nie ma, to trzeba zwrócić użytkownikowi odpowiednią informację. Możemy to zrobić, jak w przykładzie, zwracając NULL lub rzucić wyjątek.

W kolejnych krokach:

  • pobieramy pierwszy element z tablicy;
  • dekrementujemy licznik, a zarazem zmienną przechowującą rozmiar tablicy;
  • przesuwamy wszystkie pozostałe elementy w tablicy o jedną pozycję do przodu;
  • czyścimy ostatnie, już niewykorzystywane, miejsce w tablicy;
  • i zwracamy wynik.
@Override
public T poll() {
	if (size <= 0) {
		return null;
	}

	T value = (T) array[0];

	size--;

	System.arraycopy(array, 1, array, 0, size);
	array[size] = null;

	return value;
}

Przyjrzyjmy się trochę dokładniej, jak wygląda takie przesunięcie elementów w tablicy. Komenda: System.arraycopy(array, 1, array, 0, size);  skopiuje dotychczasowe elementy i wklei je, przesuwając o jedną pozycję w lewo.

A B C NULL

Jednak ostatni element będzie znajdował się w dwóch miejscach – w nowym, przesuniętym, oraz na swojej starej pozycji, dlatego musimy go wyczyścić kolejną komendą: array[size] = null; .

B C C NULL

Po tych operacjach tablica powinna zawierać następujące elementy:

B C NULL NULL

Podejrzenie elementu znajdującego się na początku kolejki (ang. peek)

Podobnie jak w przypadku metody poll, sprawdzamy, czy mamy jakieś elementy w kolejce. Jeżeli mamy, to zwracamy pierwszy z nich – znajdujący się pod indeksem 0  w tablicy.

@Override
public T peek() {
	if (size <= 0) {
		return null;
	}

	return (T) array[0];
}

Pełna implementacja

public class ArrayQueue<T> implements Queue<T> {

	private final int MAX_SIZE = 10;
	private int size = 0;
	private Object[] array = new Object[MAX_SIZE];

	@Override
	public T peek() {
		if (size <= 0) {
			return null;
		}

		return (T) array[0];
	}

	@Override
	public T poll() {
		if (size <= 0) {
			return null;
		}

		T value = (T) array[0];

		size--;

		System.arraycopy(array, 1, array, 0, size);
		array[size] = null;

		return value;
	}

	@Override
	public void offer(T value) {
		if (size == MAX_SIZE) {
			throw new IllegalArgumentException(String.format("Maximum stack size: %s has been reached.", MAX_SIZE));
		}

		array[size++] = value;
	}

	@Override
	public int size() {
		return size;
	}
}

Kolejka, queue, FIFO – zadania do samodzielnego rozwiązania

Jeżeli ciągle szukasz wyzwań i chcesz poćwiczyć zadania z wykorzystaniem kolejki – poniżej masz kilka inspiracji.

  • implementacja kolejki z listą wskaźnikową;
  • implementacja Deque – listy z możliwością dodawania elementów na początku i na końcu.

Rozwiązania zadań i inne przykłady kodu znajdziesz na repozytorium github.

Wynikami swojej pracy możesz jak zawsze podzielić się na grupie.

Kolejka, queue, FIFO – podsumowanie

To już koniec serii na temat FIFO i LIFO. Jestem przekonany, że jeżeli udało Ci się przerobić przynajmniej połowę pokazanych tu przykładów, to kolejki i stosy nie będą stanowiły dla Ciebie już żadnego problemu 🙂

Dodatkowe materiały:

 

kierunek java

No comments
Share:
Stos – LIFO

Stos (Stack) – 7+ tajników implementacji LIFO

W tym wpisie pokażę Ci, jak twórcy Javy zaimplementowali takie struktury danych, jak FIFOLIFO oraz zdradzę, jak możesz zrobić to samodzielnie.
Następnie przekonam Cię, że wcale nie warto tego robić ręcznie i lepiej skorzystać z ich pracy.
Zapraszam  do lektury.

[SprawnyProgramista_intro]

Z tej serii dowiesz się:

  • co to jest LIFO, FIFO, HIFO, FEFO, FINO oraz FISH; 🙂
  • co to jest i jak działa stos (ang. stack);
  • jak działa kolejka (ang. queue) oraz kolejka priorytetowa (ang. priority queue);
  • jak samodzielnie zaimplementować takie struktury danych;
  • oraz jak korzystać z gotowych rozwiązań.

Stos (ang. Stack)

Programiści bardzo chętnie czerpią z doświadczeń życia codziennego – podobnie jest i w tym wypadku.

Zastanów się – z czym kojarzy Ci się pojęcie stos?

Może to być: stos książek, stos talerzy do zmywania, stos drewna do palenia itp.

Jest to zwyczajnie kilka rzeczy ułożonych jedna na drugiej. Dokładnie tak samo jest w informatyce – stos danych rozumiemy jako zbiór elementów „ułożonych jeden na drugim”.

Jak w takim razie dostać się do poszczególnych elementów w takim stosie?

Wyobraź sobie, że leży przed tobą stos książek ułożonych jedna na drugiej.
Spróbuj teraz wziąć książkę, która znajduje się na samym szczycie tego stosu – będzie to dość łatwe. Prawda?

Teraz zróbmy coś trudniejszego.
Postaraj się wziąć książkę, która jest w środku tego stosu lub na jego samym spodzie.

Co musisz zrobić?
Zakładamy, że nie chcesz mieć porozrzucanych książek po całym pokoju, dlatego najrozsądniej byłoby zdejmować od góry kolejne książki i odkładać je na bok tak długo, aż znajdziesz swoją wybraną książkę.

Taki typ kolejkowaniu elementów nazywamy: LIFO.

LIFO (ang. Last In, First Out)

Wszystkie elementy w stosie ułożone są zgodnie z zasadą LIFO.

LIFO (ang. Last In, First Out) – w dosłownym tłumaczeniu oznacza: ostatnie przyszło, pierwsze wyszło.

Metoda LIFO w kontekście obsługi magazynów nazywana jest również metodą najpóźniejszej dostawy – jako pierwsze zostaną wydane elementy/produkty, które najkrócej były przechowywane.

Wracając do naszego przykładu ze stosem książek.
Żeby wyjąć książkę, która jest na samym dole stosu, musisz zdjąć z niego kolejno wszystkie książki – poczynając od tych na samej górze.

Przez takie ułożenie danych w stosie:

  • łatwo jest zdjąć z niego elementy z samego wierzchu;
  • jeżeli natomiast chcemy pobrać elementy znajdujące się niżej, to musimy przejść przez wszystkie te, które są nad nim.

LIFO vs FIFO

Przeciwieństwem do omawianego tu stosu i organizacji elementów zgodnie z LIFO
jest kolejka z elementami ułożonymi wg zasady FIFO (ang. First In, First Out) – czyli pierwszy na wejściu, pierwszy na wyjściu.

Więcej na ten temat będziesz mógł przeczytać w drugiej części tego wpisu:
Kolejka (Queue) – jak samodzielnie zaimplementować FIFO?

LIFO i stos w informatyce

Bufory w formie stosu LIFO bardzo chętnie wykorzystywane są w informatyce do przechowywania danych lub jako system planowania zadań.

Omówimy sobie teraz główne koncepcje związane z wykorzystywaniem stosu.

Głowa (ang. head)

Zacznijmy od pojęcia głowy (ang. head) stosu – jest to wskaźnik określający, w którym miejscu znajduje się najnowszy/pierwszy element stosu.

Poszczególne operacje, które możemy na nim wykonać, takie jak dodanie elementu do stosu  (ang. push), podejrzenie pierwszego elementu (ang. peek), czy jego pobranie (ang. pop), zawsze operują właśnie na tym wskaźniku.

Stos push (ang. stack push)

Metoda stos push (ang. stack push) polega na dodaniu nowego elementu – „kładziemy” nowy element na wierzchu stosu i od teraz wskaźnik head wskazuje właśnie na ten element.

Stos push (ang. stack push)

Stos push (ang. stack push)

Stos pop (ang. stack pop)

Metoda stos pop (ang. stack pop) zwraca pierwszy element ze stosu, jednocześnie go zdejmując – czyli bierzemy jedną rzecz z samej góry stosu i ją zabieramy. Przez co, po wykonaniu tej metody, wskaźnik head wskazuje na element, który był niżej w stosie lub – jeżeli nie mamy już elementów – to head = null.

Stos pop

Stos peek (ang. stack peek)

Metoda stos peek (ang. stack peek) działa podobnie jak stos pop, zwracając pierwsze element ze stosu, jednak nie modyfikuje zawartości samego stosu. Można ją wykorzystać np. do podejrzenia, jaki element jest na wierzchu naszej struktury danych.

Stos w Javie (ang. Stack Java)

Przyjrzyjmy się teraz bliżej, co Java oferuje nam w kontekście tych struktur danych.

Zamieszczone poniżej fragmenty kodu napisane są w Javie, jednak przykłady są na tyle uniwersalne, że nie powinno być problemu z odniesieniem ich do innych języków programowania.

W Javie mamy do dyspozycji kilka klas implementujących stos i LIFO.
Zaczniemy od java.util.Stack, który jest klasyczną strukturą danych dziedziczącą po java.util.Vector, a co za tym idzie – implementującą między innymi java.util.List.

Przy jej pomocy możemy wykonać wszystkie podstawowe operacje: push, pop i peek.

1. Utworzenie stosu

Stack stack = new Stack();

lub wersja ze wsparciem dla typów generycznych:

Stack<String> stack = new Stack<String>();

2. Dodawanie nowego elementu (ang. stack push)

stack.push("1");

3. Zdjęcie ze stosu pierwszego elementu (ang. stack pop)

String pop = stack.pop();

4. Pobranie pierwszego elementu bez modyfikacji stosu (ang. stack peek)

String peek = stack.peek();

5. Przeszukiwanie stosu (ang. stack search)

Stack<String> stack = new Stack<String>();
stack.push("1");
stack.push("2");
stack.push("3");
stack.push("4");

// when
int search1 = stack.search("2");    // 3
int search2 = stack.search("0");    // -1

Metoda search zwraca pozycję danego elementu na stosie lub -1, jeżeli nie znajdzie takiego elementu.

UWAGA: Pozycje numerowane są od 1, czyli obiekt, który znajduje się na samej górze stosu, ma numer 1, kolejny 2 i tak dalej.

6. Przeszukiwanie stosu – indeks elementu

Do przeszukiwania stosu możemy również wykorzystać metodę: public int indexOf(Object o) .

UWAGA: W tym wypadku jednak elementy będą numerowane od 0 i zaczynamy liczyć od elementu, który jest na samym dole stosu 🙂

int indexOf1 = stack.indexOf("2");    // 1
int idnexOf2 = stack.indexOf("0");    // -1

7. Przeglądanie stosu (ang. stack iterate)

Elementy na stosie możemy przeglądać na kilka różnych sposobów, np. korzystając ze wbudowanego iteratora: stack.iterator().
W tej sytuacji należy jednak pamiętać, że elementy będą zwracane w kolejności od tego na samym spodzie stosu!

Stack<String> stack = new Stack<String>();
stack.push("A");
stack.push("B");
stack.push("C");

Iterator<String> it = stack.iterator();
while (it.hasNext()) {
	String item = it.next();
	System.out.println(item);
}

Alternatywnie można skorzystać z pętli while oraz metody pop – jak w drugim przykładzie.

while (!stack.isEmpty()) {
	String item = stack.pop();
	System.out.println(item);
}

8. Korzystanie ze stosu przy pomocy strumieni i wyrażeń lambda (ang. stack java stream)

Nic nie stoi na przeszkodzie, żeby ze stosu korzystać przy pomocy strumieni i wyrażeń lambda.
Najpierw pobieramy strumień, korzystając z metody: stream(), i wykonujemy niezbędne operacje.

Poniżej kilka przykładów.

  • Wyświetlenie wszystkich elementów na standardowe wyjście.
Stack<Integer> stack = new Stack<>();
stack.push(1);
stack.push(2);
stack.push(3);
stack.push(4);

stack.stream().forEach(System.out::print);
System.out.println();
  • Zamiana stosu na listę.
List<Integer> list = stack.stream().collect(Collectors.toList());
System.out.println(list);
  • Usunięcie wybranych elementów.
stack.removeIf(element -> element > 3);
  • Zamiana stosu na tablicę.
int[] intArray = stack.stream()
		.mapToInt(element -> element)
		.toArray();

System.out.println(Arrays.toString(intArray));

Rekomendowana implementacja stosu w Javie (java.util.Deque)

Na java.util.Stack świat Javy się nie kończy. Do dyspozycji mamy jeszcze chociażby interfejs: java.util.Deque oraz dwie implementacje: java.util.ArrayDeque i java.util.LinkedList.

Mimo iż jest to inny interfejs i inne implementacje, to zasada działania powyższych klas z punktu widzenia użytkownika jest analogiczna.
Możemy skorzystać ze standardowych metod: push, pop i peek oraz w przypadku np. LinkedList wielu innych.

Warto jest się przyjrzeć temu rozwiązaniu nie tylko dlatego, że daje ono więcej możliwości, ale jest to również implementacja rekomendowana przez twórców samej Javy.
Jako główny argument przeciwko java.util.Stack podawany jest fakt, że nie mamy rozdzielonego interfejsu i implementacji, a sama klasa dziedziczy po przestarzałym już java.util.Vector.

Poniżej kilka przykładów z wykorzystaniem Deque.

// given
Deque<Integer> deque = new LinkedList<>();
deque.push(1);
deque.push(2);
deque.push(3);

// when
Integer pop = deque.pop();
Integer peek = deque.peek();
int size = deque.size();

// then
assertThat(pop).isEqualTo(3);
assertThat(peek).isEqualTo(2);
assertThat(size).isEqualTo(2);

Przepełnienie stosu

Poznaliśmy już podstawy, dlatego pobawmy się teraz z odrobinę ciekawszymi zagadnieniami.

A co gdyby tak dodawać do naszego stosu w nieskończoność nowe elementy? 🙂

Wracając do naszego pierwotnego przykładu z książkami – na brak książek w domu nie mogę narzekać, także raczej by mi ich szybko nie zabrakło.
Podejrzewam jednak, że powyżej pewnej wysokości wszystko by całkiem nieźle walnęło… (Znasz taką grę Jenga? Jeżeli nigdy w nią nie grałeś, to gorąco polecam.)

W informatyce taki pomysł musi skończyć się podobnie – coś na pewno się zepsuje lub skończy.

Zasadniczo mamy dwa możliwe scenariusze:

  • skończy nam się pamięć i cała aplikacja się wysypie;
  • lub implementacja stosu uzna, że nie może już przyjmować nowych obiektów i nam to zakomunikuje. Jeżeli odpowiednio przechwycimy taki komunikat, to jest szansa, że uratujemy jeszcze aplikację. Jeżeli nie, to i w tym wypadku całka aplikacja się złoży.
Deque<Long> stack = new LinkedList<>();

long i = 0;
while (true) {
	stack.push(i++);
}

OutOfMemoryError

Po wykonaniu powyższego kodu mój komputer na chwilę przygasł…
Java wykorzystała ponad 600% CPU, po czym cały proces zakończył swój żywot, zgłaszając błąd: java.lang.OutOfMemoryError: Java heap space.

java.lang.OutOfMemoryError: Java heap space

Wniosek z tego przykładu płynie taki, że nie możemy bezkarnie w nieskończoność dodawać elementów do stosu ani żadnej innej struktury danych.

Jeżeli chcemy się ustrzec przed podobnymi problemami, trzeba przemyśleć strategię usuwania starych elementów lub w pewnym momencie powiedzieć STOP i przestać dodawać kolejne elementy.

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
	at java.base/java.lang.Long.valueOf(Long.java:1180)
	at pl.stormit.stacklifo.DequeTest.x(DequeTest.java:37)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:566)

Jednak nie tylko my jako szeregowi programiści musimy uważać na tego typu problemy.
Z analogicznymi trudnościami musieli zmierzyć się również programiści samej Javy.

StackOverflowError

Przyjrzymy się teraz bliżej niechlubnemu błędowi: java.lang.StackOverflowError.

Możemy się z nim spotkać, gdy np. napiszemy nieskończoną rekurencję – fragment kodu, który w nieskończoność będzie wywoływał sam siebie.

Kod poniżej z założenia będzie wywoływał w nieskończoność tę samą metodę – chyba że…

@Test
void invinityStack2() {
	invinityStack2();
}

Chyba że skończy nam się miejsce na stosie 🙂

Każde wywołanie metody w Javie odkładane jest na wewnętrznym stosie, a po zakończeniu wykonywania takiej metody zdejmowane z tego stosu.

No chyba że wpadniemy na pomysł, żeby w nieskończoność wywoływać jakąś metodę i cały czas dodawać nowe wpisy do tego stosu.
Wtedy musimy się liczyć, że dostaniemy taki wyjątek:

java.lang.StackOverflowError
	at pl.stormit.stacklifo.DequeTest.invinityStack2(DequeTest.java:43)
	at pl.stormit.stacklifo.DequeTest.invinityStack2(DequeTest.java:43)
	at pl.stormit.stacklifo.DequeTest.invinityStack2(DequeTest.java:43)
	at pl.stormit.stacklifo.DequeTest.invinityStack2(DequeTest.java:43)
	at pl.stormit.stacklifo.DequeTest.invinityStack2(DequeTest.java:43)
	at pl.stormit.stacklifo.DequeTest.invinityStack2(DequeTest.java:43)
	at pl.stormit.stacklifo.DequeTest.invinityStack2(DequeTest.java:43)
	at pl.stormit.stacklifo.DequeTest.invinityStack2(DequeTest.java:43)

Stos w innych językach programowania (PHP, Python, C++)

PHP

W PHP stos możemy zaimplementować z wykorzystaniem np. metod: array_unshift i array_shift lub oprzeć się na gotowych rozwiązaniach.

<?php
class ReadingList
{
    protected $stack;
    protected $limit;
     
    public function __construct($limit = 10) {
        // initialize the stack
        $this->stack = array();
        // stack can only contain this many items
        $this->limit = $limit;
    }
 
    public function push($item) {
        // trap for stack overflow
        if (count($this->stack) < $this->limit) {
            // prepend item to the start of the array
            array_unshift($this->stack, $item);
        } else {
            throw new RunTimeException('Stack is full!'); 
        }
    }
 
    public function pop() {
        if ($this->isEmpty()) {
            // trap for stack underflow
          throw new RunTimeException('Stack is empty!');
      } else {
            // pop item from the start of the array
            return array_shift($this->stack);
        }
    }
 
    public function top() {
        return current($this->stack);
    }
 
    public function isEmpty() {
        return empty($this->stack);
    }
}

Źródło: Data Structures for PHP Devs: Stacks and Queues

Python

W minimalistycznej wersji w Pythonie możemy skorzystać ze zwykłej listy jako stosu.

>>> stack = []
>>> stack.append('A')
>>> stack.append('B')
>>> stack.append('C')
>>> stack.pop()
'C'
>>> stack.pop()
'B'
>>> stack.pop()
'A'
>>> stack.pop()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: pop from empty list

Po więcej szczegółów odsyłam do zewnętrznego artykułu: How to Implement a Python Stack.

C/C++

Przykładowa implementacja stosu w C++.

#include <iostream> 
#include <stack> 
using namespace std; 
  
void showstack(stack <int> s) 
{ 
    while (!s.empty()) 
    { 
        cout << '\t' << s.top(); 
        s.pop(); 
    } 
    cout << '\n'; 
} 
  
int main () 
{ 
    stack <int> s; 
    s.push(10); 
    s.push(30); 
    s.push(20); 
    s.push(5); 
    s.push(1); 
  
    cout << "The stack is : "; 
    showstack(s); 
  
    cout << "\ns.size() : " << s.size(); 
    cout << "\ns.top() : " << s.top(); 
  
  
    cout << "\ns.pop() : "; 
    s.pop(); 
    showstack(s); 
  
    return 0; 
}

Źródło: Stack in C++ STL.

Inny systemy kolejkowania

Do pełnego obrazu sytuacji brakuje nam już tylko wyjaśnienia innych skrótowców, które często pojawiają się w kontekście FIFO.

FCFS (ang. First-Come, First-Served)

FCFS (ang. First-Come, First-Served) – czyli w dosłownym tłumaczeniu: pierwsze przyjdzie, pierwsze będzie podane. Skrótowiec wykorzystywany najczęściej w kontekście zarządzania zapasami.

FEFO (ang. First Expired, First Out)

FEFO (ang. First Expired, First Out) – czyli w dosłownym tłumaczeniu pierwsze, które będzie przedawnione, pierwsze idzie na zewnątrz. Tego typu podejście może być np. wykorzystane przy łatwo psujących się produktach lub takich o krótkim terminie przydatności.

Z punktu widzenia technicznego jest to po prostu kolejka priorytetowa (ang. priority queue).

FINO (ang. First In, Never Out)

FINO (ang. First In, Never Out) – to dowód na to, że programiści też mają poczucie humoru 🙂

FINO możemy przetłumaczyć na: pierwsze weszło, nigdy nie wyszło – co oczywiście ma być prześmiewczą analogią do FIFO i LIFO.

FISH (ang. First In, Still Here)

FISH (ang. First In, Still Here) – akronim FISH powstał na podobnej zasadzie jak FINO, tłumaczymy go jako: pierwsze weszło, ciągle tam jest.

Samodzielna implementacja LIFO (Stack)

Na koniec pobawimy się jeszcze praktycznymi zadaniami.

Powiedzieliśmy sobie, że elementy w stosie ułożone są zgodnie z zasadą LIFO. Jednak sam stos może być zaimplementowany na kilka różnych sposobów.

Najczęściej możemy spotkać się z dwiema implementacjami stosu:

  • opartej o cykliczny bufor danych (ang. circular buffer) lub
  • zaimplementowanej z wykorzystaniem listy – najczęściej listy wskaźnikowej (ang. linked list),
  • choć możliwa jest też implementacja z wykorzystaniem zwykłej tablicy.

Przerobienie tych przykładów nie jest konieczne do zrozumienia omawianych tu pojęć i w zdecydowanej większości przypadków dużo lepszym wyjściem jest skorzystanie z gotowych już klas implementujących stos, takich jak java.util.LinkedList.
Mimo wszystko zachęcam do ich przejrzenia i samodzielnej próby implementacji – jest to świetny sposób na utrwalenie wiedzy w praktyce i pełniejsze zrozumienie tematu.

W poniższych przykładach skupię się na ręcznej implementacji z wykorzystaniem własnej listy wskaźnikowej (ang. linked list).

Interfejs stosu i główne wymagania

Nasz stos powinien implementować wszystkie podstawowe metody, takie jak: pop, push, peek i size. Zanim jednak przejdziemy do samej implementacji, zacznijmy od zdefiniowania interfejsu – czyli określmy, co właściwie będzie robił nasz stos.

Na tym etapie jeszcze nie określamy, jak będzie to realizowane – tym zajmiemy się podczas implementacji.

public interface Stack<T> {
	T peek();

	T pop();

	void push(T value);

	int size();
}

Wewnętrzna struktura przechowująca elementy

Każdy element na naszym stosie będzie się składał z samej wartości przechowywanego elementu oraz informacji o tym, jaki element znajduje się pod nim. Dzięki temu, mając referencję do najwyższego elementu, będziemy mogli dostać się do pozostałych.

private static class Entry<T> {
	private T value;
	private Entry<T>;

	public Entry(T value, Entry<T> prev) {
		this.value = value;
		this.prev = prev;
	}
}

Wskaźnik na głowę (ang. head) stosu

Potrzebujemy jeszcze przechować informację o tym, który element jest na samej górze – robimy to przy pomocy wskaźnika: head.

public class LinkedStack<T> implements Stack<T> {

    private Entry<T> head;
}

Rozmiar stosu (ang. stack size)

Żeby za każdym razem nie liczyć wszystkich elementów, które są na stosie, do przechowania rozmiaru wykorzystamy wewnętrzną zmienną.

private int size = 0;

Dodanie elementu do stosu (ang. push)

Dodając nowy element do stosu:

  • tworzymy wewnętrzną strukturę, która przechowuje nasz element oraz informację o poprzednim elemencie, który był na szczycie stosu, czyli dotychczasowej głowie;
  • podmieniamy wskaźnik przechowujący głowę stosu na nasz nowy obiekt;
  • i na końcu inkrementujemy zmienną przechowującą rozmiar stosu.
@Override
public void push(T value) {
	Entry<T> entry = new Entry<T>(value, head);

	head = entry;

	size++;
}

Zdjęcie elementu ze stosu

Chcąc zdjąć element ze stosu:

  • sprawdzamy, czy stos nie jest pusty (head == null);
  • pobieramy wartość elementu wskazywanego przez head;
  • nadpisujemy wskaźnik head, tak by wskazywał na element znajdujący się pod nim;
  • zwracamy wartość elementu.
public T pop() {
	if (head == null) {
		return null;
	}

	T value = head.value;

	head = head.prev;

	size--;

	return value;
}

Podejrzenie elementu znajdującego się na szczycie stosu

Metoda peek sprawdza, czy stos nie jest pusty i zwraca wartość obiektu wskazywanego przez head.

public T peek() {
	if (head == null) {
		return null;
	}

	return head.value;
}

Pełna implementacja

interface Stack<T> {
	T peek();

	T pop();

	void push(T value);

	int size();
}


class LinkedStack<T> implements Stack<T> {

	private static class Entry<T> {
		private T value;
		private Entry<T> prev;

		public Entry(T value, Entry<T> prev) {
			this.value = value;
			this.prev = prev;
		}
	}

	private Entry<T> head;

	private int size = 0;

	@Override
	public T peek() {
		if (head == null) {
			return null;
		}

		return head.value;
	}

	@Override
	public T pop() {
		if (head == null) {
			return null;
		}

		T value = head.value;

		head = head.prev;

		size--;

		return value;
	}

	@Override
	public void push(T value) {
		Entry<T> entry = new Entry<T>(value, head);

		head = entry;

		size++;
	}

	@Override
	public int size() {
		return size;
	}
}

Zadania do samodzielnego rozwiązania

Jeżeli ciągle szukasz wyzwań i chcesz poćwiczyć zadania z wykorzystaniem stosu – poniżej masz kilka inspiracji.

  • odwrócenie listy elementów przy pomocy stosu;
  • samodzielna implementacja stosu przy pomocy wewnętrznej tablicy.

Rozwiązania wszystkich zadań i inne przykłady kodu znajdziesz na repozytorium github.

Podsumowanie i druga część wpisu

Na dzisiaj to już wszystko. Bardzo Ci dziękuję, że wytrwałeś do końca. Zachęcam Cię przede wszystkim do samodzielnego wypróbowania omawianego dziś stosu oraz rozwiązania zadań. Wynikami swojej pracy możesz jak zawsze podzielić się na grupie.

A już niedługo druga część wpisu: Kolejka (Queue) – jak samodzielnie zaimplementować FIFO?

Dodatkowe materiały:

 

kierunek java

No comments
Share:
Immutable

Immutable – niezmienne obiekty

Immutable, czyli niezmienne obiekty – wady, zalety oraz kilka praktycznych przykładów.

Zastanawiałeś/zastanawiałaś się kiedyś, jak na nasze życie wpływają różne ograniczenia?
Czy zawsze są one tak złe, jak na początku nam się to wydaje?

Spokojnie! Nie chcę Cię teraz umoralniać – związek z programowaniem już za chwilę 🙂

Przypomnij sobie, jak w dzieciństwie słyszałeś od rodziców:
nie dotykaj tego, bo to gorące! lub: nie wychylaj się, bo spadniesz i inne podobne.

Dziś z perspektywy czasu i tego, że jestem ojcem, patrzę na tego typu ograniczenia trochę inaczej – lub zwyczajnie sam je nakładam…
Mam jednak świadomość, co się za nimi kryje.
Wiem, że nie są to tylko ograniczenia, które mają uprzykrzyć życie.
Wiem, że jeżeli nie będziemy ich przestrzegać, to możemy coś stracić lub może nas zwyczajnie zaboleć…
Ewentualnie w drugą stronę: jeżeli będziemy ich przestrzegać, to możemy coś zyskać.

W programowaniu też mamy takie ograniczenia. Wiele z nich na pierwszy rzut oka wydaje się bezsensowna i niestety staramy się je ominąć, bo przecież tylko utrudniają nam życie…

Widzisz już związek?

Niech pierwszy rzuci kamieniem ten, kto choć raz nie:

  • skorzystał z git push force;
  • dostał się do pola klasy przy pomocy refleksji;
  • lub zmienił modyfikator dostępu do metody lub klasy na mniej restrykcyjny.

Nie ma w tym nic złego, jeżeli rzeczywiście wiemy, co robimy, i świadomie „łamiemy te zakazy”.

Problem pojawia się jednak wtedy, gdy nie znamy konsekwencji swojego działania, czyli postępujemy podobnie jak dzieci – chcemy osiągnąć chwilową przyjemność, jednocześnie nawet nie zastanawiając się, jakie to może mieć skutki.

W dzisiejszym wpisie przyjrzymy się bliżej jednemu z takich ograniczeń – niemodyfikowalnym obiektom i zastanowimy się, co dzięki ich wykorzystaniu możemy zyskać jako programiści.

Z tego odcinka dowiesz się:

  • co to jest immutable object;
  • jak efektywnie korzystać z gotowych klas implementujących ten wzorzec;
  • jak samodzielnie zaimplementować immutable object;
  • oraz jakie są wady i zalety niemodyfikowalnych obiektów.
[SprawnyProgramista_intro]

Immutable object – czyli w dosłownym tłumaczeniu niezmienny obiekt. Jest to wzorzec projektowy, w którym finalny stan obiektu ustalany jest już podczas jego tworzenia i przez cały okres jego życia nie może zostać zmieniony. W efekcie tego, gdybyśmy chcieli wprowadzić jakąś zmianę w jego stanie, trzeba będzie utworzyć nowy obiekt z jego zmodyfikowaną wartością.

Mutable object – zmienny obiekt

Żeby było to bardziej zrozumiałe, zacznijmy od wprowadzenia pojęcia modyfikowalnych obiektów (ang. mutable objects), które są przeciwieństwem niemodyfikowalnych obiektów (ang. immutable objects).

Poniżej jest przykładowa klasa reprezentująca osobę posiadającą swoje imię oraz wiek.

class Person {
	private String name;
	private int age = 0;

	public Person(String name) {
		this.name = name;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}
}

Obiekty tego typu możemy utworzyć, przypisując im jednocześnie jakiś inicjalny stan, a następnie zmodyfikować (np. korzystając z setterów).

Person person = new Person("Tomek");
person.setAge(18);

Mimo iż podczas tworzenia obiektu person przypisaliśmy domyślny wiek (age = 0), to nie mieliśmy problemu, żeby go później zmodyfikować.

Tego typu obiekty są bardzo powszechne i najczęściej wykorzystywane przez developerów – co nie zawsze jest dobrym pomysłem, ale o tym za chwilę.

Immutable object – niezmienny obiekt

Raz utworzony immutable object nigdy nie zmieni już swojej wartości.

Co to tak naprawdę dla nas znaczy?

Takie zachowanie klasy można porównać do swego rodzaju odlewu w formie. Jeżeli potrzebujemy innego odlewu, trzeba przygotować nową formę i jeszcze raz zrobić odlew.

UWAGA: chodzi tutaj przede wszystkim o stan obiektu widoczny z zewnątrz. Może zajść taka sytuacja, że obiekt zmodyfikuje wewnętrznie jakieś swoje parametry, jednak póki nie zmienia to stanu widocznego z zewnątrz, dalej rozpatrujemy taki obiekt jako immutable.

Immutable String

Najbardziej znaną klasą niemodyfikowalną jest standardowy String wykorzystywany do przechowywania ciągu znaków.

Zobaczmy to na przykładzie:

Klasa String nie posiada żadnego settera ani innej metody, którą moglibyśmy zmienić jego wartość. Dlatego chcąc zmienić jego stan, tworzymy nowy obiekt oraz modyfikujemy referencje wskazującą na nasz obiekt.

W powyższym przykładzie utworzyliśmy nowy obiekt string o wartości „Java 8” i ustawiliśmy na niego zmienną referencyjną str.

➡ ZOBACZ 👉: String – najważniejszy typ danych, niezmienność stringów

Zobaczmy to na jeszcze jednym przykładzie. Poniższy fragment kodu wyświetli informację o miejscu w pamięci, w którym znajdują się poszczególne obiekty.

String str = "Java";
System.out.println("String str = \"Java\" => " + System.identityHashCode(str));
System.out.println("\"Java\" => " + System.identityHashCode("Java"));
System.out.println("new String(\"Java\") => " + System.identityHashCode(new String("Java")));

str += " 8";
System.out.println("str += \" 8\" => " + System.identityHashCode(str));

Z logów wynika, że każdorazowe utworzenie stringa jako literał przez wykorzystanie cudzysłowu zwraca nam ten sam obiekt – dzieje się tak, ponieważ Java wewnętrzne wykorzystuje pulę stringów.
Natomiast utworzenie nowego stringa przez słowo kluczowe new, podobnie jak konkatenacja stringów, tworzy nowe obiekty.

String str = "Java"     => 1513712028
"Java"                  => 1513712028
new String("Java")      => 1018547642
str += " 8"             => 1456208737

Alternatywą dla niemodyfikowalnego stringa są jego modyfikowalne odpowiedniki StringBuilder oraz StringBuffer. Warto rozważyć ich wykorzystanie, jeżeli wiemy, że nasz ciąg znaków będzie często modyfikowany. O obu klasach możesz przeczytać w poniższym artykule:

➡ ZOBACZ 👉: StringBuilder: czy zawsze taki szybki? | String vs StringBuilder vs StringBuffer

Równie dobrym przykładem immutable objects są obiekty klas opakowujących typy proste, takie jak Integer, Double, Float czy Boolean.

Implementacja Immutable Object w Javie

Wiemy już, jak korzystać z gotowych klas implementujących wzorzec: Immutable Object, przejdźmy teraz dalej i sami spróbujemy przygotować taką klasę.

Implementacja Immutable Object w Javie

Implementacja Immutable Object w Javie

W dokumentacji Oracle możemy przeczytać zalecenia odnośnie strategii implementacji niemodyfikowalnych obiektów. Nie jest to nic trudnego, trzeba jednak pamiętać o kilku poniższych zasadach:

  • Pola klasy oznaczone jako private i final 
    Blokujemy w ten sposób wszystkie pola przed bezpośrednim dostępem z zewnątrz klasy oraz pilnujemy samych siebie przed omyłkową ich modyfikacją w późniejszym kodzie.
    Wartość wszystkich parametrów musi zostać ustalona już w konstruktorze.
  • Brak setterów
    Rezygnujemy z pisania setterów lub innych metod modyfikujących stan pól – i tak byłoby to niemożliwe, ponieważ wszystkie pola oznaczone są już jako final.
  • Klasa final
    Dzięki temu nie będzie możliwości dziedziczenia po naszej klasie, a co za tym idzie – modyfikacji jej zachowania.
  • Opcjonalnie konstruktor prywatny + publiczna metoda fabrykująca
    Prywatny konstruktor zablokuje możliwość tworzenia obiektów tej klasy z zewnątrz, dzięki czemu publiczna metoda fabrykująca (wzorzec projektowy ang. factory method) będzie jedynym sposobem na utworzenie takiego obiektu.
  • Poszczególne pola naszej klasy też muszą być immutable.
    Wszystkie typy pól klasy również muszą być immutable, w przeciwnym wypadku będzie możliwość ich edycji.

Poniżej przykładowa implementacja immutable object reprezentująca adres.

public final class Address {
	private final String street;
	private final String city;

	public Address(String street, String city) {
		this.street = street;
		this.city = city;
	}

	public String getStreet() {
		return street;
	}

	public String getCity() {
		return city;
	}
}

Uwaga na odwołania do innych mutowalnych obiektów (Immutable Map, Immutable List)

Trochę trudniej sprawa wygląda, jeżeli zamierzamy zrobić odwołanie do innych mutowalnych obiektów, np. gdy chcemy przechować listę obiektów z wykorzystaniem kolekcji: java.util.List.

W tym wypadku nie wystarczy samo oznaczenie pola jako final, ponieważ stan takiej kolekcji dalej będzie mógł być zmodyfikowany. Nawet jeżeli kolekcja będzie przechowywała niemodyfikowalne obiekty, to będzie można np. dodać do niej nowy obiekt lub go usunąć. Żeby się przed tym ustrzec, musimy zrobić głęboką kopię obiektu. Ponieważ przechowamy lokalnie swoją prywatną kopię takiej kolekcji, to mamy pewność, że nikt już jej nie zmodyfikuje.

Możemy to osiągnąć na dwa sposoby:

  • kopiowanie w konstruktorze
    this.items1 = Collections.unmodifiableList(items1);
  • kopiowanie w getterach
    return Collections.unmodifiableList(items1);

Oba rozwiązania sprowadzają się do tego samego – poza klasę nie możemy wystawić referencji do pierwotnej kolekcji, ponieważ będzie to groziło jej modyfikacją.

public final class Address {
	/* street, city declaration */

	private final List<String> items1;
	private final List<String> items2;

	public Address(String street, String city, List<String> items1, List<String> items2) {
		this.street = street;
		this.city = city;
		this.items1 = Collections.unmodifiableList(items1);
		this.items2 = items2;
	}

	/* street, city getters */

	public List<String> getItems1() {
		return items1;
	}

	public List<String> getItems2() {
		return Collections.unmodifiableList(items1);
	}
}

Podobne rozwiązanie trzeba zastosować w przypadku innych kolekcji, map oraz każdego modyfikowalnego obiektu, który chcemy przechować.

Alternatywna implementacja z wykorzystaniem biblioteki Immutables

W celu implementacji immutable object możemy również pokusić się o wykorzystanie gotowych rozwiązań, takich jak biblioteka Immutables.
Może to pozwolić na znaczne uproszczenie naszego kodu – więcej na ten temat przeczytasz w podlinkowanym wpisie.

@Value.Immutable
public abstract class UserValueImmutable {
 
   abstract String getName();
   abstract Integer getAge();
}

Immutable – zalety

Zobaczmy teraz główne powody, dla których warto zainteresować się niemodyfikowalnymi obiektami.

  1. Prostota – łatwiejsze wykorzystanie oraz testowanie
    Z punktu widzenia użytkownika bardzo łatwo korzysta się z takich obiektów oraz je testuje – mamy pewność, że ich wartość się nie zmieni.
  2. Większa stabilność i łatwość potencjalnego szukania błędów
    Założenie niemodyfikowalności obiektów pozwala znacząco uprościć logikę w kodzie (np. nie musimy przejmować się, że obiekt przekazany przez parametr funkcji zostanie zmodyfikowany). Łatwiejszy kod oznacza większą stabilność całego rozwiania oraz mniej błędów.
  3. Możliwość keszowania (ang. cache) takich obiektów
    Niezmienność obiektów ma jeszcze jedną bardzo ważną cechę – możemy poprawić wydajność aplikacji przez keszowanie takich obiektów. Najpopularniejszym przykładem takiego keszowania jest wbudowana pula stringów (ang. String Pool).
    ➡ ZOBACZ 👉: String – najważniejszy typ danych, pula stringów.
  4. Możliwość bezpiecznego wykorzystania w Setach oraz Mapach jako klucze.
    Zmiana wartości obiektu może zmienić jego hashCode, a co za tym idzie – taki obiekt mógłby się zagubić w standardowych kolekcjach Java.
    Więcej przeczytasz o tym w poniższym wpisie:
    ➡ ZOBACZ 👉: hashCode i equals – co grozi Ci za złamanie kontraktu między nimi?
  5. Thread-safe – bezpieczniejsze i wydajniejsze programowanie wielowątkowe.
    Ponieważ stan obiektów immutable się nie zmienia, mamy pewność, że wszystkie wątki widzą to samo. Dzięki temu stosunkowo niewielkim kosztem możemy zrezygnować z czasochłonnej i problematycznej synchronizacji oraz zwiększamy bezpieczeństwo programowania wielowątkowego i rozproszonego.
  6. Wbudowana optymalizacja Garbage Gollector.
    GC jest odpowiednio zoptymalizowany do sprawnego odśmiecania małych i krótko żyjących obiektów z pamięci.
  7. Lepsze odzwierciedlenie rzeczywistości.
    Wiele elementów otaczającego nas świata z natury jest niezmienna, dlatego może być to naturalne wymaganie przy budowaniu modelu domenowego.

Immutable – wady

Przyjrzyjmy się teraz potencjalnym wadom immutable objects. Potencjalnym, dlatego że wiele z nich należałoby raczej rozpatrywać jako ich specyfikę niż rzeczywistą wadę.

  1. Trudniejsza implementacja
    Czasem jako argument przeciwko temu rozwiązaniu podaje się trudniejszą implementację. Osobiście uważam, że bardziej pasowałoby tu określenie: inna implementacja, niż trudniejsza.
  2. Konieczność inicjalizowania wszystkich własności obiektu w konstruktorze
    Może to być rzeczywiście problematyczne, szczególnie jeżeli mielibyśmy bardziej rozbudowany obiekt, z dużą ilością pól. W takich sytuacjach jednak zazwyczaj nie stosuje się immutable objects lub można skorzystać ze wzorca projektowego (ang. design pattern) budowniczy (ang. builder), który znacząco ułatwi tworzenie takiego obiektu.
  3. Każda próba zmiany obiektu wiąże się z koniecznością utworzenia nowego obiektu.
    Potencjalnie może wiązać się to ze zwiększonym zużyciem pamięci na przechowanie tych obiektów oraz CPU na ich obsługę, jednak współczesne GC są bardzo dobrze zoptymalizowane pod tym kątem.

Kiedy korzystać z immutable object?

Kiedy w takim razie powinniśmy korzystać z immutable objects, a kiedy z mutable objects?

Każdy wypadek oczywiście powinien być rozpatrywany indywidualnie, jednak można wyróżnić kilka grup problemów, przy których rozwiązaniu immutable objects może być szczególnie pomocne.

  • programowanie wielowątkowe;
  • wykorzystanie obiektów jako różnego rodzaju klucze, np. w mapach;
  • obiekt ma być typowym value object – czyli niewielkim prostym obiektem, który nie ma jednoznacznie określonej tożsamości (np. ID, pesel itp.).

Kiedy nie korzystać z immutable object?

Cytując klasyka: klasy powinny być niemodyfikowalne, chyba że jest bardzo dobry powód, żeby było inaczej. Jeżeli natomiast klasa nie może być niemodyfikowalna, to należy możliwie ograniczyć jej modyfikowalność.

Classes should be immutable unless there’s a very good reason to make them mutable… If a class cannot be made immutable, limit its mutability as much as possible.

Joshua Bloch, Effective Java

W takiej sytuacji nasuwa się pytanie: co to właściwie znaczy dobry powód?

Widzę dwa główne powody, dla których warto zastosować modyfikowalne obiekty:

  • obiekt posiada swoją „tożsamość” i reprezentuje np. osoby, rzeczy itp. Dla tego typu obiektów zmiana pewnych parametrów jest naturalna, np. osoba zmienia swój wiek, samochód zmienia prędkość itp.
  • wydajność – gdy pracujemy z dużymi obiektami, których tworzenie zajmuje dużo czasu, ich ponowne wykorzystanie może być dobrym pomysłem.

Podsumowanie i zadanie

Immutable object jest jedną z dobrych praktyk programistycznych, która potrafi nie tylko ułatwić codzienną pracę z kodem, ale również ustrzec nas przed potencjalnymi problemami w przyszłości. Zarazem jest wyjątkowo prosta do wdrożenia, dlatego warto się nią zainteresować.

Na dzisiaj to już wszystko, chciałbym jednak, żebyś spróbował przećwiczyć tę wiedzę w praktyce – korzystając z wzorca immutable object, zaimplementuj klasę Number reprezentującą liczbę całkowitą. Klasa powinna implementować przynajmniej dwie metody: Number of(int n) tworzącą nowy obiekt oraz Number add(Number number) dodającą dwa obiekty.

Number result = Number.of(1).add(Number.of(10));

Wynikami swojej pracy podziel się w komentarzu poniżej lub na naszej grupie. Przykładową implementację znajdziesz w repozytorium.

Pozdrawiam i powodzenia w realizacji zadania!

 

Dodatkowe materiały:

 

kierunek java

No comments
Share:
Backend – czy nadajesz się na backend developera?

Backend – czy nadajesz się na backend developera?

W świecie IT panuje dość powszechne przekonanie, że backend jest bardzo trudny i nie do zrozumienia dla statystycznej osoby. Dodatkowego smaczku dodaje mit programisty zamkniętego w swojej programistycznej jaskini, który komunikuje się ze światem zewnętrznym tylko przy pomocy ciągu zer i jedynek. Spróbuję dziś obalić przynajmniej część tych mitów oraz przybliżyć Ci stanowisko backend developera. Chciałbym, byś po przeczytaniu tego artykułu mógł odpowiedzieć na pytanie, czy nadajesz się na backend developera, oraz – co bardzo ważne – czy chciałbyś nim zostać. Zapraszam do lektury.

[SprawnyProgramista_intro]

Z tego odcinka dowiesz się:

  • co to jest back-end oraz front-end oraz jakie są między nimi różnice;
  • czym na co dzień zajmuje się backend developer;
  • jakie umiejętności i technologie trzeba znać, by zostać backend developerem;
  • oraz, gdzie można nauczyć się tych umiejętności.

Co to jest back-end oraz front-end?

Zacznijmy od małego wprowadzenia do terminologii. W zależności od wykonywanych zadań web developerów, czyli programistów pracujących nad aplikacjami internetowymi, możemy podzielić na trzy główne kategorie: front end, back end oraz full stack developer.

1. Front end developer

Front end to część aplikacji działająca po stronie użytkownika (ang. client-side) – czyli wszystko to, co odbywa się po stronie przeglądarki internetowej. Jako użytkownicy bezpośrednio korzystamy właśnie z tej części aplikacji. Jest to również jedyna część systemu, którą możemy obejrzeć i wejść z nią w bezpośrednią interakcję. Wszystkie pozostałe komponenty systemu są dla nas niedostępne i możemy się z nimi komunikować tylko za pomocą GUI (ang. graphical user interface) dostarczonego właśnie przez frontend.

Programiści, którzy większość czasu pracują nad tą częścią aplikacji, nazywani są frontend developerami.

2. Back end developer

Back end jest to natomiast część aplikacji znajdująca się na zewnętrznym serwerze, do której użytkownik nie ma bezpośredniego dostępu (ang. server-side). Możemy ją traktować jak swego rodzaju szarą eminencję, która działa z ukrycia i zarządza systemem. Mimo iż nie widzimy jej, to jest ona niezbędna do prawidłowego działania aplikacji.

Po stronie backendu następuje obsługa danych przetwarzanych w systemie oraz ich zapis i odczyt w bazie danych. Odpowiednio przygotowane informacje są następnie udostępniane przy pomocy API (ang. application programming interface), np. usługi typu REST do frontendu, gdzie prezentowane są użytkownikowi.

Analogicznie jak w poprzednim przypadku, programistów pracujących po stronie backendu nazywamy backend developerami.

3. Full stack developer

To stanowisko łączy w sobie dwa poprzednie, a tego typu programiści są w stanie pracować zarówno na froncie, jak i backendzie.

W tym miejscu warto zwrócić uwagę na zamieszanie powstałe w tym podziale w ostatnich latach. Niezwykle gwałtowny rozwój JavaScript (nawet jak na standardy panujące w informatyce) oraz wszystkich towarzyszących frameworków spowodował, że ten język nie jest już tak sztywno związany tylko z frontendem.

Liderem w wyścigu tych zmian od dość dawna jest Node.js, dzięki któremu z powodzeniem można pisać część aplikacji zarówno frontendowej, jak i backendowej. Jest to niewątpliwie bardzo ciekawy trend, który w kolejnych latach ma duże szanse, by jeszcze się upowszechnić.

Zostawmy jednak już świat frontendu i skupmy się na programiście backendu oraz na umiejętnościach, jakie trzeba posiąść, by móc wykonywać ten zawód.

Czym zajmuje się backend developer?

Backend developer odpowiedzialny jest za budowanie usług w aplikacjach, które następnie wystawiane są na światło dzienne przy pomocy specjalnego API. Mimo iż backend developer zajmuje się wewnętrzną częścią aplikacji, wciąż musi blisko współpracować z frontend developerami, którzy często korzystają z jego pracy, wywołując gotowe komponenty lub pobierając dane.

Taka charakterystyka pracy może być bardzo trudna dla wielu osób. Dość powszechne jest, że pracuje się całe dnie czy nawet tygodnie nad daną funkcjonalnością, a dla świata zewnętrznego wystawiony jest tylko jeden prosty endpoint, który ją wywołuje. Wynikami takiej pracy dość ciężko jest pochwalić się komuś spoza branży.

W codziennej pracy programiści tego typu najczęściej piszą swój kod w językach typu PHP, Java, czy C#. Ich zadaniem jest również zapewnienie wydajnego i szybkiego działania aplikacji – co w niektórych sytuacjach może być wyjątkowo trudne, np. podczas przetwarzania bardzo dużych zbiorów danych.

Co więcej, backend developer bardzo często przygotowuje również bazę danych, w której przechowywane są dane naszej aplikacji. Baza danych jest jednym z kluczowych elementów większości systemów i ciężko wyobrazić sobie bardziej zaawansowaną aplikację, która działałaby bez niej. Najczęściej wykorzystywane silniki baz danych to: MySQL, PostgreSQL, Oracle oraz MongoDB.

Poszczególni programiści mogą być też oddelegowani do różnych specjalistycznych zadań, jak np. obsługi security, przygotowania API, integracji danych, przygotowania bazy danych czy naprawy błędów, czyli z angielskiego: maintenance.

Z kim na co dzień pracują programiści?

Programiści typowo pracują w zespołach projektowych. Większe zespoły składają się z frontend inżynierów, specjalistów od UX, specjalistów od zapewniania jakości QA (ang. quality assurance) oraz innych programistów backendu. W zależności od potrzeb, na konkretnym stanowisku może być kilka osób w zespole lub, jeżeli są mniej potrzebne, mogą one także przynależeć do różnych innych grup.

Dość powszechną praktyką jest również tworzenie zespołów w poprzek tej struktury, tak by osoby na tym samym stanowisku mogły razem pracować. Wtedy należysz do swojego zespołu projektowego oraz np. do grupy backend developerów. Taki podział pomaga dzielić się specjalistyczną wiedzą z danej dziedziny.

Zdarza się również, że bardziej doświadczone osoby oddelegowywane są do kontaktów z klientem.

Jakie umiejętności i technologie muszę znać, by zostać backend developerem?

Zestaw umiejętności, jakimi dysponują bardziej doświadczone osoby z branży, może rzeczywiście być przytłaczający. Pamiętaj jednak, że na taki bagaż doświadczeń trzeba pracować całymi latami, a na początku kariery programistycznej wystarczy niewielki wycinek tej wiedzy.

Konkretne wymagania zazwyczaj znajdziesz w opisie stanowiska dostarczonego przez firmę szukającą pracowników. Ja ze swojej strony zebrałem jednak kilka najczęściej pojawiających się umiejętności, na które warto zwrócić uwagę na starcie.

Zachęcam również do zapoznania się z poniższymi artykułami – znajdziesz w nich praktyczne rady zebrane przez kolegów po fachu.
➡ ZOBACZ 👉:

Umiejętność #1. Bardzo dobra znajomość przynajmniej jednego języka programowania typowego dla backendu

Od tego nie uciekniesz. Język programowania jest jednym z głównych narzędzi pracy dla programisty i jego dobra znajomość to podstawa. Poniżej opis kilku częściej wykorzystywanych języków.

  • Java: to bardzo uniwersalny język programowania, oferujący współbieżność, który jest zorientowany na klasy i obiekty. Podstawowa wersja kodu bardzo mocno przypomina tę napisaną w C++, co zaowocowało łatwiejszą migracją starszych developerów do tego języka. Dzięki wykorzystaniu maszyny wirtualnej (ang. Java Virtual Machine) napisany kod jest niezależny od platformy. Motto, które przyświecało twórcom, to: „Compile once, run anywhere”. Java jest bardzo często wybierana do dużych korporacyjnych projektów, które będą rozwijane przez wiele lat. Jest to również mój główny język programowania, w którym programuję na co dzień.

➡ ZOBACZ 👉: Kurs Java | Darmowy Kurs Programowania w Javie

  • Ruby: dobrze sprawdza się dla start-upów, gdzie trzeba bardzo szybko dostarczać kolejne wersje produktu. W większości wypadków wykorzystywany jest z frameworkiem Ruby on Rails. Najpopularniejsza strona wykorzystująca tę technologię był Twitter – obecnie jednak w dużej mierze został przepisany na Java i Scala.
  • C#: to ulepszona, zorientowana obiektowo wersja języka C. Została opracowana przez Microsoft specjalnie na potrzeby .NET Framework. Najpopularniejsze portale wykorzystujące tę technologię to oczywiście microsoft.com oraz msn.com.
  • Python: kod napisany przy pomocy Pythona może być wyjątkowo krótki, a zarazem stosunkowo prosty i czytelny. Dzięki temu bardzo często wykorzystywany jest do nauki programowania oraz projektów, które muszą być szybko wypuszczone na rynek (np. wszelkiego rodzaju start-upy). Python wykorzystywany jest w tak popularnych serwisach, jak Google i YouTube.
  • PHP: PHP obecnie może pochwalić się największą ilością stron zrobioną przy jego pomocy. Ciekawostką jest to, że jako jeden z niewielu języków programowania został specjalnie zaprojektowany do tworzenia stron internetowych, a nie tylko do tego zaadaptowany. Najpopularniejszy portal społecznościowy Facebook również został w dużej mierze napisany z wykorzystaniem PHP.
  • Node.js i JavaScript: dzięki Node.js dokonał się swego rodzaju przełom. JavaScript, który do tej pory był uważany za język przeznaczony tylko do frontendu, przebojem wdarł się do aplikacji backendowych.

➡ ZOBACZ 👉: ➡ ZOBACZ 👉: Pytania rekrutacyjne JavaScript

Ruby

Ruby

Node.js

Node.js

PHP

PHP

Python

Python

C#

C#


Umiejętność #2. Znajomość baz danych

To właśnie backend developerzy odpowiedzialni są za komunikację z bazą danych, przez co na tym stanowisku wymagana jest przynajmniej podstawowa znajomość zagadnień bazodanowych. Nie znaczy to jednak, że – pracując jako programista – musisz być również specjalistą od wszelkich zaawansowanych technik optymalizacji, replikacji baz danych itp. Zazwyczaj w większych zespołach są oddelegowane do tego dedykowane osoby. W codziennej pracy programiście wystarczą podstawy komunikacji z bazą danych, które najczęściej realizowane są przy pomocy jakiejś biblioteki – np. JPA/Hibernate w Javie.

Większość projektów wykorzystuje relacyjne bazy danych i od ich poznania warto zacząć. W kolejnym kroku opłaca się zainteresować przynajmniej jedną bazą typu NoSQL – bazy tego typu coraz chętniej wykorzystywane są w większych projektach.

  • Oracle: to komercyjna baza danych obsługująca wiele różnych modeli (np. Object-relational i JSON), która rozwijana jest przez Oracle Corporation. Dość często można ją spotkać w dużych korporacyjnych projektach. Jednak mniejsze firmy częściej wybierają darmowe rozwiązania, głównie ze względu na dość drogie opłaty licencyjne.
  • MySQL: to darmowa, relacyjna baza, obecnie rozwijana również przez firmę Oracle. Jest centralnym punktem jednego z bardziej popularnych stosów technologicznych LAMP (Linux, Apache, MySQL, PHP).
  • PostgreSQL: PostgreSQL zalicza się do baz typu RDBMS (ang. Relational Database Management System) z rozszerzeniami obiektowymi.
  • MongoDB: jest to darmowa, rozwijana na licencji open source, dokumentowa baza typu NoSQL. MongoDB przechowuje dane w formacie podobnym do JSON-a, dzięki czemu struktura przechowywanych dokumentów może być modyfikowana w czasie.
MongoDB

MongoDB

MySQL

MySQL

Oracle

Oracle

Postgresql

Postgresql


Umiejętność #3. Zrozumienie technologii występujących na frontend

Dobrego specjalistę można poznać po tym, że wie i rozumie, co się wokół niego dzieje. Pisząc usługi backendowe, warto zastanowić się, kto, w jaki sposób i dlaczego będzie później z tego korzystał. Dobre zrozumienie swojego klienta, który w tym wypadku najczęściej jest programistą pracującym na frontendzie, może uchronić cały zespół przed różnego rodzaju pomyłkami i niedopowiedzeniami.

Dzięki przynajmniej podstawowej wiedzy na temat technologii, w jakich wytwarzane są aplikacje frontendowe, będziesz bardziej świadomym i docenianym programistą backendu. Nie znaczy to, że powinieneś teraz zgłębiać tajniki CSS3 czy AngularJS, warto jednak zobaczyć, jak te technologie wyglądają i jaki będą miały wpływ na Twoją pracę.

Umiejętność #4. Zarządzanie infrastrukturą i środowiskami

Przeciętny projekt składa się przynajmniej z trzech różnych środowisk: lokalnego (developerskiego), testowego oraz produkcyjnego. Zdarzają się jednak sytuacje, że bywa ich znacznie więcej, np. środowisko pod demo dla klienta, środowisko pod konkretne testy lub dedykowane na rozwój specyficznej funkcjonalności itp.

W natłoku tych różnych środowisk trzeba się jakoś odnaleźć i odpowiednio nimi zarządzać. Nawet jeżeli nie musimy tego wszystkiego samemu konfigurować, to trzeba wiedzieć, jak to działa, by móc z tego później korzystać. Całe szczęście – mamy obecnie cały zbiór narzędzi oraz dobrych praktyk, które ułatwiają ten proces.

W tym miejscu warto przede wszystkim zainteresować się Dockerem, który z całą pewnością usprawni tworzenie kolejnych podobnych środowisk i nie będzie potrzeby konfigurowania za każdym razem wszystkiego ręcznie.

Umiejętność #5. Warstwa pośrednia (ang. middleware)

Wiele aplikacji uruchamianych jest na serwerach tak zwanej warstwy pośredniej (ang. middleware). Tego typu aplikacje umieszcza się na serwerze, a dopiero w ich obrębie instalowane są nasze docelowe aplikacje. Taka dodatkowa warstwa abstrakcji umożliwia łatwiejsze i zbiorcze zarządzanie naszym systemem, np. przez jednolitą obsługę połączeń z bazą danych, zapewnienie ogólnie pojętego bezpieczeństwa czy obsługę logów itp.

Dodatkowe skomplikowanie architektury mimo swoich plusów wymaga jednak również dodatkowej wiedzy developerów, którzy później mają ją obsługiwać. Do najczęściej występujących serwerów aplikacji w środowisku Javy można zaliczyć WildFlyApache TomcatGlassFishOracle WebLogicIBM WebSphere.

Umiejętność #6. Doświadczenie z systemami kontroli wersji

Czasy trzymania różnych wersji kodu źródłowego w kolejnych katalogach z datą w nazwie całe szczęście bezpowrotnie już minęły. Obecnie najpopularniejszym systemem kontroli wersji jest GIT, który zdecydowanie zasługuje na miano lidera w swojej kategorii. Niezależnie od technologii, w jakich będziesz pracował, jest bardzo duże prawdopodobieństwo, że właśnie z nim będziesz miał do czynienia w swoim projekcie, dlatego warto się nim zainteresować już teraz.

Podstawowe założenia oraz przydatne komendy znajdziesz w podlinkowanym tutorialu:

➡ ZOBACZ 👉: Git tutorial | stash, rebase, commit, merge, checkout, push i clone

Umiejętność #7. Umiejętności miękkie

Kompetencje miękkie przez wielu traktowane są jako drugorzędne, czyli mniej ważne. Oczywiście jest to bardzo dużym błędem. Nawet jeżeli jesteś już wyjadaczem we wszystkich możliwych technologiach, a nie umiesz pracować w grupie lub – co gorsza – nawet są kłopoty, żeby się z Tobą porozumieć, to Twoja wartość na rynku pracy będzie zdecydowanie niższa, niż wskazywałyby na to twoje „twarde skile” (ang. hard skills) i doświadczenie.

Mimo iż nie jest to takie proste, zdecydowanie warto również popracować nad swoim charakterem.

➡ ZOBACZ 👉: Umiejętności i kompetencje miękkie – soft skills

Gdzie mogę nauczyć się tych umiejętności?

Większość backend developerów może pochwalić się wykształceniem kierunkowym oraz dyplomem wyższej uczelni. Mimo iż nie jest to jedyna droga do zdobycia wiedzy, w wielu, szczególnie większych firmach, jest to wymóg. Spowodowane jest to między innymi tym, że w przypadku pracy nad backendem wymagana jest często bardzo szeroka wiedza z zakresu algorytmów, struktur danych itp. oraz abstrakcyjne podejście do rozwiązywania różnorodnych problemów.

Nie chcę się jednak teraz rozwodzić nad słusznością takiego podejścia, chciałem jedynie zaznaczyć, że dość często jest to wymóg. Jeżeli jednak preferujesz samodzielną naukę, też nic straconego. Na rynku nie brakuje firm, dla których formalne wykształcenie ma drugorzędne znaczenie. W tym jednak wypadku musisz wziąć sprawy w swoje ręce i dobrze się przygotować.

Poniżej znajdziesz artykuły, które pomogą Ci w tym procesie:
➡ ZOBACZ 👉:

Podsumowanie

Backend developer pełni bardzo ważną funkcję w zespole. Bardzo często jest odpowiedzialny za dostarczenie całej funkcjonalności przy współpracy z innymi członkami zespołu. Dlatego wymagania na to stanowisko są zazwyczaj bardzo wysokie. Nie jest to jednak wiedza tajemna, a wymagania są jawne i przy odrobinie samozaparcia można je spełnić. Mimo iż nie omówiliśmy wszystkich możliwych zagadnień, to te przedstawione w artykule z pewnością stanowią bardzo dobre podstawy do rozpoczęcia pracy i dalszego pogłębiania wiedzy.

Zdecydowanie nie jest to najłatwiejszy zawód, jednak praca na tym stanowisku daje bardzo dużo możliwości i satysfakcji. Jeżeli masz tylko jakieś pytania, zapraszam do kontaktu w komentarzach poniżej. Z przyjemnością na nie odpowiem.

Pozdrawiam,
Tomek (backend developer).

Backend Developer, Back end developer I

Backend Developer, Back end developer I

Backend Developer, Back end developer II

Backend Developer, Back end developer II

Backend Developer, Back end developer III

Backend Developer, Back end developer III

Backend Developer, Back end developer IV

Backend Developer, Back end developer IV

Backend Developer, Back end developer V

Backend Developer, Back end developer V

Obrazki w treści umieszczone dzięki uprzejmości: 9gag, Bluecoders, comic.browserling, me.me.

7 komentarzy
Share:
Idempotent

Idempotent – idempotentny, czyli jaki?

Idempotentny, idempotentnośćidempotent – czyli właściwie co?

W dzisiejszym odcinku zajmiemy się dobrą praktyką programistyczną, która polega na pisaniu idempotentnego kodu.

Z tego odcinka dowiesz się:

  • co to jest idempotentny kod i dlaczego warto go pisać?
  • jak pisać skrypty bazodanowe odporne na wielokrotne uruchamianie;
  • jakie są dobre praktyki związane z pisaniem usług sieciowych typu REST;
  • co ma wspólnego rodzenie dzieci z informatyką?
[SprawnyProgramista_intro]

Idempotentny – w uproszczeniu oznacza to, że niezależnie od tego, ile razy wykonamy daną operację, to wynik zawsze będzie taki sam.

Zobaczmy to na kilku przykładach, żeby było to bardziej zrozumiałe.
Przyjrzymy się idempotentności w kontekście matematyki, codziennego życia oraz oczywiście informatyki.
Jeżeli chodzi o programowanie, przedstawię Ci kilka przykładów z wykorzystaniem baz danych oraz usług sieciowych typu REST.

Idempotent – matematyka

  1. Mnożenie przez zero
    Niezależnie od tego, ile razy pomnożymy coś przez zero, wynik zawsze będzie taki sam – zero.
    Przykładowo: 10*0=0, 100*0=0 itp.
  2. Mnożenie przez jeden
    Mnożenie przez jeden nie zmienia wyniku, dlatego bez względu na to, ile razy byśmy nie pomnożyli naszej liczby przez jeden, to wynikiem zawsze będzie ta liczba.
    Przykładowo: 10*1=10, 100*1=100 itp.

Idempotent – prawdziwe/codzienne życie

W prawdziwym życiu też mamy przykłady idempotentnych zachowań.

  1. Ciąża
    Jeżeli kobieta jest już  raz w ciąży, to bardziej już w ciąży nie będzie.
  2. Śmierć
    Podobnie jest ze śmiercią. Raz zabitej osoby nie można już bardziej zabić… choćbyś nie wiem, jak bardzo się starał. Pomijamy tu oczywiście filmy z serii: „Zabili go i uciekł”.

Idempotent – a informatyka

No dobrze, ale co to wszystkiego ma wspólnego z programowaniem?

Informatyka, a w szczególności różnego rodzaju systemy rozproszone bardzo chętnie korzystają z idempotentnych rozwiązań. Głównie dlatego, że idempotentne operacje można bezkarnie powtarzać. Jeżeli nie mamy pewności, że pierwsza operacja doszła do skutku, zamiast weryfikować to, zwyczajnie ją powtarzamy. Jest to dużo prostsze i bezpieczniejsze podejście.

Przejdźmy teraz już do przykładów ściśle związanych z informatyką.

Idempotent – a bazy danych

  1. Usuwanie rekordów – usuwanie rekordów z natury jest idempotentne – raz usunięty rekord, niezależnie od tego, ile razy byśmy nie próbowali go usunąć, będzie już usunięty.
    delete from table where id = 1;
  2. W podobny sposób funkcjonuje aktualizacja danych – można tylko raz nadpisać dane, kolejne próby aktualizacji nie zmienią już naszego wpisu.
    update table set title = 'Note 1' where id = 1;
  3. Odczyt danych z natury też jest idempotentny.
    select * from table where id = 1;

Co jednak z bardziej skomplikowanymi problemami, jak np. dodawanie nowych rekordów czy modyfikacja struktury bazy danych?
Tutaj niestety musimy radzić sobie już samodzielnie i będzie to wymagało napisania przez nad odrobiny kodu.

Dodawanie danych bez duplikatów

Standardowy insert, jeżeli będzie wielokrotnie uruchamiany, za każdym razem doda nowy wiersz do tabeli. Jest to jak najbardziej naturalne i zazwyczaj pożądane zachowanie.

W niektórych sytuacjach jednak chcemy uniknąć duplikatów, które mogły powstać przez przypadkowe wielokrotne uruchomienie skryptu lub wcześniejsze ręczne dodanie danych.

  1. UNIQUE
    W takiej sytuacji możemy skorzystać np. z ograniczenia UNIQUE na kluczu biznesowym, którego unikatowość chcemy zachować. Nie jest to złe rozwiązanie, jednak w przypadku próby dodania duplikatu zostanie zwrócony błąd, a co za tym idzie, cały nasz skrypt będzie wycofany.

    alter table note add constraint unique_title unique(title);
    SQL duplicated key

    SQL duplicated key

  2. Odczyt przed dodaniem
    Alternatywnie przed dodaniem takiego rekordu możemy najpierw sprawdzić, czy nie został on już wcześniej dodany. Czyli najpierw robimy select, a potem insert, tylko jeżeli nie znaleźliśmy odpowiedniego rekordu.

    DO $$ 
    	DECLARE
    		row record;
    	
    	BEGIN
    	    SELECT * INTO STRICT row FROM note WHERE id = 1;
    	    EXCEPTION
    	        WHEN NO_DATA_FOUND then
    	        	insert into note (id, title, content) values (1, 'Note 1', 'Note...');
    	END;
    $$
  3. Usunięcie przed dodaniem
    Na początku skryptu możemy również podjąć próbę usunięcia takiego rekordu, a potem go dodać. Nie zawsze jest to bezpieczne wyjście, ponieważ możemy stracić dodane w ten sposób dane, jednak czasami to wystarczy.
    Należy też uważać, czy podczas takiej operacji nie zmienią nam się klucze główne.

    delete from note where id = 1;
    insert into note (id, title, content) values (1, 'Note 1', 'Note...');

Modyfikacja struktury

Jedną z dobrych praktyk wdrażania zmian na bazie danych jest wykonywanie ich w ramach transakcji – dzięki czemu będziemy mieli pewność, że się wykonają całe lub wcale.

Jest to jak najbardziej słuszne podejście, jednak nie za każdym razem sprawdza się idealnie. Wyobraź sobie sytuację, w której chcesz dodać nowe pole do tabeli, a następnie dodać nowy wpis do tej samej tabeli.

alter table note add column title varchar(255);
insert into note (id, title, content) values (1, 'Note 1', 'Note...');

Jeżeli to pole istniało już wcześniej, to cały skrypt zostanie wycofany, a co za tym idzie, nasz insert nie zadziała.

DO $$ 
    BEGIN
        ALTER TABLE note ADD COLUMN title varchar(255);
    EXCEPTION
        WHEN duplicate_column THEN RAISE NOTICE 'column title already exists in note.';
    END;  
$$

Jeżeli natomiast przewidzimy w naszym skrypcie taką sytuację i przechwycimy taki wyjątek, to bez wycofywania całej transakcji możemy kontynuować wykonywanie skryptu.

Idempotent – a usługi REST

Z pojęciem idempotent można też dość często spotkać się w kontekście usług typu REST i żądań HTTP.

Nie chcę w tym miejscu skupiać się na samych usługach sieciowych, jednak tym, co dla nas jest ważne, jest to, że REST to styl architektoniczny, określający zbiór reguł i ograniczeń wykorzystywanych do tworzenia usług sieciowych. Jest to między innymi alternatywa do usług typu SOAP.

Poszczególne metody w tym podejściu określone są, między innymi, przez adres URL oraz wykorzystywaną metodę HTTP. Przykładowo, wpisując adres w przeglądarce internatowej, np. Google Chrome, i naciskając enter, wysyłamy do serwera żądanie HTTP typu GET na ten adres. Natomiast wysłanie dowolnego formularza najczęściej realizowane jest metodą POST.

Przyjrzymy się teraz kolejno większości najczęściej wykorzystywanych metod HTTP i krótko je omówimy.

Pamiętaj jednak, że poniższe założenia to tylko dobre praktyki, których my jako programiści powinniśmy przestrzegać. Niestety na te założenia należy uważać, bo może się zdarzyć, że ktoś nie przestrzegał tych reguł i zaimplementował swoją usługę z pominięciem tych dobrych praktyk.

Metoda HTTP Idempotent Bezpieczna
OPTIONS tak tak
GET tak tak
HEAD tak tak
PUT tak nie
POST nie nie
DELETE tak nie
PATCH nie nie

HTTP GET

Metoda GET wykorzystywana jest zazwyczaj tylko do odczytu danych, np. do pobrania strony przez przeglądarkę, przez co jest idempotentna oraz bezpieczna.

HTTP HEAD

Metoda HEAD działa podobnie do GET, zwracając analogiczne nagłówki – jednak bez ciała żądania – przez co jest również idempotentna i bezpieczna.

HTTP OPTIONS

Metoda OPTIONS wyświetla dostępne opcje komunikacji. Ponieważ jest metodą tylko do odczytu, jest również idempotentna i bezpieczna.

HTTP PUT

Metoda PUT wykorzystywana jest do aktualizacji danych, dlatego nie możemy jej uznać za bezpieczną, gdyż modyfikuje nasze dane. Jest natomiast idempotentna, ponieważ możemy ją wywołać wiele razy i za każdym razem wynik powinien być taki sam.

HTTP POST

Metoda POST służy do tworzenia nowych obiektów. Każde jej wywołanie powinno zakończyć się utworzeniem nowego rekordu, dlatego nie jest ani bezpieczna, ani idempotentna.

HTTP DELETE

Metoda DELETE służy do usuwania danych, przez co jej wykorzystanie jest potencjalnie niebezpieczne. Jest natomiast idempotentna – raz usunięty obiekt będzie zawsze usunięty. Tutaj jednak mała uwaga – kolejne wywołania tej metody mogą zwrócić nagłówek http 404 oznaczający brak takiego obiektu.

HTTP PATCH

Metoda PATCH służy do częściowej aktualizacji obiektu, gdy chcemy np. zaktualizować tylko imię danej osoby, ignorując całkowicie pozostałe pola. Takie wywołanie jest potencjalne niebezpieczne i nie jest idempotentne.

📢📣 Podsumowanie. Uwaga!

Pisanie idempotentnego kodu jest jedną z dobrych praktyk programistycznych, jednak i tutaj należy kierować się zdrowym rozsądkiem i korzystać z niej tylko wtedy, jeżeli tego potrzebujemy. Przygotowanie kodu, który będzie odporny na wielokrotne uruchomienie, zazwyczaj zwyczajnie jest bardziej problematyczne i czasochłonne, a może się okazać, że wcale tego nie potrzebujemy.

Koniec/ogłoszenia

Na koniec mam jeszcze kilka ogłoszeń technicznych:

  • Po pierwszych dwóch odcinkach dostałem bardzo dużo pozytywnych wiadomości – jeszcze raz bardzo mocno za nie dziękuję.
    Jest to niezmiernie miłe uczucie móc przeczytać, że to, co robię, jest dla kogoś przydatne.
  • Dzisiejszy odcinek zostanie opublikowany pod adresem stormit.pl/003 – zachęcam do odwiedzania bloga, ponieważ znajdziesz tam, między innymi, transkrypt tego odcinka, przykłady omawianych dzisiaj skryptów oraz jeszcze więcej materiałów na temat programowania.
  • Podcast został zgłoszony do iTunes i w momencie, gdy tego słuchasz, powinien być dostępny w większości aplikacji do podcastów.
    Proszę, daj mi znać, czy rzeczywiście tak jest. Będę również wdzięczny za informację, z jakiej aplikacji korzystasz do słuchania audycji.

Na dzisiaj to już wszystko, bardzo Ci dziękuję za wspólnie spędzony czas.

Pozdrawiam i miłego dnia!

 

Dodatkowe materiały

 

kierunek java

2 komentarze
Share: