wtorek, 20 czerwca 2017

Debiut prelegencki - o wrażeniach, o tym jak się przygotowywałem i co mi pomogło

Zwieńczeniem mojego udziału w tegorocznej edycji "Daj się poznać" było wystąpienie na gali finałowej, która odbyła się w siedzibie Microsoft w Warszawie. Zgłosiłem się jako ochotnik wiedząc, że jest to ogromna szansa do zaprezentowania siebie a zarazem bo zawsze chciałem to zrobić. Mam w sobie taki pociąg do dzielenia się wiedzą, lubię rozmawiać - dyskutować w grupie, prezentować swoje poglądy. Jak mi poszło, czy się stresowałem, jak wyglądały przygotowania o tym w poniższym wpisie.
Gala konkursu "Daj się poznać" - Microsoft Warszawa czerwiec 2017


Wrażenia

Na początek moje wrażenia bo cały czas jestem nabuzowany :) Było bardzo dobrze. Na luzie z odrobiną humoru. Otrzymałem wiele pozytywnych opinii i to z ust nawet doświadczonych prelegentów! Lepszej nagrody nie mogłem sobie wymarzyć. Prezentacja była miękka - motywująca. Poruszała się po dwóch obszarach jakie już opisywałem na blogu:
1. Teoria rozbitych okien
2. Personifikacja kodu

Zachęcam do zapoznania się z tymi tematami.

Wiele osób nie mogło uwierzyć, że było to moje pierwsze wystąpienie :) Tak! Jako prelegent występowałem pierwszy raz. Poświęciłem wiele czasu na przygotowania, próby ale jest jedna rzecz, która bardzo mi pomogła na scenie. Mianowicie ...

Hobbystycznie zajmuję się muzyką (pierwotnie grałem na pianinie, syntezatorach). Od jakiegoś czasu pogrywam jako DJ a więc kontakt z publicznością czy bycie w centrum kiedy to oczy ludzi skierowane są na Ciebie nie robią już na mnie takiego wrażenia.



Przygotowania

W sieci znajduję się bardzo dużo materiałów na temat sztuki prezentacji. Ja niczego nowego, rewolucyjnego nie powiem jedynie podzielę się z Wami czym się inspirowałem i jak wyglądały moje przygotowania.

Wybór tematu

Pierwsza rzecz nad jaką myślałem, zaraz po wysłaniu zgłoszenia z chęcią wystąpienia. Mieliśmy na to kilka dni i przez ten okres spisywałem w notatniku pomysły, które wpadły mi do głowy. Były to tematy techniczne z różnych dziedzin IT oraz miękkie. Drogą eliminacji zostałem przy miękkim - w tym czuje się dobrze. Prezentacja miała trwać maksymalnie 20 min i uznałem, że temat techniczny ciężko było by zaprezentować. Ostatecznie zgłosiłem temat "Mój kod, moja dzielnica" - szyfrując w nim trochę o czym będę mówić. Wpływ na ten wybór miał także pozytywny feedback, który otrzymałem od różnych osób dotyczący posta o "Teorii rozbitych okien".

Zarys prezentacji, scenariusz

Kolejnym etapem było spisanie czegoś w rodzaju scenariusza prezentacji. Wziąłem kartkę A4 na której wypisywałem kolejno punkty, złote myśli. Co chciałbym przekazać. 

Jedna mała uwaga. Na tym etapie tworzenie slajdów nie jest potrzebne a wręcz przeszkadza. 

Tak spisane kwestie nie stanowiły jeszcze tego jak będzie przebiegała prezentacja. To zmieniało się w czasie i nawet modyfikowałem jeszcze trochę kolejność poszczególnych kwestii po pierwszych próbach. W związku z tym, że było to moje pierwsze wystąpienie pozwoliłem sobie trochę bardziej rozbudować kwestię przedstawienia siebie, swojej biografii. Większość zasad mówi, że ludzi nie interesuje to kim jesteś, co robisz, tylko temat prezentacji. W tym przypadku mogłem jednak zrobić mało odstępstwo od tej normy.

Slajdy

Dla mnie chyba jedna z trudniejszych rzeczy do przygotowania. Postanowiłem trzymać się tu kilku znanych zasad, które się sprawdzają:
  • Proste slajdy, bez zbędnych grafik, logo i bajerów w postaci kwiatków, wężyków i innych dupereli. 
  • Czcionka i jej wielkość. Bezszeryfowa, duże rozmiary nagłówków i napisów. Tak żeby każdy mógł przeczytać tekst.
  • Mało treści - tylko same hasła przewodnie. W tym zakresie chyba wszyscy są zgodni, że im mniej tym lepiej. Ludzi przyszli ciebie słuchać. Rzadko kiedy chce się komu czytać ściany tekstu, zestawienia tabel itd.
  • Czasem jedna grafika, obrazek może zdziałać bardzo wiele! Działają na ludzką wyobraźnię. Szczególnie jeśli nie jesteś w stanie (lub nie czujesz się na siłach) aby dotrzeć do słuchaczy bezpośrednio poprzez obrazowanie pewnych sytuacji, opowiadanie o nich. Budujesz napięcie, zapowiadasz coś po czym "Bum!" pokazuję się super fajny mem na który cała sala reaguje śmiechem 😄
  • Notatki do slajdów. Coś co może uratować Ci tyłek jeśli się zatniesz. PowerPoint ma tą możliwość i korzystając z widoku prezentera będziesz mógł do nich zerknąć. Jednak rób to tylko w sytuacjach awaryjnych.

Próby, ćwiczenia, poznanie swoich problemów

