Podsumowanie konkursu Daj się poznać 2017

Nadszedł ten dzień, trzy miesiące minęły bezpowrotnie. Konkurs Daj się poznać 2017 dobiega końca. Pora więc na małe podsumowanie i kilka refleksji. Zapraszam do lektury!

Projekt

Dla mnie ta przyjemniejsza część konkursu. Plan minimum został wykonany, gra w podstawowej wersji działa. Co prawda muszę dodać jeszcze kilka szczegółów przed jej upublicznieniem (np. większa baza słów), ale to już jest bardziej kwestia niezwiązana z programowaniem. Co mi się udało zrobić opisałem w poprzednim poście, dlatego nie będę się na ten temat rozpisywał. Czy mogłem zrobić więcej? Ciężko mi powiedzieć. Na pewno bardzo dużo czasu poświęciłem na poznanie nowych technologii. Nie obyło się także bez walki z problemami związanymi z niestabilnymi jeszcze technologiami. Wiadomo, gdybym użył znanych mi narzędzi, dużo więcej udałoby mi się zrobić. Ale nie o to mi chodziło, to właśnie o poznanie nowych rzeczy tutaj chodziło. Czy jestem zadowolony z wyników pracy? Myślę, że tak. Powiedzmy że szklanka w tym przypadku jest w połowie pełna.

Blog

To była ciężka przeprawa. Stres związany z przelewaniem swoich myśli oraz przekazywaniem ich publicznie był na początku bardzo duży. Z czasem jednak już o tym nie myślałem, więc tutaj duży plus! Podobnie było z czasem jaki musiałem poświęcać na pisanie postów. Na początku potrzebowałem na to 3-4 godziny, nie licząc oczywiście czasu na research w danym temacie. Tutaj także nabrałem wprawy, udało mi się zejść do około 2 godzin na samo pisanie artykułów. Niestety czas pracy zacząłem zapisywać dopiero pod koniec marca, dlatego nie mam dokładnego porównania jak to się zmieniało. Często zamiast blogować, miałem ochotę dalej rozwijać projekt. Ale wiadomo, trzeba się było trzymać harmonogramu i posty musiały się pojawiać.

Podsumowanie_meme

Dzisiejszy post jest dwudziestym w trakcie trwania konkursu. Minimum wykonane, udało się wytrwać, trochę jak ten mem. Na początku konkursu posty pisałem z większym entuzjazmem niż w ostatnich tygodniach. Nie wiem czy 20 postów to aż tak dużo, ale ilość ta trochę mi ciążyła. Dlatego cieszę się że konkurs dobiega już końca(prawie tak bardzo jak fakt, że wytrzymałem do finału). Posty w których opisywałem tylko to, co udało mi się zrobić w projekcie, traktowałem jako przykry obowiązek. Jednak ku mojemu zdziwieniu, pisanie tych bardziej technicznych postów sprawiało mi wiele frajdy.

Trochę liczb

Skoro już była mowa o tym, ile czasu poświęcałem na pisanie postów, podzielę się ile czasu poświęciłem na projekt. Nie są to dane całkowite, bo zacząłem je śledzić dopiero od 26 marca, więc już praktycznie po pierwszym miesiącu. Jestem pewny, że razem z danymi za cały marzec, dużo więcej godzin znalazło by się w statystykach odnośnie pisania bloga.

Statystyki 1

Łączny czas pracy 26.03 – 30.05

Jak widać, duuużo więcej czasu poświęciłem na sam projekt. Około 24h na 12 postów. W marcu proporcje były moim zdaniem odwrotne, ale tego nie mam niestety jak sprawdzić, musicie mi uwierzyć na słowo.

Statystyki 2

Rozkład czasu pracy

Jak widać, początek kwietnia to był najbardziej pracowity okres. Tutaj prosta przyczyna, miałem kilka dni wolnego. A dalej to już różnie bywało. Powiedziałbym, że pracowałem w równych dwutygodniowych cyklach, ale nie wiem z czego to wynikało. Na koniec jeszcze ogólne podsumowanie. Można powiedzieć, że udało mi się wykręcić dodatkowe pół etatu.

Statystyki 3

Podsumowanie z podziałem na miesiące

Co dalej?

Jeżeli chodzi o projekt, to na pewno doprowadzę go do końca. Sam chcę z niego korzystać. Myślę, że moi znajomi też czasem z niego skorzystają. A co dalej z blogiem? Przyznam szczerze, że spodobało mi się pisanie postów. Spotkałem się z kilkoma miłymi słowami w związku z niektórymi postami, dlatego na pewno będę starał się wrzucać tutaj coś nowego raz na jakiś czas. Oczywiście nie z taką częstotliwością jak dotychczas, a na pewno dam sobie kilka długich dni przerwy.

Jeżeli chodzi o sam konkurs, to dał mi sporego kopa motywacyjnego do pracy. Czy wezmę jednak udział za rok? Nie wydaje mi się. Wiem już, że jeżeli chce, to potrafię wytrwać i pracować z taką regularnością. Jednak praca na blogu i tak częste jego aktualizowanie to dla mnie troszkę za dużo. Dlatego za rok będę tylko obserwował poczynania innych.

Dziękuję tym, którzy czytali moje wypociny przez ten czas. Gdyby nie Wy i ta skromna, ale regularna liczba wejść na bloga nie wytrwałbym do końca! Pozdrawiam i zapraszam ponownie!

Postęp prac nad projektem – to działa!

Dzisiaj chciałem opisać w skrócie to, co udało mi się zrobić w ostatnim czasie. Jest to ostatnia aktualizacja przed końcem konkursu. Najważniejsze się udało, czyli możliwość gry dla dwóch drużyn! W najbliższym czasie postaram się przeprowadzić testy w gronie znajomych. Później udostępnię aplikację dla wszystkich. Zaczynamy!

Tryb gry i dostępne opcje

Z dwóch trybów gry, które były w założeniach, udało mi się zrobić jeden. Jest to standardowa gra dla dwóch drużyn, gdzie pierwsza, która odkryje swoje pola, wygrywa. Rozgrywka sterowana jest za pomocą jednego urządzenia, które należy do założyciela rozgrywki. Inni gracze mogą podglądać co się dzieje na swoich urządzeniach. Dzięki temu można np. odpalić grę w salonie na telewizorze. Jest także niezbędna dla kapitanów mapa, która wskazuje, które pola należą do poszczególnych drużyn.

Mapa dla kapitanów

Mapa gry z odkrytymi polami

Mapa gry jest identyczna do planszy, ale nie można na niej wykonywać żadnych operacji. Z poziomu planszy możemy zakończyć naszą turę. Na obu ekranach w górnym panelu wyświetla się informacja o tym, która drużyna wykonuje obecnie ruch.

Przycisk zakończenia tury

Zakończenie tury i zmiana drużyny

Na podstawie skojarzeń podanych przez kapitana gracze odgadują, które pola miał na myśli. W przypadku, gdy trafią na puste pole lub pole drużyny przeciwnej, ich tura dobiega końca. W przypadku, gdy odkryją własne pole, mogą kontynuować rozgrywkę. Po odkryciu wszystkich swoich pól, wygrywają. Gdy trafią na jedną z pułapek, gra dobiega końca i wygrywa przeciwny zespół. Oczywiście wszystkie akcje synchronizowane są na wszystkich podłączonych urządzeniach.

Odgadywanie pól

Odgadywanie pól i zmiana drużyny przy złym ruchu

Tym razem nie będę opisywał żadnych technicznych szczegółów. Wszystko z czego korzystałem było opisane w moich poprzednich postach w ostatnich tygodniach. Dotyczyły one takich technologii i bibliotek jak SignalR, Asp.Net Core, Angular lub Dapper.Net. Nowe technologie nie pojawiły się w ostatnim czasie, więc chyba nie ma potrzeby powielać tutaj tych informacji.

Co jest jeszcze do zrobienia?

Sporo. Tak mógłbym w skrócie napisać. Pomimo, że gra sama w sobie działa, bardzo dużo jest jeszcze do zrobienia. Tryby dla większej ilości graczy to na pewno jedna z pierwszych rzeczy które są w moich planach. Różne mniejsze poprawki które ułatwiają życie: możliwość wchodzenia do gier znajomych, social logins(Facebook, Google etc), uruchamianie nowej gry jednym kliknięciem po zakończeniu obecnej rozgrywki lub poprawki w interfejsie. To tylko część funkcjonalności, które także chciałbym żeby znalazły się w finalnej wersji. Tryb gry, gdzie każda drużyna steruje swoim urządzeniem to także coś, co chciałbym dodać. Niestety, to raczej będzie zaimplementowane w drugiej kolejności. Ostatnia rzecz to natywny klient na system android. Szczerze, to nie wiem czy ten pomysł wejdzie w życie, zobaczymy. Obawiam się, że prędzej zajmę się nowym projektem, ale kto wie!

Podsumowanie

Plan minimum został wykonany, chociaż po cichu liczyłem na więcej. Wiadomo, życie potrafi brutalnie zweryfikować to, co sobie założymy. Patrząc na całość, jestem w miarę zadowolony z tego co zostało zrobione. Za jakiś czas, już po konkursie, na pewno pochwalę się pozostałymi rzeczami które dodałem. Na razie mam nadzieję, że wśród moich znajomych znajdą się dobrzy ludzie, którzy zechcą ze mną przetestować moją grę!

WordHunt – plansza do gry przy użyciu Flex Layout

Dzisiaj pokażę jak wygląda plansza do gry. Przyznaję, że spodziewałem się że ten element zostanie skończony już dawno, ale wyszło jak wyszło. Zadanie to sprawiło mi więcej problemów niż się spodziewałem, ale jestem w miarę zadowolony z tego co otrzymałem.

Plansza i jej elementy

Jeżeli chodzi o styl, pozostawia ona jeszcze sporo do życzenia, ale pola na planszy zachowują się tak jak chciałem. Dostosowują się do wielkości ekranu, w pełni wypełniając całą dostępną przestrzeń.

Board_mobile

Plansza do gry 5×5 na małym urządzeniu

W przypadku, gdy plansza posiada więcej słów i pola nie będą się mieścić w całości, wyrazy zostaną ucięte. W przyszłości czcionka będzie zmieniać rozmiar w zależności od wielkości ekranu i długości słowa, dzięki czemu unikniemy takich sytuacji. Na troszkę większych urządzeniach np. tabletach wyświetlanie działa tak jak należy, nawet na największej możliwej planszy 8×8.

board2_tablet_8x8

Plansza do gry 8×8 na tablecie

Teraz, gdy plansza jest już w takim stanie, zaczynam dodawać pozostałe fragmenty. Na tą chwilę jest jeszcze menu boczne, gdzie będą dodatkowe informacje oraz opcje. Żeby nie marnować miejsca, jest ono ukryte. Gdy je otworzymy, menu pojawia się nad planszą.

board3_sidenav

Plansza do gry – menu boczne

Obecnie obsługuję jedynie przycisk pominięcia rundy, dzięki czemu kolejna drużyna może wykonać ruch. Jutro dodam obsługę „odsłonięcia” pola, czyli jedną z najważniejszych rzeczy do zrobienia.

Jak to wygląda pod maską?

Skoro już zademonstrowałem jak plansza wygląda, pokażę teraz jak to działa. Wygląd aplikacja zawdzięcza komponentom Angular Material Design, natomiast sam layout planszy działa na bazie Flex Layout. Obie biblioteki są w wersji beta, ale większych bugów nie znalazłem. Muszę jednak powiedzieć, że próg wejścia do tych technologi jest troszkę większy niż to, co spotyka nas przy pierwszym kontakcie z popularnym konkurentem, czyli poczciwym Bootstrapem. Nie ma jednak tragedii i coś nawet da się z tym zrobić.

Ekran gry podzielony jest na kilka elementów. Kod głównego komponentu, na którym umieszczone są wszystkie elementy wygląda następująco:

Kontener, w którym wyświetlane jest menu boczne, toolbar gdzie jest tytuł aplikacji, a będą także ikony drużyn oraz plansza do gry. Tutaj nie musiałem dużo majstrować przy stylach. Jedynie toolbar wymagał drobnych modyfikacji.

Ręcznie modyfikuję rozmiar górnego paska aplikacji, ponieważ zmieniał się on przy zmianie wielkości okna. Powodowało to, że plansza do gry odrobinę się przesuwała i wychodziła poza ekran.
W bazowej klasie ze stylami zdefiniowałem mixin, który wykorzystujemy w innych komponentach, tak jak powyżej. Dzięki temu dokładnie i w łatwy sposób sterujemy stylami w zależności od wielkości ekranu. Był on szczególnie potrzebny w przypadku planszy, ponieważ przesuwała się ona w dół o wysokość paska górnego.

Sam kod planszy jest dosyć krótki, ale powiedziałbym że intensywny. Mamy tutaj dwa layouty fxLayout: column i row. Kolumnowy sprawia, że każdy rząd zabiera odpowiednią ilość miejsca w pionie. Dzięki temu plansza wypełnia całą przestrzeń. Każdy rząd składa się z komponentu game-field, który wyświetla słowa i odpowiadać będzie za kliknięcie na element.

Wartość fxFlex, która definiuje nam jak dużo przestrzeni ma wykorzystać każdy blok, wyliczana jest w kodzie po załadowaniu danych gry. Na podstawie ilości rzędów i kolumn dodajemy odpowiednią wartość do każdego elementu. Wartość bazowa baseFlexValue, od której liczymy wielkość elementów sprawia, że otrzymamy małe odstępy pomiędzy polami, które będą zmieniały wielkość w zależności od wielkości ekranu. Gdyby było tam 100, nie mielibyśmy przerw. Można to oczywiście zaprogramować inaczej, np. poprzez margin pól gry, ale na razie zostawię to tak jak jest.

Jeżeli chodzi o stylowanie tego komponentu, trzeba było dodać obliczenie wielkości planszy z uwzględnieniem paska górnego. Bez tego plansza była przesunięta o jego wysokość.

