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ę!

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.

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!

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.

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!

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.

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!