Mając skomponowany scenariusz oraz slajdy przystąpiłem do ćwiczenia prezentacji. Swoją prezentację podzieliłem na kilka głównych części:
  • O mnie
  • Motyw przewodni, przedstawienie tematu
  • I temat - personifikacja kodu
  • II temat - teroria rozbitych okien
  • Podsumowanie
Szczególnie ważne są dwa pierwsze punkty. Jak to mówią liczy się pierwsze wrażenie. Bardziej doświadczenie prelegenci często je ze sobą zamieniają i zaczynają od tzw. mocnego wejścia, powiedzenia czegoś kontrowersyjnego, czegoś co da do myślenia. Ja pozostałem przy takim układzie nie wrzucając sobie za dużo jak na pierwszy raz. Ale wchodząc na scenę, można rzucić jakimś małym żartem, anegdotą - pozwoli to trochę rozładować napięcie. Ok ale jak wyglądały te ćwiczenia?
  • Ćwiczyłem poszczególne elementy prezentacji osobno. Nie próbowałem od początku przejść przez wszystkie slajdy. Jeśli ułożyłem jakąś sensowną kwestię, ciąg słów, zdań zapisywałem to w notatkach. Nie chciałem improwizować i za każdą kolejną próbą mówić co innego.
  • Założyłem, że pierwsze dwa punkty muszą być wykute na blachę! Niektórzy mówią, że ma to być pierwsze 30sek.
  • Nagrywałem siebie (video + audio) po czym oglądałem. Ale żeby to przyniosło jeszcze lepszy rezultat podzieliłem się tym materiałem. Mi bardzo pomógł Szymon Kulec, któremu jeszcze raz serdecznie dziękuje! Odezwałem się na slacku DevsPL na kanale #sztuka-prezentacji z moimi pytaniami, wątpliwościami. Szymon zaproponował pomoc. Przejrzał nagranie po czym wrócił z cennymi uwagami! Problemami, których sam nie dostrzegałem! A było to:
    • Chodzenie. Nie byłem w stanie ustać w miejscu
    • Kręcenie młyneczków rękoma
    • Intonacja głosu
  • Gdy już wypracowałem mówienie poszczególnych kwestii dopracowałem przerzucanie slajdów tak aby trafiać w punkt. Nie wyprzedzić lub nie spóźnić się. Niby mała rzecz ale może spalić efekt lub gdy dorzuccisz "o tutaj slajd, który właśnie obrazuje to co powiedziałem" 😃
  • Kontrola czasu, tempa mówienia. Miałem 20 minut, których musiałem się trzymać. Pisząc scenariusz, slajdy nie wiedziałem ile opowiedzenie tego mi zajmie. Takie próby pokazują to. Czy możemy mówić trochę wolniej, szybciej, czy jest miejsce na pauzę albo czy nie trzeba wyrzucić czegoś. Lepiej skończyć wcześniej i zostawić kilka minut na ewentualne pytania niż przeciągnąć i pędzić na samym końcu.
Próby były intensywne, po kilku godzinach gardło dało znać o sobie! Więc polecam jakieś landrynki lub inne cukierki do ssania na gardło.

Eliminacja problemów

Jak już wspomniałem największymi problemami u mnie okazało się:
  • Chodzenie. Z jednego miejsca na drugie, nie mające celu. U innych może to być bujanie, tańcowanie itp. 
  • Kręcenie młyneczków rękoma, nadmierna gestykulacja.
  • Intonacja głosu. Największe zaskoczenie jak dla mnie! Okazało się, że często zdania twierdzące kończę podnosząc głos do góry, tak jakbym pytał 😊 Dopiero gdy ktoś mi to uświadomił zobaczyłem jakie to jest irytujące (a moja kochana żona mi potem powiedziała, że tak zawsze było ale już się przyzwyczaiła 😜)
Na pierwsze dwa problemy nie byłem wstanie sam znaleźć rozwiązania więc szukałem ich w internecie. Tutaj mogę polecić filmy Pana Wiktora Niedzickiego. Starsze pokolenie z pewnością go pamięta.To są krótkie acz bardzo rzeczowe filmy:
  1. Wiktor Niedzicki SZTUKA PREZENTACJI - Ręce
  2. Wiktor Niedzicki SZTUKA PREZENTACJI - Mowa ciała
Niestety kanał nie udostępnia playlist ale pozostałe filmy poruszające ten temat bez problemu znajdziecie a polecam je wszystkie.

Wyeliminować problemy można tylko poprzez ćwiczenia, ćwiczenia i jeszcze raz ćwiczenia! Pomogła mi w tym również znajomość tematu, treści którą chcę powiedzieć. Wtedy, jeśli już nie skupiasz się na tekście prezentacji możesz się skupić na swojej postawie, mowie ciała czy dbaniu o wymowę, intonację. Wszystkich rzeczy nie da się wyeliminować całkowicie od razu więc wpierw postaraj się zapanować nad rękoma czy chodzeniem. I tak po kolei eliminuj następne problemy. Jeśli jest ich dużo a czasu mało nie staraj się poprawić wszystkiego na raz. Efekt może być mizerny.


Moje inspiracje

Na koniec chciałbym podzielić się z Wami filmami, osobami, z których czerpałem inspirację dotyczące "sztuki prezentacji".

James Whittaker - ewangelista Microsoftu. Prawdziwy "wymiatacz". Nie wiem dlaczego wcześniej nie widziałem jego prezentacji.

Miałem okazję raz być na prezentacji Kamila. Było to kilka lat temu, coś o projektach informatycznych i nie przypadła mi do gustu. Jednak ten film polecam bo jest krótki i punktuje najważniejsze kwestie no i jest w stylu TED'owym a kto nie chciałby wystąpić na scenie TEDx? 😁

