środa, 3 sierpnia 2016

Java 8 - domyślne metody w interfejsie

Od javy 8 została wprowadzona interesująca zmiana. Dotychczas interfejs definiował tylko sygnatury metod (czyli zwracany typ, nazwę metody i typy argumentów bez implementacji tej metody). Przykładowo:

public interface Foo {
   void doSomething();
}

Deklarując, że klasa implementuje interfejs, wymuszało się implementację tych metod w owej klasie.

Od javy 8, wprowadzono możliwość zdefiniowania domyślnej implementacji metody:

public interface Foo {
     default void doSomething() {
        //Method body
    }
}

Interfejs nie musi już zawierać tylko deklaracji metod, może zawierać domyślną implementację!

Co to daje w praktyce?
Plusy:
Możesz napisać domyślną metodę, co może oszczędzić powielenia kodu w klasach implementujących interfejs. Klasa implementująca interfejs nie musi implementować metod, które mają domyślną implementację, ale w przypadkach gdy to potrzebne, można je nadpisać w danej klasie.




poniedziałek, 16 maja 2016

Formatki, Cache i Guava

Zastosowanie

  • Założenia:
Aplikacja wyświetla wartości słownikowe. Zakładamy, że z aplikacji w tym samym czasie korzystać będzie wielu użytkowników.

  • Przypadki: 
 - użytkownik wchodzi, wychodzi i znowu wchodzi na daną formatkę,
 - z danej listy wartości korzysta jednocześnie wielu użytkowników.

  • Zysk:
 - za każdym razem nie musimy łączyć się z bazą,
 - nie musimy trzymać wartości, gdy są już niepotrzebne (beany sesyjne itp.).

Jak:
Tworzymy singleton, w którym przechowujemy wartości. Określamy czas, przez jaki wartości mają być trzymane w pamięci.
Propozycja rozwiązania: Użyjemy biblioteki guava.

Teoria:
https://github.com/google/guava/wiki/CachesExplained

Praktyka:
  • definiujemy zmienną, w której będziemy przechowywać dane:
  • LoadingCache<Key, Graph> cache;

     Przykład:
     klucz - id oddziału, wartość - lista pracowników
     LoadingCache<Long, List<Employee>> cache;

  • definiujemy cacheLoader'a:
          private CacheLoader makeCacheLoader(){
                   return new CacheLoader<Long, List<Employee>>(){
                          @Override
                          public List<Employee> load(Long departmentId){
                                 return getFromDatabase(departmentId);
                          } 
                  };
          }

          i metodę, pobierającą dane z bazy:
          public List<Employee> getFromDatabase(Long departmentId){...}

  • dodajemy (np. w metodzie oznaczonej @PostConstruct):
          cache = CacheBuilder.newBuilder()
                      .maximumSize(100)
                      .expireAfterAccess(30, TimeUnit.MINUTES)
                      .build( makeCacheLoader());

  • metoda, która służyć będzie do pobierania wartości:
          public List<Employee> getEmployees(Long departmentsId) {
                     return cache.getUnchecked(departmentsId);
         }

Jako, że jest to meritum sprawy i punkt kulminacyjny naszego show, pochylmy się jeszcze raz nad przyświecającą nam ideą. 

Wywołując metodę getEmployees za pierwszym razem, użytkownik pobierze dane z bazy. Dane te będą trzymane w pamięci przez 30 minut od czasu ostatniego zapisu/odczytu tych wartości z cache'a (w przypadku opcji expireAfterWrite - ostatniego zapisu tych wartości do cache'a). W tym czasie przy ponownym wywołaniu metody getEmployees dla tego samego oddziału, nie będziemy pobierać ponownie danych z bazy.


sobota, 14 maja 2016

piątek, 13 maja 2016

Zanim zdecydujesz się przejść na date/time API Javy 8

Niewątpliwie czytałeś o zaletach, możliwościach nowej biblioteki javy do obsługi daty i czasu. Jeśli nie, to polecam zapoznanie się:
http://www.oracle.com/technetwork/articles/java/jf14-date-time-2125367.html

 No to gdzie haczyk?

Nie ma haczyka, niemniej chwilę po zdecydowaniu się na LocalDate, LocalDateTime, LocalTime, Duration itd. przychodzi szara rzeczywistość.

1. primefaces

Okazuje się, że komponent <p:calendar/> wymaga konwertera, gdyż przeznaczony jest do starego typu java.util.Date, podobnie <f:convertDateTime/>.
Oczywiście napisanie konwertera to nic problematycznego i jest wiele przykładów w internecie, niemniej chciałoby się od razu mieć wszystko podane na tacy, w końcu miało być lepiej.

2. dozer

Kolejny zawód :( Aktualna wersja (tj. 5.5.1) nie obsługuje nowych typów.

Tutaj możemy skorzystać z biblioteki, zawierającej konwertery. Źródła i instrukcja co i jak w linku: https://github.com/GeBeater/dozer-jdk8-support. Ok, wystarczy dodanie dependency w pom-ie i po sprawie.

Możemy też zamiast tego po prostu użyć opcji copy-by-reference.

3. hibernate

I tu możesz natknąć się na problemy. Jeśli korzystasz z hibernate, przejdź na wersję 5, która obsługuje nowe typy javy 8.


Jak już przebrniesz przez początkowe "trudności", to możesz korzystać z dobrodziejstw biblioteki java.time :) Mam nadzieję, że nie daliście się zniechęcić. Do boju!



