SlideShare a Scribd company logo
1 of 110
Download to read offline
POLITECHNIKA POZNAŃSKA
WYDZIAŁ ELEKTRYCZNY
PRACA DYPLOMOWA
MAGISTERSKA
ANALIZA PORÓWNAWCZA ŚRODOWISK
PROGRAMISTYCZNYCH OPARTYCH NA
JĘZYKACH RUBY I JAVASCRIPT
Adam SKOŁUDA
Damian ROMANÓW
Promotor:
dr inż. Anna Grocholewska-Czuryło
Poznań, 2015
Streszczenie
Analiza porównawcza środowisk programistycznych opartych na językach Ruby i Java-
Script.
W niniejszej pracy poddano analizie technologie do tworzenia aplikacji internetowych
wykorzystujące Ruby i JavaScript. Dwa narzędzia dotyczące tworzenia części klienckich
oraz trzy odpowiedzialne za logikę serwerową. Główny nacisk położony został na porów-
nanie wybranych narzędzi. Wstęp dostarcza informacji wprowadzających do zagadnienia,
a także przedstawia cel i podział pracy. Tłumaczy również motywację podjęcia tematu
pracy oraz układ rozdziałów. Wprowadzanie teoretyczne opisuje niezbędne kwestie archi-
tektury aplikacji internetowych, których zrozumienie jest kluczowe dla realizacji tematu.
Opis technologii to obszerny i ważny rozdział przybliżający wybrane biblioteki. Powyższe
rozdziały prowadzą do wielowymiarowej analizy. Rozdział ten jest porównaniem wybra-
nych narzędzi, mającym na celu wskazanie faworytów w poszczególnych kategoriach. W
zakończeniu znajduje się podsumowanie przeprowadzonych prac, wnioski płynące z ba-
dań, a także subiektywna ocena badanych technologii. Podejmuje również polemikę na
temat przyszłego kierunku rozwoju aplikacji internetowych.
Abstract
Comparative analysis of development environments based on Ruby and JavaScript.
In this thesis, we analyzed technologies for creating web applications, using Ruby and
JavaScript. Were chosen two tools for creating frontend and three responsible for the
backend. The main emphasis has been on comparison of selected tools. Preface provides
background information to the problem, presents the purpose and division of work. This
also explains the motivation to take the topic of work and arrangement of chapters.
Theoretical introduction describes the essential issues of web application architecture,
the understanding of which is crucial for the realization of the theme. Description of the
technology is a important chapter, which describes the selected libraries. These chapters
lead to the multivariate analysis. This chapter is a comparison of selected tools, aimed to
identify the best in each category. At the end, there is a summary of the work carried out,
the conclusions of the study, as well as a subjective assessment of examined technologies.
It also takes a polemic about the future direction of web applications.
Spis treści
Spis treści 7
Spis rysunków 10
Spis listingów 12
1 Wstęp 15
1.1 Motywacje podjęcia tematu . . . . . . . . . . . . . . . . . . . . . . . . . . 16
1.2 Podział prac . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
1.3 Cel pracy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
1.4 Układ pracy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
2 Wprowadzenie teorytyczne 19
2.1 REST . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
2.2 AJAX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
2.3 SPA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
2.4 Model - View - Controller . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
2.5 Języki . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
2.5.1 Ruby . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
2.5.2 JavaScript . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
2.6 Środowiska programistyczne . . . . . . . . . . . . . . . . . . . . . . . . . . 34
2.6.1 Ekosystem Rubiego . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
2.6.2 Node . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
2.7 Bezpieczeństwo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
2.7.1 Uwierzytelnianie . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
2.7.2 Autoryzacja . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
3 Opis technologii 45
3.1 ReactJS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
3.1.1 Deklaratywny charakter widoków . . . . . . . . . . . . . . . . . . . 46
7
SPIS TREŚCI 8
3.1.2 Props . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
3.1.3 State . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
3.1.4 Flux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
3.1.5 Virtual DOM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
3.1.6 Diff Algorithm . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
3.1.7 JSX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
3.1.8 Backbone . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
3.2 AngularJS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
3.2.1 Kompilator HTML . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
3.2.2 Dwustronne wiązanie danych . . . . . . . . . . . . . . . . . . . . . 55
3.2.3 Obiekt $scope . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
3.2.4 Dziedziczenie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
3.2.5 Metody $digest(), $apply() i $watch() . . . . . . . . . . . . . . . . . 59
3.2.6 Modularność . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
3.2.7 Wstrzykiwanie zależności . . . . . . . . . . . . . . . . . . . . . . . . 63
3.2.8 Dyrektywy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
3.2.9 Komunikacja z serwerem . . . . . . . . . . . . . . . . . . . . . . . . 65
3.3 Rails . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
3.3.1 MVC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
3.3.2 DRY . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
3.3.3 Generatory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
3.3.4 Struktura projektu . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
3.3.5 Konwencja ponad konfiguracją . . . . . . . . . . . . . . . . . . . . . 75
3.3.6 TDD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
3.3.7 Aktywna społeczność . . . . . . . . . . . . . . . . . . . . . . . . . . 78
3.4 Sinatra . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80
3.4.1 Elastyczność . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
3.4.2 Wydajność . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
3.4.3 Prostota . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
3.5 Grape . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
3.5.1 Elastyczność . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
3.5.2 Wydajność . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
3.5.3 Prostota . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
4 Analiza 87
4.1 AngularJS - ReactJS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
SPIS TREŚCI 9
4.1.1 Próg wejścia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88
4.1.2 Komplementarność . . . . . . . . . . . . . . . . . . . . . . . . . . . 88
4.1.3 Poziom ekspresji kodu . . . . . . . . . . . . . . . . . . . . . . . . . 88
4.1.4 Wydajność . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
4.1.5 Debuggowanie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
4.1.6 Przepływ danych . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
4.1.7 Szablony . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
4.1.8 Społeczność i popularność . . . . . . . . . . . . . . . . . . . . . . . 96
4.1.9 Podsumowanie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
4.2 Rails - Sinatra - Grape . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98
4.2.1 Wydajność . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98
4.2.2 Społeczność i popularność . . . . . . . . . . . . . . . . . . . . . . . 100
4.2.3 Podsumowanie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100
5 Zakończenie 103
Bibliografia 107
Wykaz skrótów 108
Spis rysunków
2.1 Porównanie ilości ofert pracy dla popularnych języków serwerowych, [źró-
dło: http://www.indeed.com/jobtrends]. . . . . . . . . . . . . . . . . . . 29
2.2 Wykres pokazujący ilość ofert pracy dla języków JavaScript, C++, C#,
PHP oraz Python, [źródło: http://www.indeed.com/jobtrends]. . . . . . 30
2.3 Przykład nieblokującej operacji wejścia-wyjścia wykonywanej przez Node,
[źródło: [3]]. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
2.4 Porównanie ilości ofert pracy dla popularnych platform serwerowych, [źró-
dło: http://www.indeed.com/jobtrends]. . . . . . . . . . . . . . . . . . . 40
2.5 Dostęp do Internetu stacjonarnego w Polsce, [źródło: http://pclab.pl/
news63802.html]. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
3.1 Diagram obrazujący przepływ sterowania w architekturze Flux, [źródło:
https://github.com/facebook/flux]. . . . . . . . . . . . . . . . . . . . . 49
3.2 Porównanie ilości ofert pracy dla popularnych platform klienckich typu
MVC, [źródło: http://www.indeed.com/jobtrends]. . . . . . . . . . . . . 55
3.3 Jednostronne wiązanie danych w AngularJS, [źródło: https://docs.angularjs.
org/guide/databinding]. . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
3.4 Dwustronne wiązanie danych w AngularJS, [źródło: https://docs.angularjs.
org/guide/databinding]. . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
3.5 Wykres pokazujący dominację platformy Rails, pod względem ilości ofert
pracy, [źródło: http://www.indeed.com/jobtrends]. . . . . . . . . . . . . 68
3.6 Komunikat informujący o wynikach testów Guard. . . . . . . . . . . . . . . 77
3.7 Statystyki pobrań najpopularniejszych gemów ze strony https://rubygems.
org/. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79
3.8 Statystyki kontrybucji do repozytorium rails z serwisu GitHub, [źródło:
https://github.com/rails/rails/graphs/contributors]. . . . . . . . . 80
3.9 Liczba kontrybucji, gałęzi, wydań oraz wkładców w repozytorium rails z
serwisu GitHub, [źródło: https://github.com/rails/rails/]. . . . . . . 80
10
SPIS RYSUNKÓW 11
3.10 Liczba obserwatorów, gwiazdek oraz rozgałęzień repozytorium Rails z ser-
wisu GitHub, [źródło: https://github.com/rails/rails/]. . . . . . . . . 80
4.1 Testy renderowania obiektów z wykorzystaniem: AngularJS, ReactJS - ska-
la liniowa. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
4.2 Testy renderowania obiektów z wykorzystaniem: AngularJS, ReactJS - ska-
la logarytmiczna. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
4.3 Porównanie czasu operacji na liście 100 zadań do zrobienia w ms, [źródło:
http://evancz.github.io/todomvc-perf-comparison/]. . . . . . . . . . 94
4.4 Problem z dwustronnym wiązaniem danych w AngularJS, [źródło: http://
techblog.constantcontact.com/software-development/reactive-component-
based-uis/]. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
4.5 Rozwiązanie problemu z wiązaniem danych w ReactJS, [źródło: http://
survivejs.com/webpack_react/react_and_flux/]. . . . . . . . . . . . . 95
4.6 Statystyki dotyczące AngularJS ze strony https://github.com/angular/
angular.js/. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
4.7 Statystyki dotyczące ReactJS ze strony https://github.com/facebook/
react. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
4.8 Porównanie ilości wyszukiwań w Google. . . . . . . . . . . . . . . . . . . . 97
4.9 Porównanie wydajności Rails, Grape oraz Sinatra pod względem ilości ob-
służonych żądań na minutę. . . . . . . . . . . . . . . . . . . . . . . . . . . 99
4.10 Porównanie wydajności Rails, Grape oraz Sinatra pod względem średniego
czasu dla jednego zapytania. . . . . . . . . . . . . . . . . . . . . . . . . . . 99
4.11 Porównanie ilości pobrań ze strony https://rubygems.org/. . . . . . . . . 101
Spis listingow:
2.1 Przykład kodu jQuery . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
2.2 Przykład kodu czysty Javascript . . . . . . . . . . . . . . . . . . . . . . . . 22
2.3 Elastyczność języka Ruby . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
2.4 Obiektowość języka Ruby . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
2.5 Funkcyjność języka Ruby . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
2.6 Typy danych w języku JavaScript . . . . . . . . . . . . . . . . . . . . . . . 30
2.7 Komentarz blokowy w języku JavaScript . . . . . . . . . . . . . . . . . . . 30
2.8 Komentarz liniowy w języku JavaScript . . . . . . . . . . . . . . . . . . . . 31
2.9 Instrukcja if w języku JavaScript . . . . . . . . . . . . . . . . . . . . . . . 31
2.10 Pęta while w języku JavaScript . . . . . . . . . . . . . . . . . . . . . . . . 31
2.11 Pętla do...while w języku JavaScript . . . . . . . . . . . . . . . . . . . . . . 31
2.12 Pętla for w języku JavaScript . . . . . . . . . . . . . . . . . . . . . . . . . 31
2.13 Pętla for...in oraz for...of w języku JavaScript . . . . . . . . . . . . . . . . 31
2.14 Instrukcja switch w języku JavaScript . . . . . . . . . . . . . . . . . . . . . 31
2.15 Notacja kropkowa wywołania metody w języku JavaScript . . . . . . . . . 32
2.16 Notacja z nawiasami kwadratowymi wywołania metody w języku JavaScript 32
2.17 Funkcja konstruktora w języku JavaScript . . . . . . . . . . . . . . . . . . 32
2.18 Tworzenie instancji klasy Obiekt w języku JavaScript . . . . . . . . . . . . 33
2.19 Definicja funkcji w języku JavaScript . . . . . . . . . . . . . . . . . . . . . 33
2.20 Dziedziczenie w języku JavaScript . . . . . . . . . . . . . . . . . . . . . . . 33
2.21 Przkład instalacji gema ”Devise” . . . . . . . . . . . . . . . . . . . . . . . 34
2.22 Zmiana wersji Rubiego na 2.2.3 . . . . . . . . . . . . . . . . . . . . . . . . 35
2.23 Przykładowy Gemfile . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
2.24 Przykładowy Gemfile.lock . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
2.25 ”Hello World” w irb . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
2.26 Zmiana hasła klienta o id 1 . . . . . . . . . . . . . . . . . . . . . . . . . . 37
2.27 Przykład modelu ”Post” i zabezpieczonego kontrolera . . . . . . . . . . . . 43
2.28 Przykład zabezpieczenia metody ”update” kontrolera . . . . . . . . . . . . 43
12
SPIS LISTINGOW: 13
2.29 Przykład definicji uprawnień w bibliotece ”cancancan” . . . . . . . . . . . 44
3.1 Przykład funkcji ”render” dla elementu listy rzeczy do zrobienia . . . . . . 46
3.2 Przekazanie funkcji do subkomponentu . . . . . . . . . . . . . . . . . . . . 47
3.3 Ustawienie początkowego stanu komponentu w ReactJS . . . . . . . . . . . 48
3.4 Zmiana stanu komponentu w ReactJS . . . . . . . . . . . . . . . . . . . . . 48
3.5 Część kodu obiektu Dispatcher . . . . . . . . . . . . . . . . . . . . . . . . . 50
3.6 Operacje na DOM przykład . . . . . . . . . . . . . . . . . . . . . . . . . . 51
3.7 React transformacja węzłów różnych typów . . . . . . . . . . . . . . . . . . 52
3.8 React transformacja węzłów o takich samych typach . . . . . . . . . . . . . 52
3.9 Porównanie budowy szablonów z użyciem JSX i bez . . . . . . . . . . . . . 53
3.10 Przypisywanie atrybutów i funkcji w AngularJS . . . . . . . . . . . . . . . 58
3.11 Dziedziczenie realizowane w AngularJS . . . . . . . . . . . . . . . . . . . . 59
3.12 Kontroler ParentController . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
3.13 Kontroler ChildController . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
3.14 Przykład wykorzystania metody $watch . . . . . . . . . . . . . . . . . . . 60
3.15 Przykład wykorzystania metoty $apply . . . . . . . . . . . . . . . . . . . . 61
3.16 Przykład deklaracji modułu w AngularJS . . . . . . . . . . . . . . . . . . . 62
3.17 Plik controller.js . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
3.18 Szkielet aplikacji w AngularJS . . . . . . . . . . . . . . . . . . . . . . . . . 62
3.19 Przykłady wstrzykiwania zależności w AngularJS . . . . . . . . . . . . . . 63
3.20 Przykłady własnej dyrektywy w AngularJS . . . . . . . . . . . . . . . . . . 64
3.21 Pole konfiguracji dyrektywy restrict E w AngularJS . . . . . . . . . . . . . 65
3.22 Pole konfiguracji dyrektywy restrict A w AngularJS . . . . . . . . . . . . . 65
3.23 Pole konfiguracji dyrektywy restrict C w AngularJS . . . . . . . . . . . . . 65
3.24 Pole konfiguracji dyrektywy restrict M w AngularJS . . . . . . . . . . . . . 65
3.25 Przykładowe zapytanie GET z wykorzystaniem metody $http w AngularJS 65
3.26 Przykładowe zapytanie POST z wykorzystaniem metody $http w AngularJS 66
3.27 Przykład użycia ”scope” w modelu Rails. . . . . . . . . . . . . . . . . . . . 69
3.28 Przykład walidacji formatu adresu email. . . . . . . . . . . . . . . . . . . . 69
3.29 Przykład helpera zamieniającego liczbę na walutę. . . . . . . . . . . . . . . 69
3.30 Przykład użycia ”before action” do uwierzytelnienia użytkownika. . . . . . 70
3.31 Model wpisu oraz polubienia . . . . . . . . . . . . . . . . . . . . . . . . . . 71
3.32 Modele wpisu, wydarzenia i polubienia wraz z wyekstrahowanym modułem 71
3.33 Przykład wykorzystania generatora w Rails . . . . . . . . . . . . . . . . . . 72
3.34 Przykład definicji ścieżek dla nowego obiektu . . . . . . . . . . . . . . . . . 75
3.35 Przykład utworzonych przez Rails ścieżek API dla operacji CRUD . . . . . 75
SPIS LISTINGOW: 14
3.36 Przykład testu modelu w bibliotece RSpec . . . . . . . . . . . . . . . . . . 76
3.37 Przykład ”fabryki” klientów w bibliotece Factory Girl . . . . . . . . . . . . 77
3.38 Przykład użycia biblioteki ”faker” . . . . . . . . . . . . . . . . . . . . . . . 78
3.39 Aplikacja ”Hello World” w Sinatrze . . . . . . . . . . . . . . . . . . . . . . 80
3.40 Obsługa żądania POST pod adresem ”/todos” . . . . . . . . . . . . . . . . 81
3.41 Aplikacja ”Hello World” w Grape . . . . . . . . . . . . . . . . . . . . . . . 84
3.42 Operacje CRUD w Grape . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
4.1 Przykład ilustrujący ”boilerplate code” w AngularJS - HTML . . . . . . . 88
4.2 Przykład ilustrujący ”boilerplate code” w ReactJS - HTML . . . . . . . . 89
4.3 Przykład ilustrujący ”boilerplate code” w AngularJS - JavaScript . . . . . 89
4.4 Przykład ilustrujący ”boilerplate code” w ReactJS - JavaScript . . . . . . . 91
4.5 Przykład szablonu listy w ReactJS . . . . . . . . . . . . . . . . . . . . . . 94
4.6 Przykład szablonu listy w AngularJS . . . . . . . . . . . . . . . . . . . . . 96
Rozdział 1
Wstęp
Internet jako wynalazek bez wątpienia stawiany jest w jednym szeregu z powstaniem
takich innowacji jak wynalezienie elektryczności, druku czy też maszyny parowej. Każdy
z tych patentów usprawniał w znaczący sposób proces wykonywania pracy. Nie inaczej
jest w przypadku Internetu. W dobie powszechnej informatyzacji bardzo mocno rozwija
się rynek aplikacji internetowych, których w większości głównym zadaniem jest wspo-
maganie procesu wymiany i przetwarzania danych pomiędzy użytkownikami. W związ-
ku z tym powstało wiele różnych metod, architektur, języków programowania, a także
sposobów tworzenia interfejsów użytkownika. Wszystko po to, aby proces korzystania z
aplikacji internetowej był jak najbardziej intuicyjny, wygodny, szybki dla użytkownika.
Współcześni klienci firm tworzących oprogramowanie stawiają duże wymagania. Aplika-
cja w większości przypadków musi być intuicyjna, musi podpowiadać użytkownikowi co
ma zrobić, gdy ten się zgubi, powinna przechowywać dane o każdej czynności użytkow-
nika, powinna mieć dynamiczny charakter, powinna przetwarzać dane w locie, dostęp do
danych musi być zapewniony w każdym momencie a na dodatek aplikacja powinna działać
tak samo dobrze na każdym urządzeniu i platformie. Te i inne wymagania wymusiły na
programistach i firmach tworzących oprogramowanie, podejście do tematu aplikacji inter-
netowych w różny sposób. Dzięki temu, aby ułatwić proces wytwarzania oprogramowania,
które spełniałoby wygórowane wymagania klientów, powstało wiele różnych koncepcji, z
których przetrwały tylko te które miały zasadność istnienia. Natomiast każdy sposób re-
alizacji oprogramowania wiąże się także z odpowiednim doborem technologii do wymagań
dla oprogramowania. Przykładem takiej koncepcji tworzenia oprogramowania mogą być
bardzo popularne ostatnio aplikacje typu Single Page Application, które mają wyraźny
podział na warstwę kliencką i serwerową. Posiadają one bardzo mocno rozbudowaną war-
stwę prezentacji i odpytują tylko serwer celem pobrania danych do wyświetlenia. W tego
typu aplikacjach deweloperzy mają do wyboru wiele różnych technologi do implementacji
15
Rozdział 1. Wstęp 16
zarówno części serwerowych np. Ruby on Rails, Python i Django lub PHP i Laravel, a
także części klienckich np. Angular, Ember, React czy też Backbone.
1.1 Motywacje podjęcia tematu
Aktualne trendy na rynku aplikacji internetowych skłoniły nas do zainteresowania się
najczęściej wykorzystywanymi technologiami do ich realizacji. W dzisiejszym świecie, aby
być konkurencyjnym, wiele firm skazanych jest na posiadanie własnych systemów infor-
matycznych. Przekłada się to na stosunkowo dużą liczbę ofert pracy dla programistów w
różnych technologiach oraz na różnych poziomach zaawansowania. Dlatego też posiadanie
wiedzy i umiejętności pozwalających realizować tego typu systemy zwiększa atrakcyj-
ność programisty na rynku pracy. Kolejnym powodem, który skłonił nas do wybrania
realizowanego tematu, był fakt, iż chcieliśmy rozpoznać najpopularniejsze narzędzia do
implementacji części serwerowych i klienckich aplikacji sieciowych, poznać ich zalety i
wady, wyrobić sobie opinię na temat każdego z nich i wybrać najlepszy naszym zdaniem
zestaw bibliotek, który mógłby w przyszłości być przez nas wykorzystany do realizacji
komercyjnego systemu informatycznego. W związku z tym, że podczas przebiegu studiów
mieliśmy okazję poznać wystarczające spektrum języków programowania, podjęliśmy de-
cyzję o wyborze języka Ruby i wokół tego języka zostały dobrane biblioteki w przypadku
części serwerowych. Natomiast jeżeli chodzi o wybór języka do implementacji warstwy
prezentacji aplikacji, to wyboru w zasadzie nie ma i musi być to język JavaScript i to
dla niego wybrane zostały najpopularniejsze biblioteki wspomagające tworzenie bogatych
aplikacji internetowych.
1.2 Podział prac
Damian Romanów Adam Skołuda
1 Wstęp
2 Wprowadzenie teorytyczne
2.1 REST
2.2 AJAX
2.3 SPA
2.4 Model - View - Controller
2.5 Języki
2.5.1 Ruby
Rozdział 1. Wstęp 17
2.5.2 JavaScript
2.6 Środowiska programistyczne
2.6.1 Ekosystem Rubiego
2.6.2 Node
2.7 Bezpieczeństwo
2.7.1 Uwierzytelnianie
2.7.2 Autoryzacja
3 Opis technologii
3.1 ReactJS
3.2 AngularJS
3.3 Rails
3.3.1 MVC
3.3.2 DRY
3.3.3 Generatory
3.3.4 Struktura projektu
3.3.5 Konwencja ponad konfiguracją
3.3.6 TDD
3.3.7 Aktywna społeczność
3.4 Sinatra
3.5 Grape
4 Analiza
4.1 AngularJS - ReactJS
4.1.1 Próg wejścia
4.1.2 Komplementarność
4.1.3 Poziom ekspresji kodu
4.1.4 Wydajność
4.1.5 Debuggowanie
4.1.6 Przepływ danych
4.1.7 Szablony
4.1.8 Społeczność i popularność
4.1.9 Podsumowanie
4.2 Rails - Sinatra - Grap
4.2.2 Wydajność
4.2.3 Społeczność i popularność
4.2.4 Podsumowanie 4.2.4 Podsumowanie
Rozdział 1. Wstęp 18
5 Zakończenie
1.3 Cel pracy
Głównym celem niniejszej pracy była analiza bibliotek do tworzenia aplikacji interne-
towych w środowiskach Ruby i JavaScript. Brane były pod uwagę narzędzia do tworzenia
zarówno części klienckiej, jak i serwerowej. Podejmowany temat wymagał odpowiedniego
zaznajomienia się z wybranymi technologiami. Analiza została oparta przede wszystkim
o badanie zaimplementowanych aplikacji do tworzenia listy zadań. Dodatkowo, spostrze-
żenia i konkluzje autorów pracy zostały skonfrontowane z zewnętrznymi źródłami, co
pozwoliło szerzej spojrzeć na przedstawiane zagadnienie.
1.4 Układ pracy
Praca została podzielona na rozdziały. Każdy z nich opisuje część rozważań dotyczą-
cych analizowanych technologii. Struktura rozdziałów została zdefiniowana w taki sposób,
aby praca miała logiczny i chronologiczny układ. Wprowadzenie teoretyczne przedstawia
podstawowe informację na temat architektury aplikacji internetowych. Opis technologii
ma na celu szczegółowe przedstawienie wybranych narzędzi i rozwiązań. Rozdział ”Anali-
za” zawiera rozważania dotyczące każdej z wykorzystanych technologii. Rozważania te do-
tyczą samej implementacji, a także porównania pod kątem architektury i bezpieczeństwa.
Zawarte są w nim również wyniki przeprowadzonych prób wydajnościowych poszczegól-
nych bibliotek. Rozdział ”Zakończenie” jest bardzo subiektywnym spojrzeniem na każde
z analizowanych rozwiązań technologicznych oraz wybór naszym zdaniem najlepszej z
punktu widzenia programisty. Zakończenie jest podsumowaniem całej pracy, zawiera spis
zrealizowanych zadań, napotkane trudności oraz próbę prognozowania dalszego rozwoju
badanych technologii.
Rozdział 2
Wprowadzenie teorytyczne
Niniejsza praca ma na celu analizę technologii tworzenia aplikacji internetowych (web
application). W poprzednim rozdziale zostało wspomniane, że teraźniejszy użytkownik
oczekuje od nich wiele. Należałoby zatem zdefiniować pojęcie ”aplikacja internetowa”,
czym różni się od strony internetowej i czy w ogóle się od niej różni. Do zdefiniowania
powyższych wymagane będzie przedstawienie kilku innych technologii. Internet nie był-
by tym, czym jest obecnie bez HTTP (Hypertext Transfer Protocol) - protokołu typu
żądanie-odpowiedź działającego w architekturze klient-serwer. Rolę serwera odgrywają
programy osadzone na publicznie dostępnym węźle sieciowym. Ogromną zaletą jest tutaj
dowolność w wyborze języka implementacyjnego. Może to być C, C++, C# czy Java.
Programista może wybrać jeden z języków predestynowanych do tego typu zastosowań
(ze względu na samą składnię czy też zestawy bibliotek ułatwiających tworzenie serwe-
rów) np. PHP, Python, Scala czy też omawiany szerzej w niniejszej pracy Ruby. Bar-
dziej niekonwencjonalne, badawcze podejście doprowadziło nawet do powstania serwerów
w Prologu [27] czy Assemblerze [26]. Jedynym wymogiem jest zgodność ze standardem
HTTP [25]. Specyfikacja HTTP obejmuje kilka metod, z czego najważniejsze z nich to
GET, POST, PUT, DELETE. Architektura usług sieciowych bardzo często, a w wręcz
powinna opierać się na REST (Representational State Transfer). Kolejnym elementem
układanki jest język do opisu struktury dokumentów (stron) w Internecie - HTML (Hy-
pertext Markup Language) [24]. Znaczniki HTML są nośnikami dla tekstów, obrazków czy
hiperłączy. Dokument HTML jest odpowiedzią serwera na zapytanie klienta. Klientem
jest zazwyczaj przeglądarka internetowa, parsująca odpowiedź z serwera i wyświetlająca
ją użytkownikowi. Jak się okazało, te dwie proste technologie stworzyły duet, który prze-
trwał próbę czasu i położył podwaliny pod dzisiejszy kształt aplikacji internetowych. Czy
zatem każda strona internetowa jest aplikacją internetową? Odpowiedź na to pytanie nie
jest oczywista i jednoznaczna. Pomocne może okazać się odwołane do klasycznych aplika-
19
Rozdział 2. Wprowadzenie teorytyczne 20
cji - np. okienkowych programów na komputery PC. Aplikacja służy do realizacji celu, jest
narzędziem, dzięki któremu użytkownik może zrealizować swoje potrzeby. Np. program
graficzny pozwala nam na obróbkę czy retusz zdjęć. Czy sam folder ze zdjęciami nazwa-
libyśmy narzędziem, który realizuje jakiś cel? Oczywiście pozwala na ich wyświetlanie.
Nie jest to jednak twórcze działanie, a jedynie sama prezentacja treści. Można powie-
dzieć, że wspólnym mianownikiem wszystkich aplikacji jest możliwość kreacji. Zatem czy
strona internetowa prezentująca zawsze taką samą zawartość jest aplikacją? W świetle
powyższej argumentacji z pewnością nie. Przykładami aplikacji internetowych mogą być
Facebook, dokumenty Google czy Twitter - narzędzia umożliwiające użytkownikowi twór-
cze działanie. Ze względu na swoją budowę aplikację internetową można nazwać również
stroną internetową - jednak w obecnych czasach jest to spore uproszczenie i spłycenie jej
funkcjonalności.
2.1 REST
Protokół HTTP jest wystarczający do tworzenia serwerów dostarczających treści (za-
sobów). Przy małych aplikacjach ścieżki dostępu do zasobów (URI) można definiować
w zasadzie dowolnie. Złożone systemy wymuszają jednak stosowanie pewnych konwencji.
Brak wzorców i konwencji jest jedną z przyczyn regresji. W świecie usług sieciowych liczą
się dwa wzorce czy też style tworzenia systemów - SOAP (Simple Object Access Protocol)
oraz REST (Representional State Transfer). SOAP opiera się na RPC, jest raczej wy-
korzystywany do komunikacji komputer-komputer, zachodzi tutaj silne wiązanie serwera
z klientem. Jest to właściwie protokół. REST, to natomiast to wzorzec architektural-
ny do projektowania złożonych, skalowalnych i wydajnych usług sieciowych. Jest bardzo
elastyczny, o ile jest właściwie zaimplementowany. Opiera się na zasobach, standaryzuje
sposób dostępu do nich. Żeby można było mówić o usłudze sieciowej RESTful konieczne
jest spełnienie wszystkich czterech głównych reguł:
• Model klient-serwer
Polega na podziale odpowiedzialności między tymi dwoma bytami. Klient nie po-
siada informacji o sposobie przechowywania zasobów na serwerze. Nie jest dla nie-
go ważne czy jest to baza danych, zwykły plik czy też inna usługa sieciowa. Nie
jest ważny język programowania, użyte biblioteki czy sam sposób implementacji. Z
drugiej strony serwer nie jest obciążony przechowywaniem stanu klienta, nie mu-
si wiedzieć nic o interfejsie użytkownika. Elementem spajającym jest API. Można
dowolnie zamieniać oba elementy, pod warunkiem utrzymywania jednolitego inter-
fejsu. Cecha ta została wykorzystana w niniejszej pracy. Zaimplementowane zostały
Rozdział 2. Wprowadzenie teorytyczne 21
3 serwery HTTP i 2 klienty utrzymując niezmienne API. Pozwoliło to osiągnąć dużą
niezależność poszczególnych elementów
• Bezstanowość
Jak zostało wspomniane wyżej, serwer nie przechowuje stanu czy sesji klienta. Zatem
każde żądanie musi zawierać wszystkie informacje potrzebne do jego obsłużenia.
Korzystając z Internetu, bardzo często użytkownik ulega złudzeniu, że jest inaczej.
Wiele aplikacji oferuje możliwość logowania, a nawet zapamiętywania tego logowania
przez dłuższy okres. Powyższe funkcjonalności nie naruszają jednak architektury
REST. W momencie logowania serwer generuje token, który jest przesyłany do
klienta i zapisywany w tzw. ”ciasteczku” (HTTP cookie). W kolejnych żądaniach
legitymujący się nim klient jest uważany za zalogowanego.
• Cacheability
Cecha, która nie ma dobrego odpowiednika w języku polskim. Chodzi to tu o składo-
wanie wyników poprzednich zapytań, aby umożliwić szybki do nich dostęp w przy-
szłości. Z jednej strony umożliwia dostęp do niektórych zasobów niemal w czasie
rzeczywistym, a z drugiej zmniejsza obciążenie samej sieci oraz serwera.
• Wielowarstwowość
Architektura REST nie wymaga, aby końcowym serwerem była jedna maszyna.
Możliwe jest zastosowanie kilku warstw pośredniczących i sterowanie obciążeniem.
Klient końcowy postrzega taki system w ten sam sposób jak jeden serwer.
2.2 AJAX
Przez długi czas zachowanie stron internetowych było dość sekwencyjne. Użytkownik
klikał w hiperłącze, żądanie było wysyłane do serwera. Po otrzymaniu odpowiedzi cała
strona, a właściwie DOM (Document Object Model) były renderowane. Nie zawsze takie
zachowanie jest jednak potrzebne i pożądane. Zajmuje ono dość sporo czasu oraz powodu-
je specyficzne ”mignięcie” zawartości. Czasem zmianom ulegają bardzo niewielkie części
całego dokumentu. Rozwiązaniem tego problemu jest technika AJAX (Asynchronous Ja-
vaScript and XML) (w większości przypadków używa się jednak formatu JSON zamiast
XML - mówi się wtedy o AJAJ). Dzięki niej komunikacja użytkownika z treścią w Inter-
necie stała się bardziej dynamiczna, poprzez swoją asynchroniczność. Tym samym strony
internetowe bardziej zbliżyły się do standardowych programów komputerowych. Warto
w tym miejscu wspomnieć o bibliotece jQuery, która bardzo uprościła używanie AJAX.
Rozdział 2. Wprowadzenie teorytyczne 22
Przykład asynchronicznego zapytania GET w czystym JavaScripcie na listingu 2.1 oraz
przy pomocy jQuery na 2.2.
Listing 2.1: Przykład kodu jQuery
1 $.getJSON(’/my/url’, function(data) {
2 });
Listing 2.2: Przykład kodu czysty Javascript
1 var request = new XMLHttpRequest ();
2 request.open(’GET’, ’/my/url’, true);
3
4 request.onload = function () {
5 if (request.status >= 200 && request.status < 400) {
6 // Success!
7 var data = JSON.parse(request.responseText);
8 } else {
9 // We reached our target server , but it returned an error
10
11 }
12 };
13
14 request.onerror = function () {
15 // There was a connection error of some sort
16 };
17 request.send ();
Wszystkie żadania asynchroniczne wykonywane w języku JavaScript należą do żądań XHR
(XMLHttpRequest). Są nośnikiem obiektów o tej samej nazwie. AJAX posiada jednak pew-
ne ograniczenia. Jego funkcjonowanie opiera się na języku JavaScript. Użytkownik może
wyłączyć jego obsługę w przeglądarce, w takim przypadku AJAX będzie bezużyteczny.
2.3 SPA
AJAX przyczynił się do sporej zmiany Internetu. Uatrakcyjnił interakcję użytkownika
z aplikacją internetową, upodobnił ją do swoich ”desktopowych” pierwowzorów. Jeśli moż-
na część danych pobrać z serwera w tle, na żądanie użytkownika lub wtedy kiedy będzie to
konieczne, to dlaczego nie sprawić, aby cała aplikacja działała w ten sposób? SPA (Single-
page application) to podzbiór aplikacji internetowych charakteryzujący się pojedynczym
przeładowaniem strony, przy jej początkowym wyświetleniu. Dalsza komunikacja odbywa
się za pomocą JavaScripti i żądań XHR.
Rozdział 2. Wprowadzenie teorytyczne 23
Zalety:
• Rozdzielenie logiki serwera i klienta
Standardowe serwery HTTP są odpowiedzialne również za tworzenie dokumentu
HTML wraz z osadzonymi w nim zmiennymi, czy tworzenie formularzy. W przy-
padku SPA zadania te zostają w całości przerzucone na język JavaScript. Serwer
udostępnia tylko API, czyli szynę wymiany danych. Podejście takie przynosi wiele
korzyści. Jako że są to tak naprawdę dwie osobne aplikacje - mogą być rozwija-
ne przez niezależne zespoły. Logika biznesowa czy szczegóły działania procesów na
serwerze są niewidoczne dla klienta.
• Elastyczność i atrakcyjność interfejsu użytkownika
HTML generowany serwerowo ma pewne ograniczenia. Interakcja z użytkownikiem
opiera się na formularzach, a te przy skomplikowanych interakcjach stają się często
wąskim gardłem. Problematyczna staje się implementacja funkcjonalności działają-
cych ”na żywo”. Formularze mają swoje prawa, muszą zostać wysłane na serwer,
obsłużone, wtedy klient dostaje odpowiedź. Wykorzystanie JavaScriptu daje możli-
wość niemal natychmiastowego komunikowania o wprowadzonych zmianach, również
wprowadzenia stosownych efektów wizualnych. Przykładem może być załadowanie
zdjęcia profilowego na serwer. W standardowym formularzu HTML możemy wybrać
zdjęcie, po czym widzimy ewentualnie jego nazwę. Dopiero po wysłaniu i przetwo-
rzeniu, serwer jest w stanie pokazać nam wynik tego działania. Przy wykorzystaniu
JS, widzimy natychmiastowo wybrany obrazek. Wiele aplikacji oferuje też możliwość
jego przycięcia. Jest to funkcjonalność nieosiągalna dla zwykłych formularzy.
• Wiele klientów
Jako że serwer nie posiada żadnej wiedzy o kliencie, wprowadzanie kolejnych apli-
kacji klienckich, w dowolnych technologiach nie pociąga za sobą żadnych zmian w
kodzie serwera. W dzisiejszym świecie bardzo często się mówi o tzw. IoT (Internet
of Things). Tworzenie aplikacji z wyraźnym rozdziałem serwera i klienta stwarza
idealne warunki do rozszerzenia systemu o aplikacji mobilne. Jest to bardzo ważny
aspekt z punktu widzenia świata biznesu. Obecnie bardzo często tworzy się całe eko-
systemy powiązanych ze sobą aplikacji - włączając w to klienty www, czy mobilne
np. Android, czy iOS.
Wady:
• Niedojrzałość JS
Technologia tworzenia warstw klienckich aplikacji internetowych całkowicie opar-
Rozdział 2. Wprowadzenie teorytyczne 24
tych o język JavaScript jest stosunkowo nowym podejściem. Same frameworki JS-
owe rozwijają się bardzo szybko. Z jednej strony jest to pozytywne zjawisko, rozwój
zawsze jest dobry. Obserwując jednak ewolucję (czy raczej rewolucję) takich rozwią-
zań jak AngularJS czy ReactJS, trudno pozbyć się wrażenia, że programista jest w
pewnym sensie królikiem doświadczalnym, a jego produkt poligonem ćwiczebnym.
Jak wiadomo w świecie technologii rok to bardzo dużo czasu, wiele rzeczy może się
zmienić. W świecie JavaScriptu standardy mogą zmienić się w tydzień. I mowa tutaj
o fundamentalnych kwestiach architekturalnych, a nie kosmetycznych poprawkach.
Brakuje nienaruszalnych zasad i standardów, na których można oprzeć budowanie
aplikacji. Te wszystkie względy czynią użycie wspomnianych rozwiązań w poważ-
nych, komercyjnych aplikacjach co najmniej ryzykownym. Technologie nastawione
raczej na back-end (np. Ruby on Rails, PHP Symphony) istnieją o wiele dłużej. Ich
wybór jest bezpieczniejszym wyjściem.
• Niezawodność
Całkowite rozdzielenie warstw klienta i serwera ma niewątpliwie swoje plusy, nie
jest jednak pozbawione wad. Dwie osobne aplikacje to z pewnością więcej kodu niż
jedna. Dodatkowo warstwa front-endowa cechuje się dużą asynchronicznością, jest
sterowana zdarzeniami (kliknięcia, interakcje). Nie ma tutaj tak jasnego przepływu
danych, jak po stronie serwera (zapytanie - odpowiedź). Wszystko to sprawia, że
całość jest dużo trudniejsza do automatycznego testowania, co za tym idzie bardziej
zawodna. Należy też dodać, że pojedynczy błąd w klienckim kodzie JavaScript,
skutkuje bardzo często zaprzestaniem dalszego wykonywania programu.
• Synchronizacja stanu
Aplikacja kliencka jest w całości odpowiedzialna za generowanie i zmienianie doku-
mentu HTML widocznego dla użytkownika. Szablony do jego tworzenia są ustalone
wcześniej i znane. Zmienne, które trzeba w nim osadzić - nie. Zostają one pobrane
z serwera przy pomocy XHR podczas działania aplikacji. Stan aplikacji po stro-
nie klienta musi być synchronizowany z tym, co rezyduje w bazie danych serwera.
Wprowadza to konieczność częściowej duplikacji logiki serwera, a co za tym idzie
jeszcze bardziej zwiększa objętość kodu.
• Indeksowanie
W projektowaniu aplikacji internetowych bardzo ważnym zagadnieniem jest opty-
malizacja ich zawartości pod kątem algorytmów wyszukiwarek internetowych (SEO).
Właściciel serwisu chce, aby jego strona była atrakcyjna, ale co ważniejsze, aby była
łatwo dostępna dla potencjalnych klientów. Polega to m.in. na odpowiednim osa-
Rozdział 2. Wprowadzenie teorytyczne 25
dzeniu słów kluczowych czy meta-opisów. Jeśli chodzi o SPA - zadanie komplikuje
się nieco. Cała zawartość (w tym słowa kluczowe) pobierana jest poprzez AJAX
już po pierwszym załadowaniu strony. Dla użytkownika nie jest to problem, ale
web crawlery nie obsługują tego typu treści. Rozwiązaniem problemu jest dodat-
kowe generowanie dokumentu HTML po stronie serwera, specjalnie dla silników
wyszukiwarek. Zagadnienie to jest jednak dość złożone, nie wszystkie frameworki
dostarczają tego typu rozwiązań. Przy braku powyższych dodatkowych czynności,
strona internetowa widziana przez wyszukiwarkę np. Google jest pusta. Taki stan
rzeczy ma fatalny wpływ na indeksowanie strony i jest nie do przyjęcia.
• Początkowe ładowanie
Kolejną niedogodnością jest tzw. ”slow start”. Aplikacja tego typu może ładować
się znacznie dłużej niż standardowa strona. Oczywiście dzięki temu eliminuje się
późniejsze przeładowania, a sama strona działa dużo płynniej. Co jednak w przy-
padku gdy aplikacja potrzebuje kilku (kilkanastu) sekund do załadowania? (co nie
jest odosobnionym przypadkiem, zwłaszcza przy dużych aplikacjach, a także przy
wolnym połączeniu internetowym) Dzisiejszy użytkownik jest bardzo niecierpliwy i
nieprzyzwyczajony do czekania na treść. Jego pierwsze wrażenie kształtuje się już w
przeciągu ułamków sekundy, a utwierdza się w tym przekonaniu w czasie do kilku
sekund. Co, jeśli przez cały ten czas będzie wpatrywał się w pasek ładowania, albo
co gorsza, pustą stronę?
• Wyłączony JS
Wydaje się, że temat braku obsługi języka JavaScript przez przeglądarki interne-
towe w roku 2015 nie powinien być podniesiony. Wciaż jednak istnieje grupa użyt-
kowników (czasem całych korporacji) korzystająych z przestarzałych przeglądarek
(wczesne wersje IE) z wyłączonym JavaScriptem. Nie jest to duży odsetek, ale pro-
gramista wybierający zestaw technologii powinien się z nim liczyć. W przypadku
gdy głównym odbiorcą aplikacji ma być powyższa grupa, implementacja systemu w
technice SPA byłaby błędem.
2.4 Model - View - Controller
W informatyce bardzo powszechnym podejściem jest dekompozycja problemu. Ła-
twiejsze staje się rozwiązanie trzech małych problemów niż jednego dużego. Na podobną
myśl w odniesieniu do aplikacji z interfejsem użytkownika wpadł już w 1970 roku Try-
gve Reenskaug. Współczesne programy komputerowe potrafią być bardzo złożone, ofe-
Rozdział 2. Wprowadzenie teorytyczne 26
rując użytkownikowi cały wachlarz funkcjonalności. Gdyby jednak rozłożyć każdą z nich
na czynniki pierwsze, okazałoby się, że złożony obiekt składa się z małych niezależnych
bloczków - modelu, widoku i kontrolera. Wydawać się może, że tylko 3 byty to za mało
dużych aplikacji. Jak pokazuje jednak historia informatyki, najprostsze rozwiązania są
najlepsze (REST), a utrzymanie prostej i spójnej architektury kluczem do sukcesu. Echo
MVC pobrzmiewa bardzo silnie w ekosystemie WWW. Jak się okazało, forma aplikacji
internetowych, jest bardzo spójna z tym, co proponuje MVC. Współcześnie wszystkie
liczące się technologie do zastosowań webowych korzystają z MVC. Framework ”Rails”
bardzo silnie wypromował wzorzec MVC - do tego stopnia, że programiści zaczęli tworzyć
frameworki w innych językach, inspirowane właśnie Railsami [18]. Kolejnym dowodem
słuszności MVC, może być fakt jego stosowania również po stronie klienta JavaScript.
Początkowo nie było to potrzebne, jednak obecnie ilość potrzebnych informacji i stopień
skomplikowania logiki stał się na tyle duży, że wzorzec MVC (lub jego odmiany) stały
się koniecznością. Brak jego zastosowania bardzo często skutkuje regresją kodu, wzrostem
zawodności oraz spadkiem czytelności (spagetti code). Wzorzec MVC opisuje przeznacze-
nie i sposób interakcji między trzema tytularnymi typami obiektów. Krótki opis każdego
z nich:
• Model
Odpowiedzialny za przechowywanie informacji związanych z obiektem, jedyny no-
śnik logiki biznesowej. W większości przypadków powiązany z bazą danych (ORM
- mapowanie obiektowo-relacyjne). Niezależny od widoku.
• Widok
Sposób prezentacji danych (np. z modelu) oraz interfejs użytkownika.
• Kontroler
Obiekt spinający dwa powyższe - pozwala przechwytać interakcje użytkownika zapo-
czątkowane na komponentach widoku i przekazywać je do modelu. Z drugiej strony
dostarcza danych z modelu do widoku, odpowiedzialny również za dobór właściwego
modelu (np. wpis o odpowiednim id)
2.5 Języki
Języki programowania są podobnie jak języki mowy naturalnej zbiorem pewnych reguł
syntaktycznych oraz semantycznych dzięki którym człowiek w tym przypadku programista
może wydawać zrozumiałe polecenia do wykonania przez komputer. Prawo relatywizmu
językowego zaproponowane ok. 1930r przez Sapira i Whorfa mówi o tym, że używany
Rozdział 2. Wprowadzenie teorytyczne 27
język wpływa w większym lub mniejszym stopniu na myślenie i sposób postrzegania ota-
czającego nas świata. Pomimo tego, iż hipoteza ta dotyczy języka mowy, jej założenia
znajdują także odzwierciedlenie w posługiwaniu się językami programowania. Dlatego też
wybór danego języka także w informatyce jest bardzo istotny. Natomiast warto pamiętać
o tym, iż w większości przypadków nowe języki programowania postrzegane są błędnie
jako cudowne narzędzia rozwiązujące wszystkie problemy. Nie istnieje jedno uniwersalne
narzędzie do wszystkiego. Wynika to z tego, iż występuje bardzo duża liczba zbiorów pro-
blemów a każdy z nich ma zbyt dużą ilość ograniczeń. Skutkiem tego jest fakt, iż z reguły
języki programowania specjalizują się w rozwiązywaniu problemów zwykle z wąskiego
zakresu danej dziedziny. Jednakże wśród programistów już zawsze będą trwały swojego
rodzaju ”wojny na języki” podyktowane zazwyczaj indywidualnymi preferencjami, ale
także szerokim wachlarzem dostępnych narzędzi.
2.5.1 Ruby
Ruby jest popularnym, dynamicznym językiem skryptowym, który ma na celu dać
programiście duże możliwości, poczucie swobody oraz ma sprawić, aby programowanie
w tym języku było tak naturalne i przyjemne jak to tylko możliwe. Według jego twórcy
Yukihiro “Matz” Matsumoto Ruby jest językiem starannie dobranej równowagi. Aby to
osiągnąć, jego autor połączył wybrane elementy każdego z języków Perla, Smalltalka, Eif-
fel, Ady, i Lispa, by stworzyć język, który balansuje programowanie funkcjonalne wraz z
programowaniem imperatywnym. Pierwsze publiczne ukazanie języka Ruby nastąpiło w
1995 roku. Natomiast dopiero w 2006 język ten zyskał większą popularność oraz przychyl-
ność środowiska programistów. Stało się tak głównie za sprawą powstania i popularyzacji
frameworka do tworzenia aplikacji internetowych Rails, o którym więcej w rozdziale 3.3.
Kolejnym powodem, dla którego omawiany język stał się tak popularny, co obrazuje Rys.
2.1, jest fakt, iż Ruby jest językiem całkowicie darmowym także w rozumieniu kopiowania,
modyfikowania i rozprowadzania tego języka. Oto najważniejsze cechy języka:
• Ruby jest językiem zwinnym. A to dlatego, że udostępnia programiście, możliwość
dowolnego modyfikowania jego części czego skutkiem jest zachęta społeczności do
ciągłego udoskonalania wykorzystywanego przez nich języka. Ruby stara się nie na-
rzucać żadnych ograniczeń programiście co pozwala w zależności od intencji usunąć
lub przedefiniować podstawowe elementy języka. Przykładowo operację dodawania
wykonuje się za pomocą operatora ”+”. Natomiast istnieje możliwość wykonania
tego działania za pomocą słowa ”plus”. W tym celu należałoby dodać odpowiednią
metodę do klasy ”Numeric”.
Rozdział 2. Wprowadzenie teorytyczne 28
Listing 2.3: Elastyczność języka Ruby
1 class Numeric
2 def plus(x)
3 self .+(x)
4 end
5 end
6
7 y = 1. plus 3
Wynikiem działania jest oczywiście 4. Operatory w języku Ruby są tak zwanym
”lukrem” składniowym dla metod, które również można w dowolny sposób przede-
finiować.
• Ruby jest językiem bardzo wysokiego poziomu. Twórcy języka kierowali się zasadą,
że to komputer powinien pracować dla programisty, a nie odwrotnie. Dzięki temu
nawet najbardziej skomplikowane operacje możemy wykonywać za pomocą stosun-
kowo nie dużej ilości kodu w porównaniu z językami niższego poziomu.
• Ruby jest językiem silnie obiektowym. Dzięki temu każda część kodu może mieć
własne atrybuty w postaci zmiennych instancji oraz własne metody. Dzięki temu
możemy wywołać metodę na liczbie:
Listing 2.4: Obiektowość języka Ruby
1 10. times { print "Everything is an object!" }
Istnieje wiele języków programowania, w których np. liczby i inne bazowe typy
nie zachowują się jak obiekty. Inaczej jest w przypadku Rubiego, który tę cechę
odziedziczył po Smalltalku, co znacznie ułatwia korzystanie z języka, dlatego że
zasady dotyczące obiektów mają również zastosowanie dla całego języka.
• Ruby posiada cechy języków funkcyjnych. Dzięki temu, możemy dołączyć do do-
wolnej metody domknięcie, które opisuje sposób działania danej metody. Tego typu
domknięcie nazywa się blokiem i zostało zaczerpnięte przez twórców z języka funk-
cyjnego Lisp.
Listing 2.5: Funkcyjność języka Ruby
1 ruby_traits =
2 %w[Agile Object -oriented High -level ].map do |trait|
3 "Ruby is " + trait.downcase + " language!"
4 end
Rozdział 2. Wprowadzenie teorytyczne 29
Rysunek 2.1: Porównanie ilości ofert pracy dla popularnych języków serwerowych, [źródło:
http://www.indeed.com/jobtrends].
Powyższy przykład pokazuje blok, który znajduje się między słowami kluczowymi
”do” i ”end”. Bloki mogą być definiowane w dowolny sposób i realizować złożone
operacje.
• Ruby realizuje paradygmat dziedziczenia. Natomiast robi to inaczej niż w większo-
ści języków programowania. Ruby realizuje celowo tylko dziedziczenie jednokrotne,
natomiast dla programistów tego języka wprowadzono możliwość korzystania z mo-
dułów, które są zbiorami metod. Do każdej klasy może zostać dołączony tego typu
moduł, który rozszerza klasę o implementacje metod z danego modułu. Tego typu
rozwiązanie uznawane jest przez programistów Rubiego za prostsze i wygodniejsze
względem wielokrotnego dziedziczenia, które nakłada wiele ograniczeń i może być
stosunkowo skomplikowane.
• Ruby posiada mechanizm odśmiecania pamięci. Tak jak w wielu nowoczesnych ję-
zykach programowania, tak i w Rubim występuje garbage collector z prawdziwego
zdarzenia typu mark-and-sweep, który wykorzystywany jest dla wszystkich obiektów
żyjących w pamięci obiektowej. Według twórców języka nie istnieje potrzeba prze-
trzymywania informacji na temat liczby odniesień do obiektu tak jak w metodach
odśmiecania typu reference counting.
Rozdział 2. Wprowadzenie teorytyczne 30
Rysunek 2.2: Wykres pokazujący ilość ofert pracy dla języków JavaScript, C++, C#,
PHP oraz Python, [źródło: http://www.indeed.com/jobtrends].
2.5.2 JavaScript
JavaScript jest skryptowym językiem programowania, który pojawił się w już w 1995
za sprawą firmy Netscape. Wbrew pozorom geneza jego nazwy ma nie wiele wspólnego
z językiem Java. Powstała ona po prostu w wyniku kontraktów biznesowych pomiędzy
firma Netscape i Sun Microsystems. W 1997 roku ECMA stworzyła standard dla języka
JavaScript zwany ECMAScript. JavaScript zyskał dużą popularność za sprawą rozwoju
dynamicznych aplikacji internetowych, co można zauważyć na wykresie 2.2 trendów od-
nośnie zatrudnienia. Dzisiaj już nikt nie wyobraża sobie funkcjonowania aplikacji www
bez korzystania z JavaScriptu. Na bazie tego języka powstało wiele rozbudowanych fra-
meworków frontendowych o których więcej w rodziale 3 a nawet backendowych opisanych
w rozdziale 2.6.2 co także miało duże znaczenie na zwiększenie popularności tego Java-
Scriptu a co za tym idzie także programistów posługujących się tym językiem. Elementy
języka JavaScript zgodne ze standardem ECMAScript:
• Niektóre podstawowe typy danych i obiekty wykorzystywane w JavaScripcie.
Listing 2.6: Typy danych w języku JavaScript
1 String , Boolean , Number , Object , Math , Array
• JavaScript odziedziczył podstawowe instrukcje sterujące po językach C++ i Java.
Listing 2.7: Komentarz blokowy w języku JavaScript
Rozdział 2. Wprowadzenie teorytyczne 31
1 /* To jest komentarz
2 blokowy zajmujacy
3 kilka linii */
Listing 2.8: Komentarz liniowy w języku JavaScript
1 // To jest komentarz liniowy
Listing 2.9: Instrukcja if w języku JavaScript
1 if (warunki) {
2 instrukcje;
3 }
4 else {
5 instrukcje;
6 }
Listing 2.10: Pęta while w języku JavaScript
1 while (warunki) {
2 instrukcje;
3 }
Listing 2.11: Pętla do...while w języku JavaScript
1 do {
2 instrukcje
3 } while (warunki);
Listing 2.12: Pętla for w języku JavaScript
1 for ([ poczatkowe ]; [warunki ]; [krokowe ]) {
2 instrukcje;
3 }
Listing 2.13: Pętla for...in oraz for...of w języku JavaScript
1 for (wlasnosc in obiekt) {
2 instrukcje;
3 }
Listing 2.14: Instrukcja switch w języku JavaScript
1 switch (wyrazenie) {
Rozdział 2. Wprowadzenie teorytyczne 32
2 case wartosc1:
3 instrukcje;
4 break;
5 case wartosc2:
6 instrukcje;
7 break;
8 default:
9 instrukcje;
10 break;
11 }
• W JavaScripcie występują obiekty i typy prymitywne. Według standardu ECMA-
Script obiekty są tablicami asocjacyjnymi. Ze względu na to iż w JavaScripcie me-
toda danego obiektu jest także jego polem istnieją dwa sposoby odwołania:
Listing 2.15: Notacja kropkowa wywołania metody w języku JavaScript
1 m.metoda1 ();
Listing 2.16: Notacja z nawiasami kwadratowymi wywołania metody w języku JavaScript
1 m["metoda1"]();
• Aby utworzyć w JavaScripcie własny obiekt trzeba stworzyć funkcję konstruktora.
Listing 2.17: Funkcja konstruktora w języku JavaScript
1 function Obiekt(pole1 , pole2) {
2 this.pole1 = pole1;
3 this.pole2 = pole2;
4
5 function metoda1 () {
6 alert("Obiekt :: metoda1 ()");
7 }
8 this.metoda1 = metoda1;
9
10 function metoda2 () {
11 alert("Obiekt :: metoda2 ()");
12 }
13 this.metoda2 = metoda2;
14 }
Rozdział 2. Wprowadzenie teorytyczne 33
• W większości współczesnych języków obiektowych występują ”klasy” które pozwala-
ją tworzyć własne niestandardowe typy. Inaczej jest w przypadku języka JavaScript,
ponieważ według ECMA pojęcie ”klasy” nie istnieje w sensie formalnym. Mówiąc o
”klasach” w JavaScripcie mamy na myśli obiekty stworzone z wykorzystaniem tego
samego konstruktora.
Listing 2.18: Tworzenie instancji klasy Obiekt w języku JavaScript
1 var m = new Obiekt (1, 2);
• Definiowanie funkcji w JavaScripcie odbywa się za pomocją słowa kluczowego func-
tion. Zgodnie z ECMAScript funkcje są jednocześnie obiektami klasy Function.
Listing 2.19: Definicja funkcji w języku JavaScript
1 function dodajLiczby(a, b) {
2 return a+b;
3 }
• JavaScript implementuje także paradygmat dziedziczenia, ale w uproszczony sposób
wykorzystując prototypy.
Listing 2.20: Dziedziczenie w języku JavaScript
1 function KlasaBazowa () {
2 this.metoda1 = function () {
3 alert("KlasaBazowa ::1()");
4 }
5 this.metoda2 = function () {
6 alert("KlasaBazowa ::2()");
7 }
8 }
9
10 function KlasaPochodna () {
11 // metoda2 przeciaza odpowiednia metode z klasy KlasaBazowa:
12 this.metoda2 = function () {
13 alert("KlasaPochodna ::2()");
14 }
15 }
16 KlasaPochodna.prototype = new KlasaBazowa ();
17
18 x = new KlasaBazowa ();
19 y = new KlasaPochodna ();
Rozdział 2. Wprowadzenie teorytyczne 34
Rozdział opracowany na podstawie [15]
2.6 Środowiska programistyczne
Poprzez pojęcie środowiska programistyczne rozumiemy tu technologie, narzędzia oraz
biblioteki zorientowane wokół danego języka programowania wraz z tymi językami, które
zostały bliżej przedstawione w rozdziale 2.5. Należy pamiętać o tym, iż wybór danego
języka determinuje całe środowisko pracy danego programisty. Dlatego też w tym rozdziale
przedstawione zostaną bliżej konkretne zestawy narzędzi i bibliotek, ich geneza oraz baza
teoretyczna dla wybranych w poprzednim rozdziale języków programowania.
2.6.1 Ekosystem Rubiego
Język Ruby sam w sobie jest świetnym narzędziem, nastawionym na tworzenie czy-
stego, zrozumiałego kodu. Jest to język powszechnego zastosowania, w praktyce jednak
używany w większości przypadków w zestawieniu z Railsem. Czy popularność powyższych
można tłumaczyć tylko wysoką estetyką kodu? Ma to z pewnością wielkie znaczenie, jed-
nak nie mniej ważny jest aspekt open-source. Zarówno Ruby, jak i Rails to środowiska
otwarte. Każdy ma dostęp do kodu źródłowego, każdy może go modyfikować na własne
potrzeby. Może również tymi modyfikacjami dzielić się z twórcami, aby każdy mógł korzy-
stać z nowych funkcjonalności czy poprawek. Podobnie jest ze wszystkimi gemami (”gem”
to nazwa dodatkowej biblioteki w języku Ruby. Nawiązuje do nazewnictwa języka, ruby
- rubin. Jest to nazwa własna i dość charakterystyczna, dlatego w dalszej części pracy,
pojęcia te będą używane zamiennie). I to właśnie otwartość środowiska jest motorem
napędzającym cały ekosystem.
RubyGems
Ruby od wersji 1.9 jest dostarczany z wbudowanym menadżerem pakietów - Ruby-
Gems. Moduł ten jest domyślnie połączony z repozytorium gemów - rubygems.org. Jeśli
wskazana biblioteka znajduje się w repozytorium, zostanie automatycznie pobrana. Ist-
nieje możliwość wskazywania również innych źródeł. Instalacja nowego gema ogranicza się
do wywołania jednej komendy, np:
Listing 2.21: Przkład instalacji gema ”Devise”
1 gem install devise
Narzędzie RubyGems zostało szerzej opisane w [17] w rozdziale 21.1.
Rozdział 2. Wprowadzenie teorytyczne 35
RVM
Bardzo często zdarza się, że programista pracuje nad kilkoma projektami. Nie wszyst-
kie z nich musza korzystać z tej samej wersji języka Ruby. W standardowych okoliczno-
ściach każda zmiana projektu wiązałaby się z reainstalacją Rubiego wraz z potrzebnymi
gemami. Takie działanie byłoby ogromną stratą czasu. Z pomocą przychodzi RVM, czyli
menadżer wersji języka Ruby. Dzięki niemu w systemie rezydują obok siebie różne wersje
wraz z zainstalowanymy gemami. Zmiana wersji odbywa się za pomocą prostej komendy:
Listing 2.22: Zmiana wersji Rubiego na 2.2.3
1 rvm use 2.2.3
2 ruby -v
3 ruby 2.2.3 p173 (2015 -08 -18 revision 51636) [x86_64 -darwin14]
Bundler
Instalacja pakietów jest prosta dzięki RubyGems. Bardzo często zdarza się jednak, że
gemy bazują na innych gemach (dependency). Ręczne sprawdzanie zależności i instalacja
odpowiednich wersji bibliotek, byłoby bardzo czasochłonnym zajęciem. W dodaktu cały
proces należałoby powtarzać przy każdej aktualizacji gemów. Powyższe zadanie jest trudne
dla człowieka, jednak komputery radzą sobie z nim bez problemu. Gem ”bundler” auto-
matycznie negocjuje wersje pakietów, znajduje takie, które spełniają oczekiwania każdego
gema (o ile to możliwe). Programista tworzy jedynie plik Gemfile, w którym wylistowane
są potrzebne gemy. Bundler tworzy na jego podstawie plik Gemfile.lock wskazujący na
ich konkretne wersje. Poniżej przykłady wymienionych plików:
Listing 2.23: Przykładowy Gemfile
1 source ’https :// rubygems.org’
2
3 gem ’guard ’
4 gem ’guard -shell ’
5 gem ’terminal -notifier -guard ’
Listing 2.24: Przykładowy Gemfile.lock
1 GEM
2 remote: https :// rubygems.org/
3 specs:
4 coderay (1.1.0)
5 ffi (1.9.10)
Rozdział 2. Wprowadzenie teorytyczne 36
6 formatador (0.2.5)
7 guard (2.13.0)
8 formatador (>= 0.2.4)
9 listen (>= 2.7, <= 4.0)
10 lumberjack (~> 1.0)
11 nenv (~> 0.1)
12 notiffany (~> 0.0)
13 pry (>= 0.9.12)
14 shellany (~> 0.0)
15 thor (>= 0.18.1)
16 guard -compat (1.2.1)
17 guard -shell (0.7.1)
18 guard (>= 2.0.0)
19 guard -compat (~> 1.0)
20 listen (3.0.3)
21 rb -fsevent (>= 0.9.3)
22 rb -inotify (>= 0.9)
23 lumberjack (1.0.9)
24 method_source (0.8.2)
25 nenv (0.2.0)
26 notiffany (0.0.7)
27 nenv (~> 0.1)
28 shellany (~> 0.0)
29 pry (0.9.12.6)
30 coderay (~> 1.0)
31 method_source (~> 0.8)
32 slop (~> 3.4)
33 rb -fsevent (0.9.5)
34 rb -inotify (0.9.5)
35 ffi (>= 0.5.0)
36 shellany (0.0.1)
37 slop (3.6.0)
38 terminal -notifier -guard (1.6.4)
39 thor (0.19.1)
40
41 PLATFORMS
42 ruby
43
44 DEPENDENCIES
45 guard
46 guard -shell
47 terminal -notifier -guard
Rozdział 2. Wprowadzenie teorytyczne 37
irb
Bardzo wygodnym narzędziem jest interaktywna konsola języka Ruby (irb - interactive
Ruby). Jako że Ruby jest językiem interpretowalnym, można dynamicznie wykonywać jego
instrukcje i prezentować ich wyniki. Irb jest przydatne w przypadku chęci przetestowania
działania napisanego kodu. Poniżej przykład użycia irb:
Listing 2.25: ”Hello World” w irb
1 $ irb
2 :001 > puts ’Hello World ’
3 Hello World
4 => nil
Jeszcze ciekawszym narzędziem jest rails console. Jest bardzo podobne do konsoli irb,
używane jest jednak tylko w obrębie aplikacji Rails. Dzięki niemu możemy korzystać
ze wszystkich klas i metod napisanych w obrębie tej aplikacji. Np. możliwe staje się
uzyskanie dostępu do bazy danych poprzez ORM. Możemy wprowadzić zmiany, operując
na modelach, a nie tabelach bazodanowych. Przykład użycia rails console:
Listing 2.26: Zmiana hasła klienta o id 1
1 $ rails console
2 przykladowa_aplikacja >> Client.find_by(id: 1). update_attributes
password: ’nowe haslo ’
3 Client Load (19.4 ms) SELECT "clients".* FROM "clients" WHERE "
clients"."id" = $1 LIMIT 1 [["id", 1]]
4 (2.2 ms) BEGIN
5 SQL (0.6 ms) UPDATE "clients" SET " encrypted_password " = $1 , "
updated_at" = $2 WHERE "clients"."id" = $3 [["
encrypted_password ", " $2a$10$fOjZciThhpJ9flUV0B5f1 .. qbsZXgEBfYb
/5 PJkQMGWxww0XKbbj ."], ["updated_at", "2015 -08 -29
15:41:19.559307 "], ["id", 1]]
6 (48.7 ms) COMMIT
7 => true
Rake
Odpowiednik narzędzia ”make” z systemów UNIX. Pozwala na konstruowanie zadań,
reguł. Umożliwia zarządzane zależnoścami. Zadania definiuje się w języku Ruby, dzię-
ki zastosowaniu specjalnego DSL. Co ciekawe umożliwia budowanie także programów w
innych językach, np. C.
Rozdział 2. Wprowadzenie teorytyczne 38
2.6.2 Node
Node.js jest platformą stworzoną na bazie środowiska uruchomieniowego JavaScript.
Projekt ten jest stosunkowo młody, gdyż pojawił się w 2009 roku i bardzo szybko zyskał
dużą popularność, co widać na Rys. 2.4. Społeczność wokół Node.js rośnie tak szybko, że
obecnie projekt ten jest drugi co do liczby obserwatorów w portalu GitHub i aktualnie
istnieje ok. 70 000 modułów stworzonych na licencji ”Open Source” dostępnych z poziomu
menadżera pakietów dla Node.js npm. Główne cechy platformy Node.js:
• Podstawą działania Node.js jest język JavaScript, o którym więcej w rozdziale 2.5.2.
Do wykonywania kodu po stronie serwera Node stosuje wirtualną maszynę Java-
Script V8, z której korzysta przeglądarka Google Chrome. Dzięki temu aplikacje
tworzone w Node zyskują dużą wydajność z tego względu, iż zamiast uruchamiania
kodu bajtowego z wykorzystaniem interpretera Node kompiluje program do kodu
maszynowego. Wykorzystanie języka JavaScript po stronie serwera przynosi kilka
istotnych korzyści. Po pierwsze w wyniku tego, iż aplikacje internetowe mogą być
tworzone z wykorzystaniem tylko jednego języka programowania zarówno po stronie
klienckiej, jak i serwerowej minimalizowany jest proces przełączania kontekstu. Po
drugie Node wykorzystuje JSON jako format wymiany danych zyskujący dużą popu-
larność w dziedzinie tworzenia aplikacji internetowych będący natywnym formatem
dla języka JavaScript. Dzięki temu, że Node korzysta z dokładnie jednej maszyny
wirtualnej V8, zgodnej ze standardem ECMAScript, korzystanie z nowych funk-
cji języka JavaScript nie jest ograniczone przez spóźnione aktualizacje przeglądarek
internetowych różnych producentów.
• Obsługa operacji wejścia-wyjścia na serwerze. Zgodnie z rysunkiem 2.3 obrazują-
cym wykonywanie nieblokującej operacji Node jest serwerem asynchronicznym. W
standardowym podejściu komunikacji z serwerem mamy model typu zapytanie - od-
powiedź kóre realizowane jest w głównym wątku aplikacji i kolejne zapytania do
serwera są zwyczajnie kolejkowane. Natomiast w przypadku Node.js istnieje tzw.
pętla zdarzeń, która dopiero po otrzymaniu odpowiedzi wykonuje operacje zdefinio-
wane w funkcji zwrotnej.
• Tworzenie aplikacji typu DIRT. W związku z tym, że Node dzięki nieblokującemu
przetwarzaniu akcji wejścia-wyjścia powoduje małe obciążenie podczas przetwarza-
nia operacji, często jest wykorzystywany jako pośrednik w przekazywaniu różnych
strumieni danych z różnych źródeł. Ta cecha powoduję, iż Node staję się popularny
w aplikacjach przetwarzających dużą ilość danych w czasie rzeczywistym. Przykła-
Rozdział 2. Wprowadzenie teorytyczne 39
Rysunek 2.3: Przykład nieblokującej operacji wejścia-wyjścia wykonywanej przez Node,
[źródło: [3]].
dem aplikacji typu DIRT napisanej w Node jest [16] która służy do testowania stron
internetowych na różnych platformach w czasie rzeczywistym.
W związku z dużym rozwojem frameworków frontendowych rosnącym ich skompli-
kowaniem oraz tendencją do upodabniania się do aplikacji backendowych pojawiły się
zapotrzebowania na dodatkowe narzędzia i biblioteki do odpowiedniego zarządzania tymi
frameworkami. I tutaj do gry wchodzi Node.js, który wprowadza między innymi mena-
dżer zarządzania pakietami npm, które można porównać do gemów w środowisku Ruby
oraz nvm, który służy do zarządzania wersjami Node.js. Nvm jest odpowiednikiem rvm,
o którym więcej w rozdziale 2.6.1. W wyniku tego, iż technologie aplikacji klienckich nie
podlegają w zasadzie żadnej standaryzacji tego, typu rozwiązań open source jest bardzo
dużo i nie sposób je wszystkie opisać a co dopiero używać.
2.7 Bezpieczeństwo
W dzisiejszym świecie Internet jest medium, w którym dochodzi do olbrzymiej wy-
miany informacji. Dane przesyłane w Internecie dotyczą każdego aspektu życia, dlatego
też kluczowym pojęciem stało się bezpieczeństwo. Według jednej z definicji komputer jest
Rozdział 2. Wprowadzenie teorytyczne 40
Rysunek 2.4: Porównanie ilości ofert pracy dla popularnych platform serwerowych, [źródło:
http://www.indeed.com/jobtrends].
uznawany za bezpieczny wówczas, gdy można stwierdzić, że sprzęt oraz oprogramowanie
na nim znajdujące się działają zgodnie z oczekiwaniami użytkownika. Natomiast w obliczu
bardzo szybkiego rozwoju globalnej sieci, jaką jest Internet Rys. 2.5 oraz sposobu i skali
publikacji informacji, powstała potrzeba bezpieczeństwa ukierunkowana na WWW. Defi-
niuje się je jako zbiór technologii, procedur i metod wykorzystywanych do zabezpieczania
serwerów WWW, użytkowników, a także organizacje stające za nimi. Wprowadzane środki
bezpieczeństwa mają za zadanie ustrzec użytkowników przed nieoczekiwanym zachowa-
niem komputerów. Istnieje wiele znaczących czynników, które wpływają na odmienne i
bardziej ukierunkowane podejście do bezpieczeństwa WWW:
• Internet z założenia jest siecią dwukierunkową. Publikowane za jej pomocą informa-
cje znajdują się na serwerach WWW, do których dostęp mogą mieć miliony osób
na całym świecie. Tego typu zagrożenia nie występują w przypadku innych mediów
np. gazeta, faks, telefon.
• Sieć WWW wykorzystywana jest przez duże organizacje komercyjne, ale także i rzą-
dowe do przechowywania i dostępu do wielu różnych danych także tych wrażliwych.
Skutkiem tego jest wymagane zwiększone bezpieczeństwo dostępu do tych danych
oraz większa kontrola nad tym, kto posiada dostęp do nich.
• Pomimo tego, że sieć internetowa tworzona była i standaryzowana od początku swo-
jego istnienia przez wiele lat to poziom skomplikowania zarówno z punktu widzenia
sprzętowego, jak i oprogramowania jest na tyle duży, że liczba występujących błę-
Rozdział 2. Wprowadzenie teorytyczne 41
dów bardzo mocno podnosi ryzyko zagrożenia bezpieczeństwa. Przykładem takiego
oprogramowania mogą być przeglądarki internetowe, którym cały czas zdarzają się
często poważne luki w zabezpieczeniach.
• Na poziom istotności zabezpieczeń serwerów WWW w znaczący sposób wpływa
fakt, iż większość użytkowników Internetu nie posiada wystarczającej wiedzy, do-
świadczenia ani świadomości zagrożeń, jakie mogą się pojawić.
• W większości przypadków naprawa skutków naruszeń bezpieczeństwa wymaga wię-
cej zasobów czasu i pieniędzy niż wprowadzenie odpowiednich zabezpieczeń.
• W dzisiejszym świecie za pośrednictwem sieci WWW codziennie dochodzi do nie-
zliczonej ilości transakcji finansowych wraz z wymianą informacji poufnych typu
numery kart kredytowych czy też dane personalne obu kontrahentów.
• Wiele firm wykorzystuje sieć WWW do komunikacji z zewnętrznymi odbiorcami,
którymi mogą być partnerskie firmy bądź kontrahenci zlokalizowani na całym świe-
cie. Zastrzeżone dane wymieniane pomiędzy tymi firmami mogą się stać celem przy-
kładowo dla wrogów danej firmy.
Problem zapewnienia bezpieczeństwa WWW należy podzielić na trzy główne elementy, z
których każdy musi spełniać warunki bezpieczeństwa, aby całość przetwarzania danych w
obrębie WWW można było nazwać bezpiecznym:
• Odpowiednie zabezpieczenie serwera WWW oraz informacji na nim przechowywa-
nych w taki sposób, aby mieć pewność, że serwer będzie działał ciągle i poprawnie.
Przechowywane dane na serwerze WWW nie mogą być modyfikowane przez nieupo-
ważnione do tej operacji osoby oraz mogą być udostępniane tylko i wyłącznie dla
osób autoryzowanych, czyli takich, które posiadają prawa dostępu do tych informa-
cji.
• Jak w każdym systemie informatycznym tak i w sieci WWW największe zagrożenie,
jeżeli chodzi o bezpieczeństwo, występuje na styku dwóch różnych systemów. Klu-
czowym elementem jest zabezpieczenie przekazywanych informacji w szczególności
tych poufnych od klienta do serwera. Głównym zagrożeniem bezpieczeństwa komu-
nikacji na linii klient-serwer są wszelkiego rodzaju podsłuchy np. atak ”man in the
middle”.
• Zabezpieczenie komputera klienta, czyli użytkownika końcowego zwykle bywa naj-
trudniejszym elementem dla zapewnienia bezpieczeństwa. Klient powinien być pew-
Rozdział 2. Wprowadzenie teorytyczne 42
Rysunek 2.5: Dostęp do Internetu stacjonarnego w Polsce, [źródło: http://pclab.pl/
news63802.html].
ny tego, że dane przesyłane na jego komputer są zgodne z oczekiwaniami i nie
spowodują uszkodzenia innych danych bądź urządzeń.
2.7.1 Uwierzytelnianie
Uwierzytelnianie jest procesem mającym na celu potwierdzenie tożsamości danego
użytkownika. Metoda ta jest podstawowym mechanizmem bezpieczeństwa danych. W
przypadku poprawnego uwierzytelnienia istnieje pewność, że dany użytkownik jest osobą,
za którą się podaje, czego konsekwencją z kolei jest przydzielenie mu dostępu do zasobów,
czyli uwierzytelnienie co jest opisane dokładniej w rozdziale 2.7.2.
2.7.2 Autoryzacja
Samo uwierzytelnienie klienta wobec serwera nie jest wystarczające, aby zapewnić
bezpieczeństwo. Możliwe jest w ten sposób ograniczenie dostępu do pewnych rejonów
aplikacji, aż do momentu zalogowania. Złożone aplikacje internetowe dają użytkowni-
kom dostęp do ogromu treści. Czasem aplikacja przechowuje jednak dane, które nie po-
winny być oglądane przez osoby niebędące z nimi powiązane. Np. aplikacja bankowa
umożliwia przeglądanie historii swoich transakcji pod adresem http://przykladowy-
bank/user/transactions. Użytkownik może wyświetlić szczegóły pojedynczej transak-
cji pod adresem http://przykladowy-bank/user/transactions/:id, gdzie :id to nu-
mer transakcji. Nie byłoby jednak właściwe, gdyby inna osoba mogła uzyskać dostęp
Rozdział 2. Wprowadzenie teorytyczne 43
do tych danych, po prostu przeszukując wszystkie możliwe numery transakcji. Kolejnym
przykładem może być blog gdzie pod adresem http://blog.com/recent posts możemy
wszystkie posty utworzone w ciągu ostatnich 5 dni. Co, jednak jeśli chcemy, aby tylko
użytkownicy ze specjalnymi uprawnieniami mogli wyświetlać posty oznaczone jak taj-
ne? Problemem do rozwiązania jest w tym przypadku filtrowanie treści w zależności od
uprawnień użytkownika. Wracając do przykładu z najnowszymi postami. Przekazując do
widoku kolekcję wszystkich postów, należy wziąć pod uwagę uprawnienia (np. czy mamy
do czynienia z administratorem) użytkownika (w tym przypadku zmienna current user).
Listing 2.27: Przykład modelu ”Post” i zabezpieczonego kontrolera
1 class Post < ActiveRecord :: Base
2 scope :recent , -> { where(’created_at BETWEEN ? AND ?’, 5. days.ago ,
Time.now) }
3 scope :visible_by , -> (client) { client.admin ? all : where(
supersecret: false) }
4 end
5
6 class PostsController < BaseController
7 def index
8 render Post.visible_by(current_user).recent
9 end
10 end
Kolejnym problemem, który trzeba rozważyć w powyższym przykładzie, jest możliwość
edycji posta. Funkcjonalność edycji utworzonych przez siebie bytów jest konieczna w więk-
szości przypadków. Nie chcemy jednak aby ktoś inny mógł edytować nasze posty. Zabez-
pieczenie kontrolera na powyższy przypadek wygląda następująco:
Listing 2.28: Przykład zabezpieczenia metody ”update” kontrolera
1 class PostsController < BaseController
2 before_action : check_ownership !, only: :update
3 expose (: post)
4
5 def update
6 post. update_attributes (body: params [: body ])
7 redirect_to post_path(@post)
8 end
9
10 private
11
12 def check_ownership !
13 fail UnauthorizedAccess unless post.author == current_user
Rozdział 2. Wprowadzenie teorytyczne 44
14 end
15 end
Przed wykonaniem akcji update serwer sprawdza, czy użytkownik domagający się takiej
akcji jest autorem posta. Jeśli nie jest, wzbudza wyjątek UnauthorizedAccess, a następ-
nie może wyświetlić użytkownikowi informację, że może edytować tylko swoje posty. Jeśli
test na autorstwo przejdzie pozytywnie, pozwala wykonać żądaną akcję. Powyższe za-
bezpieczenia wydają się trywialne, ale są bardzo ważne do zachowania bezpieczeństwa
całej aplikacji. Edycja czyjegoś wpisu nie jest może dużą stratą, ale wszędzie tam gdzie
system obraca jakimikolwiek środkami pieniężnymi, stawka jest dużo większa. Mimo tego
programiści bardzo często niedostatecznie zabezpieczają dostęp do usług.
Biblioteką, która podchodzi do powyższego zagadnienia kompleksowo, jest cancan-
can[22]. Jej twórcy zaproponowali deklaratywne podejście do uprawnień użytkowników.
Zamiast w każdym miejscu sprawdzać, czy dane konto ma rzeczywiście dostęp do konkret-
nego zasobu, definiuje się jego uprawnienia w jednym pliku. Podczas dostępu do zasobów
biblioteka sprawdza, czy żądany obiekt znajduje się na liście uprawnień. Przykład definicji
uprawnień:
Listing 2.29: Przykład definicji uprawnień w bibliotece ”cancancan”
1 class Ability
2 include CanCan :: Ability
3
4 def initialize(user)
5 user ||= User.new # guest user (not logged in)
6 if user.admin?
7 can :read , Post
8 else
9 can :read , supersecret: false
10 end
11 end
12 end
Klasa Ability definiuje zdolności użytkownika. Powyższy definicja jest intuicyjna i zbli-
żona do pseudokodu. Może być zrozumiana również przez kadrę menadżerską, co jest dużą
zaletą i ułatwia komunikację w zespołach. Jest to jeden z atutów języka Ruby.
Rozdział 3
Opis technologii
W niniejszym rozdziale zostaną wprowadzone analizowane technologie do tworzenia
aplikacji klienckich typu SPA: ReactJS oraz AngularJS (rozdziały 3.1 i 3.2). W dalszej
częsci przedstawione zostaną technologie serwerowe, mianowicie: Rails, Sinatra oraz Gra-
pe (3.3, 3.4, 3.5). Wprowadzenie zawierać będzie informacje ogólne, krótki rys historyczny,
a także czynniki motywujące autorów powyższych technologii do użycia takich czy innych
rozwiązań. Autorzy pracy będą starali się wskazać najbardziej charakterystyczne cechy
analizowanych bibliotek. Duży nacisk zostanie położony również na architekturę przesta-
wianych rozwiązań, z uwzględnieniem wzorców projektowych i modelowania przepływu
informacji. Tam gdzie to konieczne, wprowadzone zostaną szczegóły użytych algorytmów
(Diff Algorithm 3.1.6). Konkretne elementy bibliotek, zostaną podparte przykładami ko-
du, czy to z zaimplementowanych aplikacji, czy dokumentacji.
3.1 ReactJS
Biblioteka ReactJS napisana w języku JavaScript, przez programistę Facebooka Jorda-
na Walke, jest z całą pewnością najciekawszą pozycją w niniejszej pracy. Celem przyświe-
cającym jej twórcom było usprawnienie projektowania interfejsów użytkownika, poprzez
wprowadzenie deklaratywnych, modularnych i dajacych się ponownie używać komponen-
tów. Jeśli rozważalibyśmy jej umiejscowienie w modelu MVC - byłaby to litera V - widok.
Wydaje się, że odpowiedzialność widoku w powyższym wzorcu jest dość mała. React jed-
nak prezentuje rewolucyjne, a także dość kontrowersyjne podeście, wymuszając zmiany
na całym przepływie danych. Sama biblioteka jest dość minimalistyczna. Nie wymusza
na programiście konkretnej architektury projektu. Nie jest wskazany preferowany spo-
sób komunikacji z serwerem, struktura klas czy folderów. Twórcy Reacta proponują co
prawda wzorzec o nazwie ”Flux” (o którym będzie też mowa w tym rozdziale), ale jest
45
Rozdział 3. Opis technologii 46
to opcjonalne. Takie podejście daje dużą elastyczność, jest jednak sporym wyzwaniem.
Samodzielne dobieranie komponentów i projektowanie architektury wymaga pewnego do-
świadczenia. Jako materiał do analizy w niniejszej pracy posłużyło połączenie Reacta,
Fluxa i lekkiej biblioteki BackboneJS (tylko elementy do komunikacji z API). Więcej o
tych technologiach można znaleźć w [9] i [13].
3.1.1 Deklaratywny charakter widoków
Opisywany w rozdziale 3.2 AngularJS korzysta z rozwiązania o nazwie ”two-way data
binding”. Jest to funkcjonalność wbudowana w tę bilbiotekę (podobne rozwiązanie zasto-
sowano w EmberJS - więcej informacji o nim w [10]). Przez długi czas był to standard
wiązania danych z szablonem. Zarządzanie stanem obiektów po stronie klienta i ich syn-
chronizacja z serwerem jest zadaniem trudnym. ”Two-way data binding” zdaje się cudow-
nym rozwiązaniem. Programista nie musi ręcznie kontrolować wartości przechowywanych
w formularzach i zapisywać ich w specjalnych obiektach. Po powiązaniu elementu inter-
fejsu użytkownika z konkretnym modelem każda zmiana jednego z nich będzie skutkowała
też zmianą drugiego. Twórcy Reacta przekonują, że takie wiązanie danych, jest źródłem
wielu problemów. Ciężko stwierdzić jak głęboko może sięgać łańcuch takich zmian. Za-
miast tego proponują prostsze rozwiązanie - ”unidirectional data flow”. Każdy komponent
posiada funkcję ”render”. W niej za pomocą biblioteki JSX definiowany jest wygląd tego
elementu, poniżej przykład z zaimplementowanej aplikacji:
Listing 3.1: Przykład funkcji ”render” dla elementu listy rzeczy do zrobienia
1 render: function () {
2 var todo = this.props.todo;
3 var iClassName = ’fa fa -2x action check ’
4 var trClassName = ’row ’
5 if (todo.get(’completed ’)) {
6 iClassName += ’fa -check -square ’;
7 trClassName += ’bg -success ’;
8 } else {
9 iClassName += ’fa -square -o’;
10 };
11 if (this.props.showCompleted === false && todo.get(’completed ’) ===
true) {
12 return null
13 };
14
15 return (
16 <tr className ={ trClassName}>
Rozdział 3. Opis technologii 47
17 <td >
18 <i className ={ iClassName} onClick ={ this. _onToggleComplete }/>
19 </td >
20 <td >{ todo.get(’name ’)}</td >
21 <td className=’inline ’>
22 <i className=’fa fa -times -circle fa -2x delete pull -right
action close ’ onClick ={ this. _onDestroyClick }/>
23 </td >
24 </tr >
25 );
26 }
Programista definiuje wygląd komponentu tylko raz. Jeśli zajdą jakieś zmiany w przeka-
zywanych parametrach lub jego stanie, cały DOM zostanie przerenderowany.
3.1.2 Props
W powyższym przykładzie pokazane zostało użycie funkcji Reacta o nazwie ”props”,
pochodzącej od słowa ”properties”. Służy ona do przekazywania danych z widoku nad-
rzędnego do osadzenia w szablonie JSX (hierarchia widoków może być złożona, zgodnie ze
wzorcem projektowym o nazwie kompozyt, opisanym szerzej w [11]). Co ciekawe można
przekazywać w ten sposób nie tylko prymitywy, ale też złożone obiekty, np. JSON czy też
funkcje. Przekazanie funkcji w taki sposób jest również dobrą praktyką - jest to zgodne ze
wzorcem projektowym obserwator [11]. Zapobiega to zbędnemu i szkodliwemu wiązaniu
obiektów. Obserwowany obiekt nie ma dostępu do rodzica, potrafi wywyłać tylko metodę,
którą otrzymał. Poniżej przykład takiego działania:
Listing 3.2: Przekazanie funkcji do subkomponentu
1 // Przekazanie funkcji do subkomponentu
2 return (
3 <div id=’main ’>
4 <TodoTextInput onSave ={ this.createTodo }/>
5 ...
6 </div >
7 );
8
9 // Wywolanie funkcji przekazanej z komponentu glownego
10 _save: function () {
11 this.props.onSave(this.state.value);
12 this.setState ({
13 value: ’’
Rozdział 3. Opis technologii 48
14 });
15 }
Należy zaznaczyć, że wszystkie dane przekazane przez ”props” są niezmienne (immutable)
dla komponentu, który je otrzymał.
3.1.3 State
Bardzo często zdarza się, że elementy interfejsu użytkownika muszą reagować na inte-
rakcje. Przykładowo przycisk ”Lubię to” na Facebooku, zmienia swój wygląd po kliknię-
ciu, komunikując użytkownikowi wykonanie akcji. Jak zostało wspomniane w poprzednim
podrozdziale dane pochodzące z ”props” są niezmienne. ”State” jest miejscem przecho-
wywania danych dynamicznie zmieniających się podczas cyklu życia komponentu. Do
ustawienia początkowego stanu służy funkcja ”getInitialState”. Poniżej przykład użycia
z aplikacji ”Todo”:
Listing 3.3: Ustawienie początkowego stanu komponentu w ReactJS
1 getInitialState : function () {
2 return {
3 value: this.props.value || ’’
4 };
5 }
W trakcie działania aplikacji, komponent może zmienić swój stan, dzięki funkcji ”setSta-
te”, poniżej przykład użycia:
Listing 3.4: Zmiana stanu komponentu w ReactJS
1 // Element UI ktory jest zmieniany
2 <input className="form -control fw" autoFocus ={ true} value ={ this.state
.value} onChange ={ this._onChange} placeholder="Task to be done ..."
type="name"/>
3
4 // Funkcja wywolywana po zmianie
5 _onChange: function(/* object */ event) {
6 this.setState ({
7 value: event.target.value
8 });
9 },
Rozdział 3. Opis technologii 49
Rysunek 3.1: Diagram obrazujący przepływ sterowania w architekturze Flux, [źródło:
https://github.com/facebook/flux].
3.1.4 Flux
Przepływ danych narzucony przez Reacta jest bardzo przyjazny dla programisty. Lu-
dzie nie są przystosowani do pracy nad kilkoma zadaniami jednocześnie. W dwustronnym
przepływie danych analiza zachowania aplikacji często wymagania śledzenia długiego łan-
cucha zmian. W takim przypadku łatwo o pomyłkę. React proponuje zastosowanie wzorca
SSoT - jedynego źródła prawdy (ang. Single Source of Truth). Pomysł na architekturę
całej aplikacji klienckiej dostarcza właśnie Flux (szerzej opisany w [1]). Przepływ danych
we Fluxie został przedstawiony na rysunku 3.1: Flux składa się z kilku głównych elemen-
tów (rysunek 3.1). Przepływ sterowania odbywa się w pętli po każdym z nich. Poniżej ich
opis (ułożone są chronologicznie, od punktu rozpoczęcia interakcji przez użytkownika, aż
do pełnego przerysowania dokumentu HTML):
• Widok
Komponent Reacta. Wchodzi w interakcje z użytkownikiem, renderuje HTML. Opi-
sany szerzej w 3.1.1
• Action Creator
Dodatkowa warstwa abstrakcji służąca do tworzenia akcji. Została utworzona po
to, aby programista inicjował zmiany danych tylko w jednym miejscu. Jego funk-
cje mogą przyjmować argumenty, wynikiem ich działania jest przekazanie akcji do
Dispatchera
Rozdział 3. Opis technologii 50
• Dispatcher
Kolejna warstwa abstrakcji. W tym miejscu podejmowane są decyzje, co należy
zrobić z akcją. Zazwyczaj przekazywane są dalej, jednak możliwe są inne możliwości.
Poniżej wycinek kodu z Dispatchera zaimplementowanej aplikacji. Akcja o typie
”TODO CREATE” jest wywoływana tylko wtedy, gdy jej atrybut ”text” nie jest
pusty:
Listing 3.5: Część kodu obiektu Dispatcher
1 switch(action.actionType) {
2 case TodoConstants. TODO_LOAD_ALL_COMPLETE :
3 TodoStore.emitChange ();
4 break;
5
6 case TodoConstants.TODO_CREATE:
7 text = action.text.trim ();
8 if (text !== ’’) {
9 create(text);
10 }
11 break;
12 // ...
13 }
• Store
Centralny punkt składowania danych, również miejsce komunikacji z API. W zaim-
plementowanej aplikacji do tego celu została użytka biblioteka BackboneJS (opisana
szerzej w 3.1.8). Po wykonaniu działań na danych, obiekt Store emituje globalne zda-
rzenie, na które reagują wszystkie komponenty. Cały interfejs, wszystkie formularze,
przyciski, pola tekstowe zostają wyrenderowane ponownie. Wydaje się, że jest to nie-
efektywne działanie i przy standardowym pełnym odświeżeniu tak by było. Jednak
jedna bardzo ważna właściwość Reacta sprawia, że takie działanie ma sens.
3.1.5 Virtual DOM
DOM został stworzony do reprezentacji dokumentów HTML niezależnie od platfor-
my i języka. Ma strukturę drzewa. Przez długi czas był stosowany tylko do wyświetlenia
informacji. Nie został stworzony z myślą o złożonych operacjach dodawania, usuwania i
zmieniania węzłów. Te uwarunkowania czynią działania na nim wąskim gardłem (co po-
kazały testy przeprowadzone przez autorów pracy 4, a także przeprowadzone przez inne
osoby). React został zaprojektowany z myślą o przejrzystej architekturze i łatwo roz-
Rozdział 3. Opis technologii 51
wijalnym, modularnym kodzie. Rozpoznawalny jest jednak chyba głównie dzięki swojej
wydajności. Z każdą zmianą stanu, React przerenderowuje całą aplikację. Jednak robi to
w specyficzny sposób.
Virtual DOM to dodatkowa warstwa abstrakcji, lekka kopia prawdziwego DOM. Wszystkie
zmiany stanu są odzwierciedlane najpierw w Virtual DOM. Operacje na nim są szybsze,
gdyż obiekt ten jest tylko wirtualny - nie musi zostać przerysowywany po każdej opera-
cji. W przypadku zwyczajnego DOM bardzo często zdarza się, że przeplatając operacje
odczytu i zapisu, wymagany jest tzw. ”reflow” i to nawet kilkukrotny. Ilustruje to listing
3.6:
Listing 3.6: Operacje na DOM przykład
1 // Wejscie
2 <div>
3 <div>a</div>
4 <div>b</div>
5 </div>
6
7 // Wyjscie
8 <div>
9 <div>c</div>
10 <div>d</div>
11 </div>
W standardowej manipulacji na DOM, przeglądarka wykonałaby ”reflow” 4 razy. Przy
operowaniu na znaczącej liczbie węzłów liczonej w tysiącach, byłoby to już zauważalne
dla użytkownika. React oblicza minimalną liczbę zmian między drzewami (diff algorithm),
a dopiero później aplikuje je do DOM. Dlatego fakt, że cała aplikacja przerysowuje się z
każdą zmianą danych, nie niesie za sobą spadku wydajności, a jedynie wzrost przejrzystości
architektury.
3.1.6 Diff Algorithm
Operacja obliczania minimalnej liczby transformacji jednego drzewa w drugie ma zlo-
żoność rzędu O(n3
). W przypadku manipulacji tysiącem węzłów (co nie jest rzadkim
przypadkiem), koniecznie jest wykonanie jednego miliarda operacji. Taka złożoność jest
jednak nie do przyjęcia. Autorzy Reacta oparli swój algorytm na dwóch dodatkowych
założeniach:
• Dwa komponenty tej samej klasy wygenerują podobne drzewa, a dwa komponenty
różnych klas wygenerują różne drzewa.
Rozdział 3. Opis technologii 52
• Możliwym jest dostarczenie unikalnych kluczy, dla elementów niezmiennych przy
ponownym rysowaniu.
Algorytm porównywania drzew ma rekurencyjny charakter. Zatem chcąc operować na
całym drzewie, należy najpierw zdefiniować operację na jednym węźle. React rozróżnia 3
typy takiej operacji:
• Różne typy węzła
Listing 3.7: React transformacja węzłów różnych typów
1 renderA: <div />
2 renderB: <span />
3 => [removeNode <div />], [insertNode <span />]
W takim przypadku React nie podejmuje próby negoncjacji atrybutów, czy węzłów
potomnych. Cała gałąź drzewa zostaje usunięta i zastąpiona nową.
• Zgodne typy węzła
Listing 3.8: React transformacja węzłów o takich samych typach
1 renderA: <div style ={{ color: ’red’}} />
2 renderB: <div style ={{ fontWeight: ’bold ’}} />
3 => [removeStyle color], [addStyle font -weight ’bold ’]
Tutaj bardziej opłacalnym działaniem staje się zmiana atrybutu. Należy dodać, że
style elementu (które w HTML są po prostu zmienną typu String), traktowane są
jako tablica asocjacyjna.
• Inteligentne operowanie na liście
Najbardziej problematyczne jest obliczanie różnic w liście węzłów. Przypadek ze
stałą liczbą elementów jest prosty - React porównuje po prostu obie listy, element
po elemencie. Złożoność operacji to O(n). Dodanie elementu na końcu listy, również
nie jest skomplikowane (złożoność nie wzrasta). Co jednak w przypadku dodawania
elementów na początku lub w środku listy? Rozwiązaniem tego problemu mogłoby
być obliczenie odległośi Levenshteina (złożoność O(n2
)). Jednak ten algorytm mimo
wyższej złożoności, nie pozwala na wykrycie zmiany kolejności elementów. Algoryt-
my, które na to pozwalają, mają jeszcze większą złożoność.
Rozdział 3. Opis technologii 53
Twórcy Reacta zaproponowali prostsze rozwiązanie. Zamiast skomplikowaych ob-
liczeń na elementach listy, nadali każdemu z nich unikalny (w lokalnym zakresie)
klucz, niezmienialny przy kolejnych przerysowaniach. Dzięki temu iterowanie po li-
ście sprowadza się do iteracji po wszystkich kluczach tablicy asocjacyjnej (złożoność
O(n)).
3.1.7 JSX
Kolejną rzeczą wyróżniającą Reacta jest biblioteka JSX do pisania szablonów. Należy
zaznaczyć, że jest całkiem opcjonalna. Dzięki niej programista może osadzać elementy o
bardzo podobnej składni do HTMLa, w kodzie JavaScript. Różnice obu podejść na listingu
3.9
Listing 3.9: Porównanie budowy szablonów z użyciem JSX i bez
1 // Komponent HelloMessage zbudowany z pomoca JSX
2 var HelloMessage = React.createClass ({
3 render: function () {
4 return <div >Hello {this.props.name}</div >;
5 }
6 });
7 React.render(<HelloMessage name="John" />, mountNode);
8
9 // Komponent HelloMessage zbudowany w czystym JS
10 var HelloMessage = React.createClass ({ displayName: "HelloMessage",
11 render: function () {
12 return React.createElement("div", null , "Hello ", this.props.name
);
13 }
14 });
15 React.render(React.createElement(HelloMessage , {name: "John"}),
mountNode);
3.1.8 Backbone
React, czy też architektura Flux, nie dostarcza gotowych narzędzi do komunikacji z
API. Programista ma więc wolny wybór. Istnieje możliwość używania czystego JavaScrip-
tu, jQuery lub dodatkowej biblioteki. Bardzo często spotyka się implementacje Fluxa wraz
z minimalistyczną biblioteką BackboneJS, która dostarcza dodatkową warstwę abstrakcji,
w postaci modeli i kolekcji. Dzięki nim nie ma potrzeby konstruowania skomplikowanych
Rozdział 3. Opis technologii 54
zapytań XHR. Wszystko to zostało opakowane w wygodne funkcje, np. fetch() - do po-
bierania listy obiektów, save() - zapisywania stanu obiektu na serwerze, czy destroy() -
do usuwania obiektu.
3.2 AngularJS
Angular z języka angielskiego znaczy w tłumaczeniu dosłownym kanciasty, kątowy,
narożny. Czy nazwa tego frameworka mówi coś więcej na temat jego funkcjonalności, ten
rozdział postara się na to i inne pytania odpowiedzieć. AngularJS jest to zestaw narzę-
dzi JavaScript do tworzenia aplikacji frontendowych typu SPA. Koncepcja SPA została
omówiona w rozdziale 2.3. Historia Angulara sięga roku 2009. W początkowym etapie
projekt ten był zaledwie małym prywatnym pomysłem realizowanym przez pracowników
firmy Google Adama Abronsa i Misko Hevery’ego. Zarząd koncernu Google uznał projekt
AngularJS na tyle ciekawy, że otrzymał oficjalne wsparcie wraz z zespołem programi-
stów który miał za zadanie go rozwijać. W 2012 roku po raz pierwszy framework został
upubliczniony. Wiele zalet Angulara zaczerpnięto ze sprawdzonych metod, co pozwoliło
na stworzenie wydajnego i efektywnego frameworka, który zapewnia nieskomplikowaną
strukturę, szerokie spektrum możliwości oraz wygodne metody testowania. Bardzo duży
udział w rozwoju Angulara ma także społeczność internetowa. Dzięki ciągłej wymianie do-
świadczeń pomiędzy programistami AngularJS framework jest poddawany ciągłym ulep-
szeniom. Programiści chcący poznać wady i zalety Angulara w praktyce powinni odwiedzić
stronę [8] na której znajdują się dokumentacje, kursy, poradniki, opisy API i inne rzeczy
przydatne dla deweloperów. Przykłady aplikacji napisanych w Angularze znajdziemy na
stronie https://builtwith.angularjs.org/. Bardzo istotnym aspektem dotyczącym Angula-
ra jest fakt, iż jest on publikowany na licencji MIT, co oznacza, że jest w pełni darmowy.
AngularJS pozwala w teorii w szybki i łatwy sposób budować warstwę kliencką aplikacji
internetowych. Koncepcja omawianego frameworka zakłada tzw. MVW, czyli organizację
aplikacji w obrębie model-widok-cokolwiek dzięki, czemu można pogodzić idee JavaScript
z modelem MVC. W ostatnim czasie omawiany framwework stał się bardzo popularny,
co zaobserwować możemy na wykresie 3.2 oraz zaczął być wykorzystywany w aplikacjach
typu enterprise. Za pomocą Angulara stworzone zostały między innymi YouTube na Play
Station 3 oraz platforma muzyczna VEVO.
AngularJS posiada kilka interesujących rozwiązań, których próżno szukać w innych
frameworkach. Oto niektóre z nich:
Rozdział 3. Opis technologii 55
Rysunek 3.2: Porównanie ilości ofert pracy dla popularnych platform klienckich typu
MVC, [źródło: http://www.indeed.com/jobtrends].
3.2.1 Kompilator HTML
Główną cechą odróżniającą Angulara od reszty tego typu narzędzi to fakt posiadania
własnego kompilatora HTML. Dzięki temu można w prosty sposób rozszerzyć HTML o
nowe zdeiniowne wcześniej tagi, które mogą realizować nowe funkcje.
3.2.2 Dwustronne wiązanie danych
W przeszłości, zanim technologia AJAX opisana w rozdziale 2.2, była szerzej wykorzy-
stywana, do konstruowania interfejsu użytkownika wykorzystywane były narzędzia typu
PHP, Rails, ASP.NET lub inne. Serwer odpowiadał za generowanie widoku HTML przed
prezentacją go dla użytkownika. Dzięki wykorzystaniu biblioteki jQuery dla języka Ja-
vaScript można odświerzać wybrane elementy DOM bez konieczności przeładowywania
całej strony. W HTML wstrzykiwane są dane, a następnie wynik jest dodawany do do-
wolnej części DOM z wykorzystaniem atrybutu ”inneHtml” dla właściwego elementu. W
koncepcji one way binding informacje są pobierane z modelu, który służy za swego ro-
dzaju kontener do przechowywania danych i wysyłane do widoku, który ma za zadanie je
wyświetlić. Natomiast nie istnieje możliwość wpływania na model z poziomu widoku przy
tym podejściu. Zgodnie z diagramem 3.3 dane synchronizowane są tylko z widokiem, to
znaczy, że programista musi zaimplementować mechanizm synchronizacji widoku z mo-
delem, gdy przykładowo użytkownik wprowadzi dane do aplikacji. Przykładem takiego
frameworka jest BackboneJS. Problem ten został rozwiązany w Angularze. Omawiany
Rozdział 3. Opis technologii 56
Rysunek 3.3: Jednostronne wiązanie danych w AngularJS, [źródło: https://docs.
angularjs.org/guide/databinding].
framework posiada tak zwane dwustronne wiązanie danych, które pozwala na synchroni-
zację stanu widoku i modelu po stronie JavaScript. Wystarczy dodać prostą deklarację,
która zdefiniuje, jakie obiekty po stronie kontrolera lub widoku będą ze sobą powiązane.
W tej deklaracji wykorzystujemy obiekt $scope oraz dyrektywę ”ng-model”. Na rysun-
ku 3.4 możemy zobaczyć, że gdy dajmy na to, zostanie wprowadzona zmiana w widoku,
przykładowo wprowadzimy tekst w polu formularza, to dane te automatycznie zostaną
zsynchronizowane z modelem. Podobnie działa to w drugą stronę. To znaczy, gdy przy-
kładowo dane w modelu zmienią się w wyniku odpowiedzi na zapytanie do API serwera,
to mechanizm podwójnego wiązania uaktualni te dane w widoku, czyli w warstwie pre-
zentacji dla użytkownika. Dzieki temu rozwiązaniu programista jest odciążony z dbania o
aktualny stan danych w każdym miejscu w aplikacji.
3.2.3 Obiekt $scope
Charakterystyczną cechą Angulara jest obiekt $scope. Służy on do transportowania
modelu pomiędzy widokiem a kontrolerem. Odpowiada też za nasłuchiwanie zdarzeń lub
zmian zachodzących w modelu, a także za propagację tych zmian. Pomimo że $scope jest
traktowany przez twórców omawianego frameworka, w sposób wyjątkowy to wpsomniany
obiekt jest tak naprawdę zwykłym obiektem typu POJO, którego atrybutami możemy
Rozdział 3. Opis technologii 57
Rysunek 3.4: Dwustronne wiązanie danych w AngularJS, [źródło: https://docs.
angularjs.org/guide/databinding].
dowolnie manipulować. Warty uwagi jest fakt, iż generalnie $scope jest tworzony i wstrzy-
kiwany w sposób automatyczny bez udziału programisty. AngularJS w początkowej fazie
ładowania aplikacji tworzy powiązanie między tagiem zawierającym dyrektywę ”ng-app”
a wszystkimi elementami znajdującymi się poniżej obiektu $scope. Najwyżej w hierarchii
obiektów znajduje się $rootScope, który jest rodzicem wszystkich obiektów $scope. Każ-
da aplikacja posiada tylko jeden obiekt typu $rootScope, po którym dziedziczą wszystkie
inne obiekty $scope. W fazie początkowej ładowania aplikacji tworzona jest nadrzędna
instancja $rootScope. Dobrą praktyką jest relatywnie mała liczba atrybutów przypiasna
do niego, gdyż pełni on rolę obiektu golobalnego, który powinien zawierać tylko rzeczy
najistotniejsze. Przy korzystaniu z dużej ilości bibliotek zewnętrznych pojawia się ryzyko,
iż wystąpi zbieżność nazw medod lub atrybutów przypisanych do obiektów typu $rootSco-
pe dlatego też unikanie tego rodzaju sytuacji może zaoczędzić programiście wiele czasu
i nerwów. W związku z tym, że zmienna $scope jest inicjalizowana w procesie począt-
kowego ładowania aplikacji, czyli tzw. bootstrap elementy przypisane tej zmiennej są od
początku dostępne w widoku. Na listingu 3.10 zaczerpniętego z książki [7] mamy przy-
kład przypisywania funkcji i atrybutów do modelu po stronie kontrolera. W omawianym
przykładzie został zdefiniowany atrybut dateOriginal w globalnym obiekcie $rootScope a
Master Thesis - Comparative analysis of programming Environments based on Ruby and JavaScript.
Master Thesis - Comparative analysis of programming Environments based on Ruby and JavaScript.
Master Thesis - Comparative analysis of programming Environments based on Ruby and JavaScript.
Master Thesis - Comparative analysis of programming Environments based on Ruby and JavaScript.
Master Thesis - Comparative analysis of programming Environments based on Ruby and JavaScript.
Master Thesis - Comparative analysis of programming Environments based on Ruby and JavaScript.
Master Thesis - Comparative analysis of programming Environments based on Ruby and JavaScript.
Master Thesis - Comparative analysis of programming Environments based on Ruby and JavaScript.
Master Thesis - Comparative analysis of programming Environments based on Ruby and JavaScript.
Master Thesis - Comparative analysis of programming Environments based on Ruby and JavaScript.
Master Thesis - Comparative analysis of programming Environments based on Ruby and JavaScript.
Master Thesis - Comparative analysis of programming Environments based on Ruby and JavaScript.
Master Thesis - Comparative analysis of programming Environments based on Ruby and JavaScript.
Master Thesis - Comparative analysis of programming Environments based on Ruby and JavaScript.
Master Thesis - Comparative analysis of programming Environments based on Ruby and JavaScript.
Master Thesis - Comparative analysis of programming Environments based on Ruby and JavaScript.
Master Thesis - Comparative analysis of programming Environments based on Ruby and JavaScript.
Master Thesis - Comparative analysis of programming Environments based on Ruby and JavaScript.
Master Thesis - Comparative analysis of programming Environments based on Ruby and JavaScript.
Master Thesis - Comparative analysis of programming Environments based on Ruby and JavaScript.
Master Thesis - Comparative analysis of programming Environments based on Ruby and JavaScript.
Master Thesis - Comparative analysis of programming Environments based on Ruby and JavaScript.
Master Thesis - Comparative analysis of programming Environments based on Ruby and JavaScript.
Master Thesis - Comparative analysis of programming Environments based on Ruby and JavaScript.
Master Thesis - Comparative analysis of programming Environments based on Ruby and JavaScript.
Master Thesis - Comparative analysis of programming Environments based on Ruby and JavaScript.
Master Thesis - Comparative analysis of programming Environments based on Ruby and JavaScript.
Master Thesis - Comparative analysis of programming Environments based on Ruby and JavaScript.
Master Thesis - Comparative analysis of programming Environments based on Ruby and JavaScript.
Master Thesis - Comparative analysis of programming Environments based on Ruby and JavaScript.
Master Thesis - Comparative analysis of programming Environments based on Ruby and JavaScript.
Master Thesis - Comparative analysis of programming Environments based on Ruby and JavaScript.
Master Thesis - Comparative analysis of programming Environments based on Ruby and JavaScript.
Master Thesis - Comparative analysis of programming Environments based on Ruby and JavaScript.
Master Thesis - Comparative analysis of programming Environments based on Ruby and JavaScript.
Master Thesis - Comparative analysis of programming Environments based on Ruby and JavaScript.
Master Thesis - Comparative analysis of programming Environments based on Ruby and JavaScript.
Master Thesis - Comparative analysis of programming Environments based on Ruby and JavaScript.
Master Thesis - Comparative analysis of programming Environments based on Ruby and JavaScript.
Master Thesis - Comparative analysis of programming Environments based on Ruby and JavaScript.
Master Thesis - Comparative analysis of programming Environments based on Ruby and JavaScript.
Master Thesis - Comparative analysis of programming Environments based on Ruby and JavaScript.
Master Thesis - Comparative analysis of programming Environments based on Ruby and JavaScript.
Master Thesis - Comparative analysis of programming Environments based on Ruby and JavaScript.
Master Thesis - Comparative analysis of programming Environments based on Ruby and JavaScript.
Master Thesis - Comparative analysis of programming Environments based on Ruby and JavaScript.
Master Thesis - Comparative analysis of programming Environments based on Ruby and JavaScript.
Master Thesis - Comparative analysis of programming Environments based on Ruby and JavaScript.
Master Thesis - Comparative analysis of programming Environments based on Ruby and JavaScript.
Master Thesis - Comparative analysis of programming Environments based on Ruby and JavaScript.
Master Thesis - Comparative analysis of programming Environments based on Ruby and JavaScript.
Master Thesis - Comparative analysis of programming Environments based on Ruby and JavaScript.
Master Thesis - Comparative analysis of programming Environments based on Ruby and JavaScript.

More Related Content

What's hot

Phân tích tình tài chính tại công ty tnhh xây dựng và thương mại nam hải
Phân tích tình tài chính tại công ty tnhh xây dựng và thương mại nam hảiPhân tích tình tài chính tại công ty tnhh xây dựng và thương mại nam hải
Phân tích tình tài chính tại công ty tnhh xây dựng và thương mại nam hảihttps://www.facebook.com/garmentspace
 
Luận văn: Hoàn thiện quản lý tài chính tại các trường đại học công lập tự chủ...
Luận văn: Hoàn thiện quản lý tài chính tại các trường đại học công lập tự chủ...Luận văn: Hoàn thiện quản lý tài chính tại các trường đại học công lập tự chủ...
Luận văn: Hoàn thiện quản lý tài chính tại các trường đại học công lập tự chủ...Viết thuê trọn gói ZALO 0934573149
 
CASE IH JX95 TRACTOR Service Repair Manual
CASE IH JX95 TRACTOR Service Repair ManualCASE IH JX95 TRACTOR Service Repair Manual
CASE IH JX95 TRACTOR Service Repair Manualjkejdkm
 
Đề tài: Hoàn thiện công tác kế toán doanh thu, chi phí và xác định kết quả ki...
Đề tài: Hoàn thiện công tác kế toán doanh thu, chi phí và xác định kết quả ki...Đề tài: Hoàn thiện công tác kế toán doanh thu, chi phí và xác định kết quả ki...
Đề tài: Hoàn thiện công tác kế toán doanh thu, chi phí và xác định kết quả ki...Viết thuê trọn gói ZALO 0934573149
 
Luận Văn Các Yếu Tố Tác Động Đến Tỷ Suất Sinh Lợi Theo Mô Hình Fama French 3 ...
Luận Văn Các Yếu Tố Tác Động Đến Tỷ Suất Sinh Lợi Theo Mô Hình Fama French 3 ...Luận Văn Các Yếu Tố Tác Động Đến Tỷ Suất Sinh Lợi Theo Mô Hình Fama French 3 ...
Luận Văn Các Yếu Tố Tác Động Đến Tỷ Suất Sinh Lợi Theo Mô Hình Fama French 3 ...Viết Thuê Luận Văn Luanvanpanda.com
 
Giải pháp nâng cao chất lượng cho vay tại ngân hàng thương mại cổ phần đông á
Giải pháp nâng cao chất lượng cho vay tại ngân hàng thương mại cổ phần đông áGiải pháp nâng cao chất lượng cho vay tại ngân hàng thương mại cổ phần đông á
Giải pháp nâng cao chất lượng cho vay tại ngân hàng thương mại cổ phần đông áhttps://www.facebook.com/garmentspace
 
Hiệu quả sử dụng vốn kinh doanh tại Công ty cổ phần Dịch vụ đường cao tốc Việ...
Hiệu quả sử dụng vốn kinh doanh tại Công ty cổ phần Dịch vụ đường cao tốc Việ...Hiệu quả sử dụng vốn kinh doanh tại Công ty cổ phần Dịch vụ đường cao tốc Việ...
Hiệu quả sử dụng vốn kinh doanh tại Công ty cổ phần Dịch vụ đường cao tốc Việ...luanvantrust
 
CASE IH JX90 TRACTOR Service Repair Manual
CASE IH JX90 TRACTOR Service Repair ManualCASE IH JX90 TRACTOR Service Repair Manual
CASE IH JX90 TRACTOR Service Repair Manualjksemmmd
 
Đề tài: Biện pháp nhằm cải thiện tình hình tài chính công ty cổ phần cảng Nam...
Đề tài: Biện pháp nhằm cải thiện tình hình tài chính công ty cổ phần cảng Nam...Đề tài: Biện pháp nhằm cải thiện tình hình tài chính công ty cổ phần cảng Nam...
Đề tài: Biện pháp nhằm cải thiện tình hình tài chính công ty cổ phần cảng Nam...Viết thuê trọn gói ZALO 0934573149
 
Giải Pháp Nhằm Hoàn Thiện Hoạt Động Quản Trị Bán Hàng Tại Công Ty Bánh Kẹo.docx
Giải Pháp Nhằm Hoàn Thiện Hoạt Động Quản Trị Bán Hàng Tại Công Ty Bánh Kẹo.docxGiải Pháp Nhằm Hoàn Thiện Hoạt Động Quản Trị Bán Hàng Tại Công Ty Bánh Kẹo.docx
Giải Pháp Nhằm Hoàn Thiện Hoạt Động Quản Trị Bán Hàng Tại Công Ty Bánh Kẹo.docxNhận Viết Đề Tài Trọn Gói ZALO 0932091562
 
Thực trạng và giải pháp nâng cao hiệu quả sử dụng vốn lưu động tại công ty cổ...
Thực trạng và giải pháp nâng cao hiệu quả sử dụng vốn lưu động tại công ty cổ...Thực trạng và giải pháp nâng cao hiệu quả sử dụng vốn lưu động tại công ty cổ...
Thực trạng và giải pháp nâng cao hiệu quả sử dụng vốn lưu động tại công ty cổ...https://www.facebook.com/garmentspace
 
Quan ly chat luong bai giang
Quan ly chat luong  bai giangQuan ly chat luong  bai giang
Quan ly chat luong bai gianghoanglamhn2012
 

What's hot (20)

Đề tài: Hoàn thiện công tác Quản trị bán hàng của cty Nhựa Nam Việt
Đề tài: Hoàn thiện công tác Quản trị bán hàng của cty Nhựa Nam ViệtĐề tài: Hoàn thiện công tác Quản trị bán hàng của cty Nhựa Nam Việt
Đề tài: Hoàn thiện công tác Quản trị bán hàng của cty Nhựa Nam Việt
 
Phân tích tình tài chính tại công ty tnhh xây dựng và thương mại nam hải
Phân tích tình tài chính tại công ty tnhh xây dựng và thương mại nam hảiPhân tích tình tài chính tại công ty tnhh xây dựng và thương mại nam hải
Phân tích tình tài chính tại công ty tnhh xây dựng và thương mại nam hải
 
Luận văn: Hoàn thiện quản lý tài chính tại các trường đại học công lập tự chủ...
Luận văn: Hoàn thiện quản lý tài chính tại các trường đại học công lập tự chủ...Luận văn: Hoàn thiện quản lý tài chính tại các trường đại học công lập tự chủ...
Luận văn: Hoàn thiện quản lý tài chính tại các trường đại học công lập tự chủ...
 
Đề tài: Thẩm định giá máy, thiết bị làm tài sản đảm bảo tại VietBank
Đề tài: Thẩm định giá máy, thiết bị làm tài sản đảm bảo tại VietBankĐề tài: Thẩm định giá máy, thiết bị làm tài sản đảm bảo tại VietBank
Đề tài: Thẩm định giá máy, thiết bị làm tài sản đảm bảo tại VietBank
 
CASE IH JX95 TRACTOR Service Repair Manual
CASE IH JX95 TRACTOR Service Repair ManualCASE IH JX95 TRACTOR Service Repair Manual
CASE IH JX95 TRACTOR Service Repair Manual
 
Đề tài: Hoàn thiện công tác kế toán doanh thu, chi phí và xác định kết quả ki...
Đề tài: Hoàn thiện công tác kế toán doanh thu, chi phí và xác định kết quả ki...Đề tài: Hoàn thiện công tác kế toán doanh thu, chi phí và xác định kết quả ki...
Đề tài: Hoàn thiện công tác kế toán doanh thu, chi phí và xác định kết quả ki...
 
Báo Cáo Thực Tập Hoàn Thiện Hoạt Động Bán Hàng Ô Tô Của Công Ty.docx
Báo Cáo Thực Tập  Hoàn Thiện Hoạt Động Bán Hàng Ô Tô Của Công Ty.docxBáo Cáo Thực Tập  Hoàn Thiện Hoạt Động Bán Hàng Ô Tô Của Công Ty.docx
Báo Cáo Thực Tập Hoàn Thiện Hoạt Động Bán Hàng Ô Tô Của Công Ty.docx
 
Luận Văn Các Yếu Tố Tác Động Đến Tỷ Suất Sinh Lợi Theo Mô Hình Fama French 3 ...
Luận Văn Các Yếu Tố Tác Động Đến Tỷ Suất Sinh Lợi Theo Mô Hình Fama French 3 ...Luận Văn Các Yếu Tố Tác Động Đến Tỷ Suất Sinh Lợi Theo Mô Hình Fama French 3 ...
Luận Văn Các Yếu Tố Tác Động Đến Tỷ Suất Sinh Lợi Theo Mô Hình Fama French 3 ...
 
Báo cáo thực tập khoa Kế toán Trường đại học lao động – xã hội.docx
Báo cáo thực tập khoa Kế toán Trường đại học lao động – xã hội.docxBáo cáo thực tập khoa Kế toán Trường đại học lao động – xã hội.docx
Báo cáo thực tập khoa Kế toán Trường đại học lao động – xã hội.docx
 
Giải pháp nâng cao chất lượng cho vay tại ngân hàng thương mại cổ phần đông á
Giải pháp nâng cao chất lượng cho vay tại ngân hàng thương mại cổ phần đông áGiải pháp nâng cao chất lượng cho vay tại ngân hàng thương mại cổ phần đông á
Giải pháp nâng cao chất lượng cho vay tại ngân hàng thương mại cổ phần đông á
 
Hiệu quả sử dụng vốn kinh doanh tại Công ty cổ phần Dịch vụ đường cao tốc Việ...
Hiệu quả sử dụng vốn kinh doanh tại Công ty cổ phần Dịch vụ đường cao tốc Việ...Hiệu quả sử dụng vốn kinh doanh tại Công ty cổ phần Dịch vụ đường cao tốc Việ...
Hiệu quả sử dụng vốn kinh doanh tại Công ty cổ phần Dịch vụ đường cao tốc Việ...
 
Kế toán nguyên vật liệu tại công ty xây dựng Bạch Đằng 234, 9đ
Kế toán nguyên vật liệu tại công ty xây dựng Bạch Đằng 234, 9đKế toán nguyên vật liệu tại công ty xây dựng Bạch Đằng 234, 9đ
Kế toán nguyên vật liệu tại công ty xây dựng Bạch Đằng 234, 9đ
 
CASE IH JX90 TRACTOR Service Repair Manual
CASE IH JX90 TRACTOR Service Repair ManualCASE IH JX90 TRACTOR Service Repair Manual
CASE IH JX90 TRACTOR Service Repair Manual
 
Đề tài: Biện pháp nhằm cải thiện tình hình tài chính công ty cổ phần cảng Nam...
Đề tài: Biện pháp nhằm cải thiện tình hình tài chính công ty cổ phần cảng Nam...Đề tài: Biện pháp nhằm cải thiện tình hình tài chính công ty cổ phần cảng Nam...
Đề tài: Biện pháp nhằm cải thiện tình hình tài chính công ty cổ phần cảng Nam...
 
Giải Pháp Nhằm Hoàn Thiện Hoạt Động Quản Trị Bán Hàng Tại Công Ty Bánh Kẹo.docx
Giải Pháp Nhằm Hoàn Thiện Hoạt Động Quản Trị Bán Hàng Tại Công Ty Bánh Kẹo.docxGiải Pháp Nhằm Hoàn Thiện Hoạt Động Quản Trị Bán Hàng Tại Công Ty Bánh Kẹo.docx
Giải Pháp Nhằm Hoàn Thiện Hoạt Động Quản Trị Bán Hàng Tại Công Ty Bánh Kẹo.docx
 
Thực trạng và giải pháp nâng cao hiệu quả sử dụng vốn lưu động tại công ty cổ...
Thực trạng và giải pháp nâng cao hiệu quả sử dụng vốn lưu động tại công ty cổ...Thực trạng và giải pháp nâng cao hiệu quả sử dụng vốn lưu động tại công ty cổ...
Thực trạng và giải pháp nâng cao hiệu quả sử dụng vốn lưu động tại công ty cổ...
 
Quan ly chat luong bai giang
Quan ly chat luong  bai giangQuan ly chat luong  bai giang
Quan ly chat luong bai giang
 
De cuong so bo
De cuong so boDe cuong so bo
De cuong so bo
 
Đề tài thực trạng kinh doanh vi tính, ĐIỂM 8
Đề tài  thực trạng kinh doanh vi tính, ĐIỂM 8Đề tài  thực trạng kinh doanh vi tính, ĐIỂM 8
Đề tài thực trạng kinh doanh vi tính, ĐIỂM 8
 
Đề tài: Phân tích hiệu quả sử dụng vốn tại Công ty TNHH, HAY, 9 Điểm!
Đề tài: Phân tích hiệu quả sử dụng vốn tại Công ty TNHH, HAY, 9 Điểm!Đề tài: Phân tích hiệu quả sử dụng vốn tại Công ty TNHH, HAY, 9 Điểm!
Đề tài: Phân tích hiệu quả sử dụng vốn tại Công ty TNHH, HAY, 9 Điểm!
 

Similar to Master Thesis - Comparative analysis of programming Environments based on Ruby and JavaScript.

Core Java Servlets i JavaServer Pages. Tom II. Wydanie II
Core Java Servlets i JavaServer Pages. Tom II. Wydanie IICore Java Servlets i JavaServer Pages. Tom II. Wydanie II
Core Java Servlets i JavaServer Pages. Tom II. Wydanie IIWydawnictwo Helion
 
Tworzenie aplikacji dla Windows. Od prostych programów do gier komputerowych
Tworzenie aplikacji dla Windows. Od prostych programów do gier komputerowychTworzenie aplikacji dla Windows. Od prostych programów do gier komputerowych
Tworzenie aplikacji dla Windows. Od prostych programów do gier komputerowychWydawnictwo Helion
 
Mikrokontrolery avr język c podstawy programowania
Mikrokontrolery avr język c podstawy programowaniaMikrokontrolery avr język c podstawy programowania
Mikrokontrolery avr język c podstawy programowaniaWKL49
 
Mikrokontrolery avr język c podstawy programowania
Mikrokontrolery avr język c podstawy programowaniaMikrokontrolery avr język c podstawy programowania
Mikrokontrolery avr język c podstawy programowaniaWKL49
 
Microsoft Visual C++ 2008. Tworzenie aplikacji dla Windows
Microsoft Visual C++ 2008. Tworzenie aplikacji dla WindowsMicrosoft Visual C++ 2008. Tworzenie aplikacji dla Windows
Microsoft Visual C++ 2008. Tworzenie aplikacji dla WindowsWydawnictwo Helion
 
Wybrane zagadnienia wizualizacji wirtualnego środowiska za pomocą biblioteki ...
Wybrane zagadnienia wizualizacji wirtualnego środowiska za pomocą biblioteki ...Wybrane zagadnienia wizualizacji wirtualnego środowiska za pomocą biblioteki ...
Wybrane zagadnienia wizualizacji wirtualnego środowiska za pomocą biblioteki ...Łukasz Szczepański
 
.Net. Najpilniej strzeżone tajemnice
.Net. Najpilniej strzeżone tajemnice.Net. Najpilniej strzeżone tajemnice
.Net. Najpilniej strzeżone tajemniceWydawnictwo Helion
 
Visual Basic 2008. Warsztat programisty
Visual Basic 2008. Warsztat programistyVisual Basic 2008. Warsztat programisty
Visual Basic 2008. Warsztat programistyWydawnictwo Helion
 
Java. Techniki zaawansowane. Wydanie VIII
Java. Techniki zaawansowane. Wydanie VIIIJava. Techniki zaawansowane. Wydanie VIII
Java. Techniki zaawansowane. Wydanie VIIIWydawnictwo Helion
 
Czytanie kodu. Punkt widzenia twórców oprogramowania open source
Czytanie kodu. Punkt widzenia twórców oprogramowania open sourceCzytanie kodu. Punkt widzenia twórców oprogramowania open source
Czytanie kodu. Punkt widzenia twórców oprogramowania open sourceWydawnictwo Helion
 
Ajax, JavaScript i PHP. Intensywny trening
Ajax, JavaScript i PHP. Intensywny treningAjax, JavaScript i PHP. Intensywny trening
Ajax, JavaScript i PHP. Intensywny treningWydawnictwo Helion
 
Oracle Database 11g. Programowanie w języku PL/SQL
Oracle Database 11g. Programowanie w języku PL/SQLOracle Database 11g. Programowanie w języku PL/SQL
Oracle Database 11g. Programowanie w języku PL/SQLWydawnictwo Helion
 
Serwer SQL 2008. Administracja i programowanie
Serwer SQL 2008. Administracja i programowanieSerwer SQL 2008. Administracja i programowanie
Serwer SQL 2008. Administracja i programowanieWydawnictwo Helion
 
Język C++. Gotowe rozwiązania dla programistów
Język C++. Gotowe rozwiązania dla programistówJęzyk C++. Gotowe rozwiązania dla programistów
Język C++. Gotowe rozwiązania dla programistówWydawnictwo Helion
 
Triangledigger Thesis
Triangledigger ThesisTriangledigger Thesis
Triangledigger Thesisguest7d27f2
 

Similar to Master Thesis - Comparative analysis of programming Environments based on Ruby and JavaScript. (20)

mgr
mgrmgr
mgr
 
Core Java Servlets i JavaServer Pages. Tom II. Wydanie II
Core Java Servlets i JavaServer Pages. Tom II. Wydanie IICore Java Servlets i JavaServer Pages. Tom II. Wydanie II
Core Java Servlets i JavaServer Pages. Tom II. Wydanie II
 
Tworzenie aplikacji dla Windows. Od prostych programów do gier komputerowych
Tworzenie aplikacji dla Windows. Od prostych programów do gier komputerowychTworzenie aplikacji dla Windows. Od prostych programów do gier komputerowych
Tworzenie aplikacji dla Windows. Od prostych programów do gier komputerowych
 
Inventor. Pierwsze kroki
Inventor. Pierwsze krokiInventor. Pierwsze kroki
Inventor. Pierwsze kroki
 
JavaScript. Pierwsze starcie
JavaScript. Pierwsze starcieJavaScript. Pierwsze starcie
JavaScript. Pierwsze starcie
 
Mikrokontrolery avr język c podstawy programowania
Mikrokontrolery avr język c podstawy programowaniaMikrokontrolery avr język c podstawy programowania
Mikrokontrolery avr język c podstawy programowania
 
Mikrokontrolery avr język c podstawy programowania
Mikrokontrolery avr język c podstawy programowaniaMikrokontrolery avr język c podstawy programowania
Mikrokontrolery avr język c podstawy programowania
 
Microsoft Visual C++ 2008. Tworzenie aplikacji dla Windows
Microsoft Visual C++ 2008. Tworzenie aplikacji dla WindowsMicrosoft Visual C++ 2008. Tworzenie aplikacji dla Windows
Microsoft Visual C++ 2008. Tworzenie aplikacji dla Windows
 
Uczta programistów
Uczta programistówUczta programistów
Uczta programistów
 
Wybrane zagadnienia wizualizacji wirtualnego środowiska za pomocą biblioteki ...
Wybrane zagadnienia wizualizacji wirtualnego środowiska za pomocą biblioteki ...Wybrane zagadnienia wizualizacji wirtualnego środowiska za pomocą biblioteki ...
Wybrane zagadnienia wizualizacji wirtualnego środowiska za pomocą biblioteki ...
 
.Net. Najpilniej strzeżone tajemnice
.Net. Najpilniej strzeżone tajemnice.Net. Najpilniej strzeżone tajemnice
.Net. Najpilniej strzeżone tajemnice
 
Visual Basic 2008. Warsztat programisty
Visual Basic 2008. Warsztat programistyVisual Basic 2008. Warsztat programisty
Visual Basic 2008. Warsztat programisty
 
Java. Techniki zaawansowane. Wydanie VIII
Java. Techniki zaawansowane. Wydanie VIIIJava. Techniki zaawansowane. Wydanie VIII
Java. Techniki zaawansowane. Wydanie VIII
 
Czytanie kodu. Punkt widzenia twórców oprogramowania open source
Czytanie kodu. Punkt widzenia twórców oprogramowania open sourceCzytanie kodu. Punkt widzenia twórców oprogramowania open source
Czytanie kodu. Punkt widzenia twórców oprogramowania open source
 
Ajax, JavaScript i PHP. Intensywny trening
Ajax, JavaScript i PHP. Intensywny treningAjax, JavaScript i PHP. Intensywny trening
Ajax, JavaScript i PHP. Intensywny trening
 
Oracle Database 11g. Programowanie w języku PL/SQL
Oracle Database 11g. Programowanie w języku PL/SQLOracle Database 11g. Programowanie w języku PL/SQL
Oracle Database 11g. Programowanie w języku PL/SQL
 
Windows PowerShell. Podstawy
Windows PowerShell. PodstawyWindows PowerShell. Podstawy
Windows PowerShell. Podstawy
 
Serwer SQL 2008. Administracja i programowanie
Serwer SQL 2008. Administracja i programowanieSerwer SQL 2008. Administracja i programowanie
Serwer SQL 2008. Administracja i programowanie
 
Język C++. Gotowe rozwiązania dla programistów
Język C++. Gotowe rozwiązania dla programistówJęzyk C++. Gotowe rozwiązania dla programistów
Język C++. Gotowe rozwiązania dla programistów
 
Triangledigger Thesis
Triangledigger ThesisTriangledigger Thesis
Triangledigger Thesis
 

Master Thesis - Comparative analysis of programming Environments based on Ruby and JavaScript.

  • 1. POLITECHNIKA POZNAŃSKA WYDZIAŁ ELEKTRYCZNY PRACA DYPLOMOWA MAGISTERSKA ANALIZA PORÓWNAWCZA ŚRODOWISK PROGRAMISTYCZNYCH OPARTYCH NA JĘZYKACH RUBY I JAVASCRIPT Adam SKOŁUDA Damian ROMANÓW Promotor: dr inż. Anna Grocholewska-Czuryło Poznań, 2015
  • 2.
  • 3. Streszczenie Analiza porównawcza środowisk programistycznych opartych na językach Ruby i Java- Script. W niniejszej pracy poddano analizie technologie do tworzenia aplikacji internetowych wykorzystujące Ruby i JavaScript. Dwa narzędzia dotyczące tworzenia części klienckich oraz trzy odpowiedzialne za logikę serwerową. Główny nacisk położony został na porów- nanie wybranych narzędzi. Wstęp dostarcza informacji wprowadzających do zagadnienia, a także przedstawia cel i podział pracy. Tłumaczy również motywację podjęcia tematu pracy oraz układ rozdziałów. Wprowadzanie teoretyczne opisuje niezbędne kwestie archi- tektury aplikacji internetowych, których zrozumienie jest kluczowe dla realizacji tematu. Opis technologii to obszerny i ważny rozdział przybliżający wybrane biblioteki. Powyższe rozdziały prowadzą do wielowymiarowej analizy. Rozdział ten jest porównaniem wybra- nych narzędzi, mającym na celu wskazanie faworytów w poszczególnych kategoriach. W zakończeniu znajduje się podsumowanie przeprowadzonych prac, wnioski płynące z ba- dań, a także subiektywna ocena badanych technologii. Podejmuje również polemikę na temat przyszłego kierunku rozwoju aplikacji internetowych.
  • 4.
  • 5. Abstract Comparative analysis of development environments based on Ruby and JavaScript. In this thesis, we analyzed technologies for creating web applications, using Ruby and JavaScript. Were chosen two tools for creating frontend and three responsible for the backend. The main emphasis has been on comparison of selected tools. Preface provides background information to the problem, presents the purpose and division of work. This also explains the motivation to take the topic of work and arrangement of chapters. Theoretical introduction describes the essential issues of web application architecture, the understanding of which is crucial for the realization of the theme. Description of the technology is a important chapter, which describes the selected libraries. These chapters lead to the multivariate analysis. This chapter is a comparison of selected tools, aimed to identify the best in each category. At the end, there is a summary of the work carried out, the conclusions of the study, as well as a subjective assessment of examined technologies. It also takes a polemic about the future direction of web applications.
  • 6.
  • 7. Spis treści Spis treści 7 Spis rysunków 10 Spis listingów 12 1 Wstęp 15 1.1 Motywacje podjęcia tematu . . . . . . . . . . . . . . . . . . . . . . . . . . 16 1.2 Podział prac . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 1.3 Cel pracy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18 1.4 Układ pracy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18 2 Wprowadzenie teorytyczne 19 2.1 REST . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20 2.2 AJAX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21 2.3 SPA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22 2.4 Model - View - Controller . . . . . . . . . . . . . . . . . . . . . . . . . . . 25 2.5 Języki . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26 2.5.1 Ruby . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 2.5.2 JavaScript . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30 2.6 Środowiska programistyczne . . . . . . . . . . . . . . . . . . . . . . . . . . 34 2.6.1 Ekosystem Rubiego . . . . . . . . . . . . . . . . . . . . . . . . . . . 34 2.6.2 Node . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38 2.7 Bezpieczeństwo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39 2.7.1 Uwierzytelnianie . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42 2.7.2 Autoryzacja . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42 3 Opis technologii 45 3.1 ReactJS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45 3.1.1 Deklaratywny charakter widoków . . . . . . . . . . . . . . . . . . . 46 7
  • 8. SPIS TREŚCI 8 3.1.2 Props . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47 3.1.3 State . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48 3.1.4 Flux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49 3.1.5 Virtual DOM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50 3.1.6 Diff Algorithm . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51 3.1.7 JSX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53 3.1.8 Backbone . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53 3.2 AngularJS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54 3.2.1 Kompilator HTML . . . . . . . . . . . . . . . . . . . . . . . . . . . 55 3.2.2 Dwustronne wiązanie danych . . . . . . . . . . . . . . . . . . . . . 55 3.2.3 Obiekt $scope . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56 3.2.4 Dziedziczenie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58 3.2.5 Metody $digest(), $apply() i $watch() . . . . . . . . . . . . . . . . . 59 3.2.6 Modularność . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62 3.2.7 Wstrzykiwanie zależności . . . . . . . . . . . . . . . . . . . . . . . . 63 3.2.8 Dyrektywy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64 3.2.9 Komunikacja z serwerem . . . . . . . . . . . . . . . . . . . . . . . . 65 3.3 Rails . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66 3.3.1 MVC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67 3.3.2 DRY . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70 3.3.3 Generatory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72 3.3.4 Struktura projektu . . . . . . . . . . . . . . . . . . . . . . . . . . . 73 3.3.5 Konwencja ponad konfiguracją . . . . . . . . . . . . . . . . . . . . . 75 3.3.6 TDD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76 3.3.7 Aktywna społeczność . . . . . . . . . . . . . . . . . . . . . . . . . . 78 3.4 Sinatra . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80 3.4.1 Elastyczność . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81 3.4.2 Wydajność . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81 3.4.3 Prostota . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81 3.5 Grape . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83 3.5.1 Elastyczność . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84 3.5.2 Wydajność . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84 3.5.3 Prostota . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84 4 Analiza 87 4.1 AngularJS - ReactJS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
  • 9. SPIS TREŚCI 9 4.1.1 Próg wejścia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88 4.1.2 Komplementarność . . . . . . . . . . . . . . . . . . . . . . . . . . . 88 4.1.3 Poziom ekspresji kodu . . . . . . . . . . . . . . . . . . . . . . . . . 88 4.1.4 Wydajność . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92 4.1.5 Debuggowanie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92 4.1.6 Przepływ danych . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92 4.1.7 Szablony . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94 4.1.8 Społeczność i popularność . . . . . . . . . . . . . . . . . . . . . . . 96 4.1.9 Podsumowanie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97 4.2 Rails - Sinatra - Grape . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98 4.2.1 Wydajność . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98 4.2.2 Społeczność i popularność . . . . . . . . . . . . . . . . . . . . . . . 100 4.2.3 Podsumowanie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100 5 Zakończenie 103 Bibliografia 107 Wykaz skrótów 108
  • 10. Spis rysunków 2.1 Porównanie ilości ofert pracy dla popularnych języków serwerowych, [źró- dło: http://www.indeed.com/jobtrends]. . . . . . . . . . . . . . . . . . . 29 2.2 Wykres pokazujący ilość ofert pracy dla języków JavaScript, C++, C#, PHP oraz Python, [źródło: http://www.indeed.com/jobtrends]. . . . . . 30 2.3 Przykład nieblokującej operacji wejścia-wyjścia wykonywanej przez Node, [źródło: [3]]. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39 2.4 Porównanie ilości ofert pracy dla popularnych platform serwerowych, [źró- dło: http://www.indeed.com/jobtrends]. . . . . . . . . . . . . . . . . . . 40 2.5 Dostęp do Internetu stacjonarnego w Polsce, [źródło: http://pclab.pl/ news63802.html]. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42 3.1 Diagram obrazujący przepływ sterowania w architekturze Flux, [źródło: https://github.com/facebook/flux]. . . . . . . . . . . . . . . . . . . . . 49 3.2 Porównanie ilości ofert pracy dla popularnych platform klienckich typu MVC, [źródło: http://www.indeed.com/jobtrends]. . . . . . . . . . . . . 55 3.3 Jednostronne wiązanie danych w AngularJS, [źródło: https://docs.angularjs. org/guide/databinding]. . . . . . . . . . . . . . . . . . . . . . . . . . . . 56 3.4 Dwustronne wiązanie danych w AngularJS, [źródło: https://docs.angularjs. org/guide/databinding]. . . . . . . . . . . . . . . . . . . . . . . . . . . . 57 3.5 Wykres pokazujący dominację platformy Rails, pod względem ilości ofert pracy, [źródło: http://www.indeed.com/jobtrends]. . . . . . . . . . . . . 68 3.6 Komunikat informujący o wynikach testów Guard. . . . . . . . . . . . . . . 77 3.7 Statystyki pobrań najpopularniejszych gemów ze strony https://rubygems. org/. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79 3.8 Statystyki kontrybucji do repozytorium rails z serwisu GitHub, [źródło: https://github.com/rails/rails/graphs/contributors]. . . . . . . . . 80 3.9 Liczba kontrybucji, gałęzi, wydań oraz wkładców w repozytorium rails z serwisu GitHub, [źródło: https://github.com/rails/rails/]. . . . . . . 80 10
  • 11. SPIS RYSUNKÓW 11 3.10 Liczba obserwatorów, gwiazdek oraz rozgałęzień repozytorium Rails z ser- wisu GitHub, [źródło: https://github.com/rails/rails/]. . . . . . . . . 80 4.1 Testy renderowania obiektów z wykorzystaniem: AngularJS, ReactJS - ska- la liniowa. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93 4.2 Testy renderowania obiektów z wykorzystaniem: AngularJS, ReactJS - ska- la logarytmiczna. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93 4.3 Porównanie czasu operacji na liście 100 zadań do zrobienia w ms, [źródło: http://evancz.github.io/todomvc-perf-comparison/]. . . . . . . . . . 94 4.4 Problem z dwustronnym wiązaniem danych w AngularJS, [źródło: http:// techblog.constantcontact.com/software-development/reactive-component- based-uis/]. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95 4.5 Rozwiązanie problemu z wiązaniem danych w ReactJS, [źródło: http:// survivejs.com/webpack_react/react_and_flux/]. . . . . . . . . . . . . 95 4.6 Statystyki dotyczące AngularJS ze strony https://github.com/angular/ angular.js/. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96 4.7 Statystyki dotyczące ReactJS ze strony https://github.com/facebook/ react. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97 4.8 Porównanie ilości wyszukiwań w Google. . . . . . . . . . . . . . . . . . . . 97 4.9 Porównanie wydajności Rails, Grape oraz Sinatra pod względem ilości ob- służonych żądań na minutę. . . . . . . . . . . . . . . . . . . . . . . . . . . 99 4.10 Porównanie wydajności Rails, Grape oraz Sinatra pod względem średniego czasu dla jednego zapytania. . . . . . . . . . . . . . . . . . . . . . . . . . . 99 4.11 Porównanie ilości pobrań ze strony https://rubygems.org/. . . . . . . . . 101
  • 12. Spis listingow: 2.1 Przykład kodu jQuery . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22 2.2 Przykład kodu czysty Javascript . . . . . . . . . . . . . . . . . . . . . . . . 22 2.3 Elastyczność języka Ruby . . . . . . . . . . . . . . . . . . . . . . . . . . . 28 2.4 Obiektowość języka Ruby . . . . . . . . . . . . . . . . . . . . . . . . . . . 28 2.5 Funkcyjność języka Ruby . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28 2.6 Typy danych w języku JavaScript . . . . . . . . . . . . . . . . . . . . . . . 30 2.7 Komentarz blokowy w języku JavaScript . . . . . . . . . . . . . . . . . . . 30 2.8 Komentarz liniowy w języku JavaScript . . . . . . . . . . . . . . . . . . . . 31 2.9 Instrukcja if w języku JavaScript . . . . . . . . . . . . . . . . . . . . . . . 31 2.10 Pęta while w języku JavaScript . . . . . . . . . . . . . . . . . . . . . . . . 31 2.11 Pętla do...while w języku JavaScript . . . . . . . . . . . . . . . . . . . . . . 31 2.12 Pętla for w języku JavaScript . . . . . . . . . . . . . . . . . . . . . . . . . 31 2.13 Pętla for...in oraz for...of w języku JavaScript . . . . . . . . . . . . . . . . 31 2.14 Instrukcja switch w języku JavaScript . . . . . . . . . . . . . . . . . . . . . 31 2.15 Notacja kropkowa wywołania metody w języku JavaScript . . . . . . . . . 32 2.16 Notacja z nawiasami kwadratowymi wywołania metody w języku JavaScript 32 2.17 Funkcja konstruktora w języku JavaScript . . . . . . . . . . . . . . . . . . 32 2.18 Tworzenie instancji klasy Obiekt w języku JavaScript . . . . . . . . . . . . 33 2.19 Definicja funkcji w języku JavaScript . . . . . . . . . . . . . . . . . . . . . 33 2.20 Dziedziczenie w języku JavaScript . . . . . . . . . . . . . . . . . . . . . . . 33 2.21 Przkład instalacji gema ”Devise” . . . . . . . . . . . . . . . . . . . . . . . 34 2.22 Zmiana wersji Rubiego na 2.2.3 . . . . . . . . . . . . . . . . . . . . . . . . 35 2.23 Przykładowy Gemfile . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35 2.24 Przykładowy Gemfile.lock . . . . . . . . . . . . . . . . . . . . . . . . . . . 35 2.25 ”Hello World” w irb . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37 2.26 Zmiana hasła klienta o id 1 . . . . . . . . . . . . . . . . . . . . . . . . . . 37 2.27 Przykład modelu ”Post” i zabezpieczonego kontrolera . . . . . . . . . . . . 43 2.28 Przykład zabezpieczenia metody ”update” kontrolera . . . . . . . . . . . . 43 12
  • 13. SPIS LISTINGOW: 13 2.29 Przykład definicji uprawnień w bibliotece ”cancancan” . . . . . . . . . . . 44 3.1 Przykład funkcji ”render” dla elementu listy rzeczy do zrobienia . . . . . . 46 3.2 Przekazanie funkcji do subkomponentu . . . . . . . . . . . . . . . . . . . . 47 3.3 Ustawienie początkowego stanu komponentu w ReactJS . . . . . . . . . . . 48 3.4 Zmiana stanu komponentu w ReactJS . . . . . . . . . . . . . . . . . . . . . 48 3.5 Część kodu obiektu Dispatcher . . . . . . . . . . . . . . . . . . . . . . . . . 50 3.6 Operacje na DOM przykład . . . . . . . . . . . . . . . . . . . . . . . . . . 51 3.7 React transformacja węzłów różnych typów . . . . . . . . . . . . . . . . . . 52 3.8 React transformacja węzłów o takich samych typach . . . . . . . . . . . . . 52 3.9 Porównanie budowy szablonów z użyciem JSX i bez . . . . . . . . . . . . . 53 3.10 Przypisywanie atrybutów i funkcji w AngularJS . . . . . . . . . . . . . . . 58 3.11 Dziedziczenie realizowane w AngularJS . . . . . . . . . . . . . . . . . . . . 59 3.12 Kontroler ParentController . . . . . . . . . . . . . . . . . . . . . . . . . . . 59 3.13 Kontroler ChildController . . . . . . . . . . . . . . . . . . . . . . . . . . . 59 3.14 Przykład wykorzystania metody $watch . . . . . . . . . . . . . . . . . . . 60 3.15 Przykład wykorzystania metoty $apply . . . . . . . . . . . . . . . . . . . . 61 3.16 Przykład deklaracji modułu w AngularJS . . . . . . . . . . . . . . . . . . . 62 3.17 Plik controller.js . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62 3.18 Szkielet aplikacji w AngularJS . . . . . . . . . . . . . . . . . . . . . . . . . 62 3.19 Przykłady wstrzykiwania zależności w AngularJS . . . . . . . . . . . . . . 63 3.20 Przykłady własnej dyrektywy w AngularJS . . . . . . . . . . . . . . . . . . 64 3.21 Pole konfiguracji dyrektywy restrict E w AngularJS . . . . . . . . . . . . . 65 3.22 Pole konfiguracji dyrektywy restrict A w AngularJS . . . . . . . . . . . . . 65 3.23 Pole konfiguracji dyrektywy restrict C w AngularJS . . . . . . . . . . . . . 65 3.24 Pole konfiguracji dyrektywy restrict M w AngularJS . . . . . . . . . . . . . 65 3.25 Przykładowe zapytanie GET z wykorzystaniem metody $http w AngularJS 65 3.26 Przykładowe zapytanie POST z wykorzystaniem metody $http w AngularJS 66 3.27 Przykład użycia ”scope” w modelu Rails. . . . . . . . . . . . . . . . . . . . 69 3.28 Przykład walidacji formatu adresu email. . . . . . . . . . . . . . . . . . . . 69 3.29 Przykład helpera zamieniającego liczbę na walutę. . . . . . . . . . . . . . . 69 3.30 Przykład użycia ”before action” do uwierzytelnienia użytkownika. . . . . . 70 3.31 Model wpisu oraz polubienia . . . . . . . . . . . . . . . . . . . . . . . . . . 71 3.32 Modele wpisu, wydarzenia i polubienia wraz z wyekstrahowanym modułem 71 3.33 Przykład wykorzystania generatora w Rails . . . . . . . . . . . . . . . . . . 72 3.34 Przykład definicji ścieżek dla nowego obiektu . . . . . . . . . . . . . . . . . 75 3.35 Przykład utworzonych przez Rails ścieżek API dla operacji CRUD . . . . . 75
  • 14. SPIS LISTINGOW: 14 3.36 Przykład testu modelu w bibliotece RSpec . . . . . . . . . . . . . . . . . . 76 3.37 Przykład ”fabryki” klientów w bibliotece Factory Girl . . . . . . . . . . . . 77 3.38 Przykład użycia biblioteki ”faker” . . . . . . . . . . . . . . . . . . . . . . . 78 3.39 Aplikacja ”Hello World” w Sinatrze . . . . . . . . . . . . . . . . . . . . . . 80 3.40 Obsługa żądania POST pod adresem ”/todos” . . . . . . . . . . . . . . . . 81 3.41 Aplikacja ”Hello World” w Grape . . . . . . . . . . . . . . . . . . . . . . . 84 3.42 Operacje CRUD w Grape . . . . . . . . . . . . . . . . . . . . . . . . . . . 85 4.1 Przykład ilustrujący ”boilerplate code” w AngularJS - HTML . . . . . . . 88 4.2 Przykład ilustrujący ”boilerplate code” w ReactJS - HTML . . . . . . . . 89 4.3 Przykład ilustrujący ”boilerplate code” w AngularJS - JavaScript . . . . . 89 4.4 Przykład ilustrujący ”boilerplate code” w ReactJS - JavaScript . . . . . . . 91 4.5 Przykład szablonu listy w ReactJS . . . . . . . . . . . . . . . . . . . . . . 94 4.6 Przykład szablonu listy w AngularJS . . . . . . . . . . . . . . . . . . . . . 96
  • 15. Rozdział 1 Wstęp Internet jako wynalazek bez wątpienia stawiany jest w jednym szeregu z powstaniem takich innowacji jak wynalezienie elektryczności, druku czy też maszyny parowej. Każdy z tych patentów usprawniał w znaczący sposób proces wykonywania pracy. Nie inaczej jest w przypadku Internetu. W dobie powszechnej informatyzacji bardzo mocno rozwija się rynek aplikacji internetowych, których w większości głównym zadaniem jest wspo- maganie procesu wymiany i przetwarzania danych pomiędzy użytkownikami. W związ- ku z tym powstało wiele różnych metod, architektur, języków programowania, a także sposobów tworzenia interfejsów użytkownika. Wszystko po to, aby proces korzystania z aplikacji internetowej był jak najbardziej intuicyjny, wygodny, szybki dla użytkownika. Współcześni klienci firm tworzących oprogramowanie stawiają duże wymagania. Aplika- cja w większości przypadków musi być intuicyjna, musi podpowiadać użytkownikowi co ma zrobić, gdy ten się zgubi, powinna przechowywać dane o każdej czynności użytkow- nika, powinna mieć dynamiczny charakter, powinna przetwarzać dane w locie, dostęp do danych musi być zapewniony w każdym momencie a na dodatek aplikacja powinna działać tak samo dobrze na każdym urządzeniu i platformie. Te i inne wymagania wymusiły na programistach i firmach tworzących oprogramowanie, podejście do tematu aplikacji inter- netowych w różny sposób. Dzięki temu, aby ułatwić proces wytwarzania oprogramowania, które spełniałoby wygórowane wymagania klientów, powstało wiele różnych koncepcji, z których przetrwały tylko te które miały zasadność istnienia. Natomiast każdy sposób re- alizacji oprogramowania wiąże się także z odpowiednim doborem technologii do wymagań dla oprogramowania. Przykładem takiej koncepcji tworzenia oprogramowania mogą być bardzo popularne ostatnio aplikacje typu Single Page Application, które mają wyraźny podział na warstwę kliencką i serwerową. Posiadają one bardzo mocno rozbudowaną war- stwę prezentacji i odpytują tylko serwer celem pobrania danych do wyświetlenia. W tego typu aplikacjach deweloperzy mają do wyboru wiele różnych technologi do implementacji 15
  • 16. Rozdział 1. Wstęp 16 zarówno części serwerowych np. Ruby on Rails, Python i Django lub PHP i Laravel, a także części klienckich np. Angular, Ember, React czy też Backbone. 1.1 Motywacje podjęcia tematu Aktualne trendy na rynku aplikacji internetowych skłoniły nas do zainteresowania się najczęściej wykorzystywanymi technologiami do ich realizacji. W dzisiejszym świecie, aby być konkurencyjnym, wiele firm skazanych jest na posiadanie własnych systemów infor- matycznych. Przekłada się to na stosunkowo dużą liczbę ofert pracy dla programistów w różnych technologiach oraz na różnych poziomach zaawansowania. Dlatego też posiadanie wiedzy i umiejętności pozwalających realizować tego typu systemy zwiększa atrakcyj- ność programisty na rynku pracy. Kolejnym powodem, który skłonił nas do wybrania realizowanego tematu, był fakt, iż chcieliśmy rozpoznać najpopularniejsze narzędzia do implementacji części serwerowych i klienckich aplikacji sieciowych, poznać ich zalety i wady, wyrobić sobie opinię na temat każdego z nich i wybrać najlepszy naszym zdaniem zestaw bibliotek, który mógłby w przyszłości być przez nas wykorzystany do realizacji komercyjnego systemu informatycznego. W związku z tym, że podczas przebiegu studiów mieliśmy okazję poznać wystarczające spektrum języków programowania, podjęliśmy de- cyzję o wyborze języka Ruby i wokół tego języka zostały dobrane biblioteki w przypadku części serwerowych. Natomiast jeżeli chodzi o wybór języka do implementacji warstwy prezentacji aplikacji, to wyboru w zasadzie nie ma i musi być to język JavaScript i to dla niego wybrane zostały najpopularniejsze biblioteki wspomagające tworzenie bogatych aplikacji internetowych. 1.2 Podział prac Damian Romanów Adam Skołuda 1 Wstęp 2 Wprowadzenie teorytyczne 2.1 REST 2.2 AJAX 2.3 SPA 2.4 Model - View - Controller 2.5 Języki 2.5.1 Ruby
  • 17. Rozdział 1. Wstęp 17 2.5.2 JavaScript 2.6 Środowiska programistyczne 2.6.1 Ekosystem Rubiego 2.6.2 Node 2.7 Bezpieczeństwo 2.7.1 Uwierzytelnianie 2.7.2 Autoryzacja 3 Opis technologii 3.1 ReactJS 3.2 AngularJS 3.3 Rails 3.3.1 MVC 3.3.2 DRY 3.3.3 Generatory 3.3.4 Struktura projektu 3.3.5 Konwencja ponad konfiguracją 3.3.6 TDD 3.3.7 Aktywna społeczność 3.4 Sinatra 3.5 Grape 4 Analiza 4.1 AngularJS - ReactJS 4.1.1 Próg wejścia 4.1.2 Komplementarność 4.1.3 Poziom ekspresji kodu 4.1.4 Wydajność 4.1.5 Debuggowanie 4.1.6 Przepływ danych 4.1.7 Szablony 4.1.8 Społeczność i popularność 4.1.9 Podsumowanie 4.2 Rails - Sinatra - Grap 4.2.2 Wydajność 4.2.3 Społeczność i popularność 4.2.4 Podsumowanie 4.2.4 Podsumowanie
  • 18. Rozdział 1. Wstęp 18 5 Zakończenie 1.3 Cel pracy Głównym celem niniejszej pracy była analiza bibliotek do tworzenia aplikacji interne- towych w środowiskach Ruby i JavaScript. Brane były pod uwagę narzędzia do tworzenia zarówno części klienckiej, jak i serwerowej. Podejmowany temat wymagał odpowiedniego zaznajomienia się z wybranymi technologiami. Analiza została oparta przede wszystkim o badanie zaimplementowanych aplikacji do tworzenia listy zadań. Dodatkowo, spostrze- żenia i konkluzje autorów pracy zostały skonfrontowane z zewnętrznymi źródłami, co pozwoliło szerzej spojrzeć na przedstawiane zagadnienie. 1.4 Układ pracy Praca została podzielona na rozdziały. Każdy z nich opisuje część rozważań dotyczą- cych analizowanych technologii. Struktura rozdziałów została zdefiniowana w taki sposób, aby praca miała logiczny i chronologiczny układ. Wprowadzenie teoretyczne przedstawia podstawowe informację na temat architektury aplikacji internetowych. Opis technologii ma na celu szczegółowe przedstawienie wybranych narzędzi i rozwiązań. Rozdział ”Anali- za” zawiera rozważania dotyczące każdej z wykorzystanych technologii. Rozważania te do- tyczą samej implementacji, a także porównania pod kątem architektury i bezpieczeństwa. Zawarte są w nim również wyniki przeprowadzonych prób wydajnościowych poszczegól- nych bibliotek. Rozdział ”Zakończenie” jest bardzo subiektywnym spojrzeniem na każde z analizowanych rozwiązań technologicznych oraz wybór naszym zdaniem najlepszej z punktu widzenia programisty. Zakończenie jest podsumowaniem całej pracy, zawiera spis zrealizowanych zadań, napotkane trudności oraz próbę prognozowania dalszego rozwoju badanych technologii.
  • 19. Rozdział 2 Wprowadzenie teorytyczne Niniejsza praca ma na celu analizę technologii tworzenia aplikacji internetowych (web application). W poprzednim rozdziale zostało wspomniane, że teraźniejszy użytkownik oczekuje od nich wiele. Należałoby zatem zdefiniować pojęcie ”aplikacja internetowa”, czym różni się od strony internetowej i czy w ogóle się od niej różni. Do zdefiniowania powyższych wymagane będzie przedstawienie kilku innych technologii. Internet nie był- by tym, czym jest obecnie bez HTTP (Hypertext Transfer Protocol) - protokołu typu żądanie-odpowiedź działającego w architekturze klient-serwer. Rolę serwera odgrywają programy osadzone na publicznie dostępnym węźle sieciowym. Ogromną zaletą jest tutaj dowolność w wyborze języka implementacyjnego. Może to być C, C++, C# czy Java. Programista może wybrać jeden z języków predestynowanych do tego typu zastosowań (ze względu na samą składnię czy też zestawy bibliotek ułatwiających tworzenie serwe- rów) np. PHP, Python, Scala czy też omawiany szerzej w niniejszej pracy Ruby. Bar- dziej niekonwencjonalne, badawcze podejście doprowadziło nawet do powstania serwerów w Prologu [27] czy Assemblerze [26]. Jedynym wymogiem jest zgodność ze standardem HTTP [25]. Specyfikacja HTTP obejmuje kilka metod, z czego najważniejsze z nich to GET, POST, PUT, DELETE. Architektura usług sieciowych bardzo często, a w wręcz powinna opierać się na REST (Representational State Transfer). Kolejnym elementem układanki jest język do opisu struktury dokumentów (stron) w Internecie - HTML (Hy- pertext Markup Language) [24]. Znaczniki HTML są nośnikami dla tekstów, obrazków czy hiperłączy. Dokument HTML jest odpowiedzią serwera na zapytanie klienta. Klientem jest zazwyczaj przeglądarka internetowa, parsująca odpowiedź z serwera i wyświetlająca ją użytkownikowi. Jak się okazało, te dwie proste technologie stworzyły duet, który prze- trwał próbę czasu i położył podwaliny pod dzisiejszy kształt aplikacji internetowych. Czy zatem każda strona internetowa jest aplikacją internetową? Odpowiedź na to pytanie nie jest oczywista i jednoznaczna. Pomocne może okazać się odwołane do klasycznych aplika- 19
  • 20. Rozdział 2. Wprowadzenie teorytyczne 20 cji - np. okienkowych programów na komputery PC. Aplikacja służy do realizacji celu, jest narzędziem, dzięki któremu użytkownik może zrealizować swoje potrzeby. Np. program graficzny pozwala nam na obróbkę czy retusz zdjęć. Czy sam folder ze zdjęciami nazwa- libyśmy narzędziem, który realizuje jakiś cel? Oczywiście pozwala na ich wyświetlanie. Nie jest to jednak twórcze działanie, a jedynie sama prezentacja treści. Można powie- dzieć, że wspólnym mianownikiem wszystkich aplikacji jest możliwość kreacji. Zatem czy strona internetowa prezentująca zawsze taką samą zawartość jest aplikacją? W świetle powyższej argumentacji z pewnością nie. Przykładami aplikacji internetowych mogą być Facebook, dokumenty Google czy Twitter - narzędzia umożliwiające użytkownikowi twór- cze działanie. Ze względu na swoją budowę aplikację internetową można nazwać również stroną internetową - jednak w obecnych czasach jest to spore uproszczenie i spłycenie jej funkcjonalności. 2.1 REST Protokół HTTP jest wystarczający do tworzenia serwerów dostarczających treści (za- sobów). Przy małych aplikacjach ścieżki dostępu do zasobów (URI) można definiować w zasadzie dowolnie. Złożone systemy wymuszają jednak stosowanie pewnych konwencji. Brak wzorców i konwencji jest jedną z przyczyn regresji. W świecie usług sieciowych liczą się dwa wzorce czy też style tworzenia systemów - SOAP (Simple Object Access Protocol) oraz REST (Representional State Transfer). SOAP opiera się na RPC, jest raczej wy- korzystywany do komunikacji komputer-komputer, zachodzi tutaj silne wiązanie serwera z klientem. Jest to właściwie protokół. REST, to natomiast to wzorzec architektural- ny do projektowania złożonych, skalowalnych i wydajnych usług sieciowych. Jest bardzo elastyczny, o ile jest właściwie zaimplementowany. Opiera się na zasobach, standaryzuje sposób dostępu do nich. Żeby można było mówić o usłudze sieciowej RESTful konieczne jest spełnienie wszystkich czterech głównych reguł: • Model klient-serwer Polega na podziale odpowiedzialności między tymi dwoma bytami. Klient nie po- siada informacji o sposobie przechowywania zasobów na serwerze. Nie jest dla nie- go ważne czy jest to baza danych, zwykły plik czy też inna usługa sieciowa. Nie jest ważny język programowania, użyte biblioteki czy sam sposób implementacji. Z drugiej strony serwer nie jest obciążony przechowywaniem stanu klienta, nie mu- si wiedzieć nic o interfejsie użytkownika. Elementem spajającym jest API. Można dowolnie zamieniać oba elementy, pod warunkiem utrzymywania jednolitego inter- fejsu. Cecha ta została wykorzystana w niniejszej pracy. Zaimplementowane zostały
  • 21. Rozdział 2. Wprowadzenie teorytyczne 21 3 serwery HTTP i 2 klienty utrzymując niezmienne API. Pozwoliło to osiągnąć dużą niezależność poszczególnych elementów • Bezstanowość Jak zostało wspomniane wyżej, serwer nie przechowuje stanu czy sesji klienta. Zatem każde żądanie musi zawierać wszystkie informacje potrzebne do jego obsłużenia. Korzystając z Internetu, bardzo często użytkownik ulega złudzeniu, że jest inaczej. Wiele aplikacji oferuje możliwość logowania, a nawet zapamiętywania tego logowania przez dłuższy okres. Powyższe funkcjonalności nie naruszają jednak architektury REST. W momencie logowania serwer generuje token, który jest przesyłany do klienta i zapisywany w tzw. ”ciasteczku” (HTTP cookie). W kolejnych żądaniach legitymujący się nim klient jest uważany za zalogowanego. • Cacheability Cecha, która nie ma dobrego odpowiednika w języku polskim. Chodzi to tu o składo- wanie wyników poprzednich zapytań, aby umożliwić szybki do nich dostęp w przy- szłości. Z jednej strony umożliwia dostęp do niektórych zasobów niemal w czasie rzeczywistym, a z drugiej zmniejsza obciążenie samej sieci oraz serwera. • Wielowarstwowość Architektura REST nie wymaga, aby końcowym serwerem była jedna maszyna. Możliwe jest zastosowanie kilku warstw pośredniczących i sterowanie obciążeniem. Klient końcowy postrzega taki system w ten sam sposób jak jeden serwer. 2.2 AJAX Przez długi czas zachowanie stron internetowych było dość sekwencyjne. Użytkownik klikał w hiperłącze, żądanie było wysyłane do serwera. Po otrzymaniu odpowiedzi cała strona, a właściwie DOM (Document Object Model) były renderowane. Nie zawsze takie zachowanie jest jednak potrzebne i pożądane. Zajmuje ono dość sporo czasu oraz powodu- je specyficzne ”mignięcie” zawartości. Czasem zmianom ulegają bardzo niewielkie części całego dokumentu. Rozwiązaniem tego problemu jest technika AJAX (Asynchronous Ja- vaScript and XML) (w większości przypadków używa się jednak formatu JSON zamiast XML - mówi się wtedy o AJAJ). Dzięki niej komunikacja użytkownika z treścią w Inter- necie stała się bardziej dynamiczna, poprzez swoją asynchroniczność. Tym samym strony internetowe bardziej zbliżyły się do standardowych programów komputerowych. Warto w tym miejscu wspomnieć o bibliotece jQuery, która bardzo uprościła używanie AJAX.
  • 22. Rozdział 2. Wprowadzenie teorytyczne 22 Przykład asynchronicznego zapytania GET w czystym JavaScripcie na listingu 2.1 oraz przy pomocy jQuery na 2.2. Listing 2.1: Przykład kodu jQuery 1 $.getJSON(’/my/url’, function(data) { 2 }); Listing 2.2: Przykład kodu czysty Javascript 1 var request = new XMLHttpRequest (); 2 request.open(’GET’, ’/my/url’, true); 3 4 request.onload = function () { 5 if (request.status >= 200 && request.status < 400) { 6 // Success! 7 var data = JSON.parse(request.responseText); 8 } else { 9 // We reached our target server , but it returned an error 10 11 } 12 }; 13 14 request.onerror = function () { 15 // There was a connection error of some sort 16 }; 17 request.send (); Wszystkie żadania asynchroniczne wykonywane w języku JavaScript należą do żądań XHR (XMLHttpRequest). Są nośnikiem obiektów o tej samej nazwie. AJAX posiada jednak pew- ne ograniczenia. Jego funkcjonowanie opiera się na języku JavaScript. Użytkownik może wyłączyć jego obsługę w przeglądarce, w takim przypadku AJAX będzie bezużyteczny. 2.3 SPA AJAX przyczynił się do sporej zmiany Internetu. Uatrakcyjnił interakcję użytkownika z aplikacją internetową, upodobnił ją do swoich ”desktopowych” pierwowzorów. Jeśli moż- na część danych pobrać z serwera w tle, na żądanie użytkownika lub wtedy kiedy będzie to konieczne, to dlaczego nie sprawić, aby cała aplikacja działała w ten sposób? SPA (Single- page application) to podzbiór aplikacji internetowych charakteryzujący się pojedynczym przeładowaniem strony, przy jej początkowym wyświetleniu. Dalsza komunikacja odbywa się za pomocą JavaScripti i żądań XHR.
  • 23. Rozdział 2. Wprowadzenie teorytyczne 23 Zalety: • Rozdzielenie logiki serwera i klienta Standardowe serwery HTTP są odpowiedzialne również za tworzenie dokumentu HTML wraz z osadzonymi w nim zmiennymi, czy tworzenie formularzy. W przy- padku SPA zadania te zostają w całości przerzucone na język JavaScript. Serwer udostępnia tylko API, czyli szynę wymiany danych. Podejście takie przynosi wiele korzyści. Jako że są to tak naprawdę dwie osobne aplikacje - mogą być rozwija- ne przez niezależne zespoły. Logika biznesowa czy szczegóły działania procesów na serwerze są niewidoczne dla klienta. • Elastyczność i atrakcyjność interfejsu użytkownika HTML generowany serwerowo ma pewne ograniczenia. Interakcja z użytkownikiem opiera się na formularzach, a te przy skomplikowanych interakcjach stają się często wąskim gardłem. Problematyczna staje się implementacja funkcjonalności działają- cych ”na żywo”. Formularze mają swoje prawa, muszą zostać wysłane na serwer, obsłużone, wtedy klient dostaje odpowiedź. Wykorzystanie JavaScriptu daje możli- wość niemal natychmiastowego komunikowania o wprowadzonych zmianach, również wprowadzenia stosownych efektów wizualnych. Przykładem może być załadowanie zdjęcia profilowego na serwer. W standardowym formularzu HTML możemy wybrać zdjęcie, po czym widzimy ewentualnie jego nazwę. Dopiero po wysłaniu i przetwo- rzeniu, serwer jest w stanie pokazać nam wynik tego działania. Przy wykorzystaniu JS, widzimy natychmiastowo wybrany obrazek. Wiele aplikacji oferuje też możliwość jego przycięcia. Jest to funkcjonalność nieosiągalna dla zwykłych formularzy. • Wiele klientów Jako że serwer nie posiada żadnej wiedzy o kliencie, wprowadzanie kolejnych apli- kacji klienckich, w dowolnych technologiach nie pociąga za sobą żadnych zmian w kodzie serwera. W dzisiejszym świecie bardzo często się mówi o tzw. IoT (Internet of Things). Tworzenie aplikacji z wyraźnym rozdziałem serwera i klienta stwarza idealne warunki do rozszerzenia systemu o aplikacji mobilne. Jest to bardzo ważny aspekt z punktu widzenia świata biznesu. Obecnie bardzo często tworzy się całe eko- systemy powiązanych ze sobą aplikacji - włączając w to klienty www, czy mobilne np. Android, czy iOS. Wady: • Niedojrzałość JS Technologia tworzenia warstw klienckich aplikacji internetowych całkowicie opar-
  • 24. Rozdział 2. Wprowadzenie teorytyczne 24 tych o język JavaScript jest stosunkowo nowym podejściem. Same frameworki JS- owe rozwijają się bardzo szybko. Z jednej strony jest to pozytywne zjawisko, rozwój zawsze jest dobry. Obserwując jednak ewolucję (czy raczej rewolucję) takich rozwią- zań jak AngularJS czy ReactJS, trudno pozbyć się wrażenia, że programista jest w pewnym sensie królikiem doświadczalnym, a jego produkt poligonem ćwiczebnym. Jak wiadomo w świecie technologii rok to bardzo dużo czasu, wiele rzeczy może się zmienić. W świecie JavaScriptu standardy mogą zmienić się w tydzień. I mowa tutaj o fundamentalnych kwestiach architekturalnych, a nie kosmetycznych poprawkach. Brakuje nienaruszalnych zasad i standardów, na których można oprzeć budowanie aplikacji. Te wszystkie względy czynią użycie wspomnianych rozwiązań w poważ- nych, komercyjnych aplikacjach co najmniej ryzykownym. Technologie nastawione raczej na back-end (np. Ruby on Rails, PHP Symphony) istnieją o wiele dłużej. Ich wybór jest bezpieczniejszym wyjściem. • Niezawodność Całkowite rozdzielenie warstw klienta i serwera ma niewątpliwie swoje plusy, nie jest jednak pozbawione wad. Dwie osobne aplikacje to z pewnością więcej kodu niż jedna. Dodatkowo warstwa front-endowa cechuje się dużą asynchronicznością, jest sterowana zdarzeniami (kliknięcia, interakcje). Nie ma tutaj tak jasnego przepływu danych, jak po stronie serwera (zapytanie - odpowiedź). Wszystko to sprawia, że całość jest dużo trudniejsza do automatycznego testowania, co za tym idzie bardziej zawodna. Należy też dodać, że pojedynczy błąd w klienckim kodzie JavaScript, skutkuje bardzo często zaprzestaniem dalszego wykonywania programu. • Synchronizacja stanu Aplikacja kliencka jest w całości odpowiedzialna za generowanie i zmienianie doku- mentu HTML widocznego dla użytkownika. Szablony do jego tworzenia są ustalone wcześniej i znane. Zmienne, które trzeba w nim osadzić - nie. Zostają one pobrane z serwera przy pomocy XHR podczas działania aplikacji. Stan aplikacji po stro- nie klienta musi być synchronizowany z tym, co rezyduje w bazie danych serwera. Wprowadza to konieczność częściowej duplikacji logiki serwera, a co za tym idzie jeszcze bardziej zwiększa objętość kodu. • Indeksowanie W projektowaniu aplikacji internetowych bardzo ważnym zagadnieniem jest opty- malizacja ich zawartości pod kątem algorytmów wyszukiwarek internetowych (SEO). Właściciel serwisu chce, aby jego strona była atrakcyjna, ale co ważniejsze, aby była łatwo dostępna dla potencjalnych klientów. Polega to m.in. na odpowiednim osa-
  • 25. Rozdział 2. Wprowadzenie teorytyczne 25 dzeniu słów kluczowych czy meta-opisów. Jeśli chodzi o SPA - zadanie komplikuje się nieco. Cała zawartość (w tym słowa kluczowe) pobierana jest poprzez AJAX już po pierwszym załadowaniu strony. Dla użytkownika nie jest to problem, ale web crawlery nie obsługują tego typu treści. Rozwiązaniem problemu jest dodat- kowe generowanie dokumentu HTML po stronie serwera, specjalnie dla silników wyszukiwarek. Zagadnienie to jest jednak dość złożone, nie wszystkie frameworki dostarczają tego typu rozwiązań. Przy braku powyższych dodatkowych czynności, strona internetowa widziana przez wyszukiwarkę np. Google jest pusta. Taki stan rzeczy ma fatalny wpływ na indeksowanie strony i jest nie do przyjęcia. • Początkowe ładowanie Kolejną niedogodnością jest tzw. ”slow start”. Aplikacja tego typu może ładować się znacznie dłużej niż standardowa strona. Oczywiście dzięki temu eliminuje się późniejsze przeładowania, a sama strona działa dużo płynniej. Co jednak w przy- padku gdy aplikacja potrzebuje kilku (kilkanastu) sekund do załadowania? (co nie jest odosobnionym przypadkiem, zwłaszcza przy dużych aplikacjach, a także przy wolnym połączeniu internetowym) Dzisiejszy użytkownik jest bardzo niecierpliwy i nieprzyzwyczajony do czekania na treść. Jego pierwsze wrażenie kształtuje się już w przeciągu ułamków sekundy, a utwierdza się w tym przekonaniu w czasie do kilku sekund. Co, jeśli przez cały ten czas będzie wpatrywał się w pasek ładowania, albo co gorsza, pustą stronę? • Wyłączony JS Wydaje się, że temat braku obsługi języka JavaScript przez przeglądarki interne- towe w roku 2015 nie powinien być podniesiony. Wciaż jednak istnieje grupa użyt- kowników (czasem całych korporacji) korzystająych z przestarzałych przeglądarek (wczesne wersje IE) z wyłączonym JavaScriptem. Nie jest to duży odsetek, ale pro- gramista wybierający zestaw technologii powinien się z nim liczyć. W przypadku gdy głównym odbiorcą aplikacji ma być powyższa grupa, implementacja systemu w technice SPA byłaby błędem. 2.4 Model - View - Controller W informatyce bardzo powszechnym podejściem jest dekompozycja problemu. Ła- twiejsze staje się rozwiązanie trzech małych problemów niż jednego dużego. Na podobną myśl w odniesieniu do aplikacji z interfejsem użytkownika wpadł już w 1970 roku Try- gve Reenskaug. Współczesne programy komputerowe potrafią być bardzo złożone, ofe-
  • 26. Rozdział 2. Wprowadzenie teorytyczne 26 rując użytkownikowi cały wachlarz funkcjonalności. Gdyby jednak rozłożyć każdą z nich na czynniki pierwsze, okazałoby się, że złożony obiekt składa się z małych niezależnych bloczków - modelu, widoku i kontrolera. Wydawać się może, że tylko 3 byty to za mało dużych aplikacji. Jak pokazuje jednak historia informatyki, najprostsze rozwiązania są najlepsze (REST), a utrzymanie prostej i spójnej architektury kluczem do sukcesu. Echo MVC pobrzmiewa bardzo silnie w ekosystemie WWW. Jak się okazało, forma aplikacji internetowych, jest bardzo spójna z tym, co proponuje MVC. Współcześnie wszystkie liczące się technologie do zastosowań webowych korzystają z MVC. Framework ”Rails” bardzo silnie wypromował wzorzec MVC - do tego stopnia, że programiści zaczęli tworzyć frameworki w innych językach, inspirowane właśnie Railsami [18]. Kolejnym dowodem słuszności MVC, może być fakt jego stosowania również po stronie klienta JavaScript. Początkowo nie było to potrzebne, jednak obecnie ilość potrzebnych informacji i stopień skomplikowania logiki stał się na tyle duży, że wzorzec MVC (lub jego odmiany) stały się koniecznością. Brak jego zastosowania bardzo często skutkuje regresją kodu, wzrostem zawodności oraz spadkiem czytelności (spagetti code). Wzorzec MVC opisuje przeznacze- nie i sposób interakcji między trzema tytularnymi typami obiektów. Krótki opis każdego z nich: • Model Odpowiedzialny za przechowywanie informacji związanych z obiektem, jedyny no- śnik logiki biznesowej. W większości przypadków powiązany z bazą danych (ORM - mapowanie obiektowo-relacyjne). Niezależny od widoku. • Widok Sposób prezentacji danych (np. z modelu) oraz interfejs użytkownika. • Kontroler Obiekt spinający dwa powyższe - pozwala przechwytać interakcje użytkownika zapo- czątkowane na komponentach widoku i przekazywać je do modelu. Z drugiej strony dostarcza danych z modelu do widoku, odpowiedzialny również za dobór właściwego modelu (np. wpis o odpowiednim id) 2.5 Języki Języki programowania są podobnie jak języki mowy naturalnej zbiorem pewnych reguł syntaktycznych oraz semantycznych dzięki którym człowiek w tym przypadku programista może wydawać zrozumiałe polecenia do wykonania przez komputer. Prawo relatywizmu językowego zaproponowane ok. 1930r przez Sapira i Whorfa mówi o tym, że używany
  • 27. Rozdział 2. Wprowadzenie teorytyczne 27 język wpływa w większym lub mniejszym stopniu na myślenie i sposób postrzegania ota- czającego nas świata. Pomimo tego, iż hipoteza ta dotyczy języka mowy, jej założenia znajdują także odzwierciedlenie w posługiwaniu się językami programowania. Dlatego też wybór danego języka także w informatyce jest bardzo istotny. Natomiast warto pamiętać o tym, iż w większości przypadków nowe języki programowania postrzegane są błędnie jako cudowne narzędzia rozwiązujące wszystkie problemy. Nie istnieje jedno uniwersalne narzędzie do wszystkiego. Wynika to z tego, iż występuje bardzo duża liczba zbiorów pro- blemów a każdy z nich ma zbyt dużą ilość ograniczeń. Skutkiem tego jest fakt, iż z reguły języki programowania specjalizują się w rozwiązywaniu problemów zwykle z wąskiego zakresu danej dziedziny. Jednakże wśród programistów już zawsze będą trwały swojego rodzaju ”wojny na języki” podyktowane zazwyczaj indywidualnymi preferencjami, ale także szerokim wachlarzem dostępnych narzędzi. 2.5.1 Ruby Ruby jest popularnym, dynamicznym językiem skryptowym, który ma na celu dać programiście duże możliwości, poczucie swobody oraz ma sprawić, aby programowanie w tym języku było tak naturalne i przyjemne jak to tylko możliwe. Według jego twórcy Yukihiro “Matz” Matsumoto Ruby jest językiem starannie dobranej równowagi. Aby to osiągnąć, jego autor połączył wybrane elementy każdego z języków Perla, Smalltalka, Eif- fel, Ady, i Lispa, by stworzyć język, który balansuje programowanie funkcjonalne wraz z programowaniem imperatywnym. Pierwsze publiczne ukazanie języka Ruby nastąpiło w 1995 roku. Natomiast dopiero w 2006 język ten zyskał większą popularność oraz przychyl- ność środowiska programistów. Stało się tak głównie za sprawą powstania i popularyzacji frameworka do tworzenia aplikacji internetowych Rails, o którym więcej w rozdziale 3.3. Kolejnym powodem, dla którego omawiany język stał się tak popularny, co obrazuje Rys. 2.1, jest fakt, iż Ruby jest językiem całkowicie darmowym także w rozumieniu kopiowania, modyfikowania i rozprowadzania tego języka. Oto najważniejsze cechy języka: • Ruby jest językiem zwinnym. A to dlatego, że udostępnia programiście, możliwość dowolnego modyfikowania jego części czego skutkiem jest zachęta społeczności do ciągłego udoskonalania wykorzystywanego przez nich języka. Ruby stara się nie na- rzucać żadnych ograniczeń programiście co pozwala w zależności od intencji usunąć lub przedefiniować podstawowe elementy języka. Przykładowo operację dodawania wykonuje się za pomocą operatora ”+”. Natomiast istnieje możliwość wykonania tego działania za pomocą słowa ”plus”. W tym celu należałoby dodać odpowiednią metodę do klasy ”Numeric”.
  • 28. Rozdział 2. Wprowadzenie teorytyczne 28 Listing 2.3: Elastyczność języka Ruby 1 class Numeric 2 def plus(x) 3 self .+(x) 4 end 5 end 6 7 y = 1. plus 3 Wynikiem działania jest oczywiście 4. Operatory w języku Ruby są tak zwanym ”lukrem” składniowym dla metod, które również można w dowolny sposób przede- finiować. • Ruby jest językiem bardzo wysokiego poziomu. Twórcy języka kierowali się zasadą, że to komputer powinien pracować dla programisty, a nie odwrotnie. Dzięki temu nawet najbardziej skomplikowane operacje możemy wykonywać za pomocą stosun- kowo nie dużej ilości kodu w porównaniu z językami niższego poziomu. • Ruby jest językiem silnie obiektowym. Dzięki temu każda część kodu może mieć własne atrybuty w postaci zmiennych instancji oraz własne metody. Dzięki temu możemy wywołać metodę na liczbie: Listing 2.4: Obiektowość języka Ruby 1 10. times { print "Everything is an object!" } Istnieje wiele języków programowania, w których np. liczby i inne bazowe typy nie zachowują się jak obiekty. Inaczej jest w przypadku Rubiego, który tę cechę odziedziczył po Smalltalku, co znacznie ułatwia korzystanie z języka, dlatego że zasady dotyczące obiektów mają również zastosowanie dla całego języka. • Ruby posiada cechy języków funkcyjnych. Dzięki temu, możemy dołączyć do do- wolnej metody domknięcie, które opisuje sposób działania danej metody. Tego typu domknięcie nazywa się blokiem i zostało zaczerpnięte przez twórców z języka funk- cyjnego Lisp. Listing 2.5: Funkcyjność języka Ruby 1 ruby_traits = 2 %w[Agile Object -oriented High -level ].map do |trait| 3 "Ruby is " + trait.downcase + " language!" 4 end
  • 29. Rozdział 2. Wprowadzenie teorytyczne 29 Rysunek 2.1: Porównanie ilości ofert pracy dla popularnych języków serwerowych, [źródło: http://www.indeed.com/jobtrends]. Powyższy przykład pokazuje blok, który znajduje się między słowami kluczowymi ”do” i ”end”. Bloki mogą być definiowane w dowolny sposób i realizować złożone operacje. • Ruby realizuje paradygmat dziedziczenia. Natomiast robi to inaczej niż w większo- ści języków programowania. Ruby realizuje celowo tylko dziedziczenie jednokrotne, natomiast dla programistów tego języka wprowadzono możliwość korzystania z mo- dułów, które są zbiorami metod. Do każdej klasy może zostać dołączony tego typu moduł, który rozszerza klasę o implementacje metod z danego modułu. Tego typu rozwiązanie uznawane jest przez programistów Rubiego za prostsze i wygodniejsze względem wielokrotnego dziedziczenia, które nakłada wiele ograniczeń i może być stosunkowo skomplikowane. • Ruby posiada mechanizm odśmiecania pamięci. Tak jak w wielu nowoczesnych ję- zykach programowania, tak i w Rubim występuje garbage collector z prawdziwego zdarzenia typu mark-and-sweep, który wykorzystywany jest dla wszystkich obiektów żyjących w pamięci obiektowej. Według twórców języka nie istnieje potrzeba prze- trzymywania informacji na temat liczby odniesień do obiektu tak jak w metodach odśmiecania typu reference counting.
  • 30. Rozdział 2. Wprowadzenie teorytyczne 30 Rysunek 2.2: Wykres pokazujący ilość ofert pracy dla języków JavaScript, C++, C#, PHP oraz Python, [źródło: http://www.indeed.com/jobtrends]. 2.5.2 JavaScript JavaScript jest skryptowym językiem programowania, który pojawił się w już w 1995 za sprawą firmy Netscape. Wbrew pozorom geneza jego nazwy ma nie wiele wspólnego z językiem Java. Powstała ona po prostu w wyniku kontraktów biznesowych pomiędzy firma Netscape i Sun Microsystems. W 1997 roku ECMA stworzyła standard dla języka JavaScript zwany ECMAScript. JavaScript zyskał dużą popularność za sprawą rozwoju dynamicznych aplikacji internetowych, co można zauważyć na wykresie 2.2 trendów od- nośnie zatrudnienia. Dzisiaj już nikt nie wyobraża sobie funkcjonowania aplikacji www bez korzystania z JavaScriptu. Na bazie tego języka powstało wiele rozbudowanych fra- meworków frontendowych o których więcej w rodziale 3 a nawet backendowych opisanych w rozdziale 2.6.2 co także miało duże znaczenie na zwiększenie popularności tego Java- Scriptu a co za tym idzie także programistów posługujących się tym językiem. Elementy języka JavaScript zgodne ze standardem ECMAScript: • Niektóre podstawowe typy danych i obiekty wykorzystywane w JavaScripcie. Listing 2.6: Typy danych w języku JavaScript 1 String , Boolean , Number , Object , Math , Array • JavaScript odziedziczył podstawowe instrukcje sterujące po językach C++ i Java. Listing 2.7: Komentarz blokowy w języku JavaScript
  • 31. Rozdział 2. Wprowadzenie teorytyczne 31 1 /* To jest komentarz 2 blokowy zajmujacy 3 kilka linii */ Listing 2.8: Komentarz liniowy w języku JavaScript 1 // To jest komentarz liniowy Listing 2.9: Instrukcja if w języku JavaScript 1 if (warunki) { 2 instrukcje; 3 } 4 else { 5 instrukcje; 6 } Listing 2.10: Pęta while w języku JavaScript 1 while (warunki) { 2 instrukcje; 3 } Listing 2.11: Pętla do...while w języku JavaScript 1 do { 2 instrukcje 3 } while (warunki); Listing 2.12: Pętla for w języku JavaScript 1 for ([ poczatkowe ]; [warunki ]; [krokowe ]) { 2 instrukcje; 3 } Listing 2.13: Pętla for...in oraz for...of w języku JavaScript 1 for (wlasnosc in obiekt) { 2 instrukcje; 3 } Listing 2.14: Instrukcja switch w języku JavaScript 1 switch (wyrazenie) {
  • 32. Rozdział 2. Wprowadzenie teorytyczne 32 2 case wartosc1: 3 instrukcje; 4 break; 5 case wartosc2: 6 instrukcje; 7 break; 8 default: 9 instrukcje; 10 break; 11 } • W JavaScripcie występują obiekty i typy prymitywne. Według standardu ECMA- Script obiekty są tablicami asocjacyjnymi. Ze względu na to iż w JavaScripcie me- toda danego obiektu jest także jego polem istnieją dwa sposoby odwołania: Listing 2.15: Notacja kropkowa wywołania metody w języku JavaScript 1 m.metoda1 (); Listing 2.16: Notacja z nawiasami kwadratowymi wywołania metody w języku JavaScript 1 m["metoda1"](); • Aby utworzyć w JavaScripcie własny obiekt trzeba stworzyć funkcję konstruktora. Listing 2.17: Funkcja konstruktora w języku JavaScript 1 function Obiekt(pole1 , pole2) { 2 this.pole1 = pole1; 3 this.pole2 = pole2; 4 5 function metoda1 () { 6 alert("Obiekt :: metoda1 ()"); 7 } 8 this.metoda1 = metoda1; 9 10 function metoda2 () { 11 alert("Obiekt :: metoda2 ()"); 12 } 13 this.metoda2 = metoda2; 14 }
  • 33. Rozdział 2. Wprowadzenie teorytyczne 33 • W większości współczesnych języków obiektowych występują ”klasy” które pozwala- ją tworzyć własne niestandardowe typy. Inaczej jest w przypadku języka JavaScript, ponieważ według ECMA pojęcie ”klasy” nie istnieje w sensie formalnym. Mówiąc o ”klasach” w JavaScripcie mamy na myśli obiekty stworzone z wykorzystaniem tego samego konstruktora. Listing 2.18: Tworzenie instancji klasy Obiekt w języku JavaScript 1 var m = new Obiekt (1, 2); • Definiowanie funkcji w JavaScripcie odbywa się za pomocją słowa kluczowego func- tion. Zgodnie z ECMAScript funkcje są jednocześnie obiektami klasy Function. Listing 2.19: Definicja funkcji w języku JavaScript 1 function dodajLiczby(a, b) { 2 return a+b; 3 } • JavaScript implementuje także paradygmat dziedziczenia, ale w uproszczony sposób wykorzystując prototypy. Listing 2.20: Dziedziczenie w języku JavaScript 1 function KlasaBazowa () { 2 this.metoda1 = function () { 3 alert("KlasaBazowa ::1()"); 4 } 5 this.metoda2 = function () { 6 alert("KlasaBazowa ::2()"); 7 } 8 } 9 10 function KlasaPochodna () { 11 // metoda2 przeciaza odpowiednia metode z klasy KlasaBazowa: 12 this.metoda2 = function () { 13 alert("KlasaPochodna ::2()"); 14 } 15 } 16 KlasaPochodna.prototype = new KlasaBazowa (); 17 18 x = new KlasaBazowa (); 19 y = new KlasaPochodna ();
  • 34. Rozdział 2. Wprowadzenie teorytyczne 34 Rozdział opracowany na podstawie [15] 2.6 Środowiska programistyczne Poprzez pojęcie środowiska programistyczne rozumiemy tu technologie, narzędzia oraz biblioteki zorientowane wokół danego języka programowania wraz z tymi językami, które zostały bliżej przedstawione w rozdziale 2.5. Należy pamiętać o tym, iż wybór danego języka determinuje całe środowisko pracy danego programisty. Dlatego też w tym rozdziale przedstawione zostaną bliżej konkretne zestawy narzędzi i bibliotek, ich geneza oraz baza teoretyczna dla wybranych w poprzednim rozdziale języków programowania. 2.6.1 Ekosystem Rubiego Język Ruby sam w sobie jest świetnym narzędziem, nastawionym na tworzenie czy- stego, zrozumiałego kodu. Jest to język powszechnego zastosowania, w praktyce jednak używany w większości przypadków w zestawieniu z Railsem. Czy popularność powyższych można tłumaczyć tylko wysoką estetyką kodu? Ma to z pewnością wielkie znaczenie, jed- nak nie mniej ważny jest aspekt open-source. Zarówno Ruby, jak i Rails to środowiska otwarte. Każdy ma dostęp do kodu źródłowego, każdy może go modyfikować na własne potrzeby. Może również tymi modyfikacjami dzielić się z twórcami, aby każdy mógł korzy- stać z nowych funkcjonalności czy poprawek. Podobnie jest ze wszystkimi gemami (”gem” to nazwa dodatkowej biblioteki w języku Ruby. Nawiązuje do nazewnictwa języka, ruby - rubin. Jest to nazwa własna i dość charakterystyczna, dlatego w dalszej części pracy, pojęcia te będą używane zamiennie). I to właśnie otwartość środowiska jest motorem napędzającym cały ekosystem. RubyGems Ruby od wersji 1.9 jest dostarczany z wbudowanym menadżerem pakietów - Ruby- Gems. Moduł ten jest domyślnie połączony z repozytorium gemów - rubygems.org. Jeśli wskazana biblioteka znajduje się w repozytorium, zostanie automatycznie pobrana. Ist- nieje możliwość wskazywania również innych źródeł. Instalacja nowego gema ogranicza się do wywołania jednej komendy, np: Listing 2.21: Przkład instalacji gema ”Devise” 1 gem install devise Narzędzie RubyGems zostało szerzej opisane w [17] w rozdziale 21.1.
  • 35. Rozdział 2. Wprowadzenie teorytyczne 35 RVM Bardzo często zdarza się, że programista pracuje nad kilkoma projektami. Nie wszyst- kie z nich musza korzystać z tej samej wersji języka Ruby. W standardowych okoliczno- ściach każda zmiana projektu wiązałaby się z reainstalacją Rubiego wraz z potrzebnymi gemami. Takie działanie byłoby ogromną stratą czasu. Z pomocą przychodzi RVM, czyli menadżer wersji języka Ruby. Dzięki niemu w systemie rezydują obok siebie różne wersje wraz z zainstalowanymy gemami. Zmiana wersji odbywa się za pomocą prostej komendy: Listing 2.22: Zmiana wersji Rubiego na 2.2.3 1 rvm use 2.2.3 2 ruby -v 3 ruby 2.2.3 p173 (2015 -08 -18 revision 51636) [x86_64 -darwin14] Bundler Instalacja pakietów jest prosta dzięki RubyGems. Bardzo często zdarza się jednak, że gemy bazują na innych gemach (dependency). Ręczne sprawdzanie zależności i instalacja odpowiednich wersji bibliotek, byłoby bardzo czasochłonnym zajęciem. W dodaktu cały proces należałoby powtarzać przy każdej aktualizacji gemów. Powyższe zadanie jest trudne dla człowieka, jednak komputery radzą sobie z nim bez problemu. Gem ”bundler” auto- matycznie negocjuje wersje pakietów, znajduje takie, które spełniają oczekiwania każdego gema (o ile to możliwe). Programista tworzy jedynie plik Gemfile, w którym wylistowane są potrzebne gemy. Bundler tworzy na jego podstawie plik Gemfile.lock wskazujący na ich konkretne wersje. Poniżej przykłady wymienionych plików: Listing 2.23: Przykładowy Gemfile 1 source ’https :// rubygems.org’ 2 3 gem ’guard ’ 4 gem ’guard -shell ’ 5 gem ’terminal -notifier -guard ’ Listing 2.24: Przykładowy Gemfile.lock 1 GEM 2 remote: https :// rubygems.org/ 3 specs: 4 coderay (1.1.0) 5 ffi (1.9.10)
  • 36. Rozdział 2. Wprowadzenie teorytyczne 36 6 formatador (0.2.5) 7 guard (2.13.0) 8 formatador (>= 0.2.4) 9 listen (>= 2.7, <= 4.0) 10 lumberjack (~> 1.0) 11 nenv (~> 0.1) 12 notiffany (~> 0.0) 13 pry (>= 0.9.12) 14 shellany (~> 0.0) 15 thor (>= 0.18.1) 16 guard -compat (1.2.1) 17 guard -shell (0.7.1) 18 guard (>= 2.0.0) 19 guard -compat (~> 1.0) 20 listen (3.0.3) 21 rb -fsevent (>= 0.9.3) 22 rb -inotify (>= 0.9) 23 lumberjack (1.0.9) 24 method_source (0.8.2) 25 nenv (0.2.0) 26 notiffany (0.0.7) 27 nenv (~> 0.1) 28 shellany (~> 0.0) 29 pry (0.9.12.6) 30 coderay (~> 1.0) 31 method_source (~> 0.8) 32 slop (~> 3.4) 33 rb -fsevent (0.9.5) 34 rb -inotify (0.9.5) 35 ffi (>= 0.5.0) 36 shellany (0.0.1) 37 slop (3.6.0) 38 terminal -notifier -guard (1.6.4) 39 thor (0.19.1) 40 41 PLATFORMS 42 ruby 43 44 DEPENDENCIES 45 guard 46 guard -shell 47 terminal -notifier -guard
  • 37. Rozdział 2. Wprowadzenie teorytyczne 37 irb Bardzo wygodnym narzędziem jest interaktywna konsola języka Ruby (irb - interactive Ruby). Jako że Ruby jest językiem interpretowalnym, można dynamicznie wykonywać jego instrukcje i prezentować ich wyniki. Irb jest przydatne w przypadku chęci przetestowania działania napisanego kodu. Poniżej przykład użycia irb: Listing 2.25: ”Hello World” w irb 1 $ irb 2 :001 > puts ’Hello World ’ 3 Hello World 4 => nil Jeszcze ciekawszym narzędziem jest rails console. Jest bardzo podobne do konsoli irb, używane jest jednak tylko w obrębie aplikacji Rails. Dzięki niemu możemy korzystać ze wszystkich klas i metod napisanych w obrębie tej aplikacji. Np. możliwe staje się uzyskanie dostępu do bazy danych poprzez ORM. Możemy wprowadzić zmiany, operując na modelach, a nie tabelach bazodanowych. Przykład użycia rails console: Listing 2.26: Zmiana hasła klienta o id 1 1 $ rails console 2 przykladowa_aplikacja >> Client.find_by(id: 1). update_attributes password: ’nowe haslo ’ 3 Client Load (19.4 ms) SELECT "clients".* FROM "clients" WHERE " clients"."id" = $1 LIMIT 1 [["id", 1]] 4 (2.2 ms) BEGIN 5 SQL (0.6 ms) UPDATE "clients" SET " encrypted_password " = $1 , " updated_at" = $2 WHERE "clients"."id" = $3 [[" encrypted_password ", " $2a$10$fOjZciThhpJ9flUV0B5f1 .. qbsZXgEBfYb /5 PJkQMGWxww0XKbbj ."], ["updated_at", "2015 -08 -29 15:41:19.559307 "], ["id", 1]] 6 (48.7 ms) COMMIT 7 => true Rake Odpowiednik narzędzia ”make” z systemów UNIX. Pozwala na konstruowanie zadań, reguł. Umożliwia zarządzane zależnoścami. Zadania definiuje się w języku Ruby, dzię- ki zastosowaniu specjalnego DSL. Co ciekawe umożliwia budowanie także programów w innych językach, np. C.
  • 38. Rozdział 2. Wprowadzenie teorytyczne 38 2.6.2 Node Node.js jest platformą stworzoną na bazie środowiska uruchomieniowego JavaScript. Projekt ten jest stosunkowo młody, gdyż pojawił się w 2009 roku i bardzo szybko zyskał dużą popularność, co widać na Rys. 2.4. Społeczność wokół Node.js rośnie tak szybko, że obecnie projekt ten jest drugi co do liczby obserwatorów w portalu GitHub i aktualnie istnieje ok. 70 000 modułów stworzonych na licencji ”Open Source” dostępnych z poziomu menadżera pakietów dla Node.js npm. Główne cechy platformy Node.js: • Podstawą działania Node.js jest język JavaScript, o którym więcej w rozdziale 2.5.2. Do wykonywania kodu po stronie serwera Node stosuje wirtualną maszynę Java- Script V8, z której korzysta przeglądarka Google Chrome. Dzięki temu aplikacje tworzone w Node zyskują dużą wydajność z tego względu, iż zamiast uruchamiania kodu bajtowego z wykorzystaniem interpretera Node kompiluje program do kodu maszynowego. Wykorzystanie języka JavaScript po stronie serwera przynosi kilka istotnych korzyści. Po pierwsze w wyniku tego, iż aplikacje internetowe mogą być tworzone z wykorzystaniem tylko jednego języka programowania zarówno po stronie klienckiej, jak i serwerowej minimalizowany jest proces przełączania kontekstu. Po drugie Node wykorzystuje JSON jako format wymiany danych zyskujący dużą popu- larność w dziedzinie tworzenia aplikacji internetowych będący natywnym formatem dla języka JavaScript. Dzięki temu, że Node korzysta z dokładnie jednej maszyny wirtualnej V8, zgodnej ze standardem ECMAScript, korzystanie z nowych funk- cji języka JavaScript nie jest ograniczone przez spóźnione aktualizacje przeglądarek internetowych różnych producentów. • Obsługa operacji wejścia-wyjścia na serwerze. Zgodnie z rysunkiem 2.3 obrazują- cym wykonywanie nieblokującej operacji Node jest serwerem asynchronicznym. W standardowym podejściu komunikacji z serwerem mamy model typu zapytanie - od- powiedź kóre realizowane jest w głównym wątku aplikacji i kolejne zapytania do serwera są zwyczajnie kolejkowane. Natomiast w przypadku Node.js istnieje tzw. pętla zdarzeń, która dopiero po otrzymaniu odpowiedzi wykonuje operacje zdefinio- wane w funkcji zwrotnej. • Tworzenie aplikacji typu DIRT. W związku z tym, że Node dzięki nieblokującemu przetwarzaniu akcji wejścia-wyjścia powoduje małe obciążenie podczas przetwarza- nia operacji, często jest wykorzystywany jako pośrednik w przekazywaniu różnych strumieni danych z różnych źródeł. Ta cecha powoduję, iż Node staję się popularny w aplikacjach przetwarzających dużą ilość danych w czasie rzeczywistym. Przykła-
  • 39. Rozdział 2. Wprowadzenie teorytyczne 39 Rysunek 2.3: Przykład nieblokującej operacji wejścia-wyjścia wykonywanej przez Node, [źródło: [3]]. dem aplikacji typu DIRT napisanej w Node jest [16] która służy do testowania stron internetowych na różnych platformach w czasie rzeczywistym. W związku z dużym rozwojem frameworków frontendowych rosnącym ich skompli- kowaniem oraz tendencją do upodabniania się do aplikacji backendowych pojawiły się zapotrzebowania na dodatkowe narzędzia i biblioteki do odpowiedniego zarządzania tymi frameworkami. I tutaj do gry wchodzi Node.js, który wprowadza między innymi mena- dżer zarządzania pakietami npm, które można porównać do gemów w środowisku Ruby oraz nvm, który służy do zarządzania wersjami Node.js. Nvm jest odpowiednikiem rvm, o którym więcej w rozdziale 2.6.1. W wyniku tego, iż technologie aplikacji klienckich nie podlegają w zasadzie żadnej standaryzacji tego, typu rozwiązań open source jest bardzo dużo i nie sposób je wszystkie opisać a co dopiero używać. 2.7 Bezpieczeństwo W dzisiejszym świecie Internet jest medium, w którym dochodzi do olbrzymiej wy- miany informacji. Dane przesyłane w Internecie dotyczą każdego aspektu życia, dlatego też kluczowym pojęciem stało się bezpieczeństwo. Według jednej z definicji komputer jest
  • 40. Rozdział 2. Wprowadzenie teorytyczne 40 Rysunek 2.4: Porównanie ilości ofert pracy dla popularnych platform serwerowych, [źródło: http://www.indeed.com/jobtrends]. uznawany za bezpieczny wówczas, gdy można stwierdzić, że sprzęt oraz oprogramowanie na nim znajdujące się działają zgodnie z oczekiwaniami użytkownika. Natomiast w obliczu bardzo szybkiego rozwoju globalnej sieci, jaką jest Internet Rys. 2.5 oraz sposobu i skali publikacji informacji, powstała potrzeba bezpieczeństwa ukierunkowana na WWW. Defi- niuje się je jako zbiór technologii, procedur i metod wykorzystywanych do zabezpieczania serwerów WWW, użytkowników, a także organizacje stające za nimi. Wprowadzane środki bezpieczeństwa mają za zadanie ustrzec użytkowników przed nieoczekiwanym zachowa- niem komputerów. Istnieje wiele znaczących czynników, które wpływają na odmienne i bardziej ukierunkowane podejście do bezpieczeństwa WWW: • Internet z założenia jest siecią dwukierunkową. Publikowane za jej pomocą informa- cje znajdują się na serwerach WWW, do których dostęp mogą mieć miliony osób na całym świecie. Tego typu zagrożenia nie występują w przypadku innych mediów np. gazeta, faks, telefon. • Sieć WWW wykorzystywana jest przez duże organizacje komercyjne, ale także i rzą- dowe do przechowywania i dostępu do wielu różnych danych także tych wrażliwych. Skutkiem tego jest wymagane zwiększone bezpieczeństwo dostępu do tych danych oraz większa kontrola nad tym, kto posiada dostęp do nich. • Pomimo tego, że sieć internetowa tworzona była i standaryzowana od początku swo- jego istnienia przez wiele lat to poziom skomplikowania zarówno z punktu widzenia sprzętowego, jak i oprogramowania jest na tyle duży, że liczba występujących błę-
  • 41. Rozdział 2. Wprowadzenie teorytyczne 41 dów bardzo mocno podnosi ryzyko zagrożenia bezpieczeństwa. Przykładem takiego oprogramowania mogą być przeglądarki internetowe, którym cały czas zdarzają się często poważne luki w zabezpieczeniach. • Na poziom istotności zabezpieczeń serwerów WWW w znaczący sposób wpływa fakt, iż większość użytkowników Internetu nie posiada wystarczającej wiedzy, do- świadczenia ani świadomości zagrożeń, jakie mogą się pojawić. • W większości przypadków naprawa skutków naruszeń bezpieczeństwa wymaga wię- cej zasobów czasu i pieniędzy niż wprowadzenie odpowiednich zabezpieczeń. • W dzisiejszym świecie za pośrednictwem sieci WWW codziennie dochodzi do nie- zliczonej ilości transakcji finansowych wraz z wymianą informacji poufnych typu numery kart kredytowych czy też dane personalne obu kontrahentów. • Wiele firm wykorzystuje sieć WWW do komunikacji z zewnętrznymi odbiorcami, którymi mogą być partnerskie firmy bądź kontrahenci zlokalizowani na całym świe- cie. Zastrzeżone dane wymieniane pomiędzy tymi firmami mogą się stać celem przy- kładowo dla wrogów danej firmy. Problem zapewnienia bezpieczeństwa WWW należy podzielić na trzy główne elementy, z których każdy musi spełniać warunki bezpieczeństwa, aby całość przetwarzania danych w obrębie WWW można było nazwać bezpiecznym: • Odpowiednie zabezpieczenie serwera WWW oraz informacji na nim przechowywa- nych w taki sposób, aby mieć pewność, że serwer będzie działał ciągle i poprawnie. Przechowywane dane na serwerze WWW nie mogą być modyfikowane przez nieupo- ważnione do tej operacji osoby oraz mogą być udostępniane tylko i wyłącznie dla osób autoryzowanych, czyli takich, które posiadają prawa dostępu do tych informa- cji. • Jak w każdym systemie informatycznym tak i w sieci WWW największe zagrożenie, jeżeli chodzi o bezpieczeństwo, występuje na styku dwóch różnych systemów. Klu- czowym elementem jest zabezpieczenie przekazywanych informacji w szczególności tych poufnych od klienta do serwera. Głównym zagrożeniem bezpieczeństwa komu- nikacji na linii klient-serwer są wszelkiego rodzaju podsłuchy np. atak ”man in the middle”. • Zabezpieczenie komputera klienta, czyli użytkownika końcowego zwykle bywa naj- trudniejszym elementem dla zapewnienia bezpieczeństwa. Klient powinien być pew-
  • 42. Rozdział 2. Wprowadzenie teorytyczne 42 Rysunek 2.5: Dostęp do Internetu stacjonarnego w Polsce, [źródło: http://pclab.pl/ news63802.html]. ny tego, że dane przesyłane na jego komputer są zgodne z oczekiwaniami i nie spowodują uszkodzenia innych danych bądź urządzeń. 2.7.1 Uwierzytelnianie Uwierzytelnianie jest procesem mającym na celu potwierdzenie tożsamości danego użytkownika. Metoda ta jest podstawowym mechanizmem bezpieczeństwa danych. W przypadku poprawnego uwierzytelnienia istnieje pewność, że dany użytkownik jest osobą, za którą się podaje, czego konsekwencją z kolei jest przydzielenie mu dostępu do zasobów, czyli uwierzytelnienie co jest opisane dokładniej w rozdziale 2.7.2. 2.7.2 Autoryzacja Samo uwierzytelnienie klienta wobec serwera nie jest wystarczające, aby zapewnić bezpieczeństwo. Możliwe jest w ten sposób ograniczenie dostępu do pewnych rejonów aplikacji, aż do momentu zalogowania. Złożone aplikacje internetowe dają użytkowni- kom dostęp do ogromu treści. Czasem aplikacja przechowuje jednak dane, które nie po- winny być oglądane przez osoby niebędące z nimi powiązane. Np. aplikacja bankowa umożliwia przeglądanie historii swoich transakcji pod adresem http://przykladowy- bank/user/transactions. Użytkownik może wyświetlić szczegóły pojedynczej transak- cji pod adresem http://przykladowy-bank/user/transactions/:id, gdzie :id to nu- mer transakcji. Nie byłoby jednak właściwe, gdyby inna osoba mogła uzyskać dostęp
  • 43. Rozdział 2. Wprowadzenie teorytyczne 43 do tych danych, po prostu przeszukując wszystkie możliwe numery transakcji. Kolejnym przykładem może być blog gdzie pod adresem http://blog.com/recent posts możemy wszystkie posty utworzone w ciągu ostatnich 5 dni. Co, jednak jeśli chcemy, aby tylko użytkownicy ze specjalnymi uprawnieniami mogli wyświetlać posty oznaczone jak taj- ne? Problemem do rozwiązania jest w tym przypadku filtrowanie treści w zależności od uprawnień użytkownika. Wracając do przykładu z najnowszymi postami. Przekazując do widoku kolekcję wszystkich postów, należy wziąć pod uwagę uprawnienia (np. czy mamy do czynienia z administratorem) użytkownika (w tym przypadku zmienna current user). Listing 2.27: Przykład modelu ”Post” i zabezpieczonego kontrolera 1 class Post < ActiveRecord :: Base 2 scope :recent , -> { where(’created_at BETWEEN ? AND ?’, 5. days.ago , Time.now) } 3 scope :visible_by , -> (client) { client.admin ? all : where( supersecret: false) } 4 end 5 6 class PostsController < BaseController 7 def index 8 render Post.visible_by(current_user).recent 9 end 10 end Kolejnym problemem, który trzeba rozważyć w powyższym przykładzie, jest możliwość edycji posta. Funkcjonalność edycji utworzonych przez siebie bytów jest konieczna w więk- szości przypadków. Nie chcemy jednak aby ktoś inny mógł edytować nasze posty. Zabez- pieczenie kontrolera na powyższy przypadek wygląda następująco: Listing 2.28: Przykład zabezpieczenia metody ”update” kontrolera 1 class PostsController < BaseController 2 before_action : check_ownership !, only: :update 3 expose (: post) 4 5 def update 6 post. update_attributes (body: params [: body ]) 7 redirect_to post_path(@post) 8 end 9 10 private 11 12 def check_ownership ! 13 fail UnauthorizedAccess unless post.author == current_user
  • 44. Rozdział 2. Wprowadzenie teorytyczne 44 14 end 15 end Przed wykonaniem akcji update serwer sprawdza, czy użytkownik domagający się takiej akcji jest autorem posta. Jeśli nie jest, wzbudza wyjątek UnauthorizedAccess, a następ- nie może wyświetlić użytkownikowi informację, że może edytować tylko swoje posty. Jeśli test na autorstwo przejdzie pozytywnie, pozwala wykonać żądaną akcję. Powyższe za- bezpieczenia wydają się trywialne, ale są bardzo ważne do zachowania bezpieczeństwa całej aplikacji. Edycja czyjegoś wpisu nie jest może dużą stratą, ale wszędzie tam gdzie system obraca jakimikolwiek środkami pieniężnymi, stawka jest dużo większa. Mimo tego programiści bardzo często niedostatecznie zabezpieczają dostęp do usług. Biblioteką, która podchodzi do powyższego zagadnienia kompleksowo, jest cancan- can[22]. Jej twórcy zaproponowali deklaratywne podejście do uprawnień użytkowników. Zamiast w każdym miejscu sprawdzać, czy dane konto ma rzeczywiście dostęp do konkret- nego zasobu, definiuje się jego uprawnienia w jednym pliku. Podczas dostępu do zasobów biblioteka sprawdza, czy żądany obiekt znajduje się na liście uprawnień. Przykład definicji uprawnień: Listing 2.29: Przykład definicji uprawnień w bibliotece ”cancancan” 1 class Ability 2 include CanCan :: Ability 3 4 def initialize(user) 5 user ||= User.new # guest user (not logged in) 6 if user.admin? 7 can :read , Post 8 else 9 can :read , supersecret: false 10 end 11 end 12 end Klasa Ability definiuje zdolności użytkownika. Powyższy definicja jest intuicyjna i zbli- żona do pseudokodu. Może być zrozumiana również przez kadrę menadżerską, co jest dużą zaletą i ułatwia komunikację w zespołach. Jest to jeden z atutów języka Ruby.
  • 45. Rozdział 3 Opis technologii W niniejszym rozdziale zostaną wprowadzone analizowane technologie do tworzenia aplikacji klienckich typu SPA: ReactJS oraz AngularJS (rozdziały 3.1 i 3.2). W dalszej częsci przedstawione zostaną technologie serwerowe, mianowicie: Rails, Sinatra oraz Gra- pe (3.3, 3.4, 3.5). Wprowadzenie zawierać będzie informacje ogólne, krótki rys historyczny, a także czynniki motywujące autorów powyższych technologii do użycia takich czy innych rozwiązań. Autorzy pracy będą starali się wskazać najbardziej charakterystyczne cechy analizowanych bibliotek. Duży nacisk zostanie położony również na architekturę przesta- wianych rozwiązań, z uwzględnieniem wzorców projektowych i modelowania przepływu informacji. Tam gdzie to konieczne, wprowadzone zostaną szczegóły użytych algorytmów (Diff Algorithm 3.1.6). Konkretne elementy bibliotek, zostaną podparte przykładami ko- du, czy to z zaimplementowanych aplikacji, czy dokumentacji. 3.1 ReactJS Biblioteka ReactJS napisana w języku JavaScript, przez programistę Facebooka Jorda- na Walke, jest z całą pewnością najciekawszą pozycją w niniejszej pracy. Celem przyświe- cającym jej twórcom było usprawnienie projektowania interfejsów użytkownika, poprzez wprowadzenie deklaratywnych, modularnych i dajacych się ponownie używać komponen- tów. Jeśli rozważalibyśmy jej umiejscowienie w modelu MVC - byłaby to litera V - widok. Wydaje się, że odpowiedzialność widoku w powyższym wzorcu jest dość mała. React jed- nak prezentuje rewolucyjne, a także dość kontrowersyjne podeście, wymuszając zmiany na całym przepływie danych. Sama biblioteka jest dość minimalistyczna. Nie wymusza na programiście konkretnej architektury projektu. Nie jest wskazany preferowany spo- sób komunikacji z serwerem, struktura klas czy folderów. Twórcy Reacta proponują co prawda wzorzec o nazwie ”Flux” (o którym będzie też mowa w tym rozdziale), ale jest 45
  • 46. Rozdział 3. Opis technologii 46 to opcjonalne. Takie podejście daje dużą elastyczność, jest jednak sporym wyzwaniem. Samodzielne dobieranie komponentów i projektowanie architektury wymaga pewnego do- świadczenia. Jako materiał do analizy w niniejszej pracy posłużyło połączenie Reacta, Fluxa i lekkiej biblioteki BackboneJS (tylko elementy do komunikacji z API). Więcej o tych technologiach można znaleźć w [9] i [13]. 3.1.1 Deklaratywny charakter widoków Opisywany w rozdziale 3.2 AngularJS korzysta z rozwiązania o nazwie ”two-way data binding”. Jest to funkcjonalność wbudowana w tę bilbiotekę (podobne rozwiązanie zasto- sowano w EmberJS - więcej informacji o nim w [10]). Przez długi czas był to standard wiązania danych z szablonem. Zarządzanie stanem obiektów po stronie klienta i ich syn- chronizacja z serwerem jest zadaniem trudnym. ”Two-way data binding” zdaje się cudow- nym rozwiązaniem. Programista nie musi ręcznie kontrolować wartości przechowywanych w formularzach i zapisywać ich w specjalnych obiektach. Po powiązaniu elementu inter- fejsu użytkownika z konkretnym modelem każda zmiana jednego z nich będzie skutkowała też zmianą drugiego. Twórcy Reacta przekonują, że takie wiązanie danych, jest źródłem wielu problemów. Ciężko stwierdzić jak głęboko może sięgać łańcuch takich zmian. Za- miast tego proponują prostsze rozwiązanie - ”unidirectional data flow”. Każdy komponent posiada funkcję ”render”. W niej za pomocą biblioteki JSX definiowany jest wygląd tego elementu, poniżej przykład z zaimplementowanej aplikacji: Listing 3.1: Przykład funkcji ”render” dla elementu listy rzeczy do zrobienia 1 render: function () { 2 var todo = this.props.todo; 3 var iClassName = ’fa fa -2x action check ’ 4 var trClassName = ’row ’ 5 if (todo.get(’completed ’)) { 6 iClassName += ’fa -check -square ’; 7 trClassName += ’bg -success ’; 8 } else { 9 iClassName += ’fa -square -o’; 10 }; 11 if (this.props.showCompleted === false && todo.get(’completed ’) === true) { 12 return null 13 }; 14 15 return ( 16 <tr className ={ trClassName}>
  • 47. Rozdział 3. Opis technologii 47 17 <td > 18 <i className ={ iClassName} onClick ={ this. _onToggleComplete }/> 19 </td > 20 <td >{ todo.get(’name ’)}</td > 21 <td className=’inline ’> 22 <i className=’fa fa -times -circle fa -2x delete pull -right action close ’ onClick ={ this. _onDestroyClick }/> 23 </td > 24 </tr > 25 ); 26 } Programista definiuje wygląd komponentu tylko raz. Jeśli zajdą jakieś zmiany w przeka- zywanych parametrach lub jego stanie, cały DOM zostanie przerenderowany. 3.1.2 Props W powyższym przykładzie pokazane zostało użycie funkcji Reacta o nazwie ”props”, pochodzącej od słowa ”properties”. Służy ona do przekazywania danych z widoku nad- rzędnego do osadzenia w szablonie JSX (hierarchia widoków może być złożona, zgodnie ze wzorcem projektowym o nazwie kompozyt, opisanym szerzej w [11]). Co ciekawe można przekazywać w ten sposób nie tylko prymitywy, ale też złożone obiekty, np. JSON czy też funkcje. Przekazanie funkcji w taki sposób jest również dobrą praktyką - jest to zgodne ze wzorcem projektowym obserwator [11]. Zapobiega to zbędnemu i szkodliwemu wiązaniu obiektów. Obserwowany obiekt nie ma dostępu do rodzica, potrafi wywyłać tylko metodę, którą otrzymał. Poniżej przykład takiego działania: Listing 3.2: Przekazanie funkcji do subkomponentu 1 // Przekazanie funkcji do subkomponentu 2 return ( 3 <div id=’main ’> 4 <TodoTextInput onSave ={ this.createTodo }/> 5 ... 6 </div > 7 ); 8 9 // Wywolanie funkcji przekazanej z komponentu glownego 10 _save: function () { 11 this.props.onSave(this.state.value); 12 this.setState ({ 13 value: ’’
  • 48. Rozdział 3. Opis technologii 48 14 }); 15 } Należy zaznaczyć, że wszystkie dane przekazane przez ”props” są niezmienne (immutable) dla komponentu, który je otrzymał. 3.1.3 State Bardzo często zdarza się, że elementy interfejsu użytkownika muszą reagować na inte- rakcje. Przykładowo przycisk ”Lubię to” na Facebooku, zmienia swój wygląd po kliknię- ciu, komunikując użytkownikowi wykonanie akcji. Jak zostało wspomniane w poprzednim podrozdziale dane pochodzące z ”props” są niezmienne. ”State” jest miejscem przecho- wywania danych dynamicznie zmieniających się podczas cyklu życia komponentu. Do ustawienia początkowego stanu służy funkcja ”getInitialState”. Poniżej przykład użycia z aplikacji ”Todo”: Listing 3.3: Ustawienie początkowego stanu komponentu w ReactJS 1 getInitialState : function () { 2 return { 3 value: this.props.value || ’’ 4 }; 5 } W trakcie działania aplikacji, komponent może zmienić swój stan, dzięki funkcji ”setSta- te”, poniżej przykład użycia: Listing 3.4: Zmiana stanu komponentu w ReactJS 1 // Element UI ktory jest zmieniany 2 <input className="form -control fw" autoFocus ={ true} value ={ this.state .value} onChange ={ this._onChange} placeholder="Task to be done ..." type="name"/> 3 4 // Funkcja wywolywana po zmianie 5 _onChange: function(/* object */ event) { 6 this.setState ({ 7 value: event.target.value 8 }); 9 },
  • 49. Rozdział 3. Opis technologii 49 Rysunek 3.1: Diagram obrazujący przepływ sterowania w architekturze Flux, [źródło: https://github.com/facebook/flux]. 3.1.4 Flux Przepływ danych narzucony przez Reacta jest bardzo przyjazny dla programisty. Lu- dzie nie są przystosowani do pracy nad kilkoma zadaniami jednocześnie. W dwustronnym przepływie danych analiza zachowania aplikacji często wymagania śledzenia długiego łan- cucha zmian. W takim przypadku łatwo o pomyłkę. React proponuje zastosowanie wzorca SSoT - jedynego źródła prawdy (ang. Single Source of Truth). Pomysł na architekturę całej aplikacji klienckiej dostarcza właśnie Flux (szerzej opisany w [1]). Przepływ danych we Fluxie został przedstawiony na rysunku 3.1: Flux składa się z kilku głównych elemen- tów (rysunek 3.1). Przepływ sterowania odbywa się w pętli po każdym z nich. Poniżej ich opis (ułożone są chronologicznie, od punktu rozpoczęcia interakcji przez użytkownika, aż do pełnego przerysowania dokumentu HTML): • Widok Komponent Reacta. Wchodzi w interakcje z użytkownikiem, renderuje HTML. Opi- sany szerzej w 3.1.1 • Action Creator Dodatkowa warstwa abstrakcji służąca do tworzenia akcji. Została utworzona po to, aby programista inicjował zmiany danych tylko w jednym miejscu. Jego funk- cje mogą przyjmować argumenty, wynikiem ich działania jest przekazanie akcji do Dispatchera
  • 50. Rozdział 3. Opis technologii 50 • Dispatcher Kolejna warstwa abstrakcji. W tym miejscu podejmowane są decyzje, co należy zrobić z akcją. Zazwyczaj przekazywane są dalej, jednak możliwe są inne możliwości. Poniżej wycinek kodu z Dispatchera zaimplementowanej aplikacji. Akcja o typie ”TODO CREATE” jest wywoływana tylko wtedy, gdy jej atrybut ”text” nie jest pusty: Listing 3.5: Część kodu obiektu Dispatcher 1 switch(action.actionType) { 2 case TodoConstants. TODO_LOAD_ALL_COMPLETE : 3 TodoStore.emitChange (); 4 break; 5 6 case TodoConstants.TODO_CREATE: 7 text = action.text.trim (); 8 if (text !== ’’) { 9 create(text); 10 } 11 break; 12 // ... 13 } • Store Centralny punkt składowania danych, również miejsce komunikacji z API. W zaim- plementowanej aplikacji do tego celu została użytka biblioteka BackboneJS (opisana szerzej w 3.1.8). Po wykonaniu działań na danych, obiekt Store emituje globalne zda- rzenie, na które reagują wszystkie komponenty. Cały interfejs, wszystkie formularze, przyciski, pola tekstowe zostają wyrenderowane ponownie. Wydaje się, że jest to nie- efektywne działanie i przy standardowym pełnym odświeżeniu tak by było. Jednak jedna bardzo ważna właściwość Reacta sprawia, że takie działanie ma sens. 3.1.5 Virtual DOM DOM został stworzony do reprezentacji dokumentów HTML niezależnie od platfor- my i języka. Ma strukturę drzewa. Przez długi czas był stosowany tylko do wyświetlenia informacji. Nie został stworzony z myślą o złożonych operacjach dodawania, usuwania i zmieniania węzłów. Te uwarunkowania czynią działania na nim wąskim gardłem (co po- kazały testy przeprowadzone przez autorów pracy 4, a także przeprowadzone przez inne osoby). React został zaprojektowany z myślą o przejrzystej architekturze i łatwo roz-
  • 51. Rozdział 3. Opis technologii 51 wijalnym, modularnym kodzie. Rozpoznawalny jest jednak chyba głównie dzięki swojej wydajności. Z każdą zmianą stanu, React przerenderowuje całą aplikację. Jednak robi to w specyficzny sposób. Virtual DOM to dodatkowa warstwa abstrakcji, lekka kopia prawdziwego DOM. Wszystkie zmiany stanu są odzwierciedlane najpierw w Virtual DOM. Operacje na nim są szybsze, gdyż obiekt ten jest tylko wirtualny - nie musi zostać przerysowywany po każdej opera- cji. W przypadku zwyczajnego DOM bardzo często zdarza się, że przeplatając operacje odczytu i zapisu, wymagany jest tzw. ”reflow” i to nawet kilkukrotny. Ilustruje to listing 3.6: Listing 3.6: Operacje na DOM przykład 1 // Wejscie 2 <div> 3 <div>a</div> 4 <div>b</div> 5 </div> 6 7 // Wyjscie 8 <div> 9 <div>c</div> 10 <div>d</div> 11 </div> W standardowej manipulacji na DOM, przeglądarka wykonałaby ”reflow” 4 razy. Przy operowaniu na znaczącej liczbie węzłów liczonej w tysiącach, byłoby to już zauważalne dla użytkownika. React oblicza minimalną liczbę zmian między drzewami (diff algorithm), a dopiero później aplikuje je do DOM. Dlatego fakt, że cała aplikacja przerysowuje się z każdą zmianą danych, nie niesie za sobą spadku wydajności, a jedynie wzrost przejrzystości architektury. 3.1.6 Diff Algorithm Operacja obliczania minimalnej liczby transformacji jednego drzewa w drugie ma zlo- żoność rzędu O(n3 ). W przypadku manipulacji tysiącem węzłów (co nie jest rzadkim przypadkiem), koniecznie jest wykonanie jednego miliarda operacji. Taka złożoność jest jednak nie do przyjęcia. Autorzy Reacta oparli swój algorytm na dwóch dodatkowych założeniach: • Dwa komponenty tej samej klasy wygenerują podobne drzewa, a dwa komponenty różnych klas wygenerują różne drzewa.
  • 52. Rozdział 3. Opis technologii 52 • Możliwym jest dostarczenie unikalnych kluczy, dla elementów niezmiennych przy ponownym rysowaniu. Algorytm porównywania drzew ma rekurencyjny charakter. Zatem chcąc operować na całym drzewie, należy najpierw zdefiniować operację na jednym węźle. React rozróżnia 3 typy takiej operacji: • Różne typy węzła Listing 3.7: React transformacja węzłów różnych typów 1 renderA: <div /> 2 renderB: <span /> 3 => [removeNode <div />], [insertNode <span />] W takim przypadku React nie podejmuje próby negoncjacji atrybutów, czy węzłów potomnych. Cała gałąź drzewa zostaje usunięta i zastąpiona nową. • Zgodne typy węzła Listing 3.8: React transformacja węzłów o takich samych typach 1 renderA: <div style ={{ color: ’red’}} /> 2 renderB: <div style ={{ fontWeight: ’bold ’}} /> 3 => [removeStyle color], [addStyle font -weight ’bold ’] Tutaj bardziej opłacalnym działaniem staje się zmiana atrybutu. Należy dodać, że style elementu (które w HTML są po prostu zmienną typu String), traktowane są jako tablica asocjacyjna. • Inteligentne operowanie na liście Najbardziej problematyczne jest obliczanie różnic w liście węzłów. Przypadek ze stałą liczbą elementów jest prosty - React porównuje po prostu obie listy, element po elemencie. Złożoność operacji to O(n). Dodanie elementu na końcu listy, również nie jest skomplikowane (złożoność nie wzrasta). Co jednak w przypadku dodawania elementów na początku lub w środku listy? Rozwiązaniem tego problemu mogłoby być obliczenie odległośi Levenshteina (złożoność O(n2 )). Jednak ten algorytm mimo wyższej złożoności, nie pozwala na wykrycie zmiany kolejności elementów. Algoryt- my, które na to pozwalają, mają jeszcze większą złożoność.
  • 53. Rozdział 3. Opis technologii 53 Twórcy Reacta zaproponowali prostsze rozwiązanie. Zamiast skomplikowaych ob- liczeń na elementach listy, nadali każdemu z nich unikalny (w lokalnym zakresie) klucz, niezmienialny przy kolejnych przerysowaniach. Dzięki temu iterowanie po li- ście sprowadza się do iteracji po wszystkich kluczach tablicy asocjacyjnej (złożoność O(n)). 3.1.7 JSX Kolejną rzeczą wyróżniającą Reacta jest biblioteka JSX do pisania szablonów. Należy zaznaczyć, że jest całkiem opcjonalna. Dzięki niej programista może osadzać elementy o bardzo podobnej składni do HTMLa, w kodzie JavaScript. Różnice obu podejść na listingu 3.9 Listing 3.9: Porównanie budowy szablonów z użyciem JSX i bez 1 // Komponent HelloMessage zbudowany z pomoca JSX 2 var HelloMessage = React.createClass ({ 3 render: function () { 4 return <div >Hello {this.props.name}</div >; 5 } 6 }); 7 React.render(<HelloMessage name="John" />, mountNode); 8 9 // Komponent HelloMessage zbudowany w czystym JS 10 var HelloMessage = React.createClass ({ displayName: "HelloMessage", 11 render: function () { 12 return React.createElement("div", null , "Hello ", this.props.name ); 13 } 14 }); 15 React.render(React.createElement(HelloMessage , {name: "John"}), mountNode); 3.1.8 Backbone React, czy też architektura Flux, nie dostarcza gotowych narzędzi do komunikacji z API. Programista ma więc wolny wybór. Istnieje możliwość używania czystego JavaScrip- tu, jQuery lub dodatkowej biblioteki. Bardzo często spotyka się implementacje Fluxa wraz z minimalistyczną biblioteką BackboneJS, która dostarcza dodatkową warstwę abstrakcji, w postaci modeli i kolekcji. Dzięki nim nie ma potrzeby konstruowania skomplikowanych
  • 54. Rozdział 3. Opis technologii 54 zapytań XHR. Wszystko to zostało opakowane w wygodne funkcje, np. fetch() - do po- bierania listy obiektów, save() - zapisywania stanu obiektu na serwerze, czy destroy() - do usuwania obiektu. 3.2 AngularJS Angular z języka angielskiego znaczy w tłumaczeniu dosłownym kanciasty, kątowy, narożny. Czy nazwa tego frameworka mówi coś więcej na temat jego funkcjonalności, ten rozdział postara się na to i inne pytania odpowiedzieć. AngularJS jest to zestaw narzę- dzi JavaScript do tworzenia aplikacji frontendowych typu SPA. Koncepcja SPA została omówiona w rozdziale 2.3. Historia Angulara sięga roku 2009. W początkowym etapie projekt ten był zaledwie małym prywatnym pomysłem realizowanym przez pracowników firmy Google Adama Abronsa i Misko Hevery’ego. Zarząd koncernu Google uznał projekt AngularJS na tyle ciekawy, że otrzymał oficjalne wsparcie wraz z zespołem programi- stów który miał za zadanie go rozwijać. W 2012 roku po raz pierwszy framework został upubliczniony. Wiele zalet Angulara zaczerpnięto ze sprawdzonych metod, co pozwoliło na stworzenie wydajnego i efektywnego frameworka, który zapewnia nieskomplikowaną strukturę, szerokie spektrum możliwości oraz wygodne metody testowania. Bardzo duży udział w rozwoju Angulara ma także społeczność internetowa. Dzięki ciągłej wymianie do- świadczeń pomiędzy programistami AngularJS framework jest poddawany ciągłym ulep- szeniom. Programiści chcący poznać wady i zalety Angulara w praktyce powinni odwiedzić stronę [8] na której znajdują się dokumentacje, kursy, poradniki, opisy API i inne rzeczy przydatne dla deweloperów. Przykłady aplikacji napisanych w Angularze znajdziemy na stronie https://builtwith.angularjs.org/. Bardzo istotnym aspektem dotyczącym Angula- ra jest fakt, iż jest on publikowany na licencji MIT, co oznacza, że jest w pełni darmowy. AngularJS pozwala w teorii w szybki i łatwy sposób budować warstwę kliencką aplikacji internetowych. Koncepcja omawianego frameworka zakłada tzw. MVW, czyli organizację aplikacji w obrębie model-widok-cokolwiek dzięki, czemu można pogodzić idee JavaScript z modelem MVC. W ostatnim czasie omawiany framwework stał się bardzo popularny, co zaobserwować możemy na wykresie 3.2 oraz zaczął być wykorzystywany w aplikacjach typu enterprise. Za pomocą Angulara stworzone zostały między innymi YouTube na Play Station 3 oraz platforma muzyczna VEVO. AngularJS posiada kilka interesujących rozwiązań, których próżno szukać w innych frameworkach. Oto niektóre z nich:
  • 55. Rozdział 3. Opis technologii 55 Rysunek 3.2: Porównanie ilości ofert pracy dla popularnych platform klienckich typu MVC, [źródło: http://www.indeed.com/jobtrends]. 3.2.1 Kompilator HTML Główną cechą odróżniającą Angulara od reszty tego typu narzędzi to fakt posiadania własnego kompilatora HTML. Dzięki temu można w prosty sposób rozszerzyć HTML o nowe zdeiniowne wcześniej tagi, które mogą realizować nowe funkcje. 3.2.2 Dwustronne wiązanie danych W przeszłości, zanim technologia AJAX opisana w rozdziale 2.2, była szerzej wykorzy- stywana, do konstruowania interfejsu użytkownika wykorzystywane były narzędzia typu PHP, Rails, ASP.NET lub inne. Serwer odpowiadał za generowanie widoku HTML przed prezentacją go dla użytkownika. Dzięki wykorzystaniu biblioteki jQuery dla języka Ja- vaScript można odświerzać wybrane elementy DOM bez konieczności przeładowywania całej strony. W HTML wstrzykiwane są dane, a następnie wynik jest dodawany do do- wolnej części DOM z wykorzystaniem atrybutu ”inneHtml” dla właściwego elementu. W koncepcji one way binding informacje są pobierane z modelu, który służy za swego ro- dzaju kontener do przechowywania danych i wysyłane do widoku, który ma za zadanie je wyświetlić. Natomiast nie istnieje możliwość wpływania na model z poziomu widoku przy tym podejściu. Zgodnie z diagramem 3.3 dane synchronizowane są tylko z widokiem, to znaczy, że programista musi zaimplementować mechanizm synchronizacji widoku z mo- delem, gdy przykładowo użytkownik wprowadzi dane do aplikacji. Przykładem takiego frameworka jest BackboneJS. Problem ten został rozwiązany w Angularze. Omawiany
  • 56. Rozdział 3. Opis technologii 56 Rysunek 3.3: Jednostronne wiązanie danych w AngularJS, [źródło: https://docs. angularjs.org/guide/databinding]. framework posiada tak zwane dwustronne wiązanie danych, które pozwala na synchroni- zację stanu widoku i modelu po stronie JavaScript. Wystarczy dodać prostą deklarację, która zdefiniuje, jakie obiekty po stronie kontrolera lub widoku będą ze sobą powiązane. W tej deklaracji wykorzystujemy obiekt $scope oraz dyrektywę ”ng-model”. Na rysun- ku 3.4 możemy zobaczyć, że gdy dajmy na to, zostanie wprowadzona zmiana w widoku, przykładowo wprowadzimy tekst w polu formularza, to dane te automatycznie zostaną zsynchronizowane z modelem. Podobnie działa to w drugą stronę. To znaczy, gdy przy- kładowo dane w modelu zmienią się w wyniku odpowiedzi na zapytanie do API serwera, to mechanizm podwójnego wiązania uaktualni te dane w widoku, czyli w warstwie pre- zentacji dla użytkownika. Dzieki temu rozwiązaniu programista jest odciążony z dbania o aktualny stan danych w każdym miejscu w aplikacji. 3.2.3 Obiekt $scope Charakterystyczną cechą Angulara jest obiekt $scope. Służy on do transportowania modelu pomiędzy widokiem a kontrolerem. Odpowiada też za nasłuchiwanie zdarzeń lub zmian zachodzących w modelu, a także za propagację tych zmian. Pomimo że $scope jest traktowany przez twórców omawianego frameworka, w sposób wyjątkowy to wpsomniany obiekt jest tak naprawdę zwykłym obiektem typu POJO, którego atrybutami możemy
  • 57. Rozdział 3. Opis technologii 57 Rysunek 3.4: Dwustronne wiązanie danych w AngularJS, [źródło: https://docs. angularjs.org/guide/databinding]. dowolnie manipulować. Warty uwagi jest fakt, iż generalnie $scope jest tworzony i wstrzy- kiwany w sposób automatyczny bez udziału programisty. AngularJS w początkowej fazie ładowania aplikacji tworzy powiązanie między tagiem zawierającym dyrektywę ”ng-app” a wszystkimi elementami znajdującymi się poniżej obiektu $scope. Najwyżej w hierarchii obiektów znajduje się $rootScope, który jest rodzicem wszystkich obiektów $scope. Każ- da aplikacja posiada tylko jeden obiekt typu $rootScope, po którym dziedziczą wszystkie inne obiekty $scope. W fazie początkowej ładowania aplikacji tworzona jest nadrzędna instancja $rootScope. Dobrą praktyką jest relatywnie mała liczba atrybutów przypiasna do niego, gdyż pełni on rolę obiektu golobalnego, który powinien zawierać tylko rzeczy najistotniejsze. Przy korzystaniu z dużej ilości bibliotek zewnętrznych pojawia się ryzyko, iż wystąpi zbieżność nazw medod lub atrybutów przypisanych do obiektów typu $rootSco- pe dlatego też unikanie tego rodzaju sytuacji może zaoczędzić programiście wiele czasu i nerwów. W związku z tym, że zmienna $scope jest inicjalizowana w procesie począt- kowego ładowania aplikacji, czyli tzw. bootstrap elementy przypisane tej zmiennej są od początku dostępne w widoku. Na listingu 3.10 zaczerpniętego z książki [7] mamy przy- kład przypisywania funkcji i atrybutów do modelu po stronie kontrolera. W omawianym przykładzie został zdefiniowany atrybut dateOriginal w globalnym obiekcie $rootScope a