Coś dla młodszego pokolenia bo w głównej mierze zwrócona jest do maturzystów. Jednak część przekazu jest uniwersalna.

Bardzo fajny panel dyskusyjny. Dyskutują osoby z poza świata IT (jednak związane mocno ze sceną) oraz "nasz" przedstawiciel w osobie Jakuba Nabrdalika.

Podsumowując

I na tym można powiedzieć skończyła się tegoroczna przygoda z "Daj się poznać" ale na pewno zapoczątkowała u mnie coś nowego. Dała kopa, motywację do dalszych działań. Nowo poznane osoby okazały się bardzo inspirujące! Jeszcze raz dzięki za wszystkie opinie otrzymane po prezentacji. A jeśli nie miałeś okazji jej do tej pory wyrazić to nie zwlekaj. Jest ona dla mnie bardzo ważna.

ps. Ten weekend był ważny także z innego powodu.  Po wielu miesiącach oczekiwania nareszcie zawitała do Polski grupa Coldplay. Koncert był niesamowity!!! Co za weekend ...

Coldplay Warszawa 2017

środa, 31 maja 2017

Dogevents - wyszukiwanie wydarzeń wg lokalizacji

Jedną z głównych funkcjonalności w projekcie Dogevents jest wyszukiwanie wydarzeń wg lokalizacji. MongoDB natywnie udostępnia taką funkcjonalność, należy tylko posiadać dane geolokalizacyjne w odpowiednim formacie, przygotować odpowiedni indeks i wywołać odpowiednie zapytanie.

Format danych

MongoDB wspiera wiele typów GeoJSON takich jak punkt, linia, wielokąt. W moim przypadku ten pierwszy ma znaczenie gdyż miejsce wydarzenia to nic innego jak wskazanie na koordynaty (współrzędne) w postaci szerokości i długości geograficznej, np. [54.4760932,18.5446327]. 
W bazie muszą one zostać zapisane w postaci:
  • tablicy: [54.4760932,18.5446327]
  • dokumentu, np.: { lat: 54.4760932, lng: 18.5446327 }
U mnie właśnie ten wymóg okazał się barierą i musiałem dokonać zmiany w modelu. Dane na temat miejsca pobrane z Facebook graphApi zwracane są w postaci:

"place": {
    "name": "Psia Kość - szkolenie psów w Skoczowie",
    "location": {
      "city": "Skoczów",
      "country": "Poland",
      "latitude": 49.80972,
      "longitude": 18.79726,
      "street": "Wiejska 2",
      "zip": "43-430"
    },
    "id": "519318824878019"
  }

i przy próbie założenia wymaganego indeksu otrzymywałem błąd związany z brakiem możliwości rozpoznania danych lokalizacyjnych.

Transformacja danych

Aby rozwiązać powyższy problem zmieniłem mój model domenowy dodając nową klasę zgodną z formatem MongoDB i zmodyfikowałem strukturę location: 

public class Coordinates
{
    public double lng { get; set; }
    public double lat { get; set; }
}


public class Location
{
    public string City { get; set; }
    public string Country { get; set; }

    //For MongoDB geospatial search
    public Coordinates Coordinates { get; set; }

    public float Latitude { get; set; }
    public float Longitude { get; set; }
    public string Street { get; set; }
    public string Zip { get; set; }

    public Location()
    {
        this.Coordinates = new Coordinates();
    }
}

Aby dane zostały wprowadzone do nowej właściwości Coordinates dodałem metodę, która jest wołana w momencie deserializacji:

[OnDeserialized]
public void OnDeserialized(StreamingContext context)
{
    if (this.Place?.Location != null)
    {
        this.Place.Location.Coordinates.lat = this.Place.Location.Latitude;
        this.Place.Location.Coordinates.lng = this.Place.Location.Longitude;
    }
}

Jest to trochę mało eleganckie wyjście i powoduje duplikowanie danych. Ale chciałem na szybko uzyskać działający efekt. Na pewno jest to miejsce do optymalizacji, transformacji modelu. Końcowy dokument przyjął następującą formę:

"Place" : {
                "Name" : "Ośrodek Wypoczynkowy Omega",
                "Location" : {
                        "City" : "Przywidz",
                        "Country" : "Poland",
                        "Coordinates" : {
                                "lng" : 18.326669692993164,
                                "lat" : 54.193641662597656
                        },
                        "Latitude" : 54.193641662597656,
                        "Longitude" : 18.326669692993164,
                        "Street" : "Wczasowa 11",
                        "Zip" : "83-047"
                }
        },

Geospatial indeks

Kolejnym krokiem było utworzenie indeksów, który umożliwią tworzenie zapytań wykorzystujących dane lokalizacyjne. W swojej funkcjonalności będę wykorzystywał funkcję $near która wymaga tylko jednego indeksu typu 2d.

db.Events.createIndex({ "Place.Location.Coordinates":"2d" })

Przykładowe zapytanie

Tak przygotowana baza danych umożliwia rozpoczęcie wyszukiwania wydarzeń wg lokalizacji. Możliwości jest naprawdę wiele, mój przykład użycia jest jednym z prostszych! Poniższy przykład pokazuję zapytanie zwracające wydarzenia w odległości 50km od wskazanego miejsca:


db.Events.find({
    "Place.Location.Coordinates": {
        $near: {
            $geometry: {
                type: "Point",
                coordinates: [18.3737986, 54.5792772]
            },
            $maxDistance: 50 * 1000
        }
    }
}).pretty()