piątek, 6 maja 2016

Dlaczego jedne formatki są lepsze od drugich?

Czy pisanie formatek może być sztuką? No bez przesady!

Niemniej, pisząc formatki, można robić to dobrze lub nie. Zasady czystego kodu, reguła mvc i wiele innych nie obowiązują tylko dla backendu. Pisząc formatki, nie zapominajmy o jakości kodu.

Przejdźmy zatem do konkretów. Kilka praktycznych rad:

  1. Pamiętajmy o mvc - twórzmy:

  • model (mam tu na myśli view model) czyli klasę z danymi wyświetlanymi na formatce (np. DTO, listy wyświetlane w selectach, wszystkie zmienne pomocnicze),

  • kontroler (tylko metody + wstrzyknięcia serwisów, no i naszego modelu),

  • widok.

Często zdarza się, że kontroler zawiera również model, jest to podejście niezgodne z regułą mvc, zazwyczaj zaczyna się od samego DTO ale potem kontroler szybko puchnie i puchnie i puchnie.

  2. Każdy element ma swoje miejsce, nie mieszajmy jednego typu elementów z innymi!

Nie definiujmy stylów w pliku html, wszystkie style definiujmy w pliku css.
Wszelaki kod js opakowujmy w funkcje i wrzucajmy do pliku js.

  3. Nie duplikujmy kodu!!!

Jeżeli kusi cię by zrobić kopiuj wklej, przypomnij sobie, co pisał wujek Bob i tak, jak w kodzie tworzysz klasy abstrakcyjne dla wspólnych części kodu czy metody, które używasz wielokrotnie w różnych miejscach, tak samo frontend nie lubi duplikacji kodu. Jeżeli jakiś fragment lub podobny, będzie wykorzystany w innym miejscu, to należy stworzyć komponent. 

Tak samo jak korzystamy z gotowych klocków, jakie dają nam biblioteki (np. primefaces), tak samo, sami powinniśmy tworzyć swoje klocki i budować naszą aplikację z podzespołów. 

  4. Super! Tworzymy już komponenty, ale nie zapominajmy, aby komponent przyjmował atrybuty. Przesyłając atrybut definiujmy jego typ (możemy tu np. podać interfejs lub klasę abstrakcyjną by zwiększyć stosowalność komponentu). Stworzenie komponentu i zaszycie w nim "beanów", to utrata elastyczności i reużywalności komponentu. Z tego samego względu warto tworzyć komponenty o mniejszej odpowiedzialności.



czwartek, 5 maja 2016

Css dla primefaces

Pisząc aplikację z wykorzystaniem primefaces, często dochodzimy do momentu, gdy stwierdzamy, że wygląd aplikacji nas nie satysfakcjonuje. Mamy wtedy kilka opcji. Oto moje propozycje w kolejności od gotowców, do wymagających najwięcej wkładu własnego. Możemy:

1. skorzystać z jednej z dostępnych skórek dla primefaces. Podgląd dostępnych skórek: http://www.primefaces.org/showcase/ (guzik PFThemes, z pędzelkiem). Aby do aplikacji dołączyć wybraną skórkę wystarczy tylko dodać:

  •  w pliku pom.xml:

<dependency>
      <groupId>org.primefaces.themes</groupId>
      <artifactId>south-street</artifactId>
</dependency>

  • web.xml:

<context-param>
<param-name>primefaces.THEME</param-name>
<param-value>south-street</param-value>
</context-param>


2. stworzyć własny szablon stylu korzystając z generatora: http://jqueryui.com/themeroller/
    (styl stworzony w ten sposób jest bardzo ogólny, detale nie są zdefiniowane)

3. stworzyć własny css "od zera".

Decydując się stworzyć własną skórkę, warto nadpisać klasy stylów primefaces, aby styl był globalny i spójny, a tym samym, by uniknąć nazywania podstawowych i powtarzalnych elementów, co prowadziłoby do niepotrzebnego bałaganu na stronce i konieczności pamiętania, że dany element musi mieć zdefiniowaną daną klasę.

Robiąc to, warto mieć na względzie poniższe uwagi:

  • należy dodać styl css, który "zresetuje" niepożądane cechy zdefiniowanych stylów w primefaces,
  • nadpisywać klasy zdefiniowane w primefaces, tak by nie nazywać elementów powtarzalnych.

Jeżeli chcemy by jakiś element powtarzalny miał inny styl np. guzik w panelu akcji w nagłówku miał inny kolor niż w innych miejscach aplikacji, nie definiujmy klasy "greenButton", tylko klasę "headerPanel" i określmy styl guzika w tej klasie, korzystając z globalnej nazwy guzika, a następnie w htmlu stwórzmy komponent "headerPanel", który będzie wspólny dla wszystkich nagłówków, pozwoli to zachować spójność w całej aplikacji i łatwość wprowadzania zmian.

  •  warto korzystając z punktu 2. wygenerować sobie ogólny szablon (w tym np. ikonki), pozwoli to skrócić czas pracy. Mając taki szablon, można skupić się na detalach i personalizacji.


Miłej zabawy!