Tutaj uwaga! calc nie przyjmuje zmiennych z SASSa, chyba że opakujemy je w nawiasy klamrowe poprzedzone hasztagiem. Trochę mi zajęło zanim na to wpadłem… Szczerze, to boję się tego ruszać, bo już raz coś zmieniłem, co sprawiło że zepsułem cały ekran gry i naprawiałem go dobrych kilka minut. Szybko nauczyłem się robić częste commity, o których zdarza mi się zapomnieć. Kodu nie jest wiele, ale jako że nie jestem mistrzem CSS, trochę mi zajęło znalezienie takiej konfiguracji.

Podsumowanie

Plansza w wersji beta gotowa, teraz dodanie obsługi wykrywania pól oraz mapy dla kapitanów. Gdy to będzie gotowe, MVP projektu będzie skończone. Mam nadzieję że przed końcem konkursu!

Pierwszy pull request, czyli dokładamy swoją cegiełkę do projektów typu open source

Ostatnio napisałem kilka postów dotyczących wykorzystania biblioteki SignalR w moim projekcie. Opisywałem tam, jak dodać obsługę SignalR po stronie klienta napisanego we frameworku Angular. W tym celu wykorzystałem bibliotekę ng2-signalr. Podczas pracy z nią zauważyłem, że autor nie dodał jednej funkcjonalności, a dokładnie możliwości wyboru kanału transportu. Zagłębiłem się więc w kod źródłowy i zacząłem działać…

Mój pierwszy pull request

Każdy kto zna stronę GitHub, wie że służy ona do przetrzymywania kodu źródłowego projektów, ale nie tylko. Możemy tam za darmo hostować strony internetowe znajdujące się tam w repozytorium. Projekty mogą być publicznie widoczne dla każdego, lub prywatne (płatna opcja). Twórcy wielu bibliotek trzymają tam swój kod. Nie tylko możemy go przeglądać, ale także dokonywać w nich zmian, oczywiście za zgodą autora. Jak już wcześniej wspomniałem, sam znalazłem się w sytuacji, gdzie potrzebowałem drobnej modyfikacji. Zrobiłem ją na szybko w kopii biblioteki lokalnie, ale stwierdziłem, że nie potrwa to za długo żeby zrobić to jak należy. Nie będę rozpisywał się nad tym co dokładnie zrobiłem. Kto jest ciekawy, niech poczyta o tym tutaj.

Pull request na stronie GitHub.com

Niektórzy być może na co dzień pracują z pull requestami w pracy. Sam do takich osób nie należę, dlatego musiałem sprawdzić samemu jak to działa. A jest to bardzo proste. Zaczynamy oczywiście od wyboru projektu w którym chcemy dokonać zmiany. Następnie klikamy na przycisk Fork.

Fork

Dzięki temu dodana zostanie nasza kopia repozytorium. To w niej będziemy dokonywać zmian. Istnieje także drugi typ takiej pracy, gdzie jesteśmy współtwórcami repozytorium. Wtedy możemy dodać nasz branch i dodać pull request do zmian zawartych w nim. Tak jak tutaj pokazuje jest jednak łatwiej, ponieważ nie musimy posiadać żadnych uprawnień do repozytorium. Na naszym profilu GitHub widać że zrobiliśmy forka repozytorium.

fork_2

Następnym krokiem będzie dokonanie odpowiednich zmian w kodzie. Można to zrobić online z poziomu GitHuba. W przypadku poprawek dokumentacji może i tak zrobilibyśmy, ale w naszym przypadku zmian dokonywać będziemy lokalnie z wykorzystaniem naszego ulubionego IDE. Ten krok pominę, bo to co zmienimy zależy od projektu. Następnie robimy commit naszych zmian. Gdy już je zapiszemy, możemy wysłać pull request, czyli dajemy informację autorowi o tym, że dokonaliśmy poprawek i są gotowe do pobrania.

pr_1

Autor sprawdza co zrobiliśmy i akceptuje zmiany, lub zwraca nam je do poprawki. Jeżeli musimy poprawić część kodu, wystarczy później ją zapisać w naszym branchu. GitHub automatycznie zaktualizuje nasz pull request. Voila, gotowe. Nasze zmiany zostały przyjęte i są dostępne dla innych.

Po co mam robić cudzy projekt?

Niektórzy być może zadają sobie takie pytanie. Wymienię moim zdaniem kilka najbardziej oczywistych. Być może nie każdego to przekona, ale warto spróbować.

Dla spokoju w projekcie. Jeżeli korzystamy z biblioteki i musimy zrobić w niej jakąś poprawkę, najszybciej będzie zrobić kopię kodu źródłowego i dodać ją do naszego projektu. Nie musi to być poprawka zrobiona najlepiej jak się da. Wiadomo, ważne żeby działało. Wadą tego rozwiązania jest to, że jeżeli biblioteka otrzyma inne poprawki, które będziemy chcieli mieć w naszym projekcie, nasza poprawka będzie musiała zostać dodana na nowo. Pozornie łatwiejsza zmiana będzie niosła ze sobą więcej pracy w przyszłości. Naturalnie możemy liczyć na to, że ktoś inny dokona tych poprawek. Wiadomo jednak że najlepiej liczyć zawsze na siebie…

Dla satysfakcji. Tutaj bardzo obiektywna sprawa, ale mi bardzo wiele radości sprawia myśl, że mogę dodać zmiany z których inni będą korzystać. Wielu programistów ma to samo, ten moment gdy coś działa® i my to dodaliśmy. Mimo wielu lat, dalej jest to dla mnie coś bardzo przyjemnego, polecam.

Dla własnych korzyści. Dodanie w CV że aktywnie działamy podczas rozwoju kilku projektów typu open source to może być wielki plus w oczach pracodawcy. Ten punkt jest głównie dla programistów z mniejszym stażem, którzy w ten sposób mogą zapełnić swoje skromne CV. Łatwo pokazać w ten sposób że potrafimy coś zrobić i wiemy więcej niż uczą tylko na studiach. Doświadczeni programiści także mogą czerpać z tego korzyści, aktywny udział w dużych projektach i nie tylko może odróżnić nas od konkurencji na rynku.

Podsumowanie

Żałuję, że dopiero teraz udało mi się zrobić mój pierwszy wkład w projekty tego typu. Następnym razem, gdy będę korzystał z biblioteki w której będzie jakiś problem, poświęcę chwilę na sprawdzenie czy poprawka mojego problemu to duży problem. Może jednak dodanie jej własnoręcznie będzie lepsze niż szukanie obejścia problemu w internecie? Zachęcam Was do tego samego, w końcu na co dzień wszyscy korzystamy z bibliotek na które ktoś inny poświęcił swój czas. Może warto poświęcić trochę naszego?

SignalR w ASP.NET Core i Angular – implementacja po stronie klienta

Dzisiaj pora na kolejny post dotyczący wykorzystania SignalR w ASP.NET Core. Ostatnim razem pisałem o implementacji po stronie serwera, tym razem zajmiemy się klientem aplikacji z wykorzystaniem frameworka Angular. Poniżej zamieszam odnośniki do powiązanych postów.

Część pierwsza: SignalR w ASP.NET Core – instalacja i uruchomienie

Część druga: SignalR w ASP.NET Core i Angular – przykładowa implementacja

Połączenie z serwerem

Gdy pisałem o konfiguracji, podałem na przykładzie w jaki sposób możemy połączyć się z serwerem. W tym celu wykorzystałem tzw. resolver w Angularze. Działa on na takiej zasadzie, że zapytanie wykonane w nim wykonuje się przed załadowaniem naszego komponentu, czyli np. planszy do gry. Poniżej przedstawię trochę inny przykład, gdzie ręcznie wywołujemy funkcję odpowiedzialną za połączenie. Na początek dodajemy fabrykę, która potrafi utworzyć nam nowe połączenie.

Fabrykę wykorzystujemy tylko do nawiązania nowego połączenia. Jeżeli będę chciał wykorzystywać inne konfigurację niż standardowa, nie chcę dodawać tego kodu do klasy odpowiedzialnej za samo przetwarzanie komunikatów.

Dwustronna komunikacja

Następnie dodaję serwis, który będzie przetrzymywał otwarte połączenie z serwerem oraz rozsyłał komunikaty do komponentów w Angularze. Cały klient będzie miał tylko jedno otwarte połączenie, ponieważ otwarcie takiego połączenia jest czasochłonne. Dodatkowo nie ma sensu obciążać serwera wieloma połączeniami w ramach jednej aplikacji klienckiej. Poniżej przedstawiam taką klasę, która obsługuje dwa typy zdarzeń:

  • Połączenie klienta do serwera, inicjowane prze klienta
  • Zmiana drużyny która wykonuje ruch, inicjowane prze serwer

Posiada ona kilka funkcji, omówię krótko każdą z nich.

  • connect – odpowiada za nawiązanie połączenia w ramach klienta. Połączenie jest przechowywanie w hubie i dzielone pomiędzy wszystkie komponenty.
  • disconnect– analogicznie do funkcji powyżej, zamyka ono połączenie z serwerem.
  • subscribeToGame – zdarzenie inicjowane po stronie klienta. Za jej pomocą dołączamy do kanału obecnej gry, dzięki temu otrzymamy komunikaty powiązane z grą.
  • subscribed – zdarzenie inicjowane po tym, jak nowy klient zapisze się do naszej gry.
  • teamChanged – zdarzenie inicjowane po tym, gdy jedna z drużyn wykona ruch, który spowoduje zmianę kolejki na inną drużynę.

Wykorzystanie serwisu w aplikacji

Gdy mamy już gotowy serwis, możemy wykorzystać go w naszej aplikacji. Na początek w głównym komponencie gry wywołujemy połączenie z serwerem.

Dzięki jej wywołaniu kolejno:

  • nawiązujemy połączenie z serwerem
  • zapisujemy się do gry
  • ładujemy dane gry
  • inicjalizujemy komponenty

Przykładem komponentu wykorzystującego ten serwis może być menu boczne aplikacji. Z jego poziomu drużyna może pominąć kolejkę, co będzie skutkowało zmianą obecnie aktywnej drużyny. Dodatkowo, gdy nastąpi zmiana drużyny, będziemy mogli nasłuchiwać na takie zdarzenie i wyświetlić drużynę wykonującą obecnie ruch.

Mamy tutaj trzy elementy na które należy zwrócić uwagę:

  • initialize – tutaj komponent zgłasza chęć otrzymywania komunikatów związanych ze zmianą aktywnej drużyny. teamChanged przyjmuje funkcję, która wykona się za każdym razem, gdy takie zdarzenie nastąpi.
  • onTeamChanged – wspomniana wyżej funkcja, która wykona się po wystąpieniu zdarzenia zmiany drużyny. Tutaj wyświetlony zostanie tylko komunikat w konsoli.
  • skipRound – pominięcie tury. Nie odwołujemy się tutaj bezpośrednio do SignalR’a, ale wykonujemy zwykłe zapytanie do serwera. On później roześle informacje o zmianie aktywnej drużyny

Podsumowanie

Wydaje mi się, że w tych trzech wpisach pokazałem, jak wykorzystać w naszej aplikacji bibliotekę SignalR i tworzyć aplikacje działające w czasie rzeczywistym. Zachęcam do wypróbowania jej we własnym zakresie. Jeżeli jednak miałbym być szczery, to na chwilę obecną proponuję wykorzystanie tej biblioteki w starszej wersji frameworka, chyba że tak jak ja chcecie po prostu pobawić się z nowszą wersją frameworka .NET. Co prawda, pojawił się już ASP.NET Core Preview 1, ale nie jest to wersja stabilna. Taka pojawi się dopiero pod koniec obecnego roku.

SignalR w ASP.NET Core i Angular – przykładowa implementacja

Niedawno opublikowałem wpis na temat instalacji biblioteki SignalR w projekcie ASP.NET Core z wykorzystaniem Angulara. Dzisiaj chciałem kontynuować ten temat na przykładzie z mojego projektu. Zademonstruję działającą implementację po stronie serwera.

Link do poprzedniego wpisu: SignalR w ASP.NET Core – instalacja i uruchomienie

Konfiguracji ciąg dalszy

Chociaż konfiguracja jaką podałem w ostatnim wpisie wystarczała do działania, w moim rozwiązaniu musiałem dodać jeszcze kilka ustawień. Na pierwszy ogień poszedł CamelCasePropertyNamesContractResolver, dobrze znany wszystkim, którzy tworzyli kiedyś API w Asp.Net. Dzięki niemu, obiekty zwracane są z API w notacji CamelCase. Jest to domyślne ustawienie w .NET Core, ale jako że my mamy podpiętą bibliotekę ze starszej wersji frameworka, musimy ustawić to ręcznie. Przykładowa implementacja poniżej.

Następnie rejestrujemy nasz serializator w pliku Startup.cs.

Rozsyłanie eventów z poziomu backendu aplikacji

Wysłanie zdarzenia z serwera może odbyć w dwóch przypadkach:

  • Bezpośrednio z naszej klasy, dziedziczącej po Hub, w momencie gdy klient wywołuje zdalną metodę na serwerze
  • Po wywołaniu zwykłej metody HTTP w API, pośrednio poprzez Hub

O ile w pierwszym przypadku jest to bardzo proste, to ten drugi wymaga dodatkowego nakładu pracy. Załóżmy że nasz Hub ma tylko jedną metodę.

Klient, w momencie gdy wywoła metodę Subscribe, zapisze się do grupy odpowiadającej identyfikatorowi gry. Zwrócone mu zostanie id jego połączenia. Wewnątrz klasy Broadcaster możemy wysłać zdarzenie o nowej subskrypcji do wszystkich klientów. Taki przykład podałem w poprzednim poście, dlatego tutaj to pomijam (nie jest to potrzebne w moim przypadku). Efekt który chcemy tutaj osiągnąć to wysłanie do każdego klienta informacje o tym, że gracz wykonał ruch. Jako przykład posłuży tutaj zakończenie tury przez gracza.

Podczas wywołania tej akcji kontrolera, wywołujemy metodę SkipRound. Wewnątrz niej, po tym jak nastąpi zmiana kolejki, chcielibyśmy poinformować wszystkich graczy o tym fakcie. Nasz Hub to nie jest zwykła klasa, którą można po prostu wstrzyknąć do naszych obiektów. W tym celu musimy odwołać się do klasy ConnectionManager dostarczonej przez SignalR.