Koordynaty muszą zostać podane w postaci [długość_geograficzna (lng), szerokość_geograficzna (lat)]. Możemy określić maksymalny dystans (w metrach) jak również minimalny poprzez wskazane $minDistance.

Podsumowując. W bardzo prosty sposób możemy dodać do aplikacji funkcjonalność, która w połączeniu z bieżącą lokalizacją użytkownika umożliwi dostarczanie interesujących wydarzeń w w jego okolicy. Nie spodziewałem się tak szybkiego rozwiązania tego problemu. Jedynym z jakim się spotkałem to w dużej mierze brak danych lokalizacyjnych lub wpisanie samego miasta jako lokalizacji wydarzenia. Także wynik końcowy jest w dużej mierze zależny od osoby tworzącej wydarzenie.

piątek, 26 maja 2017

Relacja z CodeEurope 2017 Warszawa

Wczoraj wczesnym rankiem (pobudka 03:15 😪) wybrałem się do Warszawy na konferencję Code Europe. Trochę niedospany dotarłem na miejsce przed godz. 09:00. Kolejek do rejestracji nie było - tutaj organizatorzy w porównaniu do Wrocławia znaczącą się poprawili. Zanim opiszę po kolei prelekcje, w których uczestniczyłem kilka rzeczy, które spodobały mi się bądź nie.

✅ Cena biletu - była naprawdę niska. Przełożyło się to na mocne lokowanie produktów/firm w niektórych prezentacjach ale coś za coś.
✅ Ilość prelekcji - szeroki wybór tematyczny
✅ Miejsce - stadion, sale konferencyjne, strefy do posiedzenia, muzyczka na prawdę na plus. Może na głównym holu było momentami za ciasno ale było tam sporo stoisk firm, wystawców itp.
❌Panele ledowe (zamiast ekranów z rzutnikiem) dostępne na niektórych salach były usytuowane za nisko! Od połowy sali nie było już widać ich dolnych części.
Ostatnia prezentacja - już mało ludzi ale i tak nie widać dolnej części ekranu

❌Brak gastronomii - dostępne było tylko bistro na terenie stadionu, przydało by się kilka foodtruckow, jakiś dodatkowy wózek z kawą.

Prelekcje

A Fundamental Formula for Microservices using Docker - Ian Philpot 

Ewangelista Microsoftu w bardzo przystępny sposób przedstawił ABC związane mikroserwisami. Poparł to przykładami jak pewne rzeczy rozwiązywał w projektach, w których uczestniczył, własnym doświadczeniem. Komunikatywny, otwarty - prezentacja na plus!

Real world IoT solutions using Azure IoT & Azure Functions - Joe Raio

Na tą prezentację trafiłem bo: pierwsza "Pamiętaj o pamięci" nie odbyła się z powodu choroby prelegenta a druga "Scalling the data infrastructure @ Spotify" była wypchana po brzegi i zostały tylko miejsca na holu. 
Kolejny "przedstawiciel" Microsoftu, których przedstawił integrację czujników Ph (na platformie Arduino) z chmurą Azure, której celem było zbieranie danych i odpowiednie reagowanie na przekroczenie dopuszczalnych norm. Pokazane zostały "składniki", które zostały użyte w Azure i prostota (no może poza czujnikiem z arduino) w jaki sposób można to zrealizować. Mam już podstawowe doświadczenie z Azure ale była to okazja to poznania nowych rzeczy jak Azure IoT Hub, Azure Functions. Tutaj również wystawiam pozytywną ocenę.

Object Calisthenics - 9 steps to better OO code - Paweł Lewtak

Ta prezentacja najbardziej mnie rozczarowała. Przez 30min nie wiedziałem kto bardziej się męczy - ja czy prowadzący, którego wyraźnie wybiło z rytmu to, iż musiał poprowadzić ją po angielsku (a było nie pytać ludzi). Rzucane były kolejno przykłady złego kodu i jego dobrej wersji - taka kawa na ławę w 30min. Jak dla mnie nieprzystępnie - ocena negatywna.

One AI program to rule them all - Stanford's General Game Playing - Maciej Świechowski

Bardzo "akademicka" prezentacja z elementami matematyki ale ciekawa, coś z czym nie miałem do czynienia. Na plus prowadzącego język angielski - słychać było kilka lat spędzonych w Australii 😏
Ocena pozytywna.

The Things Git Can Do - Enrico Campidoglio

Jeden z bardziej charyzmatycznych prelegentów. Było wesoło, z żartami - w sam raz aby przebudzić słuchaczy. Enrico przedstawił podstawy Git'a - ale nie komend, tylko to co pod spodem się dzieję i dlaczego nie powinniśmy się tego bać. To nie Git jest trudny tylko komendy Gita. A to dlatego, że zostały napisane przez programistów dla programistów 😀 Jak najbardziej pozytywna ocena tej prelekcji.

Następnie wybrałem się na przerwę. Coś zjadłem, wypiłem kawę ale byłem tak zmęczony, że odpuściłem kolejną prelekcję i pokręciłem się trochę po stadionie. Niestety tak wczesna pobudka odbiła się negatywnie i przyswajanie informacji nie było dobre. Już wiem, że nie ma sensu zrywać się i jechać na cały dzień. Lepiej szukać czegoś na miejscu albo wybrać się dzień wcześniej tak aby być świeżym na prelekcjach.

Od Rest do GraphQL - Bartosz Sypytkowski

Dosyć świeża technologia od Facebooka ale będąca wartą rozważenia alternatywą dla Resta. Przystępnie pokazane plusy i minusy, wyzwania, z którymi trzeba będzie się zmierzyć. Bez fajerwerków ale solidna dawka wiedzy. Ocena pozytywna.

