Guardy i Pattern Matching, czyli czym zauroczył mnie Haskell, a brakuje mi tego w C#

Ostatnio w kręgu moich zainteresowań pojawił się język Haskell. Jest to język czysto funkcyjny o silnym typowaniu, którego premiera datowana jest na rok 1990, czyli aż dekadę wcześniej niż C#. Składnia języka przypomina inne funkcyjne języki programowania jak np. F#. Nie zagłębiając się zbytnio w niuanse języka Haskell bardzo spodobały mi się w nim dwie rzeczy.

Pierwsza jest zbyt prosta, żeby poświęcić jej cały artykuł. To leniwe wartościowanie. W Haskell-u rozwiązano to inaczej niż w C#, zamiast ręcznie decydować co powinno być „Lazy”, a co nie. Leniwe wartościowanie jest stosowane zawsze, bez potrzeby dopisywania czegokolwiek w kodzie.

Drugą, dużo bardziej interesującą cechą języka Haskell są Guardy i Pattern Matching. Nie jest to cecha tylko tego języka, ale również wielu innych języków funkcyjnych, jednak mi w oczy ich zalety rzuciły się właśnie przy okazji poznawania języka Haskell.

Czym są Guardy i Pattern Matching najłatwiej będzie zrozumieć na przykładzie, a więc do dzieła ;)
Przykłady pochodzą ze strony:
http://learnyouahaskell.com/syntax-in-functions

  • Guards (pl. strażnicy)
  • guards

    Pierwsza linijka zawiera deklarację metody bmiTell wraz z typami jakie przyjmuje i zwraca (jak już wcześniej wspominałem, język Haskell jest językiem silnie typowanym). Magia dzieje się dalej. Jak się pewnie domyślasz bmi jest parametrem. Zaś pionowe kreski od których rozpoczynają się kolejne linie to właśnie Guardy. W zależności od wartości parametru bmi otrzymamy odpowiedniego stringa. Oczywiście jest to tylko prosty przykład, guardy mogą być dużo bardziej rozbudowane. Jeśli jednak nie chcemy tworzyć wielolinijkowych metod albo zależy nam na większym odseparowaniu od siebie poszczególnych operacji powinniśmy skorzystać z PatternMatchingu.

  • Pattern Matching
  • pattern matching
    Prosty przykład użycia pattern matchingu w języku Haskell. Jak widać jego funkcjonalność jest zbliżona do tej, którą oferują Guardy. Z tą różnicą, że mamy tutaj do czynienia już nie z tylko jedną, a kilkoma funkcjami.

    pattern matching silnia
    I jeszcze jeden przykład, tym razem obliczanie silni.

    Zalety takiego rozwiązania

  • Oczywiście zastosowanie guardów nie dodaje nic nowego czego w języku C#, by dotychczas nie było. Jedyną zaletą guardów w tym przypadku jest (przynajmniej według Mnie) dużo ładniejszy zapis niż w przypadku gdy użylibyśmy instrukcji switch-case lub if-else
  • Zupełnie inaczej jest zaś z zastosowaniem Pattern-Matching-u, daje on nam możliwość przeniesienia polimorfizmu/przeciążania metod na jeszcze niższy poziom – zależny od wartości parametrów. A to pozwala np. na usunięcie z kodu if-ów i switchy do wybierania konkretnej klasy po jakieś wartości enum (fabryka). Konstrukcje w stylu switch(enum)-case mogłyby odejść zupełnie do lamusa.


  • Jaka jest na to odpowiedź twórców języka C#?
    I tutaj zaskoczenie, po tym jak zachwyciłem się Pattern Matchingiem i Guard-ami w języku Haskell, postanowiłem zrobić resarch i uwaga, jest w wersji C# 7 pojawi się Pattern Matching!

    Zerknijmy zatem w przykład.
    Przykłady pochodzą ze strony:
    https://www.kenneth-truyers.net/2016/01/20/new-features-in-c-sharp-7/

    pattern matching w csharp

    Na pierwszy rzut oka wydaje się, że wszystko świetnie, po 16 latach, język C# wreszcie doczeka się Pattern Matchingu. Ale czy użycie instrukcji switch-case w przykładzie jest celowe czy może implementacja będzie nierozłączna z używaniem kolekcji warunkowych?

    Rozważmy sobie jeszcze jeden przykład.
    csharp bez pattern matchingu

    Zagadka jest bardzo prosta. Która z metod zostanie wykonana? W tym momencie (C# 6) odpowiedź wydaje się być prosta, będzie to oczywiście metoda Print(Geometry). Co jeśli jednak zastosowalibyśmy pattrern matching. Wtedy powinna wykonać się metoda Print(Square)?

    Na odpowiedź musimy jeszcze trochę poczekać. Najbardziej prawdopodobne wydaje się, że PatternMatching będzie na poziomie wartości parametrów, a na poziomie klas zostanie on ograniczony jedynie do przypadku z przykładu. Szkoda, bo to oznacza, że zostaniemy jeszcze trochę w świecie pisania instrukcji warunkowych, bo częściowa alternatywa jaką w tej chwili jest użycie dynamic zamiast interfejsu, niestety jest zbyt wolna (instrukcja warunkowa wykona się dużo szybciej niż pierwsze użycie dynamic).

    Edit. Pattern Matching prawdopodobnie nie pojawi się w 7 wersji C#, jego wprowadzenie zostało przesunięte.

    Własne przemyślenie
    Poprzez styczność z językami funkcyjnymi w ostatnim czasie naszło mi na myśl pewne stwierdzenie. Języki obiektowe zostały stworzone, by podnosić pewnie nietrywialne (no może trochę przesada z tą nietrywialnością) problemy na poziom obiektowości i rozwiązywać je w prosty sposób, zaś języki funkcyjne dają nam narzędzia, żeby te same problemy rozwiązywać jak najłatwiej już na poziomie funkcji ;)

    Ciekaw jestem waszych opinii. Zapraszam do komentowania. Jeśli zaś spodobał Ci się ten wpis i chciałbyś odwiedzać blog pasja-programowania częściej zapraszam do polubienia fanpage’a www.facebook.com/Pasja-programowania-1649374605334405

    Opublikowano Bez kategorii | Otagowano , , , , | 2 komentarzy

    Jeszcze bardziej dynamiczne tworzenie zapytań do bazy (LinqKit)!

    Zacznijmy od tego, że ostatnio przeczytałem artykuł jednego z naszych kolegów programistów na temat dynamicznego tworzenia zapytań do EntityFramework. Link tutaj

    Artykuł fajny, rozwiązuje problem z którym Ja osobiście mierzę się dość często, ale od czasu przeczytania tego artykułu mam ogromną potrzebę pochwalenia się jak do tego problemu podchodzę ja. Tym bardziej, że uważam moje rozwiązanie za lepsze. Najlepiej różnicę będzie widać jeśli oprę się więc o ten sam przykład.

    Zacznijmy może od problemu. Czasem chcemy zbudować zapytanie, które zależne jest od jakiegoś parametru. Prosty przykład.

    public List GetProductsHiddenOnMondayAndTuesday( )
    {
    var query = products.Where(p => p.Available == true);
    if (DateTime.Now.DayOfWeek == DayOfWeek.Monday)
    query = query.Where(p => p.HiddenOnMondays == false);
    if (DateTime.Now.DayOfWeek == DayOfWeek.Tuesday)
    query = query.Where(p => p.HiddenOnTuesday == false);

    return query.ToList();
    }

    Jak widać nie jest to zbyt ładny kod dla tak trywialnego problemu, a często przychodzi nam walczyć z przykładami o wiele bardziej skomplikowanymi.

    Rozwiązanie problemu napisane w przytoczonym artykule polega na utworzeniu metody rozszerzeń do IQueryable.

    public static IQueryable TodayIs(this IQueryable query, DayOfWeek day)
    switch (day)
    {
    case DayOfWeek.Monday:
    return query.Where(p => p.HiddenOnMonday == false);
    case DayOfWeek.Tuesday:
    return query.Where(p => p.HiddenOnTuesday) == false);
    case DayOfWeek.Wednesday:
    return query.Where(p => p.HiddenOnWednesday == false);
    //etc.
    }

    Jest to oczywiście dużo ładniejsze rozwiązanie od tego w przykładzie, ale czy najlepsze? Sam autor pisze, że „typ IQueryable wymaga ostrożności i generalnie nie powinien być wyprowadzany poza repozytorium/inną warstwę dostępu do danych”. Dla Mnie osobiście pisanie takiej metody rozszerzonej jest też trochę nadużyciem, bo co jeśli byśmy chcieli wybrać np. wtorki i środy, lub jeszcze inną konfigurację? albo jak wybierać dla jednego LUB drugiego dnia?

    Na ratunek przychodzi nam biblioteka LinqKit i klasa PredicateBuilder. Klasa ta została wprost stworzona do wspomagania budowania zapytań, które podlegają filtrowaniu po wielu parametrach. Najłatwiej będzie zrozumieć to na przykładzie.

    Expression<Func> predicate = PredicateBuilder.True();
    predicate = predicate.And(x => x.Available == true)
    .And(x => x.HiddenOnMondays == true)
    .Or(x => x.HiddenOnTuesday == true);

    Najpierw tworzymy obiekt predicate, jest to expression dla zmapowanej tabeli Product. Później tworzymy serię warunków, które muszą spełnić fitrowane obiekty. Dodatkowym atutem budowania zapytań jest istnieje metody Or (alternatywa logiczna). Warunki już mamy, teraz musimy jeszcze je wykorzystać.

    public List GetFilteredProducts(Expression<Func> expression)
    {
    var query = products.AsExpandable().Where(expression);
    return query.ToList();
    }

    Jest to przykład użycia w klasie Dao produktów. Typ expression można przekazać jako parametr i użyć go wprost w metodzie where. Żeby jednak można było użyć expression potrzebne jest jeszcze dodanie AsExpandable.

    Jak widać użycie PredicateBuildera jest banalnie proste. Ważne jednak, żeby go nie nadużywać. Gdzie go więc używać? Najprościej będzie w połączeniu z zapytaniami pokroju GetFilteredSomething. Gdy używamy EntityFrameworka do połączenia z bazą danych często w Dao tworzy się wiele metod ze „sztywnymi filtrami”, możemy je zastąpić albo jedną GetFiltered i przekazywać jej kryteria z innej warstwy albo wydzielając metodę jak w przykładzie powyżej, a precyzować filtry w innych metodach dao.
    Gdzie go zaś nie używać? Tam gdzie pytania są na tyle proste i nie zależą od wielu parametrów, wtedy użycie PredicateBuildera będzie nadużyciem. Jeśli zaś korzystamy z nHibernate’a, który jest jednak dużo bardziej dojrzałym frameworkiem od EF to bardziej naturalne będzie wykorzystanie Criteria Queries, które daje nam sam framework, tutaj PredicateBuilder może okazać się zbędne.

    Jeśli spodobał Ci się ten artykuł to zapraszam do polubienia fanpage-a, na którym zawsze znajdziesz informacje o nowościach na blogu ;)
    https://www.facebook.com/Pasja-programowania-1649374605334405

    Opublikowano Bez kategorii | Otagowano , , | 3 komentarzy

    Czy interfejs może zawierać implementację metody, czyli trochę hackowania

    Język C# w całej swojej świetności ma również masę ograniczeń, oczywiście wszystko dla naszego dobra ;) Jednym z takich ograniczeń jest dziedziczenie maksymalnie po tylko jednej klasie (ale za to po wielu interfejsach). Co czasem może okazać się nie lada wyzwaniem ;) Zapraszam więc do lektury.

    Najczęstszym i najłatwiejszym rozwiązania problemu niemożności dziedziczenia po wielu klasach jest zamiana dziedziczenia na kompozycję (czy to jednej z klas po których chcieliśmy dziedziczyć czy obu/więcej). Innym równie prostym rozwiązaniem jest stworzenie odpowiedniej hierarchii klas. Najłatwiej będzie pokazać to na przykładzie.

    A chce dziedziczyć po B oraz C.
    B C
    | /
    A

    Rozwiązaniem może być np.
    C
    |
    B
    |
    A

    W ten sposób A dziedziczy zarówno, po B jak i C. Niestety nie zawsze możemy/powinniśmy skorzystać z takiego rozwiązania, szczególnie jeśli klasy B lub C dziedziczą już po jakiś innych klasach (zbytne skomplikowanie) lub klasy B i C są klasami, które kolokwialnie mówiąc, nie powinny mieć ze sobą nie wspólnego. W pewnych kontekstach klasa A mogłaby się okazać zbędna, ponieważ klasa B mogłaby ją w pełni zastąpić.

    To tylko jeden z wielu problemów jakie można napotkać i pewnie napotkamy nieraz w świecie programowania obiektowego i używania klas. Na całe szczęście istnieje „częściowa alternatywa” dla używania klas jaką są interfejsy.

    Wśród wielu różnic między klasami, a interfejsami, które pewnie doskonale znasz jedną z najważniejszych, a jeśli nie najważniejszą jest to, że interfejsy w odróżnieniu od klas mogą zawierają jedynie deklaracje metod, a nie ich implementację (oczywiście są jeszcze klasy i metody abstrakcyjne, akcesory itd. w tym artykule skupię się jednak na tej różnicy). Więc cóż nam po tym, że możemy skorzystać z wielu interfejsów, jeśli w każdej takiej klasie, musimy tworzyć odrębną implementację tychże interfejsów. Może i pewnie często powoduje to łamanie zasady DRY.

    Ale czy na pewno każda klasa musi posiadać własną implementację interfejsu? Czy interfejs nie może zawierać pełnoprawnej metod z jej implementacją? Jak się okazuje nie do końca. W tym przypadku na ratunek przychodzą nam metody rozszerzeń (nazywane także metodami rozszerzającymi albo rozszerzonymi).

    Zacznijmy od tego czym są metody rozszerzeń. Tutaj posłużę się cytatem z MSDN.

    Metody rozszerzenia umożliwiają „dodawanie” metod do istniejących typów bez konieczności tworzenia nowego typu pochodnego, ponownej kompilacji lub modyfikowania oryginalnego typu w inny sposób. Metody rozszerzenia stanowią specjalny rodzaj metod statycznych, ale są wywoływane tak, jakby były metodami wystąpień w typie rozszerzonym. W przypadku kodu klienta napisanego w języku C# i Visual Basic nie istnieje żadna widoczna różnica między wywołaniem metody rozszerzenia a wywołaniami metod, które faktycznie są zdefiniowane w typie.

    Jak się okazuje twórcy języka C# zostawili małą furtkę pozwalającą na tworzenie metod rozszerzeń również dla interfejsów. Co ciekawsze nie jest to jakby się wydawało przeoczenie programisty, a celowy zabieg z którego przywilejów korzystamy na co-dzień wszyscy, używając jednej z najpopularniejszych bibliotek platformy .Net! Ten smaczek zostawimy sobie jednak na koniec artykułu ;)

    Ale najpierw trochę kodu.

    TestInterface

    Test class

    extension

    Main

    Myślę, że kod jest na tyle prosty, że nie ma potrzeby tworzenia do niego jakiegoś szczegółowego opisu. W skrócie, tworzymy interfejs oraz przykładową klasę, która zawiera własną implementację metody interfejsu. Następnie dodane zostają dwie metody rozszerzeń dla interfejsu (warto zwrócić uwagę, że jedna z metod jest taka sama jak zadeklarowana w interfejsie i zaimplementowana w klasie). No i w końcu testujemy ;)

    main result

    Jak pewnie zauważyłeś wykonała się jedna z metod rozszerzenia oraz metoda, której implementacja jest w klasie TestClass. Czemu tak się stało? Odpowiedź jest bardzo prosta, twórcy uznali, że metoda rozszerzona nie może być bardziej ważna niż metoda, która znajduje się bezpośrednio w klasie.

    Do czego można zastosować taką metodę rozszerzoną? Pewnie wielu głównie starszych i bardziej doświadczonych programistów gotowa jest uznać, że korzystanie z takiego rozszerzenia to wręcz zbrodnia na programowaniu obiektowym. Moje zdanie zostawię dla siebie, ale myślę, że co do przydatności tego rozwiązania przekonać może jedynie fakt, że … metody rozszerzeń dla interfejsów znalazły zastosowanie w Linq. Pozwoliło to na nietworzenie z klas implementujących interfejs IEnumerable ośmiotysięczników kodu, nie ingerowanie zupełnie w istniejący już kod, a także z marketingowego punktu widzenia stworzenie odrębnego bytu jakim jest Linq.

    PS. Mimo, że korzystałem z dobrodziejstwa metod rozszerzeń od dawna, przyznaje, że nigdy nie zastanowiło mnie czemu IEnumerable i Linq są w innych namespace-ach.
    Jeśli spodobał Ci się ten artykuł to zapraszam do polubienia fanpage-a, na którym zawsze znajdziesz informacje o nowościach na blogu ;)
    https://www.facebook.com/Pasja-programowania-1649374605334405

    Opublikowano Bez kategorii | 8 komentarzy

    Kurs MVVM #5 Aplikacja wielojęzyczna

    W tej części kursu dowiesz się jak stworzyć aplikację wielojęzyczną wykorzystując bindowanie.

    Jako przykład stworzymy sobie formularz mini-formularz. Zaczynamy od stworzenia plik zasobów (ang. Resources File) w dwóch wersjach, domyślna – Polska i Angielska. Aby to zrobić do projektu dodajemy nowy element typu resx jak na obrazie poniżej.

    Add new item resource

    Plik ten wykorzystamy jako słownik domyślnego języka. Otwieramy nowo utworzony plik i dodajemy do niego kilka wpisów. W polu name wpisujemy klucz, który będzie używany w aplikacji, a value to oczywiście wartość, którą otrzymamy. Zmieniamy także pole Access Modifier z domyślnego internal na public.

    resx default pl

    Dodajemy jeszcze jeden plik resx do naszego projektu. Tutaj należy pamiętać, żeby nazwa pliku była taka sama jak nazwa pierwszego pliku zasobów z tą różnicą, że po nazwie dopisujemy kropkę i kod języka. Moja nazwa wygląda tak.

    resx en-us

    I wypełniamy go odpowiednimi wartościami.

    resx en-us values

    Skoro mamy już dane, przejdźmy do stworzenia widoku. Mój mini-formularz wygląda tak.

    view

    Jak widać wystarczy skorzystać ze statecznego bindowania do pola w słowniku. Niech nie zmyli Cię brak słowa binding, jest to po prostu skrócony zapis. Zapis pełny wyglądać może np. tak {Binding Source={x:Static StaticField}}. Zaś jeśli wejdziemy w plik designera zobaczymy, że wygenerowane zostały statyczne akcesory.

    Teraz, żeby sprawdzić czy nasz przykład na pewno działa wystarczy zmienić Thread.CurrentThread.CurrentCulture oraz Thread.CurrentThread.CurrentUICulture

    Ja zrobiłem to dodając wpis do app.config i zmieniając „Culture” w pliku App.xaml.cs

    app config

    app setting

      Podsumowanie:

    • Bindowanie pól (w rozumieniu field, property etc.) statycznych możemy wykorzystywać nie tylko gdy korzystamy z pól „słownika”, ale oczywiście wszystkich pól statycznych.
    • Pliki typu resx, nazywają się plikami zasobów, a nie słownikami nie tylko dlatego, że słowo dictionary jest już zajęte w języku C#, a dlatego, że pozwalają one na przechowywanie różnych zasobów. Są to m.in. obrazy, ikony, pliki audio, a także inne pliki dowolnego typu.
    • Jeśli jesteś zbyt leniwy :D lub popełniłeś błąd podczas tworzeniu własnej implementacji aplikacji wielojęzycznej, możesz skorzystać z mojego przykładu tutaj.
    Opublikowano Bez kategorii | 1 komentarz

    Kurs MVVM #4 DataTemplateSelector

    Wstęp
    W poprzedniej części kursu dowiedzieliśmy się jak zbindować kolekcję danych. Dzisiaj rozszerzymy sobie to o możliwość bindowania kolekcji, która zawiera różne dane albo zawiera elementy, które chcielibyśmy przedstawić w różny sposób. Do tego posłuży nam DataTemplateSelector. Jeśli mój opis jest zbyt zagmatwany polecam zapoznać się z tym.
    https://msdn.microsoft.com/pl-pl/library/system.windows.controls.datatemplateselector(v=vs.110).aspx

    Zadanie
    Utwórz galerię zdjęć w formie listy (ListView), która zawierać będzie obiekty typu GalleryItem i PhotoItem, ale znajdującej się w jednej kolekcji. Dla ułatwienia obie klasy dziedziczą po jednym (ale pustym :P) interfejsie IGalleryItem. Oznacz w wybrany przez Ciebie sposób, że obraz w galerii jest obrazem albo zdjęciem.

    Interfejs IGalleryItem

    public interface IGalleryItem
        {
        }
    

    Klasa GalleryItem

    public class GalleryItem : IGalleryItem
        {
            public BitmapImage Image { get; set; }
            public string Text { get; set; }
            public bool IsActive { get; set; }
        }
    

    Klasa PhotoItem

    public class PhotoItem: IGalleryItem
        {
            public BitmapImage Photo { get; set; }
            public string Description { get; set; }
        }
    

    Zaczniemy tradycyjnie od widoku. Sama kontrolka ListView nie będzie się różnić znacznie od tej z 3 części kursu. Jedyna zmiana to wykorzystanie właściwości ItemTemplateSelector, która umożliwi nam korzystanie z więcej niż jednego szablonu.
    ListView

    Teraz przejdziemy do szablonu, po stronie widoku wygląda on tak …
    ItemTemplateSelector

    Klucz zapewnia nam dostęp do selektora, spójrz jeszcze raz w ListView, a na pewno sam zrozumiesz w jaki sposób przypisaliśmy selektor. Reszta atrybutów to atrybuty typu datatemplate, które musimy utworzyć samemu. Im przypisujemy rzeczywiste szablony tak jak robiliśmy to w kursie poprzednim. Zapewniam jednak, że to banalnie proste. Zanim przejdziemy do utworzenia selektora, przypomnę jeszcze jak korzystać datatemplate.

    DataTemplate dla PhotoItem

    PhotoListItem

    Teraz przejdziemy wreszcie do naszego selektora.

     public class ListViewSelector : DataTemplateSelector
        {
            #region DataTemplates
    
            public DataTemplate ImageTemplate { get; set; }
            public DataTemplate PhotoTemplate { get; set; }
    
            #endregion
    
            public override DataTemplate SelectTemplate(object item, DependencyObject container)
            {
                if (item is PhotoItem)
                    return PhotoTemplate;
                if (item is GalleryItem)
                    return ImageTemplate;
                return null;
            }
        }
    

    Nasz selektor dziedziczy po klasie DataTemlateSelector, znajdującej się w przestrzeni nazw System.Windows.Controls, czyli nie potrzebujemy w tym celu instalować żadnych dodatkowych narzędzi i bibliotek. Wystarczy, że utworzymy sobie dwa pola DataTemplate, którym jak już wcześniej widzieliśmy w widoku przypiszemy odpowiednie szablony. No i najważniejsza rzecz – nadpisanie metody SelectTemplate. W naszym przypadku rozpoznajemy tylko jakiego typu jest obiekt, równie dobrze można porównywać dane jednego typu np. pracowników, którzy w zależności od szczebla mają być inaczej wyświetlani.

    Moje rozwiązanie

    https://github.com/janczewskit/MVVM-Course-4-DataTemplateSelector

    Dodatek>

  • Jeśli selektor zwróci wartość null element zostanie wyświetlony, ale tylko w postaci nazwy klasy jakiej jest dany obiekt
  • Selektor pozwala na wybieranie z tylu typów szablonów ile tylko utworzymy i oczywiście obsłużymy.
  • Do czego mogą przydać się selektory? Zastosowań jest naprawdę wiele, od prostej listy czy drzewa pracowników, którzy różnią się w zależności od stanowiska aż po mapy na których możemy oznaczyć np. terytoria, pracowników czy siedziby.


    Tym krótki i mam nadzieję przyjemnym wpisem żegnam się z wami w tym roku i do zobaczenia w kolejnym ;)

  • Opublikowano Kurs MVVM | Otagowano , , , | Skomentuj

    Kurs MVVM #3 – Galeria obrazów (ObservableCollection, AncestorType i datatemplate)

    Wprowadzenie
    W tej części kursu dowiesz się jak stworzyć prostą galerię obrazów. Co to jest kolekcja ObservableCollection. Jak połączyć kolekcję elementów z kontrolką ListView. Do czego służy AncestorType i jak stworzyć szablon dla elementów na liście. Zaczynamy !

    Zadanie
    Utwórz aplikację WPF, a w niej jeden główny widok oraz połączony z nim viewmodel. W widoku umieść kontrolkę ListView i ustaw jej orientację na horyzontalną. Utwórz kolekcję obrazów i zbinduj z kontrolką ListView. Pod kontrolką umieść blok tekstu, który po kliknięciu w wybrany obraz wyświetli nam informacje o nim.

    Rozwiązanie
    Zaczynamy jak zwykle od widoku naszej aplikacji.
    Widok z podkreśleniami

    Na początku omówię to co znajduje się w kontrolce ListView. ItemsSource odpowiada za zbindowanie kolekcji elementów z kolekcją w viewmodelu. Tutaj należy zwrócić uwagę także na tryb bindowania (Mode = TwoWay) pozwala on na aktualizowanie interfejsu użytkownika (UI) wtedy, gdy zmieni się wartość obiektu z nim połączona i na zmianę danych jeśli zmienimy coś po stronie interfejsu użytkownika (Dzisiaj nie będziemy wykorzystywać tego w praktyce. Nauczymy się jak to robić w dalszych częściach kursu.). ItemTemplate zawiera szablon, który będzie obowiązywał dla każdego pojedynczego elementu naszej listy (to omówimy szerzej za chwilę). ItemsPanel zawiera szablon, który będzie obowiązywał dla kontrolki ListView. Bardziej jako ciekawostkę zastosowałem w swoim kodzie właściwość StringFormat przy bindowaniu TextBlocku. Pozwala ona tak samo jak jej odpowiednik w języku C# (String.Format()) na formatowanie tekstu. Szczególnie przydatna może okazać się przy formatowaniu daty i czasu.

    Teraz zajmiemy się szablonami dla naszego ListView.
    DataTemplate

    Na wstępie chciałem zaznaczyć, że Ja swój szablon utworzyłem w zasobach okna (Window.Resources), ale równie dobrze można zrobić to np. w zasobach grida (Grid.Resources) czy w innych miejscach poza naszym widokiem. Jednak wtedy musimy „poinformować” nasz widok o pliku, w którym znajduje się szablon . Jak już pewnie zauważyłeś szablony nie są bardzo skomplikowane. Wystarczy nadać mu klucz i możemy zacząć implementacje naszego szablonu. Elementy zbindowane w naszym szablonie ListItem są bindowane z poszczególnymi elementami na liście, czyli szablon traktujemy tak jakbyśmy bindowali go z jednym elemenetem, a nie listą. Szablon ListPanel zastosowany został do kotrolki ListView zmieniając w ten sposób jej orientację na horyzontalną (poziomą).

    Więcej uwagi poświęcimy znacznikowi InteractionTrigger (znajduje się on w szablonie ListItem zaraz po znaczniku grid). Triggery (pol. wyzwalacz) odpowiadają za wywoływanie zdarzeń. Aby skorzystać z Triggerów należy dodać do projektu referencję do biblioteki System.Windows.Interactivity (są także inne biblioteki do obsługi triggerów, Ja skorzystałem akurat z tej), a w widoku dodać następujący wiersz. xmlns:interactivity=”http://schemas.microsoft.com/expression/2010/interactivity”

    Wcześniej w buttonach, żeby obsłużyć zdarzenie przyciśnięcia wystarczyło nam użycie command (o czym pisałem więcej w pierwszej części kursu). Jednak nie zawsze jest tak łatwo. W tym konkretnym przypadku element Grid nie posiada właściwości Command, ale posiada za to zdarzenie MouseOnLeftButtonUp (liczba zdarzeń jest obszerna, inne zdarzenia można bindować analogicznie do tego). Nazwę zdarzenia przypisujemy do właściwości EventName, ale to jeszcze nie koniec. Musimy to zdarzenie jeszcze z czymś połączyć. W następnej linii widzimy, że możemy skorzystać z komendy – uff ! :) Jednak czy przypisywanie do każdego elementu komendy ma w tym przypadku sens? Trzeba, by utworzyć w naszym modelu dla każdego elementu komendę i pewnie powiadomić o niej jeszcze viewmodel np. jakimś delegatem czy akcją. Lepiej więc będzie jak utworzymy jedną komendę w naszym viewmodelu i przekażemy jej nasz element. Aby to zrobić skorzystamy z AncestorType. W ten sposób możemy połączyć się z viewmodelem, którego używa np. nasze okno (Window, mogą być inne typy jak np. grid). Właściwość CommandParameter przekaże nam w komendzie ten element, który klikniemy (Binding bez bez parametrów przekazuje cały zbindowany element).

    Przechodzimy do viewmodelu. Na początek utworzymy naszą kolekcję obrazów oraz model.
    Images
    GalleryItem
    W tym celu korzystamy z kolekcji ObservableCollection. Zaletą tej kolekcji sposób jej działania, który różni się od innych znanych nam „klasycznych” kolekcji. Spróbujmy rozszyfrować samą jej nazwę. Co oznacza observable ? Jeśli myślisz, że może mieć to coś wspólnego z wzorcem obserwator lub z programowaniem reaktywnym ( to masz rację. Zasada działania tego typu kolekcji jest stosunkowo prosta. O każdej zmianie w kolekcji informowani są wszyscy jej obserwatorzy. W naszym przypadku jest to widok. Jeśli np. usuniemy element naszej kolekcji to automatycznie zniknie on także z naszej galerii zdjęć.

    Aby nasza galeria nie była pusta w konstruktorze klasy utworzymy kilka przykładowych elementów (Dzisiaj zrobimy to jeszcze w ten sposób, dopiero w przyszłości zajmiemy się pobieraniem obrazów z bazy danych). Tworzenie kolekcji ObservableCollection i dodawanie elementów do niej robi się w analogiczny sposób co np. w kolekcji List.

    Jakie Ty dodasz obrazy do swojej kolekcji pozostawię już Twoim upodobaniom. Do pełni działania naszej aplikacji potrzebna nam jest jeszcze komenda do obsługi wybranego elementu. Komendy omawialiśmy już w poprzednim kursie, jednak dotychczas nie przekazywaliśmy wraz z nimi żadnych argumentów. Moja komenda wygląda tak.
    Komenda z argumentem

    Myślę, że ten kod nie wymaga specjalnego omawiania. Wspomnę tylko, że w nawiasach ostrokątnych podajemy typ danych, z którego skorzystamy w podpiętej do naszej komendy metodzie. Zaś zmienna SelectedItemName w moim przypadku została zbindowana z polem tekstowym, którego zadaniem jest wyświetlanie informacji na temat wybranego obrazu z galerii.

    Mam nadzieję, że udało Ci się stworzyć w pełni zgodny z założeniami projekt. Mimo tego, że wiele rzeczy w dzisiejszym kursie było nowych. Jeśli jednak napotkałeś pewne problemu. Tutaj link do mojego projektu.

    Polecam inne wpisy z tego kursu na naszym blogu! Oraz zapraszam do obserwowania fanpage’u Pasja-programowania

    Opublikowano Kurs MVVM | Otagowano , , , | 5 komentarzy

    Kurs MVVM #2 – Konwertery i style w widoku

    Wprowadzenie
    Jak dowiedzieliśmy się w pierwszym wpisie kursu istotą wzorca MVVM jest bindowanie. Czasem jednak chcielibyśmy wykorzystać już dostępne dane do zmian w naszym widoku czy ustawić widoczność pewnych elementów, ale zmienne w elemencie widoku mają inny typ niż te które posiadamy. Najpopularniejszy przykład to zmienne typu Visibility po stronie widoku i zmiennej typu bool, które chcielibyśmy do nich przypisać. Pisanie akcesorów do widoku typu Visibility i rzucanie ich wartości za każdym razem, gdy chcemy z nich skorzystać zaciemni kod i spowoduje najczęściej złamanie zasady DRY (ang. Don’t Repeat Yourself, pol. Nie powtarzaj się). Tutaj z pomocą przychodzą nam konwertery.

    Zadanie
    Utwórz aplikację WPF z jednym widokiem oraz dołączonym do niego viewmodelem. W aplikacji umieść następujące pola tekstowe (textboxy): login oraz hasło. Poniżej dodaj przycisk, który widoczny jest tylko wtedy, gdy oba pola nie są puste.

    Rozwiązanie
    Zaczynamy tradycyjnie od utworzenia widoku i viewmodelu oraz połączenia ich ze sobą (jeśli nie wiesz jak to zrobić zacznij od wpisu Kurs MVVM #1 – Wprowadzenie.
    Mój kod widoku wygląda tak …

    Widok z oznaczonym konwerterem i stylami

    Żółtym kolorem oznaczyłem 2 elementy. Najpierw zajmiemy się właściwością Visibility, bindujemy ją z IsVerifyTrue. Niby nic nadzwyczajnego, ale zaraz po tym występuje słowo Converter. Jak już pewnie się domyślasz (powinieneś jeśli przeczytałeś wstęp ;) ) nasza zmienna IsVerifyTrue jest innego typu niż Visibility i nastąpi konwersja typów. Zanim przejdziemy do typu tej zmiennej i tego jak wygląda nasz konwerter zatrzymamy się chwilkę nad pierwszym zaznaczeniem (mowa tu „Style ={StaticResource TextBoxStyle}”).

    W języku XAML możemy tworzyć i korzystać ze styli. Jest to szczególnie przydatne, gdy chcemy zapewnić naszej aplikacji jakiś motyw lub gdy w widoku powtarzają się pewne elementy o podobnych właściwościach przynajmniej kilka razy. Style możemy deklarować w plikach widoków lub też w odrębnych plikach słownikowych (Można utworzyć sobie taki plik przez „New Item”->”Resource Dictionary(WPF)”. Zachęcam do spróbowania również tego sposobu. Tutaj link jak się za to zabrać.

    Ja dzisiaj omówię jak to robić bezpośrednio w widoku. Wiemy już jak przypisać taki styl (Style=”{StaticResource NazwaStyle}”), ale nie wiemy jeszcze w jaki sposób można go utworzyć.A robi się to tak …
    XAML konwerter i style

    Na wstępie zaznaczę, że Windows.Resources jest bezpośrednim potomkiem znacznika Windows. Omawianie zaczniemy od niebieskiej klamry. Myślę, że nazwa znacznika Style oraz znaczniki Setter są łatwe do rozszyfrowania. TargetType odpowiada za typ do jakiego odnosi się nasz styl zaś x:Key to klucz dzięki, któremu możemy użyć naszego stylu w wybranym elemencie widoku.

    Czym jest zatem żółte podkreślenie ? Dzięki tej właśnie linii możemy użyć konwertera w widoku.
    Nazwa od której zaczyna się znacznik („converters”) zawiera ścieżkę do folderu, w którym znajduje się konwerter.
    W moim przypadku jest to …
    Ścieżka do konwertera

    Mój konwerter nazwałem MainWindowViewModelToVisibleConverter. Za co odpowiedzialny jest atrybut x:key powinieneś już wiedzieć.

    Konwerter po stronie widoku mamy już omówiony. Został nam jeszcze viewmodel. Zaczynamy od deklaracji akcesora odpowiadającej temu co mamy w widoku. Ja zrobiłem to w ten sposób …
    Prop przekazywany w konwerterze

    Czemu akurat jako typ podałem viewmodel? Z dwóch powodów. Pierwszy – dlatego, że w zadaniu poproszono nas o sprawdzenie czy pola login oraz hasło nie są puste, a będzie to można sprawdzić mając dostęp zbindowanych pól z naszym viewmodelem. Drugi jest taki, że nasza zmienna zostanie przekazana do konwertera (czyli w praktyce bindować możemy niemal dowolne zmienne).

    Brakuje nam jeszcze jednej rzeczy! Oczywiście mowa tu o konwerterze. Konwerter to nic innego jak klasa, która posiada dwie metody, odpowiadające za konwersję jednego typu do drugiego (nie mylić z rzutowaniem, chociaż też taki przypadek konwersji może się oczywiście zdarzyć). Metody te zapewnia nam interfejs IValueConverter. Wystarczy je odpowiednio ukonkretnić. Ja ponadto zawsze tworzę folder na konwertery o nazwie Converters. Zobaczmy jak to wygląda w praktyce.
    Konwerter

    Zmienna value jest oczywiście zmienną typu, który zadeklarowaliśmy w viewmodelu (najczęściej w przypadku visibility będzie to jednak zmienna bool). W metodzie konwersji dążymy oczywiście do zwrócenia wyniku w typie zgodnym z XAML.

    Robimy test naszej aplikacji i okazuje się, że …. ? Przycisk się nie wyświetla mimo wypełnionych pól!
    Zapomnieliśmy o czymś! Akcja przypisana do widoczności przycisku w ogóle się nie uruchamia. Ale zaraz przecież my jej wcale nie używamy! Trzeba ją jakoś wywołać! Najprościej chyba będzie tak …
    Prop loginu z wywołaniem prop IsVerifyTrue

    Eureka! Jeśli przy zmianie w polu loginu lub hasła nastąpi zmiana to wywołamy sprawdzenie naszego założenia o widoczności przycisku. W konwerterze zostaną sprawdzone odpowiednie właściwości viewmodelu i otrzymamy żądany rezultat. Koniec ;)

    Jeśli masz jakieś problemy z powyższym zadaniem. Możesz skorzystać z mojego rozwiązania.
    Link do projektu.

    Ciekawostki

  • Jeśli w danym widoku zdefiniujemy sobie styl np. dla kontrolki Textbox i nie nadamy mu klucza (wartości x:Key) to zostanie on przypisany do wszystkich Textboxów w widoku, które nie mają przypisanego stylu.

  • Aplikacja WPF zapewnia nam pewną liczbę gotowych konwerterów. Jednym z nich jest „BooleanToVisibilityConverter” zmieniający wartość typu boolowskiego w viewmodelu na wartość Visibility w widoku. Aby skorzystać z gotowego konwertera wystarczy dodać go bez żadnego przedrostka w „resourcach” widoku.
  • Opublikowano Kurs MVVM | Skomentuj

    Kurs MVVM #1 – Wprowadzenie

    MVVMPattern
    Schemat wzorca MVVM

    Przedmowa
    Co to właściwie takiego jest MVVM ? Na czym polega bindowanie i jakie są jego rodzaje ? Jak walidować przy pomocy MVVM ? Co to logika biznesowa ? Na wszystkie te pytania oraz wiele innych, które pojawią się w trakcie trwania tego kursu postaram się odpowiedzieć i pokazać jak się za nie zabrać w formie prostych przykładów.

    Jak mówił klasyk „czasem człowiek musi, bo inaczej się udusi” – czyli będzie trochę prywaty. Kurs ten powstał z jednego bardzo ważnego powodu ! Brak (dobrej) literatury
    i jakichkolwiek kursów w tym temacie. Po prostu tragedia ! Omówione jedynie podstawy albo zupełnie tematy z innej beczki pod przykrywką nazwy z MVVM w tytule :) Jednak, żeby nie wyszło, że to tylko ból tyłka postanowiłem wziąć się do działania. Dzisiaj tylko krótkie wprowadzenie, zapraszam! ;)

    Wprowadzenie
    MVVM to wzorzec architektoniczny stosowany m.in. w technologiach Silverlight czy WPF. W języku polskim czytamy jako model-widok-widok model (ang. Model-View-ViewModel). Podobnie jak ostatnio bardzo popularny wzorzec MVC składa się on z 3 warstw.
    M – Model
    V – View (inaczej widok)
    VM – ViewModel

    Widok jest to graficzna część aplikacji. ViewModel zastępuje nam code-behind znany z takich technologii jak WinForms czy Asp.net Web Forms. Inaczej można powiedzieć, że viewmodel odpowiada za obsługę wszystkich akcji, które połączone są z widokiem. Model odpowiada zaś za logikę aplikacji. W kolejnych wpisach dowiemy się również, że m.in. tego, że pomiędzy modelem, a viewmodelem istnieje jeszcze warstwa logiki biznesowej, jednak teraz nie zaprzątajmy sobie tym głowy.

    Zadanie
    Utwórz aplikację w technologii WPF. W niej znaleźć ma się jeden widok oraz połączony z nim viewmodel. Widok ma zawierać 2 bloki tekstowe ( jeden na imię, drugi na nazwisko użytkownika) oraz przycisk. Oba pola tekstowe mają mieć wpisany tekst domyślny widoczny tak, by nigdy te pola nie były puste (przy uruchomieniu programu oraz jeśli użytkownik usunie cały tekst z pola). Kliknięcie w przycisk ma spowodować sprawdzenie czy pola zostały wypełnione przez użytkownika.

    Rozwiązanie
    Tworzymy projekt w Visual Studio typu WPF Application. W pliku MainWindow.xaml projektujemy widok naszego zadania zgodnie z wytycznymi. Np.

    widok bez połączenia z viewmodelem
    Następnie tworzymy klasę viewmodelu. Ja utworzyłem folder o nazwie viewmodels i w niej utworzyłem klasę o nazwie MainWindowViewModel. Aby ułatwić sobie pracę zgodnie z wzorcem MVVM do projektu doinstalowałem framework PRISM (istnieje wiele różnych frameworków wspomagających MVVM, można wybrać oczywiści inny). Tutaj link do paczki nuget.
    Aby nasza klasa nie była tylko klasą, a viewmodelem musimy ona dziedziczyć po klasie lub interfejsie pozwalających na komunikację z widokiem. Ja w moim rozwiązaniu korzystam z BindingBase.

    klasa viewmodelu
    Teraz musimy jakoś połączyć nasz widok z viewmodelem. Możemy to robić zarówno w code-behind widoku jaki w samym XAMLu. Ja w tym celu użyłem XAMLa, a code-behind zostawię sobie bez zmian. Najpierw trzeba zadeklarować w tym celu ścieżkę do viewmodelu, a później ustawić go jako DataContext. U mnie wygląda to tak …
    Łączenie z viewmodelem w widoku

    Żółtym kolorem została oznaczona ścieżka.
    Kod objęty klamrą łączy nasz widok z viewmodelem.

    Teraz skupimy się na najważniejszej rzeczy, którą dzisiaj chcę przedstawić.
    Jeśli dokładnie przeanalizowałeś/aś nasz kod zawierający widok mogłeś zauważyć, że w kilku miejscach znajduje się słowo binding. Słowo to jest odpowiedzialne za magię łączenia (bindowania) wartości w widoku ze zmiennymi w viewmodelu. Wróćmy jeszcze na chwilę do tego kodu …

    widok z oznaczonymi bindowaniami

    Widzimy, że elementy, które chcemy połączyć z viewmodelem nadajemy nazwy. Mamy kilka opcji bindowania oznaczonych jako mode, opcje te można samemu rozszyfrować po nazwach, zostaną one też omówione w jednym z kolejnych wpisów. Przy atrybucie tekst mamy także coś takiego co nazywa się UpdateSourceTrigger. O triggerach (wyzwalaczach) opowiem kiedyś indziej, dziś należy wiedzieć, że ustawienie tej zmiennej na propertychanged spowoduje, że przy zmianie tej wartości w viewmodelu zmieni ona się także w widoku (i w odwrotną stronę też).

    Przejdźmy teraz do widoku. Tutaj musimy „obsłużyć” to czym chcemy zarządzać. Zaczniemy od wartości tekstowych.

    Bindowanie po stronie viewmodelu

    Na powyższym obrazie Ja już napisałem logikę dla pola Name. Najważniejsze jest pole to było publicznym akcesorem (ja zwykle używam propfull i tego radziłbym się trzymać ;) no i oczywiście nazwa musi zgadzać się z tą użytą w widoku.

    Została nam jeszcze jedna rzecz. Bindowanie komend. Do tego celu używamy akcesora typu ICommand. Zobaczmy jak to wygląda w praktyce.

    Bindowanie komendy

    Myślę, że to by było na tyle. Oczywiście, żeby Twój program w pełni działał trzeba go dokończyć. Jeśli jednak nie radziłbyś sobie możesz skorzystać z mojego projektu Link do projektu. Powodzenia !

    Opublikowano Bez kategorii, Kurs MVVM | Otagowano , , , , | 7 komentarzy

    Książkowe zapiski #2 – Mistrz czystego kodu (co powinien wiedzieć zawodowy programista)

    mistrz czystego kodu
    „Mistrz czystego kodu” Autor: Robert C. Martin, Tłumaczenie: Wojciech Moch, Wydawnictwo: Helion

    W dzisiejszym, kolejnym już odcinku naszego cyklu „Książkowe zapiski” znowu posłużymy się tym co do przekazania ma nam Robert C. Martin zwany inaczej Wujkiem Bobem (ang. Uncle Bob). To, że autor w naszym cyklu nie jest pierwszy raz, nie znaczy wcale, że jest to jedyny autor, którego czytamy lub którego książki będą tutaj cytowane. Dlaczego więc wybrana została ta pozycja? Odpowiedź jest dość prosta. Książka opisywana przez nas ostatnio („Czysty kod” – również polecamy książkę jak i nasz artykuł) była przeznaczona głównie dla młodszych programistów. Dzisiejsza pozycja zaś jest skierowana do programistów z kilku letnim już stażem oraz programistycznych juniorów, którzy mimo braku doświadczenia z uniesioną wysoko głową „palą się” do pracy i przydałby im się mały kubełek zimnej wody, który trochę ostudzi ich temperament.

    Na wstępie. Jeśli ktoś nie zna jeszcze naszego cyklu chciałbym przypomnieć, że nie znajdzie tu opisu całości książki. W tym celu polecamy skorzystanie z innych źródeł. My zaś skupimy się na według nas na jednym z bardziej interesujących fragmentów (opracowanym w formie „zapisku”), który ma za zadanie zachęcić do sięgnięcia po książkę.

    W swoim dziele wujek Bob Martin podjął się bardzo trudnego zadania – zdefiniowania w formie krótkiej listy podstawowych umiejętności zawodowego programisty! Aby uniknąć polemiki o tym co jest mniej lub bardziej ważne, które narzędzie jest lepsze lub gorsze oraz to, żeby lista jednak była jak najkrótsza zbiór ten został okrojony do absolutnego minimum.

    My w swoich zapiskach nadaliśmy mu tytuł „Minimalna lista umiejętności zawodowego programisty”. Oto nasza lista (rozumiemy, że zapiski mogą być częściowo nie zrozumiałe, dlatego poniżej umieściliśmy jej bardziej szczegółowy opis):

    • 24 wzorce projektowe z książki GOF (ang. Gang of Four, pl. Wielka czwórka) oraz doświadczenie w pracy z wzorcami książka POSA
    • Zasady projektowania. Zasady oraz poszczególne terminy SOLID
    • Metodologie XP, Scrum, Lean, Kanban, wodospadu, analizy strukturalnej i programowania strukturalnego
    • Dziedziny: techiniki TDD, projektowanie obiektowe, programowanie strukturalne, ciągła integracja i programowanie w parach
    • Artefakty: jak tworzyć i korzystać z diagramów UML, wykresów struktur, sieci Petriego oraz tabel decyzjnych

    Omówienie (dla pewnie mniej doświadczonych czytelników dość niejasnych) zapisków zaczniemy od dwóch pierwszych pozycji. Dlatego, że dotyczą one tej samej grupy wiedzy, a mianowicie kodu. Na pierwszy ogień idzie „książka GOF”. Książka legenda można, by o niej powiedzieć! „Design Patterns: Elements of Reusable Object-Oriented Software”, tak brzmi jej oryginalny tytuł (książka została również przetłumaczona na język polski) została wydana jeszcze w erze dinozaurów, bo w 1994 roku. Autorzy bardzo wnikliwie opisali w niej 24 wzorce projektowe wraz z przykładami i ich zastosowaniem. Mimo 21 lat na karku książka ta nadal jest znakomitym źródłem wiedzy. Można nawet skusić się, że wyprzedziła ona swoją epokę. Przecież wcale nie tak dawno, bo jeszcze na początku XXI wieku istniało przekonanie, że języki nieobiektowe takie jak Pascal (wtedy jeszcze bardzo poplarne) nadal mogą wieść prym w programowaniu, do dziś zresztą w wielu szkołach uczy się tego języka. Właśnie dzięki m.in. takim pozycjom jak ta, zmieniło się to przekonanie i podejście do architektury kodu. Druga z pozycji, którą proponuje nam autor, czyli książka POSA (oryginalny tytuł: Pattern-Oriented Software Architecture: Patterns for Concurrent and Networked Objects, więcej można znaleźć pod
    http://www.cs.wustl.edu/~schmidt/POSA/POSA2/
    ) to kolejna, która opisuje wzorce projektowe. Niewiele mniej leciwa, niż ta autorstwa GOF za to dziś już znacznie mniej popularna. W kolejnym punkcie naszą uwagę powinien przyciągnąć skrót SOLID. Jest to 5 zasad zaproponowanych przez dobrze znanego nam już Wujka Boba ;) dotyczących programowania obiektowego. Są to: zasada jednej odpowiedzialności (ang. single responsibility), zasada otwarte-zamknięte (ang. open-close), zasada podstawienia Liskov (ang. Liskov substitution principle), zasada segregacji interfejsów (ang. interface segregation principle) oraz zasada odwrócenia zależności (ang. dependency inversion principle). Bez wątpienia można stwierdzić, że najbardziej znaną zasadą wśród programistów jest ta wymieniona jako ostatnia „zasada odwrócenia zależności” znana szerzej jako wstrzykiwanie zależności. Niestety omówienie zasad SOLID jest zbyt obszerne, żebyśmy mogli chociażby próbować zrobić to w tym artykule. Dla rządnych wiedzy polecamy jednak zagłębienie się w ten temat, a my ze swojej strony obiecujemy, że za pewien czas zasady SOLID zostaną omówione również na naszym blogu.

    Kolejny punkt na liście to metodologie. Jedni uważają je za niepotrzebne, drudzy je kochają bawiąc się nimi i dostosowując do własnych potrzeb i warunków. Dla mniej zorientowanych zacznijmy od zdefiniowania co to jest metodologia. Więc, jeżeli wykonujemy jakiś projekt samemu np. jako projekt studencki na zaliczenie (tzw. pet projekt) to wtedy nie wyznaczamy sobie np. czasu pracy na kolejne zadania. Wcale nie dzielimy sobie projektu na zadania! Nie mierzymy też jak długo zajęło nam dodanie pewnej funkcji (funkcja nie jako część kodu, ale jako pewna część programu np. moduł logowania), a zależy nam wtedy tylko i wyłącznie na tym, aby nasz kod spełniał założenia i został oddany w wyznaczonym przez nauczyciela czasie. W rzeczywistości jest trochę inaczej. Projekty często trwają wiele miesięcy, a nawet lat. W tym czasie pracują nad nimi zespoły liczące nawet kilkaset osób, a do tego są osoby, którym zależy na tym by mieć pieczę czy projekt zostanie oddany na czas oraz w jakiej fazie są poszczególne zadania. Do tego wszystkiego (i nie tylko) potrzebna jest nam właśnie metodologia. Obecnie najpopularniejszą metodologią jest Scrum. Dla osób z gorącym temperamentem ostrzegamy, że jednak nie jest to narzędzie idealne do każdego typu projektu np. metodologia XP (eXtreme Programming) ma dużo więcej zalet przy pracy nad rozwojem gotowego już projektu niż właśnie Scrum. Aby zapoznać się bliżej z tematyką metodologii w programowaniu polecamy książkę „Agile. Szybciej, łatwiej, dokładniej” autorstwa Marka Krzeminśkiego (w planach mamy artykuł o tej książce w cyklu Książkowych zapisków – czekajcie na niego!).

    Dwa ostatnie punkty naszej listy to swoisty miszmasz zaserwowany nam przez autora. Do szczegółowego opisu postanowiliśmy więc wybrać sobie tylko część zagadnień. Zaczynamy od TDD (ang. Test-driven development, pl. Programowanie sterowane testami). Jest to praktyka, która zakłada napisanie testu jednostkowego dla konkretnego przypadku testowego jeszcze przed napisaniem konkretnej metody, którą ma weryfikować. Następnie napisanie owej metody. Najpierw spełniającej szczególny przypadek testowy, później ogólne założenie. Na końcu zaś doprowadzić do tego, żeby test „przechodził” i zrefaktoryzować kod. Aby dokładniej zrozumieć TDD polecamy sięgnąć do książek, ponieważ jest to dużo bardziej skomplikowana technika niż wydaje się na pierwszy rzut oka.

    Pozwolimy sobie na pominięcie tematu ciągłej integracji. Nie ze względu małego znaczenia, bo polecamy stosowanie tej techniki, ale ze względu obszerności tego zagadnienia. Ominiemy również też ważny, chociaż według nas za bardzo specjalistyczny temat sieci Petriego, a na koniec skupimy się na diagramach UML.

    Diagramy UML to zbiór wielu różnych diagramów opisujący działanie systemu w różnych aspektach. Np. diagram klas opisuje nam kod systemu poprzez zbiór klas, ich właściwości, interfejsów i zależności między nimi. Do najpopularniejszych diagramów notacji UML należą również: diagram maszyny stanowej, bardzo popularny diagram sekwencji, diagram aktywności (inaczej zwany diagramem czynności) czy diagram przypadków użycia. Cały zbiór diagramów służy do jak najlepszego opisania aplikacji, po to, aby wyeliminować błędy jeszcze w fazie projektowania oraz zoptymalizować proces implementacji systemu.

    Na dziś to już wszystko. Koniec tej nadzwyczaj długiej lektury. Obiecujemy, że kolejne artykuły będą już krótsze i zapraszamy ponownie.

    Opublikowano Książkowe zapiski | Skomentuj

    Książkowe zapiski #1 – „Czysty kod” (znaczące nazwy)

    czykov
    „Czysty kod” Autor: Robert C. Martin, Tłumaczenie: Paweł Gonera, Wydawnictwo: Helion

    Książkowe zapiski #1 – „Czysty kod” (znaczące nazwy) – jest to pierwszy z serii artykułów „Książkowe zapiski”. W każdym z artykułów (tej serii) postaramy się omówić wybrane (przez nas ocenione jako te najbardziej wartościowe) fragmenty książek. Nie będą to ani subiektywne oceny książek, ani próba streszczeń całej książki, skupimy się naprawdę tylko na małych fragmentach, które miejmy nadzieję zasieją w was ciekawość do sięgnięcia po te właśnie książki. Tyle tytułem wstępu, o tym jak to będzie wyglądać w praktyce przekonacie się sami – zaczynamy.

    Na pierwszy ogień idzie klasyka gatunku „Czysty Kod” autorstwa Boba Martina (zwanego Wujkiem Bobem). Książka z którą powinien się prędzej czy później zetknąć każdy programista (raczej prędzej, jeszcze na studiach czy jako junior). My dzisiaj skupimy na tym co autor mówi o tym jak ważne w kodzie jest nazewnictwo.

    • Nazwa ma mieć znaczenie, nie komentarz – wujek Bob jest wrogiem komentarzy do tego stopnia, że cały rozdział swojej książki poświęcił właśnie im, kładąc nacisk głównie na to, jak źle są one używane (chociaż są sytuacje i miejsca gdzie sam zauważa potrzebę użycia komentarza) .
      //Zły przykład
      int d; // Czas trwania w dniach

      //Dobry przykład
      int elapsedTimeInDays; // czasTrwaniawDniach
      int daysSinceCreation; // dniOdUtworzenia
      int daysSinceModification; // dniOdModyfikacji

    • Kod powinien być przejrzysty
      // Zły przykład
      public List getThem
      {
      List list1 = new ArrayList();
      for(int[] x: theList)
      if (x[0] == 4)
      list1.add(x);
      return list1;
      }

      //Dobry przykład (zmienne zamiast wartości, odpowiednie nazwy zmiennych, klasy – operujemy na obiekcie i jego funkcjach)
      public List getFlaggedCells()
      {
      List flaggedCells = new ArrayList();
      for(Cell cell: gameBoard)
      if (cell.isFlagged())
      flaggedCells.add(cell);
      return flaggedCells;
      }

    • Unikanie dezinformacji : nie używanie pojedynczych liter np. O czy L, nazwy powinny się od siebie znacząco różnić (przykład błędnych nazw to np. SampleFunction i ExampleFunction), nazwy nie powinny zawiera słów kluczowych jeśli nie reprezentują tych elementów (np. Klasa Accounts zamiast AccountsList) oraz unikanie typów danych w nazwach, ponieważ typ może się przecież zmienić (błędny przykład userList, może być listą, jednak w przyszłości może być przecież inną kolekcją, dlatego lepsza będzie nazwa np. users).
    • Nazwy powinny być łatwe do wymówienia
      // Zły przykład
      class DtaRcrd102
      {
      private DateTime genymdhms;
      private DateTime modymdhms;
      private sealed String pszqint = "102";
      }

      //Dobry przykład
      class DtaRcrd102
      {
      private DateTime generationTimestamp;
      private DateTime modyficationTimestap;
      private sealed String recordId = "102";
      }

    • Nazwy powinny być łatwe do wyszukiwania
      // Zły przykład
      for(int j=0; j<34; j++)
      {
      s += (t[j] * 4) / 5;
      }

      //Dobry przykład
      int realDaysPerIdealDay = 4;
      const int WORK_DAYS_PER_WEEK = 5;
      int sum = 0;
      for(int j=0; j < NUMBER_OF_TASKS; j++)
      {
      int realTasksDays = taskEstimate[j] * readlDaysPerIdealDay;
      int realTaskWeeks = (realDays / WORK_DAYS_PER_WEEK);
      sum += realTaskWeeks;
      }

    • Notacja Węgierska jest już przeszłością – nie uwzględnia zmian typów np.
      PhoneNumber phoneString; (zmiana typu String na PhoneNumber)
    • Interfejsy – nie powinno stosować przedrostka I np. zamiast IFactory => Factory – z tym zdaniem Wujka Bob akurat można się kłócić ;).
    • Unikanie odwzorowania mentalnego np. nazywanie zmiennej zawierającej URL jako r, bo chociaż dla nas będzie to łatwe to dla innych programistów już niekoniecznie.
    • Klasy powinny mieć nazwy będące rzeczownikami pisane z dużej litery. Unikać słów typu Manager, Processor, Data czy Info.
    • Metody powinny mieć nazwy będące czasownikami np. postPayment, deletePage, save (Autor pisze nazwy metod z małej litery, ponieważ język, którego używa w książce to Java gdzie przyjęło się właśnie taki zapis).
    • Zamiast przeciążania konstruktorów fabrykowanie
      // Zły przykład
      Complex fulcrumPoint = Complex.FromRealNumber(23.0);

      // Dobry przykład
      Complex fulcrumPoint2 = new Complex(23.0);

    • Na koniec jeszcze kilka zapisków luźnych zapisków, mniej lub bardziej dotyczących nazewnictwa
      1. Nie używać dowcipnych nazw :)
      2. Jedno słowo na jedno pojęcie np. przedrostek get w metodach jako pobieranie danych
      3. Wysoka spójność, zauważać różnicę np. między add i append
      4. Kod może zawierać nazwy specjalistyczne dla programistów oraz nazwy eksperckie z dziedziny problemu, który rozwiązujemy
      5. Nie nadużywać kontekstu, klasy nie zawierają przedrostków aplikacji i w dół (klasy, metody). W praktyce oznacza to, że jeśli w klasie Users chcemy dodać metodę dodającą nowego użytkownika powinniśmy nazwać ją np. Add, nie zaś AddUser, tak by nazwa metody była niezależna od klasy w której się znajduje

    Mamy nadzieję, że dotrwałeś do końca. Jeśli nie masz jeszcze ochoty sięgnąć po „Czysty Kod” to przynajmniej spodobała Ci się nasza seria. Do „Czystego Kodu” jeszcze wrócimy w kolejnych wpisach.
    Przy okazji mała autopromocja – Zapraszamy do polubienia naszego fanpage’u
    Pasja-programowania

    Opublikowano Książkowe zapiski | Otagowano , | 2 komentarzy