Dodałem klasę EventBroadcaster, która będzie odpowiedzialna za przekazywanie informacji do klientów bezpośrednio z serwera. Posiada ona obiekt HubContext, który umożliwia takie działania. Dostępny jest po wywołaniu metody GlobalHost.ConnectionManager.GetHubContext. Ponieważ jej wywołanie jest dosyć czasochłonne, klasę EventBroadcaster rejestrujemy w systemie jako singleton.

Dzięki temu, w dowolne miejsce aplikacji możemy dodać obiekt implementujący IEventBroadcaster i wysyłać do klientów interesujące nas zdarzenia. Przykład poniżej.

Podsumowanie

Dzisiaj zademonstrowałem przykładową implementację rozsyłania zdarzeń w aplikacji po stronie serwera aplikacji. W kolejnym wpisie zajmiemy się implementacją po stronie klienta w Angularze. Dzięki za uwagę i zapraszam ponownie!

Co nowego w projekcie – aktualizacja

Od ostatniej aktualizacji minęły prawie dwa tygodnie, więc pora na krótkie podsumowanie tego, co udało mi się zrobić przez ten czas. Niestety dla projektu, przez dwa ostatnie weekendy byłem poza domem, więc nie wszystko co sobie zaplanowałem zostało zrealizowane. Jakieś postępy jednak są, dlatego zapraszam do lektury!

post-background

Exception handling w WebAPI

Przechwytywanie błędów to było coś, co mi się nie podobało w moim rozwiązaniu. Wiadomo, na początku nie było to istotne, ale w miarę jak ilość elementów aplikacji rosła, trzeba było pomyśleć nad czymś sensownym. Domyślnie, gdy w aplikacji pojawiał się błąd, wyświetlana była strona z jego treścią, standardowe zachowanie. Jako, że w API nie jest to pożądane, dodałem do aplikacji middleware który przechwytuje wszystkie wyjątki. W ten sposób nie trzeba się bawić w przekazywanie statusów z metod domeny do kontrolera – gdy trzeba rzucamy wyjątek odpowiedniego typu, a resztą zajmie się właśnie ten fragment kodu.

Teraz tylko dodajemy tą klasę do pipeline w ASP poprzez metodę UseMiddleware<ExceptionHandlingMiddleware>() i gotowe. Wszystkie wyjątki zostaną przechwycone i zwrócone do klienta. W zależności od rodzaju wyjątku, zwrócony zostanie inny status błędu.

Obsługa SignalR

Mój poprzedni post jest w całości poświęcony tej tematyce, a w szczególności wspominam tam o wszystkich problemach jakie mnie spotkały podczas dodawania tej biblioteki. Warto jednak o tym tutaj wspomnieć. Dzięki temu moja aplikacja będzie mogła działać w czasie rzeczywistym, rozsyłając komunikaty pomiędzy wszystkich klientów. O tym, jak dokładnie zostało to zaimplementowane po stronie klienta i serwera opowiem w kolejnych postach.

Praca nad widokiem aplikacji

W miarę jak dodaje kolejne elementy, powoli buduje interfejs użytkownika. Na razie ten element wyraźnie kuleje, ale nie jest to najistotniejsze w tym momencie. Wygląd na tą chwilę nie jest istotny, ważne żeby dokładać kolejne elementy funkcjonalne. Obecnie pracuje nad planszą do gry. Jest to dosyć problematyczne zadanie, ponieważ staram się żeby była możliwość gry na tabletach i smartfonach. Ciężko pomieścić tak wiele pól na małych ekranach tak, żeby były one czytelne. Do tego CSSy to nie jest moja mocna strona… Na razie poprawki tego fragmentu zostawiam na później. Nie będę się także chwalił obecnym wyglądem aplikacji, myślę że w przyszłym tygodniu coś już pokażę.

Dalsza praca z Dapperem

Tej technologii też poświęciłem już cały wpis, ale chciałem pokazać kolejną metodę którą udostępnia. Jest to QueryMultipleAsync. Tak bardzo mi się to spodobało, że postanowiłem o tym tutaj wspomnieć. Po wejściu na planszę klient chce pobrać informacje o obecnej grze: pola, status, drużyny etc. W tym celu odpytuje API. Zamiast wielu zapytań do bazy danych, całą tą operację da się zrobić w jednym zapytaniu. Można by to wydzielić na wiele mniejszych zapytań, ale stwierdziłem że to dobry moment na wykorzystanie tej metody. Poniżej implementacja.

AccessQueries w powyższym przykładzie to po prostu treści zapytań SQL. Z wielu małych zapytań generowane jest jedno wielkie. Wyniki są mapowane do poszczególnych elementów obiektu Game. W SQL Server Profilerze wyraźnie widać, wszystko wykonane w jednej operacji, bardzo miła sprawa.

Sql Server Profiler - wynik zapytania QueryMultipleAsync

Zrzut ekranu z SQL Server Profiler

Podsumowanie

Podkręciłem ostatnio tempo pracy nad projektem, dodatkowo zapowiada mi się pierwszy wolny weekend w tym miesiącu, dlatego mam spore oczekiwania względem tego, co uda mi się zrobić w najbliższych dniach! Stay tuned!

SignalR w ASP.NET Core – instalacja i uruchomienie

Dzisiaj chciałem podzielić się moimi doświadczeniami z użyciem biblioteki SignalR w projekcie .NET Core. Co prawda, nie mam jeszcze za dużo przykładów użycia w projekcie, ponieważ dopiero udało mi się zmusić ją do działania. Wydaje mi się jednak, że to co tutaj opiszę przyda się komuś, jeżeli napotka na podobne problemy co ja.

signalr sign and pretty tree

Co to jest SignalR?

SignalR to biblioteka pozwalająca na tworzenie aplikacji aktualizujących dane w czasie rzeczywistym. Co to znaczy? W standardowym scenariuszu, po uruchomieniu strony czy aplikacji pobierane są dane. Jeżeli chcemy je odświeżyć, musimy przeładować stronę lub wywołać jakąś akcję która odświeży dane (np. ponowne przefiltrowanie listy). W taki czy inny sposób wysyłamy żądanie na serwer i otrzymujemy od niego odpowiedź. Tutaj mamy do czynienia z czymś innym. To serwer informuje klienta o tym, że dane zostały zmienione. Dzięki temu natychmiast możemy mieć dostęp do interesujących nas informacji. W tym celu stosowane jest na przykład API WebSockets, czyli komunikacja dwukierunkowa klient-serwer. Do naszej dyspozycji jest także HTML5 Server-Sent Events. Tutaj komunikacja jest tylko jednokierunkowa, z serwera do klienta. Bywa jednak, że przeglądarki nie wspierają obu tych rozwiązań. Wtedy z pomocą przychodzi SignalR. Korzystając z niego nie interesuje nas w jaki sposób przebiegać będzie komunikacja, framework zajmie się tym za nas. Jeżeli tak jak wspomniałem przed chwilą, przeglądarka nie dostarcza nam tych rozwiązań, wykonane zostaną po prostu zwykłe zapytania. Ale to już jest dla programisty mało ważne, stanie się to automatycznie. To tyle w skrócie, nie są to technologie nowe, dlatego po więcej szczegółów zachęcam do dalszej lektury we własnym zakresie.

SignalR w .NET Core

Na początek pokaże, co zrobić żeby wszystko ładnie działało po stronie API naszej aplikacji. Największym problemem na jaki napotkałem był brak implementacji biblioteki pod .NET Core. Jest ona jeszcze w przygotowaniu, i żeby mieć tą wersję, trzeba ją pobrać ze specjalnego źródła, gdzie wrzucane są wersje dopiero rozwijane. Stwierdziłem, że nie będę się katował wersjami testowymi tej technologi. Sami autorzy tego nie zalecają. Do tego musiałbym podnieść wersję samego .NET Core, a tego nie chciałem robić. Wystarczą mi problemy, które mam z wersją stabilną… Jako, że byłem zmotywowany do użycia tej technologi i nie chciałem po prostu odpytywać serwera co chwilę o to, czy pozostali gracze nie wykonali ruchu, znalazłem inne rozwiązanie. Postanowiłem, że użyję frameworka .NET w wersji 4.6.2. Nie wiązało się to z przepisywaniem aplikacji od nowa. Moja aplikacja dalej pisana jest w .NET Core, ale mam możliwość korzystania ze sprawdzonych bibliotek poprzedniej wersji .NET. Wystarczy zmienić trochę plik .csproj naszej aplikacji.

Zamiast netcoreapp1.1, jako TargetFramework podajemy net462. Reszta aplikacji pozostaje w zasadzie bez zmian. Dzięki temu, dalej korzystamy z nowego .NET Core, ale możemy dodać zależności do sprawdzonego Microsoft.AspNet.SignalR.Core. W ten sposób omijamy pierwszą przeszkodę, czyli wersję biblioteki. To jednak nie wszystko.
Żeby móc podpiąć SignalR do pipeline’u naszej aplikacji, musimy dodać następujące extension methods.

Kluczowe tutaj było dodanie do pipeline UseAesDataProtectorProvider. Bez tego, SignalR działał lokalnie, ale już w środowisku produkcyjnym nie chciał nawiązać połączenia. Objawiało się to błędem Error during negotiation request.... Po wykonaniu tych czynności możemy dodać SignalR do naszej aplikacji!

A poniżej pierwszy Hub, którym testowałem, czy komunikacja działa. Nie robi nic innego, niż tylko przekazanie wszystkim połączonym klientom otrzymanej wiadomości.

SignalR w Angular

Kolejne problemy, na szczęście mniejsze, pojawiły się po stronie frontendu aplikacji. Jak zwykle jakąś rolę odegrał tutaj Webpack, ale do tego już się przyzwyczaiłem. Do komunikacji z serwerem użyłem biblioteki ng2-signalr, która dostarcza implementacje pod Angulara. Problem polegał na tym, że nie widziała ona dodanych do projektu bibliotek jQuery oraz signalr, które są konieczne do jej działania. Do obejścia tego problemu w pliku webpack.config.js należało dodać nowy plugin, który automatycznie ładuje moduły do wybranego identyfikatora. Dodatkowo w app.module.ts należało dodać importy tych bibliotek. Dzięki temu problem zniknął.

Teraz można przejść do właściwej implementacji naszego rozwiązania. Dodajemy resolver połączenia do SignalR, który już na starcie komponentu zwraca nam obiekt połączenia. W obecnej implementacji, zawsze łączy się do tego samego Huba.

Połączenie tworzone jest na podstawie domyślnej konfiguracji, która jest podawana podczas deklaracji modułu SingalR. Oto implementacja funkcji, podającej domyślną konfigurację.

Korzystam z tego samego mechanizmu, który wykorzystałem do konfiguracji całej aplikacji. Inne połączenie stosowane jest lokalnie, a inne na serwerze. Taką domyślną konfigurację przekazujemy w pliku app.module.ts.

Do funkcji connect obiektu SingalR w naszym resolverze możemy przekazać dodatkowe opcje, które nadpiszą te domyślne. W ten sposób możemy przekazać na przykład tylko nazwę Huba, do którego chcemy się połączyć. Serwer pobrany zostanie wtedy z domyślnej konfiguracji, jest to bardzo wygodne. W samym komponencie możemy teraz dostać obiekt połączenia do serwera w funkcji ngOnInit, o ile w deklaracji routingu dodaliśmy resolve przy pomocy wcześniej zaimplementowanego resolvera.

Podsumowanie

Na tą chwilę w aplikacji udało mi się zrobić tylko tyle w kwestii SignalR’a. Teraz mogę przejść do konkretnej implementacji mojego rozwiązania. Na pewno w kolejnych postach podzielę się jak ona wygląda.

Pierwsze kroki z Dapper’em oraz moje doświadczenia z ORM

Dzisiaj chciałem w skrócie opowiedzieć o tym, jak wprowadziłem do projektu nową bibliotekę. Słyszałem o niej już od jakiegoś czasu, ale nie miałem okazji z niej skorzystać. Kiedy lepiej niż teraz?! Tak więc zapraszam do krótkiego wpisu dotyczącego biblioteki Dapper.

Moja historia z ORM i nie tylko

W projektach .NETowych wykorzystywałem kilka sposobów dostępu do bazy danych. Na początku były to DataSety. Do dziś pamiętam ten dramat gdy trzeba było coś zmieniać w zapytaniach, lub wszystkie razy kiedy kod designera się wykrzaczył i trzeba było kombinować dlaczego.

Później przyszła pora na SqlCommand z ADO.NET. Ręczne mapowanie rezultatów zapytań, kolejny raz poprawianie kodu w wielu miejscach przy zmianach. Też nie było kolorowo, ale jednak nie trzeba było utrzymywać DataSetów. No i wydajność była wyśmienita. To już coś.

Następnie pojawił się EntityFramework w podejściu DatabaseFirst. Kolejny raz pojawił się designer, dodawanie tabelek, ale tutaj już nie trzeba było pisać żadnych procedur składowanych w SQL. Szybkie Linq i gotowe. Coś pięknego. Czar prysł dosyć szybko z kilku powodów. Pierwszy z nich to taki, że nie potrafiliśmy z niego dobrze korzystać. Globalny context na cały projekt? Dlaczego nie! Ogromne zapytania w Linq, które pięknie działają lokalnie, ale na produkcji już nie koniecznie. Oj tak! To było tylko kilka grzechów głównych, które popełniliśmy na początku. Kwestie wydajności można było zastąpić procedurami, ale przy takim podejściu w sumie ta praca wygląda jak ta z DataSetami, bleee. Tutaj pojawia się kolejny problem, czyli designer. Jak już wspomniałem, DataSety przebrane w kostium EF, a do tego z gorszą wydajnością. Nie będę tutaj dalej ciągnął tego wątku, bo to worek bez dna.