Exploring WebVR - Martin Splitt

Wybrałem coś lekkiego i dodatkowo otrzymaliśmy sporą dawkę humoru ze strony prowadzącego. Sytuacja była komiczna - pojawia się intro, że wystąpi Martin Splitt i nagle na rzutniku zaczynają pojawiać się nie jego slajdy. Techniczny podbiega do jego laptopa, odpina kabel a slajdy dalej lecą. Martin wybrnął widowiskowo. Zaczął po prostu opowiadać nam o tym co widać na rzutniku 😂 Kupa śmiechu na sali. Po kilku minutach techniczni ogarnęli sprzęt i przeszliśmy do wprowadzenia w świat wirtualnych technologii. Od sprzętu po możliwości przeglądarek w tym zakresie. Bardzo pozytywny prowadzący, lekka prezentacja i dodatkowo mały stand up.

It's all about the state, czyli co skrywa async/await w C#? - Dariusz Pawlukiewicz

Mięcho na sam koniec! Miałem obywa czy dam radę po całym dniu to ogarnąć ale już po kilku minutach byłem na TAK! Przystępnie zaprezentowane co dzieje się w IL'u gdy używamy async/await. Był mały problem z panelem ledowym i niewidocznym kodem. A szkoda bo live demo szło jak po sznurku bez żadnych zacięć. Brawo!

Podsumowanie

Udział w konferencji oceniam raczej pozytywnie. Zmęczenie dawało o sobie znak więc następnym razem inaczej będę planował takie wyjazdy. Dodatkowo raczej odpuszczę już sobie takie konferencję, które w dużej mierze promują produkty, zbierają masę HR'ow i firm, które chcą pozyskać deweloperów. Na tym etapie widzę większy potencjal w warsztatach, udziale w spotkaniach lokalnych grup lub bardziej technicznych konferencjach. 

środa, 24 maja 2017

DSP2017 etap 1 - czas podsumowań i gorzkich żali

Zbliżamy się do końca pierwszego etapu DSP2017. Nastał czas pierwszych podsumowań, przemyśleń i gorzkich żali. Zacznę od tego ostatniego 😕

Samotność

Po początkowej marcowej euforii przyszedł czas zniechęcenia, taki moment zawahania czy start w DSP miał jakikolwiek sens. Postępy w projekcie były znikome do tego to pisanie postów. W tym czasie wolałbym kodować! I tak nagle poczułem się samotny - nie życiowo ale taki niezauważony, niepotrzebny, nieodczuwający efektu DSP. Jedną z pierwszych myśli jaka mi w tedy przyszła do głowy to gdzie się podział organizator? zapomniał o nas? Ten konkurs jeszcze trwa? Zdaję sobie sprawę, że Maciej ma bardzo dużo na głowie ale jakaś mała forma cotygodniowej e-mobilizacji (może nawet sponsorzy mogliby się w to włączyć) byłaby fajnym wsparciem. Na szczęście było to u mnie chwilowe i dość szybko się z tym uporałem 😊

Walka z samym sobą

Ten konkurs to w dużej mierze walka z samym sobą. Ty jesteś właścicielem produktu, kierownikiem, bawisz się w marketing, projektujesz i realizujesz. Można się tutaj sprawdzić na kilku polach. Ja osobiście nie jestem dobry w marketingu i mój udział w DSP nie bardzo rozgłaszałem. Publikacja postów była rzucana na kilka kanałów społecznościowych. Myślę, że gdybym poświęcił większą uwagę temu efekt zauważenia byłby większy.

Czy konkurs DSP jest potrzebny?

Czy DSP jest mi potrzebne? Blogowanie, rozwijanie projektu - to wszystko przecież mogłem już dawno robić. No tak tylko tak to już jest, że jest potrzebny kopniak, mobilizacja, cel a może nawet ten element rywalizacji. Mam trochę żal do siebie, że tyle lat zwlekałem z tym. Inną sprawą jest, iż nie widziałem w tym żadnego celu. Dziś wiem, że po części było to także podyktowane miejscami w których pracowałem. Jeśli nie masz dobrego team leader'a, w zespole jest niemoc to twoje próby wybicia się czy różnych propozycji zmian, rozwoju są olewane.

To wszystko jest drugorzędne

Te wszystkie negatywne odczucia są drugorzędne. Ilość wiedzy i postęp jaki dotąd poczyniłem jest ogromny. Rozwijanie własnego projektu jest bardziej cenne niż takie suche przyswajanie wiedzy poprzez podcasty czy udział w konferencjach. Nie neguje tych drugich bo odgrywają swoją rolę w zdobywaniu informacji ale praktyka, pisanie kodu to jest to co daje dużego kopa! W krótkim czasie zapoznałem się m.in. z asp.net core, Vue.js, Webpack, Node, MongoDB, Azure. Wiadomo, że nie osiągnąłem poziomu specjalisty w tym zakresie ale jest to cenna wiedza i doświadczenie umożliwiające wejście do projektu i dalszy rozwój w tym obszarze.
Aspekt blogowania okazał się równie cenny. Pisząc posta za każdym razem weryfikujesz swoją wiedzę, uzupełniasz ją. Blog stanowi część twojego portfolio, jest twoją wizytówką. Dla mnie osobiście jest możliwością dzielenia się wiedzą. Być może po drugiej stronie łącza jest tam jakaś osoba, która z niej korzysta. Pamiętam jak zaczynałem przygodę z programowaniem sam miałem takich wirtualnych mentorów. Kilku nawet udało się spotkać na konferencjach 😁

środa, 17 maja 2017

MongoDB - ViewModel

Po pierwszych testach projektu zauważyłem, że wywołania REST API zwracają za dużo danych. Było to spowodowane zwracaniem modelu domenowego, który nie jest odpowiedni do tego typu operacji. Dlatego częstym zabiegiem jest wprowadzenie tzw. view model, który odpowiada danym zwracanym do interfejsu użytkownika czy wywołań API. Zazwyczaj jest on "szczuplejszy" i prostszy od domenowego.
W tym poście chciałbym pokazać rozwiązanie oparte o bazę danych MongoDB i metody generyczne.


Dogevents - domain model
IEvent - główny model domenowy. Ten interfejs zawiera wszystkie informacje o wydarzeniu. Jest złożoną strukturą, która odzwierciedla wydarzenia pobrane z Facebook przy użyciu Graph Api.

public class Event
{
    [BsonId]
    public long Id { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }

    [JsonProperty("start_time")]
    public DateTime StartTime { get; set; }

    [JsonProperty("end_time")]
    public DateTime EndTime { get; set; }

    [BsonIgnore]
    public string Url { get => $"https://www.facebook.com/events/{Id}/"; }

    public string CoverUrl { get => Cover.source; }

    [JsonProperty("is_canceled")]
    public bool IsCanceled { get; set; }

    public Cover Cover { get; set; }
    public Owner Owner { get; set; }
    public Place Place { get; set; }
    public IEnumerable<string> Categories { get; set; }
}


IViewEventModel - Podstawowy interfejs na potrzeby widoków. Stworzony do oznaczenia metod generycznych - tak aby móc wykorzystywać w nich pewne właściwości niezbędne do zapytań bazodanowych.

public interface IViewEventModel
{
    long Id { get; set; }
    string Name { get; set; }
    DateTime StartTime { get; set; }
}

View service

Aby móc wykorzystywać serwis pobierający wydarzenia z bazy MongoDB z różnymi modelami zadeklarowałem metody generyczne z ograniczeniem, że zwracany model musi implementować IViewEventModel. Jest to podyktowane tym, iż implementacja niektórych metod musi posiadać dostęp do specyficznych właściwości modelu, np. metoda GetIncoming<T>() wykorzystuje pole StartTime do zdefiniowania filtru na tym polu. Pominięcie takiego "wskazania" (z ang. constraint) uniemożliwiło by to.


public interface IViewEventsService
{
    Task<List<T>> GetPopular<T>() where T : IViewEventModel;

    Task<List<T>> GetIncoming<T>() where T : IViewEventModel;

    Task<List<T>> GetJustAdded<T>() where T : IViewEventModel;
}

View models

Następnie zdefiniowałem kilka klas, które będą zwracały tylko potrzebne w danym momencie dane. Dla przykładu jedna z klas, która zawiera tylko dane potrzebne do wyświetlania nagłówka wydarzenia, bez jego szczegółów.


public class EventCardHeaderViewModel : IViewEventModel
{
    public long Id { get; set; }
    public string Name { get; set; }
    public DateTime StartTime { get; set; }

    public string Url { get => $"https://www.facebook.com/events/{Id}/"; }
}

Przykład użycia



[HttpGet]
[Route("GetPopular")]
public async Task<IEnumerable<EventCardViewModel>> GetPopular()
{
    return await _viewEventService.GetPopular<EventCardViewModel>();
}

Powyżej przykład wywołania metody serwisowej ze wskazaniem na jaki model mają zostać zmapowane dane. Jest tylko jedno ale. Nie została wykonana pewna konfiguracja czy też zastosowana konwencja jak ma się zachowywać MongoDB podczas deserializacji danych na nasz model. Domyślnie, jeśli zabraknie definicji któregoś z pól otrzymamy wyjątek typu FormatException:



MongoDB konwencje

Aby rozwiązać ten problem należy odpowiednio skonfigurować mechanizm serializacji w MongoDB używając mechanizmu konwencji. API MongoDB udostępnia szereg wbudowanych "pakietów zachowań". Pełną listę można znaleźć tutaj: MongoDB Serialization Convetions Do rozwiązania tego problemu użyłem IgnoreExtraElementsConvention. Sama rejestracja odbywa się z użyciem klasy ConventionRegistry:



private static void RegisterConventions()
{
    ConventionRegistry.Register("DogeventsConvetion", new MongoConvention(), x => true);
}

private class MongoConvention : IConventionPack
{
    public IEnumerable<IConvention> Conventions => new List<IConvention>
    {
        new IgnoreExtraElementsConvention(true),
    };
}

niedziela, 7 maja 2017

PWA - Progressive Web Application

Czy jesteście w stanie wyobrazić sobie aplikacje na telefony bez potrzeby ich instalacji ze sklepu play store, app store? Korzystania z nich nawet w przypadku braku dostępu do internetu? Witam w świecie PWA - Progressive Web Application - nowoczesnych aplikacji internetowych.
Po raz pierwszy trafiłem na ten termin słuchając podcasta  Making a Web App Progressive with Christian Heilmann. W bardzo przystępny sposób Christian Heilmann opowiedział o idei jaka stoi za PWA, jak wyglądają bieżące możliwości przeglądarek w zakresie obsługi funkcjonalności, które mają dostarczać nowoczesne aplikacje internetowe i do czego to wszystko zmierza. Zrobiło to na mnie duże wrażenie. Nie tylko od strony technologicznej ale także praktycznej jako użytkownika takiej aplikacji. Samo odejście od braku potrzeby instalacji ze sklepu aby jej użyć już jest dla mnie bardzo wygodne. Ile to razy instalowałem aplikację aby użyć jej raz.
Co istotne aby aplikacja internetowa stała się "nowoczesną" nie trzeba pisać jej od nowa. Można dokonać pewnych modyfikacji, nowych implementacji, który przyczynią się do zmiany jej w PWA. Poniżej przedstawiam bardzo ogólne założenia, które mam nadzieję wprowadzą Cię w świat PWA.