Następnie pojawił się EntityFramework, ale już taki „prawdziwy” przy podejściu CodeFirst. Kwestie problemów z wydajnością zapytań pozostają, ale nie mamy już tego przeklętego designera. Chociaż tyle. W tym momencie miałem już dużo większe doświadczenie i wiedziałem, że nie wszystko złoto co się świeci. Do prostych zapytań, jak najbardziej! Praca jest wtedy szybka, nie przejmujemy się za bardzo warstwą bazy danych. Sprawdzamy jedynie, czy EF nie wypluwa jakiegoś kosmicznego zapytania do BD (zawsze jest ono kosmiczne, ale chodzi o to, żeby dobrze działało) i voilà. Jest pięknie. Gdy mamy jakieś skomplikowane zapytanie, nie bójmy się napisać procedury, to nie jest takie złe jeżeli nie musimy tego robić za każdym razem. Na temat EF jest wiele artykułów, wiele z nich twierdzi wręcz, że ta technologia nie nadaje się do niczego. Moim zdaniem w większości przypadków takie podejście może być wystarczające (tak jak w przypadku mojego projektu), ale nie zawsze. Można sprawić, że takie rozwiązanie będzie działało bardzo szybko, ale stracimy wtedy ostatnie zalety, jakie daje EF, np. automatyczne sprawdzanie zmian. Jeżeli zależy nam na wydajności bez kompromisów, trzeba sięgnąć po coś innego.

Dapper

No i tak oto przechodzimy do Dappera. Jak można przeczytać na jego stronie, Dapper to prosty mapper obiektów dla .NET, który rozszerza interfejs IDbConnection. Jako jego główne zalety wymienić można wydajność oraz to, że nie jest ograniczany w żaden sposób przez typ bazy danych z jakiego korzystamy. Wszystkie typy, obsługiwane w .NET ADO np. SqlLite, Firebird, Oracle, MySQL, PosgreSQL czy SQL Server.

Po dwóch dniach odkąd zacząłem z nim pracować, muszę przyznać, że jestem mile zaskoczony. Prawda, trzeba pisać kod SQL, ale samo użycie biblioteki jest bajecznie proste, co zaraz zademonstruje na przykładach. Mamy tutaj zalety EF, gdzie nie trzeba mapować obiektów ręcznie, oraz czystego ADO.NET, gdzie nie trzeba utrzymywać żadnych designerów czy wielkich klas DbContextu. W moim przypadku nie jest to do końca prawda, bo EF służy mi do zarządzania użytkownikami w ASP.NET Identity oraz do wykonywania migracji. Tak więc nie pozbędę się EF z projektu. Prawda jest taka, że na moje potrzeby wystarcza on całkowicie, chodzi tutaj bardziej o naukę.

Ten prosty kawałek dodaje nowy wiersz i jednocześnie wyciąga dane z bazy danych. Najpierw mapujemy model z danymi gry na encje, dodajemy datę zapisu (moglibyśmy to zrobić na poziomie zapytania, ale wolę takiej logiki nie wydzielać z systemu). Później otwieramy połączenie. Tutaj wykorzystuję fabrykę, która pobiera z konfiguracji connection string do bazy. Na interfejsie IDbConnection wykonujemy metodę QueryFirstAsync, która pobiera i mapuje pierwszy wynik zapytania na wskazany typ obiektu i go zwraca. Nie ma tutaj niczego skomplikowanego.

Powyżej jeszcze zapytanie które jest wykonywane. Od razu pobierane są dane, które chce zwrócić na początek. Wszystko wykonane w jednym odwołaniu do bazy danych. Bardzo miło.

Do dyspozycji mamy jeszcze inne metody, które działają bardzo podobnie, np. Execute, która nie zwraca danych z bazy. Możemy przekazać obiekt transakcji, dzięki czemu możemy wykonać rollback zapytań w razie potrzeby. Taka dygresja, tutaj przekonałem się o tym, że .NET Core jeszcze raczkuje, ponieważ nie posiada w obecnej wersji TransactionScope, znanego z poprzednich wersji frameworka. Kolejna ciekawa opcja to możliwość wykonywania wielu zapytań w jednym odwołaniu do bazy poprzez QueryMultiple. Nie będę rozpisywał się za dużo o przykładach, ponieważ pełno ich w sieci, między innymi nas tronie którą podałem na początku tego posta.

Podsumowanie

Moje doświadczenia z Dapperem są na razie bardzo pozytywne. Nie wiem, czy będę do wykorzystywał do wszystkich zapytań w moim projekcie, ale na pewno do tych bardziej skomplikowanych sięgnę właśnie po niego. Zachęcam Was do zapoznania się z tą biblioteką.

Postęp prac nad projektem WordHunt

Cześć, dziś chciałem podzielić się tym, co udało mi się zrobić do tej pory. Zauważyłem ostatnio, że robię wszystko żeby nie ukończyć tego projektu na czas… Rzeczy które powinienem zostawić na koniec, lub inne mniej ważne elementy programu zostały po części zrobione, a o samej rozgrywce ani widu, ani słychu. Skoro już zdałem sobie z tego sprawę, może teraz uda się pójść w dobrym kierunku. No, ale do rzeczy.

Model bazy danych

Zaczynam od rzeczy która jest akurat bardzo ważna. Dane oczywiście muszą być gdzieś przechowywane. Tutaj nie wymyślałem niczego interesującego, używam Microsoft SQL Server. Użytkownicy przechowywani są w tabelach, które generowane są automatycznie gdy używamy ASP.NET Core Identity. Wszystko byłoby pięknie, ale gdy projektowałem własne tabele, jako identyfikatora użyłem typu danych bigint, czyli long w C#. Domyślnym identyfikatorem użytkownika generowanym przez system był string, a w bazie danych nvarchar(450). Nie podobało mi się to, że w systemie będę miał dwa typy identyfikatora. Musiałem więc to zmienić. Zadanie to nie jest specjalnie trudne, ale zajęło mi trochę więcej czasu niż się spodziewałem. Myślę że napiszę o tym osobny post, dlatego nie będę się rozpisywał na ten temat tutaj. Tabele zostały zmienione, wszystko gra. Możemy przejść dalej. W systemie naturalnie muszą się znaleźć także moje tabele, nie tylko te domyślne. Tak więc usiadłem i zacząłem je rozpisywać. Zmieniałem je kilkukrotnie, ale mniej więcej udało mi się ustalić jak będą wyglądały, przynajmniej te podstawowe dotyczące rozgrywki.

Schemat tabel bazy danych związanych z rozgrywką

Tabele związane z rozgrywką.

Jak widać, wszystko sprowadza się do powiązania z tabelą Games, gdzie będą przechowane ustawienia gry. GameStatuses odpowiadać będzie za aktualny stan rozgrywki, czyja tura aktualnie trwa, czy została już zakończona etc. GameTeams, jak nazwa wskazuje, przechowuje dane drużyn które biorą udział w grze. W przypadku, gdy grą steruje tylko jedna osoba, nie jest ona powiązana z użytkownikiem. GameFields to pola na których znajdują się słowa, ich rodzaj, czy są przypisane do któregoś zespołu i czy zostało one odkryte. GameMoves to historia wszystkich ruchów, a GameClients to urządzenia które są połączone z rozgrywką. Jestem pewny że tabel przybędzie, ale na razie tyle powinno wystarczyć, wyjdzie w praniu.

Kolejne tabele to takie przechowujące słowa. W grze chce mieć możliwość wyboru języka, więc dodałem tabelę z językami, oraz kategorie żeby łatwiej było nimi zarządzać. Tabele te są dosyć proste, nic szczególnego.

Schemat tabel powiązanych ze słowami.

Tabele związane ze słowami.

WebAPI do zarządzania słowami

Tak, bardzo ważna rzecz w grze która jeszcze nie działa. Dodałem możliwość zarządzania językami, kategoriami i słowami. Jest ono zabezpieczone w taki sposób, że jedynie użytkownicy będący administratorami mają do nich dostęp. Tabele ze słowami są pomocne od początku, ale zarządzanie nimi mogło poczekać… Już się zabierałem za robienie interfejsu użytkownika do tego, ale na szczęście się powstrzymałem. Dalszy rozwój tej części aplikacji odkładam na później.

Routing aplikacji webowej

W poprzednich postach opisywałem routing w Angularze. Na tej samej zasadzie zrobiłem go w mojej aplikacji. Na stronę główną mają dostęp wszyscy, ale żeby zobaczyć coś więcej trzeba się zalogować. Do panelu administracyjnego dostęp mają tylko administratorzy. Wykorzystałem tutaj mechanizm o którym nie wspomniałem w tamtym poście, RouteGuards. Na pewno opiszę go w drugiej części posta dotyczącej routingu. A poniżej przykład:

Podsumowanie

Rozwój aplikacji nie przebiegał ostatnio w najlepszym tempie. Wydaje mi się jednak że zrobiłem dużo nudnych rzeczy, które i tak trzeba by było prędzej czy później dodać (może nawet bardzo później…). Dzięki temu teraz będę mógł przejść do konkretów i development przyśpieszy. Kolejne krotki to dodanie możliwości uruchomienia gry, czyli strona z wyborem ustawień, następnie zapisanie ich do bazy danych. Później przyjdzie czas na system rozgłaszania wykonanego ruchu przez użytkownika do innych klientów. Ale o tym w kolejnych postach.

Poznajmy Postman’a!

Podczas rozwijania API chcielibyśmy w łatwy sposób przetestować, czy działa ono jak należy i zwraca wartości w takiej formie, w jakiej powinno. Chciałem dzisiaj opisać pokrótce narzędzie, które nadaje się to tego celu idealnie. Znam je od dawna, ale dopiero niedawno poznałem większość z jego sporych możliwości. Mowa tutaj o Postman’ie. Jest to darmowa aplikacja, która pozwala na wykonywanie zapytań oraz przechowywanie ich historii. Zapraszam na krótkie wprowadzenie.

Logo narzędzia Postman

Instalacja

Tutaj sprawa jest bardzo prosta, jeżeli mamy przeglądarkę Chrome, wystarczy że dodamy rozszerzenie, które można pobrać tutaj. Drugą opcją jest zainstalowanie natywnej aplikacji na nasz system. Ją z kolei możemy pobrać w tym miejscu. Natywna aplikacja omija kilka ograniczeń wersji z dostępnej w przeglądarce. Następnie zakładamy konto i logujemy się do aplikacji. Możemy przejść dalej!

Podstawowe funkcje

Aplikacja moim zdaniem ma bardzo przyjemny dla oka interfejs, ale łatwo przeoczyć tutaj kilka ciekawych funkcji. Na początek zajmijmy się jednak kilkoma podstawowymi rzeczami. W menu bocznym aplikacji możemy dodawać kolekcje, które będą przechowywały nasze zapytania. Możemy tutaj także zobaczyć historię ostatnio wykonanych requestów.

Kolekcje w postmanie

Kolekcje oraz historia

Kolekcje przechowują nasze zapytania. Dodajmy więc nowy request. Wybieramy typ zapytania z listy oraz adres który będziemy odpytywać.

Nowe zapytanie

Możemy wybrać typ zabezpieczeń który jest zaimplementowany w API, dodać nagłówki oraz parametry naszego zapytania. Następnie klikamy na przycisk Send i gotowe. W odpowiedzi dostaniemy status naszego zapytania, czas wykonania, rozmiar odpowiedzi, body, ciasteczka, nagłówki. Nasze zapytanie możemy zapisać w kolekcji i szybko wykonać je ponownie później.

Animacja pokazująca wykonanie zaptania

Wykonanie zapytania

Environments

Bardzo przydatną opcją Postmana jest możliwość tworzenia profili środowiska. Jest to niesamowicie pomocne gdy chcemy w szybki sposób testować naszą aplikację lokalnie, a zaraz potem już na produkcji lub środowisku testowym. Dzięki temu nie musimy dodawać wielokrotnie tego samego zapytania lub ciągle edytować tych już istniejących.

Zarządzanie środowiskami

Definiujemy tutaj adres naszego API, istniejący token, nazwę użytkownika, hasło lub cokolwiek innego. Dodajemy takie opcje zarówno dla środowiska dev jak i produkcyjnego.

Edycja środowiska

Edycja środowiska

Następnie, tam gdzie nasze dane będą zależne od środowiska, zamiast podawać te wartości, wstawiamy zmienne środowiskowe. Zostaną one automatycznie zastąpione wartościami zdefiniowanymi w aktywnym środowisku. W tym celu używamy podwójnych nawiasów klamrowych, na przykład {{url}}.

Użycie zmiennych środowiskowych

Użycie zmiennych

Tesy oraz skrypty

Kolejną przydatną rzeczą są testy oraz skrypty wykonywane przed zapytaniem. Przed wykonaniem zapytania możemy np. ustawić obecną godzinę do zmiennej. Podobnie do skryptów działają testy.
Służą one do kilku celów. Pierwszym i oczywistym jest możliwość sprawdzenia czy wynik który otrzymaliśmy jest poprawy, posiada wszystkie pola, odpowiedni status etc. Podobnie jak w przypadku skryptów, możemy ustawić tutaj zmienną, ale tym razem mamy dostęp do tego, co zwróciło nasze zapytanie. Możemy więc wysłać zapytanie np. o token, a następnie przypisać go do zmiennej.

Taka automatyzacja może nam bardzo przyśpieszyć pracę. Nie będziemy musieli sprawdzać wszystkiego samemu, co może być problemem przy większej ilości zapytań.

Test zapytania

Testy zapytania

Wykonywanie wielu zapytań

Ostatnią rzeczą którą chciałem pokazać jest wykonywanie wielu zapytań jednocześnie, co umożliwia nam Collection Runner. Przy jego pomocy możemy wykorzystać to, o czym pisałem w poprzednim akapicie. Przykładowo, jako pierwsze zapytanie w kolekcji dodajemy takie, które odpyta nasze API o token uwierzytelniający. Zapytanie te zapisze nasz token do zmiennej,
z której później będą korzystały inne zapytania. W ten sposób możemy automatyzować wykonywanie i testowanie bardzo dużej ilości zapytań.

Podsumowanie

Mam nadzieje że tym, którzy nie znali jeszcze tego narzędzia pokazałem, jak w łatwy sposób z niego korzystać i ułatwić sobie życie. Po więcej informacji dotyczących Postmana odsyłam na jego oficjalną stronę, gdzie można znaleźć więcej przykładów i dokładny opis funkcji o których tutaj nie wspomniałem.