Główne założenia

Niezawodność

Aplikacja ma działać zawsze, w każdych warunkach. Niezależnie czy użytkownik ma dostęp do sieci czy nie. W tym celu przydatne jest buforowanie danych po stronie klienta tak aby przy braku dostępu do internetu miał do nich dostęp. Tutaj główną rolę odgrywa service-worker, który pełni rolę usługi po stronie klienta odpowiadającej za obsługę przychodzących żądań oraz zarządzanie buforowaniem danych (z ang. cache).
źródło: https://auth0.com/blog/creating-offline-first-web-apps-with-service-workers/


Szybkość


Jedna z najbardziej frustrujących rzeczy - oczekiwanie na załadowanie się strony internetowej. Aplikacja może oferować nie wiadomo jakie fajerwerki ale jeśli jest wolna, użytkownik ciągli dostaje komunikaty typu "trwa ładowanie danych, proszę czekać ...", interfejs zawiesza się lub trzeba długo czekać na jej uruchomienie to z pewnością przeważy to na jej niekorzyść i możesz być pewien że już z niej nie skorzysta.

Atrakcyjność

Pod tym pojęciem nie kryje się tylko wizualna część aplikacji ale także możliwość uruchomienia jej z ekranu startowego, obsługa na pełnym ekranie czy wysyłanie powiadomień typu push. Użytkownik nie ma odczuwać że ma do czynienia z atrapą aplikacji. Ma ona dostarczać takich samych odczuć jak użytkowanie natywnych aplikacji. Zapewnić to mogą Web App Manifest oraz wspomnianie już Web Push Notification

Przykładowe aplikacje

Istnieje już kilka rozwiązań, które całkowicie implementują PWA są to m.in.:
Moją uwagę przykuła ostatnia pozycja ze względu na udostępnienie przez autora kodu gdzie można zobaczyć cały stos technologiczny i rozwiązanie wspomnianych idei PWA.

Przydatne narzędzia

Na sam koniec wspomnę o kilku narzędziach, które mogą pomóc w pracy przy tworzeniu bądź konwersji aplikacji internetowej do PWA. Są to:
  • Lighthouse - narzędzie do badania w jakim stopniu nasza aplikacja spełnia założenia PWA.
  • Konsole deweloperskie dostępne w przeglądarkach, które w całości dostarczają nam wszystkich informacji oraz narzędzi. Polecam zapoznanie się z artykułem Tools for PWA Developers

Podsumowanie

Moim zdaniem PWA wytycza nowy kierunek aplikacji internetowych. Nie jest to może rewolucja ale ewolucja, która wprowadza wygodne dla użytkownika rozwiązania. Odchodzi od modelu instalacji aplikacji ze sklepu, pozwala na jej użytkowanie również przy braku dostępu do sieci, przeszukiwanie jej zawartości przez wyszukiwarki co zwiększa szansę na trafienie do docelowego odbiorcy. Minusem są przeglądarki internetowe, które na swój sposób realizują obsługę mechanizmów PWA i poszczególna implementacja na każdej z nich może się różnić i być na innym etapie. Oby nie tak bardzo jak w przypadku arkuszy CSS kilka lat temu 😉

środa, 3 maja 2017

Azure - Deploy Node.js + Vue + Webpack

Nie mogłem doczekać się aż napiszę tego posta. Minęło kilka dni, cisza nastała na blogu ale była spowodowana spadkiem mocy i frustracją spowodowaną wieloma bezowocnymi próbami zbudowania aplikacji node.js na serwerze Azure. Ale w końcu udało się. Można powiedzieć, że mam już prawie pełne CI 😏

Scenariusz wdrożenia

Zacznę od opisu jaki efekt chciałem uzyskać.
Azure deploy - node.js, vue.js, webpack
Lokalne zmiany są zatwierdzane i "wypychane" na serwer githuba, Następnie Azure poprzez skonfigurowany automatyczny deploy rozpoczyna całą procedurę wdrożenia:
  • Pobiera kod źródłowy z githuba do folderu \home\site\repository
  • Kopiuje pliki do folderu \home\site\wwwroot
  • Wykonuje instalację node_modules
Tak to wygląda bardzo poglądowo, w tle dzieje się wiele więcej rzeczy. 
W tym całym procesie brakowało mi aby to Azure był odpowiedzialny za uruchomienie webpacka i wykonanie całej tej procedury transformacji plików .js, .vue itd. tak aby pozbyć się z repozytorium "/dist".

Potencjalne problemy

Jak wspomniałem na początku posta, droga nie była łatwa ale też w dużej mierze przez brak doświadczenia jak działa deploy Azure i node.js w środowisku produkcyjnym. Oto kilka wskazówek:
  • Node.js na Azure działa w trybie "production". Weź to pod uwagę gdy chcesz uruchamiać skrypty które coś budują. Tutaj nie masz skonfigurowanego środowiska deweloperskiego adhoc.
  • Zwróć uwagę na użytą wersję node.js oraz npm. Większość moich problemów wynikała z dość starej wersji npm 1.4. Można to zmienić dodając ustawienie WEBSITE_NODE_DEFAULT_VERSION. Listą dostępnych runtime jest duża i można ją zobaczyć pod adresem: https://your_site_name.scm.azurewebsites.net/api/diagnostics/runtime
  • Zanim doszedłem do zmiany wersji node.js przez długi czas borykałem się ze znanym z wcześniejszych wersji windows problemem maksymalnego rozmiaru nazwy ścieżki ograniczonego do 260 znaków. Jest dostępne obejście tego problemu: #max_path-explanation-and-workarounds
  • Pamiętaj aby nie kopiować nie potrzebnych rzeczy do folderu docelowego, np. logi z builda, node_modules typu devDependencies