Zmienne środowiskowe w Angular

Często, gdy pracujemy nad naszą aplikacją musimy korzystać z innych adresów dla naszego API na produkcji, a innego lokalnie. Między innymi w takich przypadkach przychodzą nam z pomocą zmienne środowiskowe aplikacji. Dzisiaj chciałem pokazać jak w szybki sposób dodać możliwość obsługi zmiennych środowiskowych w naszej aplikacji wykorzystującej Angulara. Myślałem że będzie to coś, co jest dostępne out of the box, jednak nie zawsze tak jest. Jeżeli korzystacie z Angular-CLI, macie dostęp do nich w katalogu environments. Ja pokażę jak łatwo coś takiego zaimplementować w sytuacji, gdy nie mamy takiego udogodnienia. Mój przykład opiera się o aplikację, która powstała z szablonu dostępnego w dotnet CLI o którym pisałem w poprzednich postach. Moja aplikacja wykorzystuje Webpacka.

Implementacja serwisu z konfiguracją

Moje rozwiązanie nie jest idealne, ponieważ obsługuje jedynie dwie wersje aplikacji: lokalną czyli developerską, oraz produkcyjną. Jeżeli chcielibyśmy mieć możliwość obsługi innego środowiska, należy dodać kilka dodatkowych elementów, np. task w Gulpie, który podmieniałby nasze konfiguracje. Ja nie będę się tutaj rozpisywał na ten temat. Rozwiązanie składa się z kilku elementów. Na początek dodajemy plik app.config.ts, który przechowuje nasze zmienne.

Plik ten zawiera dwie klasy, które implementują interfejs IConfig. Dzięki temu nigdy nie przeoczymy żadnej zmiennej podczas dodawania konfiguracji. Poniżej przykład takiego intefejsu.

Następnie dodajemy serwis, który będzie przekazywany wewnątrz aplikacji.

Tutaj, w zależności od tego, czy uruchomiliśmy aplikację lokalnie, czy na produkcji, tworzymy instancję klasy zawierającej nasze konfiguracje. Funkcja isDevMode sprawdza na jakim środowisku jesteśmy. W moim przypadku to Webpack uruchamia aplikację w odpowiednim trybie (podczas publishu na produkcję dodawana jest opcja env.prod, o tym więcej w dokumentacji dotnet CLI). W serwisie definiujemy tyle pól, ile potrzebujemy. Ja użyłem tutaj składni Typescipt’u, która pozwala na dodawanie getterów. Możemy taką klasę podzielić na mniejsze, jeżeli nie chcemy mieć jednej dużej klasy z całą konfiguracją. Taki serwis możemy wstrzykiwać w inne serwisy lub komponenty naszej aplikacji, oraz podmieniać ją na inną podczas testów.

Podsumowanie

Jest to rozwiązanie, które można jeszcze rozwinąć, ale obecnie spełnia moje wszystkie wymagania. Dodatkowo jest bardzo proste w implementacji i działa automatycznie, bez konieczności wykonywania innych operacji podczas rozwoju aplikacji, takich jak uruchamianie skryptów. Mam nadzieję, że komuś się przyda!

Routing w Angular2 – pierwsze kroki

Dzisiaj chce przedstawić jak w szybki sposób dodać routing do naszej aplikacji z frameworkiem Angular. Podczas tego procesu można natknąć się na kilka problemów, o których tutaj wspomnę. Do dzieła!

Routing krok po kroku

Moje przykłady podaję na projekcie, który powstał przy użyciu dotnet CLI. Po zainstalowaniu .NET Core SDK, w konsoli wpisujemy dotnet new --install Microsoft.AspNetCore.SpaTemplates::*. Daje nam to dostęp do wielu szablonów projektów. Następnie wpisujemy dotnet new angular i mamy gotowy projekt z którym można pracować! Po więcej informacji na ten temat odsyłam na bloga jednego z autorów tych szablonów, Steve’a Sandersona. Opisał to wszystko ładnie w tym poście.

Wracając do routingu, na początek definiujemy moduł, w którym powiemy aplikacji jak ma się zachowywać, gdy użytkownik będzie chciał wejść w podany przez niego adres na naszej stronie. Później zaimportujemy go do głównego modułu, który jest uruchamiany jako pierwszy. Moduł routingu składa się z kilku części. Na początek importujemy potrzebne komponenty:

Dekorator NgModule potrzebny jest do zdefiniowania modułu. Routes oraz RouterModule potrzebne są już do napisania kodu, który pozwoli nam na nawigację wewnątrz aplikacji. Następnie importowaliśmy komponenty, które sami dodaliśmy i chcemy wyświetlić. Następnie pora na przekazanie aplikacji jak ma się zachowywać, czyli definicję ścieżek.

Import RouterModule.forRoot(routes) załatwi nam sprawę routingu.

Dzięki takiej definicji, po otwarciu aplikacji, od razu zobaczymy komponent CatComponent. Został on jawnie zaimportowany na starcie aplikacji. W tym przykładzie pokażę także jeszcze jedną ważną sprawę na którą trzeba zwrócić uwagę, w momencie gdy dodajemy routing do naszej aplikacji. CatComponent został pobrany od razu gdy weszliśmy na stronę aplikacji, mogło to wpłynąć na czas otwarcia aplikacji. Takie podejście nazywamy EagerLoading. Jeżeli byłby on duży, mogłoby to w znaczący sposób wpłynąć na to, jak użytkownik będzie odbierał naszą aplikację. Z kolei DogModule zostanie załadowany dopiero wtedy, gdy będziemy chcieli wejść do niego. Będzie wtedy można zauważyć małe opóźnienie przed otwarciem tej strony. Ta metoda z kolei nazywana jest LazyLoading. Dzięki temu, że komponent załadowany będzie później, cała strona będzie ładować się szybciej. Coś za coś, idziemy tutaj na kompromis. Jednak nie musi tak być. Wcześniej w imporcie komponentów z @angular/router zaimportowałem jeszcze klasę PreloadAllModules. Jeżeli definicję modułu zmienimy na następującą:

Moduł DogModule , oraz wszystkie inne które tak dodamy do routingu pobrane zostaną w tle po uruchomieniu aplikacji. Dzięki temu zyskujemy zarówno szybkość ładowania całej aplikacji, jak i responsywność podczas przechodzenia pomiędzy stronami. Ważna uwaga: żeby LazyLoading działał w projekcie wykorzystującym Webpacka, musimy zainstalować paczkę angular-router-loader, a następnie użyć ją w pliku webpack.config.js podczas konfiguracji plików .ts.

Kolejnym istotnym punktem jest stała routableComponents którą eksportujemy razem z modułem. Dzięki temu że tutaj dodajemy moduły, nie trzeba będzie ich na nowo importować w głównym module.Należy pamiętać, że każdy komponent który jest używany musi być dodany do declarations.

Teraz pozostaje tylko dodać moduł DogModule:

Oraz moduł routingu DogRoutingModule:

Dla takich małych modułów może się wydawać, że to spory narzut, jeżeli chodzi o ilość pracy. Ale jeżeli nasze komponenty są bardziej rozbudowane i mają swoje ścieżki podrzędne, dzięki temu nasz główny komponent nie rozrośnie się do niebotycznych rozmiarów. Dodajemy także separację do logiki naszej aplikacji, co wpływa na przejrzystość kodu.

Na koniec dodajemy nasz MainComponent, czyli główną stronę aplikacji:

Oraz szablon dla tego komponentu:

W szablonie możemy zobaczyć dwa ważne elementy: routerLink oraz router-outlet. routerLink to odpowiednik ng-href z pierwszego Angulara, czyli po prostu doda nam odpowiedni adres dla odnośnika na podstawie podanej nazwy ścieżki. router-outlet to najważniejszy element tutaj, czyli miejsce gdzie wstawione zostaną nasze komponenty, w poprzedniej wersji ng-view. Dodatkowo należy pamiętać także o dodaniu do znacznika head wartość <base href="/">, bez tego routing nie zadziała.

Podsumowanie

Przedstawiłem tutaj jedynie część możliwości jakie daje nam Angular jeżeli chodzi o routing. W kolejnych postach przedstawię bardziej skomplikowane przypadki: przekazywanie parametrów w adresie scieżki, RouteGuards, czyli mechanizm pozwalający na np. blokowanie wejścia do niektórych fragmentów aplikacji oraz wykorzystanie więcej niż jednego router-outlet.

Wprowadzenie do Sass, czyli jak ułatwić sobie życie z CSS

Trochę to trwało, ale wygląda na to, że powoli zaczynam nabierać tempa z rozwojem projektu. Odrobina wolnego czasu pozwoliła mi na ogarnięcie technologii z których będę korzystał (a gdy chcemy korzystać z nowości, czasem może zająć to dosyć długo). Ostatnio projektowałem wygląd aplikacji za pomocą mockup’ów. Nastała więc pora tchnąc trochę życia w projekt i napisać trochę kodu. Przyznam, że słaby ze mnie designer, więc nie będzie to takie proste. Jeżeli mowa o wyglądzie aplikacji webowej, raczej na pewno pojawi się temat CSS’ów. Nie jest to moja najmocniejsza strona, więc postanowiłem sobie trochę ułatwić ten temat. W tym celu sięgnąłem po Sass.

Logo Sass

Co to jest Sass?

Sass, czyli Syntactically Awesome Style Sheets, to preprocesor języka CSS. Dodaje do niego funkcje, które nie są dostępne w podstawowej wersji CSS. Kod Sass jest kompilowany do zwykłego CSSa. W wyniku tej operacji otrzymujemy więc plik zawierający czysty CSS. Można zadać sobie pytanie: po co go używać, skoro ostatecznie uzyskujemy to samo? Jest takie powiedzenie, mówiące że Nie chodzi o cel, tylko o podróż. No i właśnie, korzystając z Sass podróż ta nie jest tak męcząca… Osobiście z CSS nie miałem aż tak dużo do czynienia. Praca ta polegała głównie na drobnych poprawkach, układaniu elementów etc. Motywy były już zwykle gotowe lub korzystałem z gotowych szablonów. Gdy dużo pracy poświęcamy upiększaniu naszej aplikacji za pomocą CSS, możemy jednak natrafić na wiele drobnych lub bardziej poważnych niedogodności.

Problemy z CSS

Pomine tutaj problemy, których użycie Sassa nie rozwiąże. Każdy, kto pracował z tą technologią miał czasem wrażenie, że żyje sobie własnym życiem. W moim przypadku wynika to zwykle z niewiedzy, ale nie zawsze.
Animowany obrazek satyryczny pokazujące typowe problemy z językiem CSS. Scena z kreskówki Family Guy.
A wracając do problemów, które Sass jest w stanie pomóc rozwiązać, to są to między innymi:

  • Problem z kolorem motywów, gdy w naszych plikach CSS trzeba zmienić jakiś kolor, albo po prostu w wielu miejscach użyć tej samej barwy. Musimy kopiować lub pamiętać o jaki kolor chodzi
  • Duplikacje kodu, gdy wiele elementów będzie miało ten sam styl i musimy powielać go wielokrotnie
  • Nie mamy możliwości zagnieżdżaniastylów, co może powodować problem gdy musimy zmieniać nazwę jakiejś klasy lub identyfikatora. Dodatkowo wpływa to także na przejrzystość kodu
  • Brak możliwości wykonywania obliczeń w naszych stylach, czasem chcemy żeby niektóre wartości były od siebie zależne. Musimy robić to ręcznie, czasem w wielu miejscach
  • Import stylów, który jest obecny, ale powoduje wykonanie kolejnego zapytania do serwera po importowany styl

Sass na ratunek

Tutaj z pomocą przychodzi nam Sass. Daje on gotowe rozwiązania na powyższe problemy. Opowiem o nich w skrócie poniżej. Jak wcześniej wspomniałem, Sass to preprocesor języka CSS, przeglądarki nie wiedzą co z nim zrobić. Najpierw trzeba go przekompilować. Nie będę tego tutaj dokładnie opisywał, ponieważ to jak to zrobimy zależy od technologi w jakiej będziemy pracowali. Na początek polecam poćwiczyć online np. na CodePen. Wystarczy, że wybierzemy jako preprocesor SCSS i możemy zaczynać. Tutaj kolejna uwaga: do wyboru mamy dwie składnie Sassa: klasyczną (Sass), oraz nową (SCSS). W poniższych przykładach używam składni SCSS.

Zmienne

Problemy związanie między innymi z kolorami rozwiązuje dodanie zmiennych:

Dzięki nim jeżeli w wielu miejscach wykorzystujemy te same wartości, w przypadku zmiany możemy je łatwo podmienić. Na zmiennych można wykonywać także operacje. Tutaj dla przykładu nagłówek będzie większy od bazowego tekstu o 10px.

Zagnieżdżanie reguł

Zagnieżdżanie pozwala nam na usunięcie kodu który byłby powielany, oraz dodaje mu przejrzystości.

Dzięki temu zabiegowi na pierwszy rzut oka widać, które elementy są ze sobą powiązane. Dodatkowo elementy font zostały pogrupowane razem, co też wpływa na ich czytelność.

Import

Dyrektywa @import pozwana na modularyzację naszego kodu. Dzięki temu możemy dodać do projektu plik .scss, który zawierać będzie tylko deklarację zmiennych z kolorami. W ten sposób łatwo dodawać różne motywy do naszej aplikacji. Poniżej przykładowy plik z deklaracją zmiennych przechowujących kolory.

Następnie wykorzystujemy import pliku ze zmiennymi.

Dzięki temu że importujemy plik .scss, jako efekt tej operacji otrzymamy jeden plik zawierający całą zawartość obu tych plików. Jeżeli importowalibyśmy plik .css, podczas importu musielibyśmy pobrać plik z serwera, przez co musielibyśmy wysłać kolejne żądanie na serwer.

Dziedziczenie reguł

Kolejna dyrektywa którą chcę przedstawić to @extend. Dzięki niej możemy łatwiej definiować elementy posiadające te same style, różniące się tylko kilkoma szczegółami.

Jako element wyjściowy tej operacji otrzymamy następujący kod CSS:

Jedyne zmiana to dodanie do deklaracji bazowej klasy naszej rozszerzonej implementacji, a na końcu dodanie pozostałej części. Zmiana niewielka, ale taki zapis łatwo pokazuje, że elementy te są ze sobą powiązane w logiczny sposób (pełnią podobną rolę). W przypadku gdy będziemy implementować wiele podobnych elementów, taki zapis jest moim zdaniem o wiele bardziej czytelny.

Powtarzalne reguły

Bardzo potężne narzędzie do jakiego daje nam dostęp Sass to dyrektywa @mixin. Dzięki niej nie będziemy musieli powielać wielokrotnie tego samego kody dla różnych, niepowiązanych ze sobą elementów, które mają jednak wspólne cechy. Przykładowo możliwość dodania zaokrąglonych krawędzi. Można to zaimplementować w następujący sposób:

Taki kod sprawia, że możemy wykorzystać tą samą funkcję (funkcja nie do końca można to nazwać, ale pokazuje o co tutaj chodzi) do zaokrąglania krawędzi. Dodatkowo posiada ona parametr, który może mieć wartość domyślną, dzięki czemu wiele elementów które w różny sposób chcemy zaokrąglić może z niej skorzystać.

Funkcje

Kolejna dyrektywa w arsenale Sass to @function. Dzięki niej możemy wydzielić fragment logiki, który będziemy mogli wielokrotnie użyć.

Dzięki temu oszczędzimy czas na operacje, które będziemy wykonywać wielokrotnie.

Podsumowanie

Nie przedstawiłem wszystkich zalet, jakie niesie ze sobą używanie Sass w naszym projekcie. Jeżeli chcecie dowiedzieć się więcej na ten temat, zapraszam do przejrzenia dokumentacji. Wydaje mi się że warto spróbować, jeżeli ktoś nie miał jeszcze styczności z tego typu technologiami. Na rynku jest oczywiście wiele innych rozwiązań, które pełnią podobną fukncję: LESS, Stylus, PostCSS. Niezależnie od naszego wyboru, wydaje mi się, że zawsze będzie to krok na przód.

Wprowadzenie do Angular 2

Dzisiaj chciałem opisać w kilku punktach najważniejsze cechy frameworka Angular dla użytkowników, którzy nie mieli z nim jeszcze styczności. Na wstępnie trzeba zaznaczyć, że twórcy odeszli od nazwy Angular 2 (głównie z powodu wporwadzenia Semantic Versioning). Od teraz wersje 1.x.x nazywamy AngularJS, a do wydań oznaczonych jako 2.x.x i dalej będziemy używali krótkiej nazwy Angular. Można o tym poczytać tutaj.

Czym jest Angular?

Logo frameworka Angular

Angular to framework służący do rozwijania aplikacji webowych oraz na platformy mobilne. Nie jest to kolejna wersja swojego poprzednika, został napisany całkowicie od nowa. Wersje te nie są ze sobą kompatybilne. Na pierwszy rzut oka widać, że dwójka bardzo różni się od swojego pierwowzoru. Poniżej postaram się przedstawić te różnice i pokazać, że pomimo tego że są to całkiem inne narzędzia, developerzy korzystający z jedynki będą mogli wykorzystać część swojego doświadczenia podczas pracy z nowym wydaniem.

Wybór języka

Twórcy Angulara dają nam wybór w kwestii języka, którym będziemy się posługiwać podczas pisania naszych aplikacji. Do wyboru mamy następujące opcje:

  • ES5, czyli po prostu JavaScript. Ten sam, który był najczęściej wykorzystywany podczas rozwoju aplikacji w starym AngularJS.
  • ES6/ES2015, jest to rozszerzenie standardowego języka JavaScript, dodające nowe funkcje. Nie wszystkie przeglądarki go wspierają, dlatego podczas rozwoju aplikacji wykorzystujących ES6 należy korzystać z kompilatorów np. Babel.
  • TypeScript wprowadza do JavaScript’u jeszcze więcej możliwośći np. typy, dzięki czemu łatwiej wyłapywać błędy podczas pisania aplikacji. Jest rozszerzeniem ES6, i tak samo jak on, wymaga kompilatora. Więcej na jego temat można poczytać w tym miejscu.
  • Dart jest to język programowania stworzony przez firmę Google. Po więcej informacji na temat tego języka zapraszam tutaj.

W dalszej części tego artykuły będę posługiwał się przykładami napisanymi w TypeScripcie.

Moduły

Obie wersje Angulara przedstawiają koncepcję modułu, jako swego rodzaju punkt wejścia dla naszej aplikacji. W pierwszej wersji definiowaliśmy go w następujący sposób:

W nawiasach kwadratowych podawaliśmy zależności z których chcieliśmy korzystać w naszej aplikacji. Następnie musieliśmy oznaczyć w HTMLu gdzie nasza aplikacji ma się znajdować:

Teraz definiujemy go w następujący sposób:

Moduł tym razem służy do oznaczenia z jakich elementów nasza aplikacja będzie się składała. Do tego celu służy dekorator @NgModule, który używamy w połączeniu z klasą modułu. Wskazujemy, z jakich modułów dostarczanych z zewnątrz będziemy korzystać (imports) np. RouterModule lub BrowserModule. Deklarujemy (declarations) z jakich komponentów będziemy korzystać w naszej aplikacji. Może się ona składać z setek lub tysięcy małych komponentów. Definiujemy tutaj także komponent wejściowy przy użyciu słowa bootstrap. Komponent ten zostaje uruchomiony jako pierwszy. W górnej części tego pliku znajdują się importy, czyli mechanizm TypeScriptu, który pozwala na użycie innych bibliotek w naszej aplikacji. Modułom dokładniej przyjrzymy się w kolejnych postach.

Kontrolery i Komponenty

Angular odszedł od koncepcji kontrolerów, używanych w pierwszej wersji. Kontrolery były definiowane w widoku:

Następnie dodawany był kod, który przedstawiał jego logikę.

Obecnie w widoku używamy tylko nazwy naszego komponentu np.:

Sam komponent zaś definiuje jego logikę oraz wygląd:

Importujemy tutaj dekorator komponentu, który pozwala nam na jego definicje. Wskazujemy selector, który będzie wskazywał na nasz komponent w HTMLu, jego wygląd poprzez template (można oczywiście dodać ten szablon w osobnym pliku), oraz logikę komponentu w klasie.

Dyrektywy

Dyrektywy dostępne w Angularze uległy znacznym zmianom, ale dalej są obecne. Popularne w pierwszej wersji dyrektywy to na przykład ng-repeat oraz ng-if. W nowej wersji zostały one zastąpione przez *ngFor oraz *ngIf. Nazywamy je Structural directives, ponieważ wpływają na strukturę naszej strony (powielają elementy, usuwają etc). Są poprzedzane znakiem *. Przykłady dla AngularJS:

A teraz nowa wersja:

Różnice nie są wielkie, oprócz samej składni, dla *ngFor dochodzi także słowo kluczowe let, które definiuje zmienną lokalną.
Oprócz tego, w Angularze usunięte zostają inne dyrektywy, takie jak ng-src, ng-style, ng-href. Podobnie jest z dyrektywami, które służyły do obsługi zdarzeń np. ng-click czy ng-focus. Zamiast tego, możemy podpiąć się bezpośrednio do atrybutów lub zdarzeń w HTML, na przykład:

Do właściwości podpinamy się poprzez nawiasy kwadratowe [], a do zdarzeń nawiasy okrągłe (). Daje nam to dużo możliwości, ponieważ nie musimy już polegać na tym, czy interesująca nas dyrektywa istnieje. Zamiast tego korzystamy po prostu z atrybutów oraz zdarzeń w HTMLu.

Data binding

Tutaj także jest wiele podobieństw, chociaż ponownie składnia trochę się różni. O ile dalej możemy korzystać z nawiasów klamrowych {{...}} aby wyświetlić dane lub tworzyć wyrażenia, to two-way oraz one-way binding znany z poprzednika wygląda trochę inaczej. Działa tutaj ten sam mechanizm, który pokazałem w dyrektywach. One-way binding, w którym zmiany wychodzą z widoku do kodu, odbywa się poprzez użycie nawiasów okrągłych (). Tutaj przykładem mogą być eventy, gdzie zdarzenie wysyła nam informacje do naszej klasy. Wysyłanie danych z klasy do widoku odbywa się poprzez nawiasy kwadratowe [] (wykorzystując atrybuty, klasy, style, właściwości) lub klamrowe {} (mechanizm ten nazywa się Interpolation). Two-way binding, czyli przesył danych w obie strony, odbywa się zarówno przy użyciu nawiasów kwadratowych i okrągłych [(...)]. Składnia ta wydaje się dziwna, ale jest w 100% spójna z tym co powiedzieliśmy wcześniej: dane zarówno wysyłane są z widoku do kodu, oraz z kodu do widoku.

Zamiast nawiasów mamy możliwość korzystania z prefixów bind- lub on- dla komunikacji w jedną stronę, lub bindon- w obie strony. Przykłady:

Serwisy

W pierwszym Angularze mieliśmy do wyboru kilka metod, które pozwalały na dodawanie serwisów do aplikacji. Dzięki nim byliśmy w stanie wyciągnąć w jedno miejsce logikę, która powtarzała się w wielu fragmentach aplikacji lub pozwalały na komunikację pomiędzy różnymi jej elementami. Czasem pojawiał się problem: którą metodę wybrać? Do wyboru były popularne Factory, Service czy Provider, a także Constants oraz Values. Ten element został całkowicie zmieniony w nowej wersji. Zamiast wybierać dostępne mechanizmy, po prostu dodajemy klasę, która ma w sobie określoną funkcjonalność, a następnie używamy jej w dowolnym miejscu.

Należy jedynie dodać dekorator @Injectable, który pozwoli na wstrzyknięcie naszego serwisu np. do komponentu. O tym opowiem w kolejnym akapicie.

Dependency Injection

Dependency Injection to wzorzec architektoniczny, polegający na wstrzykiwaniu zależności do naszego kodu. Jeżeli chcemy odseparować z komponentu logikę np. pobierania użytkowników z bazy danych, a w samym komponencie zająć się jedynie ich wyświetlaniem, możemy zrobić to w łatwy sposób. Pobieranie danych wyciągamy do Serwisu, czyli innej klasy, a w komponencie wskazujemy na to, że potrzebujemy dostać obiekty do wyświetlenia. W module dodajemy komponent i serwis:

W komponencie wskazujemy, że potrzebujemy serwisu (używamy tutaj CatsService z poprzedniego akapitu), który zwróci nam nasze obiekty do wyświetlenia:

W ten sposób nasz komponent będzie w stanie wyświetlić listę naszych kotów, bez wiedzy skąd trzeba je pobrać!

Podsumowanie

Oczywiście, to co tutaj przedstawiłem to tylko część dobrodziejstw które oferuje nam Angular. Mamy jeszcze Routing, który został znacznie uproszczony, filtry, które teraz nazywają się Pipes oraz wiele innych. Wydaje mi się, że pomimo wielu różnic które pojawiły się w nowej wersji (wiele z nich moim zdaniem dobrych), kilka konceptów znanych z pierwszego wydania tego frameworka można zastosować w nowych aplikacjach, które będą już korzystały z najnowszej edycji. Dzięki temu próg wejścia w tą technologię jest dla weteranów AngularJS znacznie mniejszy.

Na dzisiaj to tyle. Tematy, które nie zostały tutaj poruszone na pewno pojawią się w przyszłości. Postaram się także rozwinąć bardziej szczegółowo to, o czym już mówiłem. Zapraszam do komentowania!

Dokładne omówienie założeń gry oraz projektowanie interfejsu aplikacji WordHunt

W zeszłym tygodniu pracowałem trochę nad backend’em aplikacji, a konkretnie zabezpieczaniem API. Chcę zacząć pracować nad interfejsem użytkownika, ale zanim się do tego zabiorę wypada dokładnie przyjrzeć się jak powinien wyglądać. Dlatego dzisiaj opiszę dokładniej jakie jak wyobrażam sobie mechanikę gry i dostępne opcje.

Przebieg rozgrywki

Obecnie zaplanowane mam dwa tryby gry, oba polegające na tym, że wszyscy gracze siedzą razem w pokoju. Rozważam jeszcze dodanie trybu czysto online, ale taki dodam jedynie wtedy, gdy będę miał zapas czasu przed końcem konkursu (czego nie przewiduję…). W grze biorą udział co najmniej dwie drużyny (można ustawić więcej), z czego jedna osoba w drużynie jest kapitanem. Plansza do gry składa się z ustalonej podczas konfiguracji ilości pól (domyślnie 5×5). Na każdym polu zawarte jest jedno słowo. Wszystkie pola są na początku gry zasłonięte, nie wiadomo które pole należy do której drużyny.

Wygląd planszy do gry.

Plansza do gry.

Kapitan ma dostęp do klucza, czyli tak zwanej mapy. Na mapie zawarte są informacje, które pole powinna odkryć (upolować) każda drużyna. Kapitan drużyny wypowiada jedno słowo, które kojarzy się z możliwie największą możliwą liczbą pól jego drużyny oraz mówi, ilu słów dane skojarzenie dotyczy. Jego zawodnicy wybierają następnie na planszy, które pola są wg nich tymi poprawnymi. Jeżeli skończą im się pomysły, mogą zakończyć turę. Ważne jest jeszcze to, że co najmniej jedno pole (także można to konfigurować) jest polem tak zwanej nagłej śmierci, jeżeli któraś z drużyn je odkryje, automatycznie przegrywa. Drużyna wygrywa, gdy jako pierwsza upoluje wszystkie słowa na swoich terenach łowieckich. Gracze mogą korzystać z wbudowanego timer’a, który odlicza pozostały na wykonanie ruchu czas. Można go wyłączyć, traktować tylko jako swego rodzaju upomnienie, że dana drużyna zbyt długo zastanawia się nad ruchem, lub spowodować, że drużyna straci ruch po przekroczeniu dostępnego czasu.

Proponowany wygląd mapy z której korzystają kapitanowie.