#1 Własny skrypt deploy.cmd

Aby ruszyć z tematem wpierw należy wykonać modyfikację automatycznego deploy poprzez utworzenie własnego skryptu. Służy do tego narzędzie azure-cli https://www.npmjs.com/package/azure-cli. Tworzy ona dwa pliki .deployment oraz deploy.cmd. Obydwa należy umieścić w katalogu root aplikacji. Do ich utworzenia służy komenda:
azure site deploymentscript --node
deploy.cmd jest skryptem batch, w którym widać kilka komend ustawiających zmienne do poleceń jak i ich wywołania. Głównie są to operacje kopiowania plików pomiędzy folderem %DEPLOYMENT_SOURCE% a %DEPLOYMENT_TARGET%
Na uwagę zasługuje zmienna %DEPLOYMENT_SOURCE%. Wskazuje ona na ścieżkę do folderu repozytorium z projektem. W moim przypadku mój projekt nie leży w głównym katalogu repozytorium, więc musiałem dokonać zmiany w ustawieniach podając prawidłowy katalog.


Dodatkowo dodałem ustawienie "command" wskazujące na mój skrypt deploy.cmd. Nie musisz tego wykonywać jeśli ten skrypt będzie umieszczony w głównym katalogu repozytorium:
Azure - deploy.cmd path

#2 Webpack build

Kolejnym krokiem jest dodanie do skryptu deploy.cmd wywołania webpack aby wykonał przetwarzanie naszego projektu. Co istotne chcę aby ten krok został wykonany jeszcze w lokalnym folderze repozytorium a nie w docelowym site/wwwroot gdzie mają znaleźć się tylko wymagane moduły produkcyjne node'a, statyczne pliki html oraz przygotowany przez webpack /dist. Pozostały kod źródłowy nie powinien w tym miejscu się znaleźć.


Całość zamyka się w takim oto wywołaniu:
deploy.cmd
:Deployment
echo Handling node.js deployment.

:: 1. Webpack Build
IF EXIST "%DEPLOYMENT_SOURCE%\webpack.config.js" (
  echo Installing node modules dev/prod
  pushd "%DEPLOYMENT_SOURCE%"
  call npm install --only=prod
  call npm install --only=dev
  echo Running webpack build
  call npm run build
  popd
  IF !ERRORLEVEL! NEQ 0 goto error
  echo Finished webpack build
)

  • Sprawdzam czy w folderze projektu znajduje się plik konfiguracyjny webpack.config.js
  • Następnie przystępuje do instalacji paczek node'a - produkcyjnych i deweloperskich. Związane jest to z tym iż package.json dzieli moduły, które są potrzebne do uruchomienia aplikacji (dependencies) od tych wymaganych tylko w środowisku deweloperskim (devDependencies). My potrzebujemy obydwie zależności.
  • następnie uruchamiam skonfigurowany w package.json "build" skrypt. Komenda npm run build
package.json
"scripts": {
    "dev": "cross-env NODE_ENV=development webpack-dev-server --open --hot",
    "build": "cross-env NODE_ENV=production webpack --progress --hide-modules"
  },

Tak wygląda log z wywołania:
Azure - deploy.cmd output
Widać, że został wykorzystany niestandardowy katalog źródłowy, własny skrypt oraz wywołanie instalacji paczek node'a i webpack.

#3 KuduSync

Kolejnym krokiem jest kopiowanie plików z folderu źródłowego do docelowego site/wwwroot. Na tym etapie należy wykluczyć niepotrzebne pliki. Komenda %KUDU_SYNC_CMD% zawiera argument "-i", który umożliwia wskazanie takich plików/folderów. Domyślnie jest dodany foldery .git oraz skrypty deploy. Resztę dopisujemy wg uznania. Na pewno nie chcę kopiować zainstalowanych na potrzeby webpack paczek node'a oraz plików źródłowych .vue. Możemy także wykluczyć pliki konfiguracyjne takie jak webpack.config.js


:: 2. KuduSync
IF /I "%IN_PLACE_DEPLOYMENT%" NEQ "1" (
  call :ExecuteCmd "%KUDU_SYNC_CMD%" -v 50 -f "%DEPLOYMENT_SOURCE%" -t "%DEPLOYMENT_TARGET%" -n "%NEXT_MANIFEST_PATH%" -p "%PREVIOUS_MANIFEST_PATH%" -i ".git;.hg;.deployment;deploy.cmd;node_modules;.vue;webpack.config.js"
  IF !ERRORLEVEL! NEQ 0 goto error
)

Podsumowanie

Dzięki własnej implementacji a raczej rozszerzeniu deploy.cmd o wywołanie webpack udało się uzyskać bardzo wygodne rozwiązanie gdzie nie muszę umieszczać w repozytorium wygenerowanych plików przerzucając to na serwer Azure. Głównym problemem, który najbardziej może doskwierać to to, iż teraz musimy niejako utrzymywać dwa środowiska deweloperskie tak aby zarówno build lokalny jak i ten na Azure wykonywały się poprawnie.