Wygląd mapy gry.

Konfiguracje sprzętowe

Pierwszy z trybów przewiduje, że wszyscy gracze będą korzystali z jednego urządzenia (np. tabletu), pełniącego rolę planszy do gry. Wszystkie drużyny będą z niego korzystać do wybierania, które pola wg nich powinni odkryć. Do dyspozycji kapitanów będzie jedno urządzenie (lub więcej, dla wygody każdy może korzystać ze swojego), które będzie wyświetlać mapę gry. Do tego celu idealnie nada się na przykład smartfon. Na innym urządzeniu opcjonalne będzie uruchomienie poglądowej planszy do gry, która nie jest interaktywna np. w salonie na telewizorze. Dzięki temu podczas gdy w zabawie będzie brało udział więcej osób, będą oni dobrze widzieć planszę.

Kofiguracja sprzętowa numer jeden, w której dostępne jest jedno urządzenie interaktywne dla wszystkich, kapitanowie posiadają jedno lub więcej map i dla wszystkich dostępna jest ewentualnie plansza poglądowa.

Przykładowa konfiguracja sprzętowa pierwszego trybu.

Druga konfiguracja różni się tym, że każda z drużyn posiada swoje urządzenie z planszą do gry. Gracze logują się do gry przed jej rozpoczęciem i wybierają którą drużynę reprezentują. Reszta pozostaje bez zmian.

Kofiguracja sprzętowa numer dwa, w której jest każda drużyna ma swoje urządzenie interaktywne, kapitanowie posiadają jedno lub więcej map i dla wszystkich dostępna jest ewentualnie plansza poglądowa.

Przykładowa konfiguracja sprzętowa drugiego trybu.

Cała aplikacja będzie zawierała jeszcze inne ekrany: konfiguracji słownika słów dostępnych w grach, konfiguracji gry czy panel użytkownika. Nie są one jednak kluczowe i nie będę ich dzisiaj przedstawiał. Na koniec zapraszam do komentowania, może podrzucisz mi jakiś ciekawy pomysł, który mogę dodać do rozgrywki. Kolejny raz zachęcam także do odwiedzenia mojego profilu na Twitterze, gdzie postaram się zamieszać więcej aktualizacji dotyczących prac nad projektem!

Zabezpieczenie WebAPI w ASP.NET Core – Wprowadzenie

Dzisiaj chciałbym w skrócie omówić jak zabezpieczyć nasze API, które napisane jest w .NET Core. Jeżeli chcemy mówić o bezpieczeństwie aplikacji, musimy poznać i zrozumieć dwa bardzo ważne pojęcia, które często są ze sobą mylone:

  • Authentication, czyli uwierzytelnianie, to proces podczas którego sprawdzamy, czy dana osoba jest rzeczywiście tym za kogo się podaje.
  • Authorization, czyli autoryzacja, polega na ustaleniu, czy podmiot ma dostęp do zasobu po który wysłał żądanie.

Bardziej na ten temat nie będę się rozpisywał, zachęcam do bardziej dogłębnej lektury, po przeczytaniu mojego wpisu oczywiście.

Zło konieczne

W wielkich systemach zabezpieczenia to sprawa oczywista: finanse, adresy etc. Nikomu nie trzeba tłumaczyć, że te dane pod żadnym pozorem nie mogą wpaść w niepowołane ręce. Jednak rozwijając małą aplikację można sobie pomyśleć: „Po co mi zabezpieczenia, to tylko mały projekt po godzinach, kto chciałby mi się tutaj włamywać?”. Takie myślenie może być zgubne. W sieci grasuje wiele niebezpieczeństw i nawet, jeżeli nie mamy żadnych danych poufnych, to po prostu możemy paść ofiarą zwykłej złośliwości i utracić cenne dla nas dane. Tak mi się skojarzyło z obrazkiem poniżej, za każdym razem jak będziesz odczuwał pokusę udostępniania API bez zabezpieczeń, przypomnij sobie słowa Melisandre.

Satyryczny obrazek postaci z serialu Gra o Tron, ostrzegający o tym że "Internet jest ciemny i pełny strachu"

„Internet jest ciemny i pełny strachu”

Zdając sobie sprawę z zagrożeń o których wspomniałem, przystąpiłem do implementacji mojego API. Osobiście uważam, że jest to bardzo nudna część projektu, zło konieczne z którym trzeba się pogodzić. Cytując słowa Scotta Hanselmana: Shave the Yak, co oznacza mniej więcej tyle, że musimy się uporać z mniejszym problem, żebyśmy mogli przejść do konkretów.

Implementacja JWT Tokens

Na szczęście, do dyspozycji mamy wiele narzędzi które ułatwiają nam życie. Ja moje API zabezpieczam przy użyciu Tokenów JWT. Na razie przedstawię podejście minimalistyczne, w którym będziemy korzystali z indywidualnych kont użytkowników. W przyszłości chcę wykorzystać Social Login, czyli po prostu stare dobre Zaloguj się poprzez fejsbuka, gdzie oczywiście zamiast tego można wykorzystywać także Google, Twittera czy innego GitHub’a. No ale przejdźmy już do konkretów.

Na wstępie musimy dodać bazę danych, gdzie przechowywać będziemy użytkowników. Ja wykorzystam do tego Entity Framework. Dane konfiguracyjne przechowuje w plikach, które nie są wrzucone do repozytorium na GitHubie, a do ich odczytu dodałem własną klasę.

Teraz definiujemy z jakich narzędzi będziemy korzystać. Dzieje się to w pliku Startup.cs, w metodzie ConfigureServices. Najpierw konfigurujemy wykorzystanie systemu identyfikacji Identity dostępnego w paczce Microsoft.AspNetCore.Identity. W tym samym miejscu definiujemy, że do tego cely wykorzystamy właśnie Entity Framework.

Następnie konfigurujemy to, w jaki sposób aplikacja będzie uwierzytelniała użytkowników. Oto fragment tej metody:

UseJwtBearerTokenAuthentication to extension method, który dodałem w celu odchudzenia pliku Startup.cs. To dopiero początek pracy nad projektem, a ten już rośnie w niebezpiecznym tempie. Dlatego staram się wydzielać część konfiguracji do innych plików. Implementacja wspomnianej metody:

Tutaj wprowadzamy nasz tajny klucz, który służy do szyfrowania naszego tokena. Jak poprzednio, przechowuje go w pliku konfiguracyjnym. Definiujemy także to kto wystawia, oraz kto będzie konsumentem naszego tokena. Wszystko to w celu jak najlepszego zabezpieczenia naszej aplikacji.

Ostatnim etapem zabezpieczenia naszej aplikacji jest dodanie klasy, która będzie generowała nam nasze tokeny. Nie będę w całości kopiował tego kodu (kod dostępny w serwisie GitHub tutaj), a tylko kilka kluczowych elementów.

W sytuacji, gdy potwierdzimy tożsamość użytkownika, generujemy klucz, tak samo jak robiliśmy to podczas konfiguracji. Następnie przy pomocy algorytmu HmacSha256 będziemy szyfrować dane. Token zawiera podstawowe informacje o użytkowniku, a także zbiór jego uprawnień, Claims. Dokładniej o tym co zawiera taki token napiszę w innym poście, gdzie opowiem więcej o wspomnianych Claims.

Teraz wywołujemy tą klasę w kontrolerze i nasi użytkownicy mogą wysłać request o token.

Podsumowanie

Gdy przejdziemy przez kroki o których wspomniałem, otrzymamy gotowe rozwiązanie które pozwoli nam w pełni zabezpieczyć naszą aplikację. Nie wspomniałem tutaj o takich pojęciach jak np. CORS oraz SSL, ale myślę że będzie jeszcze ku temu okazja w kolejnych postach. Tymczasem zapraszam do komentowania oraz odwiedzenia mojego Twittera.

Przygotowanie API – REST, czy nie do końca?

Pracę nad moim projektem zacząłem od zadania sobie pytania: jak powinna wyglądać architektura mojego programu? I chociaż na temat samej architektury dodam oddzielny post, potrzebne będzie krótkie wprowadzenie. Głównym założeniem jest powstanie aplikacji dostępnej z poziomu przeglądarki, dzięki czemu będzie można uruchomić ją na komputerach PC oraz Mac, tabletach, a nawet smartfonach. Wiadomo jednak, że na urządzeniach przenośnych dużo wygodniej korzysta się z aplikacji natywnych. Tak powstał kolejny cel, czyli apka na urządzenia zaopatrzone w system Android. Nie postanowiłem jeszcze jak będzie ona wyglądać, ale skłaniam się ku rozwiązaniu w którym będzie ona miała ten sam kod (w miarę możliwości) co strona www, dzięki zastosowaniu rozwiązań takich jak np. Adobe PhoneGap. Jeżeli tak się sprawy mają, to naturalnym wnioskiem dla mnie jest to, że muszę przygotować jakieś API, które mój klient będzie mógł wykorzystać. Tutaj pojawia się kolejne pytanie, na które chcę dzisiaj odpowiedzieć: czy moje API powinno być RESTful, czy też nie? Może wystarczy podejście RPC.

REST czy RPC? I co to takiego?

W celu podjęcia decyzji, postaram się w skrócie opisać te dwa podejścia i wskazać czym się różnią. Oba z tych rozwiązań w tym kontekście operować będą na protokole HTTP. Zapytanie przy użyciu tego protokołu składa się z między innymi:

  • Metody (Mehtod) np. GET, HEAD, POST, która decyduje o tym jaką operację wykonamy na zasobie
  • Nagłówków (Header), w których dostępne są dodatkowe informacje o żądaniu np. dane pozwalające na uwierzytelnianie
  • Ciała zapytania (Content body), które przechowuje informacje np. o zasobie który chcemy dodać/edytować

Niektóre z metod są idempotentne (Idempotent) (z założenia, tak powinny być zaimplementowane), to znaczy że nie ważne ile razy je wykonamy w danych warunkach, zawsze zwrócą tej sam wynik (np. GET i PUT). Inną cechą niektórych metod jest to że są bezpieczne (Safe), czyli nie modyfikują one danych i nie posiadają skutków ubocznych np. GET i HEAD (tak jak poprzednio, w ten sposób powinny być implementowane).

REST, czyli Representational State Transfer to architektura pozwalająca na pisanie skalowalnych usług internetowych. Nie będę rozpisywał się na temat definicji pojęcia REST. Opisując w skrócie: udostępniamy zasoby na których możemy wykonywać różne operacje za pomocą protokołu HTTP. Rodzaj operacji zależy od tego, jakiej metody użyjemy podczas zapytania. Przykładowo, poniższe trzy zapytania będą miały różne wyniki:

  • GET www.example.com/api/objects/2
  • DELETE www.example.com/api/objects/2
  • PUT www.example.com/api/objects/2

W przypadku, gdy mówimy o REST, mamy na myśli podejście zorientowane na zasoby. Definiując adres zasobu używamy rzeczowników, a to jaką akcję wykonujemy nie jest wskazywane przez dodanie czasownika, lecz przez wybór metody HTTP.

RPC (Remote procedure call) ma wiele definicji, ale w tym znaczeniu chodzi o podejście, w którym zamiast operować na zasobach, mamy do czynienia z operacjami. Operacje te w swojej nazwie sugerują co będzie efektem ich wykonania. W przypadku implementacji tego podejścia za pomocą protokołu HTTP wykorzystuje się głównie dwie metody: GET oraz POST. Nie ma tutaj jasno sformułowanych zasad, ale zazwyczaj GET służy do pobierania danych lub akcji, które nie zmieniają żadnych danych, natomiast POST służy do pozostałych operacji. Przykładowe wywołanie takich zapytań:

  • GET www.example.com/api/GetAllObjects
  • POST www.example.com/api/CreateObject

Jeżeli wiemy już jak takie zapytania wyglądają i czym się charakteryzują, możemy przystąpić do porównania. Wezmę pod uwagę kilka czynników, które moim zdaniem są ważne podczas wyboru metody implementacji naszego API.

Projektowanie

Na początek weźmy pod uwagę to, w jak łatwy sposób można projektować nasze API. Jeżeli weźmiemy pod uwagę systemy, które już istnieją np. mamy napisaną już bibliotekę i chcemy w jakiś sposób wyprowadzić ją na świat, łatwiej będzie nam użyć podejścia RPC. Dzieje się tak z reguły dla tego, że większość kodu jaki piszemy jest zorientowany na operacje i łatwiej go w ten sposób odwzorować. Łatwiej też będzie rozwijać system, który głównie opiera się o różnego rodzaju procesy, gdzie jeden obiekt ciągle zmienia się wg jakiejś logiki. Wadą tego podejścia może być to, że ponieważ nie nakłada nam ona żadnych ograniczeń, projektant musi sam pilnować tego, żeby API było spójne i składało się w logiczną całość. Z drugiej strony, REST ułatwia projektowanie prostszych systemów gdzie głównym zadaniem są operacje typu CRUD. Nawet, jeżeli projektowanie API RESTowego może być trudniejsze, dzięki założeniom jakie ze sobą niesie łatwiej otrzymać spójne i logiczne zaplecze dla naszej aplikacji. Tutaj pytanie pozostaje bez odpowiedzi moim zdaniem, ponieważ wszystko zależy od kontekstu w jakim będziemy pracować.

Dokumentacja i jak łatwo ją przygotować

W obu przypadkach możemy wykorzystać narzędzia typu Swagger do udokumentowania naszego API, więc żadne podejście nie jest tutaj lepsze. Sama nazwa zasobu/operacji także może nam sporo powiedzieć o tym, co będzie efektem wywołania danego zapytania. GET www.example.com/api/GetAllObjects czy GET www.example.com/api/objects w jasny sposób mówi nam, co dostaniemy w odpowiedzi, więc można tutaj powiedzieć w pewnym stopniu o tym jak API dokumentuje się samo. Z doświadczenia wiadomo jednak, że takie rzeczy nie zdarzają się zbyt często i trzeba posiłkować się dodatkowymi źródłami wiedzy o naszym requescie.

Semantyka i używalność

W RPC nie jesteśmy w stanie przewidzieć tego, jak dana operacja będzie się nazywać. Ta sama operacja może przybierać taki wygląd:

  • GET/POST www.example.com/api/RemoveObject/1
  • GET/POST www.example.com/api/DeleteObject/1

Zdajemy się tutaj na to, jaki styl wybiera osoba odpowiedzialna za przygotowanie API. Można założyć, że będzie się ona trzymała swojego standardu i podczas usuwania innego rodzaju obiektu użyje tej samej nazwy zapytania. Jednak może się zdarzyć, że za każdym razem trzeba będzie zagłębiać się w dokumentację. REST jest bardziej przewidywalny, dzięki wykorzystywaniu metod HTTP. Nawet, jeżeli nie wiemy dokładnie co stanie się po wykonaniu danej metody, mamy ogólne pojęcie co może być efektem końcowym. W tym przypadku, mój głos dostaje podejście REST, chociaż nie musi zawsze tak być.

Obsługa Cache

Obsługa Cache to jedna z bardzo ważnych rzeczy, które powinna zapewniać nasza RESTowa architektura. Patrząc na specyfikację metod HTTP w łatwy sposób dodać taką obsługę do naszego API. W podejściu RPC jest to dużo trudniejsze, zwłaszcza, gdy zbyt często będziemy korzystać z metody POST. Nie jest to jednak niemożliwe. W tym punkcie można skłaniać się minimalnie w stronę architektury REST.

Podsumowanie

Niektórzy stwierdzą, że wybór naszego podejścia można sprowadzić tylko do osobistych odczuć na temat tego, czy wolimy taki czy inny styl zapytań. Jednak od naszego podejścia w dużej mierze zależy to, w jaki sposób będziemy później pisać nasze aplikacje. Moim zdaniem, głównym czynnikiem jakim powinniśmy się kierować jest to, jaki jest nasz projekt i nie ma sensu od razu zakładać że zrobimy to tak, czy inaczej. Pomimo kilku punktów, w których REST jest lepszym podejściem, np. to że jest bardzo przejrzysty i przewidywalny, ma on też kilka sporych wad i nieudogodnień, które wynikają z jego ograniczeń. Dlatego ja zwykle stawiam na pragmatyzm w moich rozwiązaniach i czerpię to, co najlepsze z danych rozwiązań. Nawet, jeżeli moje API będzie bardziej skłaniało się ku architekturze REST, to nie będę bał się użyć podejścia bardziej skierowanego na operacje. Moim zdaniem POST www.example.com/api/game/1/endturn będzie lepiej opisywało sytuację, niż zmiana właściwości obiektu i wykonywanie konkretnej operacji później.

A jakie jest Twoje zdanie na ten temat? Wszelkie uwagi mile widziane! Zapraszam do komentowania i kolejny raz polecam się na Twitterze!

Relacja z WROC# 2017

Dziś chciałem podzielić się moimi wrażeniami z konferencji WROC# która odbyła się w 3 marca w piątek. Była to już trzecia edycja tego wydarzenia. Po raz pierwszy usłyszałem o niej w zeszłym roku. Słyszałem wtedy, że ciężko zdobyć na nią wejściówkę, ponieważ jest aż tylu chętnych. To, co stało się w trakcie rejestracji przeszło moje najśmielsze oczekiwania. Strona nie zdążyła mi się odświeżyć, a biletów już nie było. Ale to było rok temu. Nie zraziłem się tym i liczyłem że w tym roku będzie lepiej. Miałem ku temu podstawy, ponieważ w tym roku po raz pierwszy wprowadzono opłatę za uczestnictwo w wysokości 150zł. Warto tutaj dodać, że cała kwota zebrana z biletów przekazywana jest na cele charytatywne, tak więc dla organizatora wielki plus. W tym roku mi się udało (inaczej nie pisałbym tej relacji…), ale podobno bilety rozeszły się w około dwie minuty. Jak widać, popularności od zeszłego roku konferencja za dużo nie straciła. No ale przejdźmy już do konkretów!

Przebieg wydarzenia

Po około dwugodzinnej podróży z Zabrza, gdzie mieliśmy zbiórkę przed wyjazdem, przyjechaliśmy pod Stadion we Wrocławiu, gdzie impreza miała miejsce. Rejestracja na takich wydarzeniach może różnie wyglądać, ale tutaj wszystko przebiegało bardzo sprawnie. Dostaliśmy nasze identyfikatory wraz z upominkami, a następnie udaliśmy się na salę gdzie miały odbywać się prelekcje.

Logo WROC#

Dla uczestników dostępny był poczęstunek, drożdżówki, a później różne przekąski w takcie dnia a także obiad w połowie dnia. Wszystko było bardzo smaczne i umilało przerwy pomiędzy wystąpieniami. Dla uczestników dostępne były chillout area oraz working room, gdzie było trochę spokojniej niż w innych rejonach obiektu. Chętni mogli troszkę odsapnąć, lub w razie konieczności popracować. Później każdy chętny mógł podejść do strefy VR, gdzie zobaczyć było można Hololens, Oculus Rift i Touch, HTC Vive czy też PlayStation VR. Organizatorzy przygotowali także dwie gry z nagrodami. Moje ósme miejsce w grze E-maze-ng oraz fakt, że kilka osób nie dotrwało do rozdania nagród, pozwoliło mi wygrać przejażdżkę (tylko jako pasażer, niestety…) samochodem Tesla S P85D! Trzeba przyznać, pomimo niepozornego wyglądu, samochód ten ma niesamowitego kopa!

Prezentacje

Zdjęcie organizatorów witających uczestników konferencji

Openning session

Najważniejsze podczas tego typu wydarzeń, oprócz możliwości porozmawiania z innymi pasjonatami programowania, są oczywiście prelekcje! W kilku słowach postaram się opisać każdą z nich.

Frans Rosén Go hack yourself…or someone else will
Pierwsza prezentacja dnia, gdzie autor opowiadał o tym jak pomaga dbać o bezpieczeństwo witryn sieciowych hackując je i dostając za to nagrody! Można było zobaczyć wiele przykładów na to, czego nie powinno się robić w swoich aplikacjach oraz na co zwracać uwagę. Bardzo mi się podobało, ale jednak nie zacznę szukać dziur w Facebooku albo innych portalach.

Chris Klug AngularJS Tips from the Trenches
W tej prezentacji autor dawał wskazówki na to, jak pisać nasz kod gdy korzystamy z AngularJS. Pomimo, że przykłady dotyczyły tego konkretnego przypadku, wiele z uwag zawartych w tej mowie można wykorzystać podczas pracy z innymi frameworkami np. Aureli. Pomimo, że większość z tego co usłyszałem to podstawy, kilka rzeczy dało mi do myślenia.

Maarten Balliauw What is going on? Tips and tricks around application diagnostics on Azure
Maarten w swojej prezentacji mówił o tym, jak ważne jest zarządzanie naszą aplikacją po tym, jak już zakończymy jej rozwijanie. Czy dobrze działa? Czy użytkownicy wykorzystują jej pełny potencjał? Tego możemy się dowiedzieć jeżeli dobrze podejdziemy do tematu logowania zachowania naszej aplikacji. Spora część prezentacji poświęcona była Application Insights dostępnego na Azure. Drobne problemy z łączem internetowym to nie jest rzadkość podczas takich wystąpień i tym razem nie obyło się bez problemów. Jednak ogół prezentacji i tym razem na plus.

Steve Sanderson ASP.NET Core for Angular 2, React, and Knockout developers
Ta prezentacja troszkę mniej przypadła mi do gustu. Bardzo duża część prezentacji poświęcona szablonom projektów dostępnych dla APS.NET Core dla różnych frameworków. Moim zdaniem trochę za dużo podstaw jak na taką imprezę. Później było troszkę ciekawiej, zwłaszcza możliwość używania możliwości paczek dostępnych z NPM wewnątrz backendu. Ogólnie jednak jedna ze słabszych prezentacji.

Tess Ferrandez Debugging .NET performance problems, memory leaks and crashes
Szczerze przyznam, że podczas tej prezentacji troszkę zbyt mocno pochłonęła mnie gra, którą przygotowali organizatorzy. Jednak było tutaj pokazanych kilka ciekawych sztuczek, które pozwolą nam na optymalizację naszych aplikacji. Na pewno nadrobię to gdy tylko dostępne będą wystąpienia w formie video!

Shawn Wildermuth Developing ASP.NET Core in VS Code
Shawn przybliżał nam możliwości, które daje nam VisualStudio Code. Nie chciał sprzedawać tego środowiska na siłę, wymieniał jego mocne strony, ale także wady. Osobiście nie jestem wielkim fanem tego produktu, dużo bardziej wolę stare dobre VisualStudio. Prezentacja bardzo fajna, ale i tym razem zbyt dużo podstaw jak na taki event.

Po głównych sesjach miejsce miał Discussion panel, gdzie można było zadawać pytania prelegentom za pośrednictwem Twittera. Niestety przegapiłem ten moment, ponieważ musieliśmy odstawić samochód pod hotel. Gdy tylko będzie dostępna relacja z tej części, na pewno zobaczę z przyjemnością.

Afterparty

Po całym dniu technicznych wykładów, organizatorzy przygotowali bardzo wiele atrakcji dla tych, którzy jeszcze nie wracali do domów. Jeszcze więcej pysznego jedzenia, wiele gatunków piwa do wyboru, DJ który rozkręcał parkiet lub kilka stołów z piłkarzykami oraz przejażdżka Teslą dla szczęśliwców, do grona których sam należałem! Była to także świetna okazja do rozmowy z innymi uczestnikami. Było to świetne podsumowanie całej imprezy.

Podsumowanie

WROC# to impreza, której atmosfera oraz organizacja sprawia, że na pewno nie zabraknie mnie tutaj w przyszłości! Liczę jedynie, że będzie troszkę więcej prezentacji związanych z architekturą oprogramowania. Do zobaczenia za rok!

PS. Podczas konferencji pierwszy raz zacząłem bawić się Twitterem. Jeżeli Ty też korzystasz z tej aplikacji, zapraszam do siebie pod adresem @sakwamichal.

Daj się poznać 2017

Słów kilka na powitanie

Cześć, nazywam się Michał i pochodzę z Zabrza. Na co dzień jestem programistą .NET, czym zajmuję się już od blisko 6 lat. Do tej pory siedziałem zwykle po drugiej stronie jako czytelnik, a nie autor tego rodzaju wpisów, ale przyszła i moja kolej żeby się sprawdzić w tej roli. Przyznaję szczerze, że bez motywacji w postaci konkursu Daj się poznać raczej bym się na taki krok nie zdecydował. A jako, że wspomniałem o konkursie, wypada wyjaśnić o co chodzi!

Konkurs „Daj się poznać”

Daj się poznać 2017 to konkurs organizowany przez Maćka Aniserowicza, który prowadzi bloga devstyle.pl. Jest to kolejna edycja tego konkursu, który przyciąga rzeszę programistów, nie tylko związanych ze światem technologi dostarczanych przez firmę Microsoft. W tym roku udało się zebrać ponad 700 uczestników! Z powodu ogromnego zainteresowania rejestracja, która planowo miała trwać do końca lutego, została przedłużona do 12 marca.
Logo konkursu daj się poznać 2017

Ale o co w tym wszystkim chodzi? Sprawa jest bardzo prosta i sprowadza się do dwóch prostych rzeczy: każdy uczestnik musi rozwijać aplikację korzystając z dowolnie wybranych przez siebie technologii oraz dokumentować to wszystko na swoim blogu. To wszystko sprawiło, że jestem tutaj i piszę swój pierwszy wpis. Jestem pewny że będzie to dla mnie nie lada wyzwanie, ponieważ nigdy nie byłem najlepszy w tego typu sprawach. Przejdźmy już do tego, co tygryski lubią najbardziej, czyli samego projektu! Jeżeli interesują Cię szczegóły konkursu, lub sam chcesz wziąć udział, zapraszam na stronę autora konkursu do której link znajduje się powyżej. Masz jeszcze czas!

WordHunt, czyli moja aplikacja konkursowa

To, co w dużej mierze powstrzymało mnie przed wzięciem udziału w konkursie w zeszłym roku, to problem z wyborem odpowiedniego tematu. W tym roku było podobnie, ale po kilku dniach główkowania w końcu udało mi się wpaść na coś, co wydawało mi się w porządku. Inspiracją dla mojej aplikacji była gra towarzyska, w której dwie drużyny próbują odgadnąć które słowa są przydzielone do nich za pomocą skojarzeń, które podsyła kapitan. Plansza składa się z 25 losowych kart i klucza, który znają tylko kapitanowie. Ostatnio pomyślałem sobie, że byłoby fajnie zagrać na większej planszy oraz poszerzyć grę o więcej zespołów. Tak narodził się w mojej głowie pomysł na WordHunt. Pewnie podczas pisania wpadnę na jeszcze więcej pomysłów, ale na razie taki opis powinien wystarczyć. Jeżeli chodzi o technologie których zamierzam użyć, to cały czas rozważam moje możliwości. Na pewno będę starał się wybierać takie, z których nie korzystam w pracy. Przecież o to też tutaj chodzi, o naukę oraz dzielenie się poznaną wiedzą. Z rzeczy na które się już zdecydowałem, backend aplikacji będzie napisany w .NET Core z którym miałem już styczność, ale nie było tego za wiele. Postaram się także użyć nowych dla mnie bibliotek, na przykład Dapper.net. Jeżeli chodzi o interfejs, to tutaj ciągle nie podjąłem decyzji. Vue.js lub Angular2 to mocni kandydaci, ale mam jeszcze trochę czasu żeby to przemyśleć. W planach jest powstanie strony www oraz aplikacji na systemy android, ale zobaczymy ile uda mi się zrobić podczas trwania konkursu.

Głównym celem dla mnie jest dotarcie do końca konkursu. Patrząc na to, ile zajęło mi pisanie tego posta nie będzie to łatwe zadanie, ale zrobię co w mojej mocy żeby tak się stało! Mam nadzieję, że moje przyszłe posty przydadzą się komuś podczas pracy, na pewno sprawiłoby mi to wiele radości. Trzymajcie kciuki i zapraszam ponownie!