65
FAKULTETA ZA INFORMACIJSKE ŠTUDIJE V NOVEM MESTU D I P L O M S K A N A L O G A UNIVERZITETNEGA ŠTUDIJSKEGA PROGRAMA PRVE STOPNJE DEJAN LOKAR

D I P L O M S K A N A L O G A - dk.fis.unm.sidk.fis.unm.si/dip/UN_2014_Dejan_Lokar.pdf · POVZETEK V diplomski nalogi primerjam dve odprtokodni ogrodji za izdelavo spletnih aplikacij

  • Upload
    others

  • View
    3

  • Download
    0

Embed Size (px)

Citation preview

FAKULTETA ZA INFORMACIJSKE ŠTUDIJE

V NOVEM MESTU

D I P L O M S K A N A L O G A

UNIVERZITETNEGA ŠTUDIJSKEGA PROGRAMA PRVE STOPNJE

DEJAN LOKAR

FAKULTETA ZA INFORMACIJSKE ŠTUDIJE

V NOVEM MESTU

DIPLOMSKA NALOGA

PRIMERJAVA DVEH LAHKIH OGRODIJ ZA

IZDELAVOSPLETNIH APLIKACIJ NA PRIMERU

PROCESA SESTAVE LOKALNE KOŠARICE

Mentor : doc. dr. Matej Mertik

Novo mesto, julij 2014 Dejan Lokar

IZJAVA O AVTORSTVU

Podpisani Dejan Lokar, študent FIŠ Novo mesto, izjavljam:

da sem diplomsko nalogo pripravljal samostojno na podlagi virov, ki so navedeni v

diplomski nalogi,

da dovoljujem objavo diplomske naloge v polnem tekstu, v prostem dostopu, na spletni

strani FIŠ oz. v elektronski knjižnici FIŠ,

da je diplomska naloga, ki sem jo oddal v elektronski obliki identična tiskani verziji,

da je diplomska naloga lektorirana.

V Novem mestu, dne _________________ Podpis avtorja ______________________

POVZETEK

V diplomski nalogi primerjam dve odprtokodni ogrodji za izdelavo spletnih aplikacij na strani

odjemalca, ki vodijo v arhitekturo preprostega strežnika in zahtevnega odjemalca. Ogrodji

primerjam s primerjalno analizo na primeru izgradnje aplikacije za povezovanje lokalnih

ponudnikov hrane in glede na njuni skupnosti. Med raziskavo izpostavljam prednosti in slabosti

ogrodij. Na podlagi ugotovitev na koncu izberem najbolj primerno.

KLJUČNE BESEDE: spletne aplikacije, odprta koda, Angular, Ember, ogrodje

ABSTRACT

In the thesis I compare two open source, client side frameworks for making modern web

applications, with thin server and thick client architecture. Frameworks are compared in a

comparative analysis in which I implement a part of application for connecting local food

suppliers and based on the community frameworks attracted. During the research I expose

advantages and disadvantages of each framework and select the best fit for building that

application.

KEY WORDS: web application, client-side application, open source, angular, ember, framework

KAZALO

1 UVOD .................................................................................................................................... 1

2 OZADJE RAZISKAVE ......................................................................................................... 2

2.1 Spletne aplikacije .............................................................................................................. 4

2.2 Odprta koda ....................................................................................................................... 5

3 OPIS PROBLEMA IN RAZISKOVALNO VPRAŠANJE .................................................... 8

4 METODOLOGIJA ................................................................................................................. 8

4.1 Analiza implementacije ..................................................................................................... 9

4.2 Analiza kode ...................................................................................................................... 9

4.3 Analiza skupnosti ............................................................................................................ 10

5 PRIMERJALNA ANALIZA ................................................................................................ 10

5.1 Specifikacija najmanjšega izvedljivega produkta (MVP) ............................................... 10

5.2 Visokonivojski MVP implementiran z Angular-jem ....................................................... 12

5.3 Visokonivojski MVP implementiran z Ember-jem ......................................................... 13

5.4 Analiza implementacije ................................................................................................... 15

5.4.1 Zagon aplikacije ..................................................................................................... 16

5.4.2 Statični del strani ................................................................................................... 17

5.4.3 Usmerjanje ............................................................................................................. 18

5.4.4 Pridobivanje podatkov iz strežnika ........................................................................ 20

5.4.5 Kontroler ................................................................................................................ 23

5.4.6 Uporabniški vmesnik (ang. view layer).................................................................. 29

5.4.7 Direktive in komponente ........................................................................................ 34

5.4.8 Testi enot (ang. unit test) ........................................................................................ 38

5.4.9 Integracijski testi .................................................................................................... 40

5.4.10 Razlike .................................................................................................................... 42

5.5 Analiza kode .................................................................................................................... 43

5.6 Analiza skupnosti ............................................................................................................ 46

6 ZAKLJUČEK ....................................................................................................................... 48

7 LITERATURA IN VIRI ....................................................................................................... 51

KAZALO DIAGRAMOV

Diagram 5.1: Poslovni proces sestave košarice s hrano ................................................................. 11

Diagram 5.2: Proces sestave košarice implementiran z Angularjem ............................................. 12

Diagram 5.3: Proces sestave košarice implementiran z Emberjem ............................................... 14

KAZALO GRAFOV

Graf 4.1: Popularnost ogrodij glede na število uporabnikov, ki spremlja njihove repozitorije ....... 8

Graf 5.1: Iskanje po ključnih besedah obeh ogrodij ...................................................................... 46

Graf 5.2: Iskanje po ključnih besedah. .......................................................................................... 46

KAZALO SLIK

Slika 2.1: Arhitektura kompleksnega strežnika levo in kompleksnega odjemalca desno ............... 5

Slika 5.1: Uporabniški vmesnik aplikacije za sestavo košarice .................................................... 12

KAZALO TABEL

Tabela 5.1: Pokazatelji kompleksnosti kode .................................................................................. 45

Tabela 5.2: Število razvijalcev, ki repozitoriju projektov prispeva, ga spremlja, ga je označilo

z zvezdo ali ga je odcepilo .......................................................................................... 47

Tabela 5.3: Število vprašanj glede ogrodij postavljenih v enem dnevu, tednu in do zdaj ............. 48

1

1. UVOD

V zadnjem desetletju je internet doživel ogromno rast kot aplikacijska platforma. Začelo se je s

spletnimi strani z nekaj interaktivnimi elementi, ki jih je omogočil javascript. Nato odkritje

pristopa AJAX odpre vrata spletnim aplikacijam, ki z uporabnostjo konkurirajo aplikacijam v

operacijskem sistemu in odkrijejo novo raven povezovanja uporabnikov. Velikanska popularnost

teh aplikacij in interneta na splošno je gonilna sila, ki vodi razvoj brskalnikov in spletnih

tehnologij. Brskalnik, kot kompleksen kos programske opreme in okolje za izvajanje aplikacij

lahko danes primerjamo že z operacijskim sistemom.

V zadnjih letih razvijalci vedno bolj eksperimentirajo s spletnimi aplikacijami, ki izkoriščajo ves

ta potencial odjemalcev za dostavo boljših spletnih aplikacij. Danes je razvitih že več ogrodij, ki

logiko interaktivne spletne aplikacije izvajajo na strani odjemalca do te mere, da strežnik lahko

deluje le kot api dostopna točka z JSON podatki.

V diplomski raziskavi primerjam dve ogrodji, ki sta v pomoč pri razvoju aplikacij na eni strani, z

logiko na strani odjemalca. Te postajajo pogoste in pričakovane, kjer je njihova uporaba

primerna. Omogočil jih je razvoj tehnologij svetovnega spleta kot so html, css, javascript in

akumulirano znanje razvijalcev, ki sestavljajo takšne aplikacije in podporna orodja. Uporabniška

izkušnja je podobna tisti v aplikacijah, ki tečejo neposredno v operacijskem sistemu, poleg tega

pa so lahko dostopne, vedno posodobljene, delujejo na različnih operacijskih sistemih z

različnimi brskalniki ter navadno spodbujajo sodelovanje uporabnikov.

Aplikacije na eni strani prepoznamo po uporabniški izkušnji boljši od spletnih strani, ki

poenostavi uporabnikovo opravilo, estetskem in bogatem uporabniškem vmesniku ter

osredotočenosti na opravilo ki mu je namenjena. Aplikacije so samostojne v tem pogledu, da za

dosego opravila ne preusmerijo uporabnika, opravilo poteka na eni strani, na kateri se menjajo

pogledi oz. deli strani. Uporabljajo gumbe, dialoge in komponente na enak način kot namizne

aplikacije. Navadno ne uporabljajo navigacijskega menija ob strani ali na vrhu in brskalnikovih

gumbov za prehod na prejšnjo ali naslednjo stran, namesto tega so uporabljeni za prehod med

2

stanji aplikacije. Dobre aplikacije spodbujajo interakcijo in so takoj uporabne brez treningov ali

navodil (Appward, 2012).

S pomočjo raziskave želim ugotoviti katero MVC ogrodje, ki se izvaja v brskalniku je najbolj

primerno za izgradnjo aplikacije, ki dela z virom podatkov in lahko dodaja nove postavke,

posodablja obstoječe ali jih odstrani (ang. CRUD application).

Ogrodij za izdelavo takšnih aplikacij je preveč, da bi lahko primerjal vse, zato izberem dve

popularni ogrodji s podobnim obsegom funkcionalnosti in primerjam oba pristopa k izdelavi

aplikacije na eni strani. Podrobnejši razlogi za izbiro Emberja in Angularja so zapisani v

metodologiji. V prvem delu primerjave opisujem ogrodji na primeru aplikacije za povezovanje

lokalnih ponudnikov hrane. V aplikaciji pripravim stran s košaricami in pod strani posameznih

košaric, ki jih lahko urejamo. Reševanje tega problema pa je reprezentativno bolj širokemu prej

omenjenemu tipu aplikacij, ki urejajo vir podatkov. Primerjavi implementacije sledi kratka

analiza kode z osnovnimi metrikami in nazadnje še primerjava skupnosti obeh odprtokodnih

ogrodij.

Smiselnost raziskave utemeljujem z veliko potrebo po takšnih aplikacijah in zanimanju

razvijalcev za ogrodja MVC, ki se izvajajo na strani klienta.

2. OZADJE RAZISKAVE

Svetovni splet (www) je izumil Tim Berners-Lee leta 1989. Znanstvenik takrat zaposlen pri

CERN-u, je mrežo razvil za deljenje informacij med znanstveniki z različnih univerz in ustanov

po svetu. Postavil je prvo spletno stran ki opisuje osnovne cilje spleta, deljenje dokumentov in

vzpostavitev strežnika. Od leta 2013 je stran vnovič objavljena na svojem izvornem naslovu

info.cern.ch.

30. aprila 1993 je CERN premaknil splet v javno domeno. Naslednje različice so imele odprto

3

licenco s katero so zagotovili hitro širjenje tehnologije in razcvet svetovnega spleta. Vpliv spleta

se je širil iz raziskovalnega področja na poslovno, izobraževalno in osebno področje ter

preoblikoval način komunikacije, dela, inoviranja in življenja (O'Luanaigh, 2014).

Ena glavnih komponent odprte spletne platforme je HTML (ang. Hypertext Markup Language)

družina jezikov, ki z oznakami ovijejo vsebino in določijo postavitev in osnovno oblikovanje.

Prvo različico je definiral Tim Berners-Lee leta 1991. Sprva je jezik vseboval le nekaj oznak

potrebnih za zapis znanstvenih besedil, tem pa so dodajali nove, potem ko je tehnologija prešla v

javno domeno in širšo uporabo. Inženirji za Netscape Navigator in Internet Explorer

brskalnikoma so z novimi oznakami poskušali priti do konkurenčne prednosti, kar je vodilo v

nezdružljivost oznak med brskalnikoma. V odgovor Berners-Lee oktobra 1994 ustanovi W3C

(ang. The World Wide Web Consortium), organizacijo, ki od takrat ustvarja in vzdržuje standarde

svetovnega spleta. Današnje priporočilo W3C organizacije je uporaba html 4.01 jezika iz leta

1999, v praksi pa je dobro podprt v brskalnikih in uporabljen tudi html 5.

Maja leta 1995 je Brendan Eich, takrat zaposlen pri Netscapu razvil skriptni jezik, danes znan kot

JavaScript za uporabo v drugi verziji njihovega brskalnika Navigator. Namenjen je bil

preverjanju podatkov, vnesenih v obrazce, in podobnim, predvsem majhnim opravilom.

JavaScript je postal takojšnji hit in konkurenčna prednost Netscapa. Microsoft je sledil s svojo

implementacijo, imenovano JScript. To je pomenilo dve implementaciji brez standarda,

dopolnjevanje brez medsebojnega usklajevanja pa je vodilo v razlike, zaradi katerih spletne strani

niso več delovale v obeh brskalnikih. Med letoma 1996 in 1997 so JavaScript poslali organizaciji

ECMA (ang. European Computer Manufacturers Association) z namenom razvoja standarda, na

podlagi Natscapove implementacije. Organizacija je producirala standard, imenovan

ECMAScript, ki služi za implementacijo JavaScripta in tudi nekaj drugih jezikov. Od prvega

standarda iz leta 1997 in zelo omejene uporabnosti jezika je JavaScript doživel ogromno

popularnost in aktiven razvoj. Dve nadaljnji različici ECMAScript 3 in trenutna implementacija v

brskalnikih ECMAScript 5 uravnovešata izboljševanje jezika ter pomembno povratno

združljivost, v razvoju pa je šesta različica standarda.

Okoli leta 2001 se je končala tako imenovana vojna brskalnikov s prevlado Internet Explorer-ja.

4

Sledilo je obdobje dozorevanja in standardizacije tehnologij. Razvijalci postajajo bolj izkušeni in

producirajo uporabne ter dostopne strani (Stefanov 2008, str. 11).

Naslednji pomemben preboj se zgodi leta 2005, ko Jasse Gerrett predstavi nov način uporabe

obstoječih tehnologij, ki so bile dostopne že leta 2001, in s pristopom, imenovanim Ajax,

predstavi možnost posodobitve strani brez vnovičnega nalaganja. S tem odpre vrata spletnim

aplikacijam, katerih uporabniška izkušnja je primerljiva namiznim programom. Ena prvih in

najbolj vplivnih je Googlova gmail aplikacija za upravljanje z elektronsko pošto.

2.1 Spletne aplikacije

S preoblikovanjem svetovnega spleta v aplikacijsko platformo se začnejo pojavljati knjižnice, ki

pomagajo pri razvoju interaktivnih strani in spletnih aplikacij. Najbolj pogosto uporabljene

rešujejo problem pravilnega delovanja v različnih brskalnikih s svojim apijem za posodobitev

DOM-a, asinhrone zahteve na strežnik, upravljanje z dogodki in podobna opravila. Zadnjih nekaj

let je za zgoraj našteta opravila najbolj pogosto uporabljena knjižnica jQuery.

Na strani strežnika je navadno uporabljeno eno izmed mnogih ogrodij MVC. Ta arhitektura vodi

v preprost odjemalec in kompleksen strežnik, ki dinamično pripravlja poglede (V iz MVC) glede

na navodila kontrolerja in izvaja poslovno logiko nad podatki, odjemalcu pa odgovarja s

pripravljenimi stranmi html. Alternativno se v zadnjih letih uveljavlja arhitektura kompleksnega

odjemalca in preprostega strežnika ali hibridni pristop. MVC se izvaja na strani odjemalca in vse,

kar preostane strežniku, je pošiljanje statičnih datotek in izvajanje poslovne logike ter pošiljanje

podatkov odjemalcu. S tem pristopom so sistemske zahteve strežnika nižje in uporaba sredstev

odjemalca višja, količina poslanih podatkov je manjša, saj je statične datoteke mogoče hraniti pri

odjemalcu, prenašajo se le spremenljivi podatki. Odzivnost aplikacije se z izvajanjem kode MVC

pri odjemalcu poveča. Slabe strani pa so popolno nedelovanje aplikacije v primeru, da odjemalec

ne izvaja JavaScripta, nemogoče optimiziranje za spletne iskalnike in daljše prvo nalaganje.

5

2.2 Odprta koda

Odprta koda kot družbena organizacija produkcije in kot oblika tehnološke inovacije, temelji na

novem konceptu lastniških pravic. Nanaša se na obliko socialne organizacije produkcije, ki izhaja

iz razvoja programske opreme in omogoča prvenstveno odprt dostop do znanja o izvorni kodi

računalniškega programa. Izvorna koda je formula za razumevanje logike programa, ki si ga

lahko vsakdo, ki ima tehnično znanje prilagaja. Lastniška programska oprema temelji na nadzoru

lastniških pravic za izvorno kodo. Uporabniki morajo kupiti program, kot jim je ponujen, ker

nimajo dostopa do logike programa, in ga zato ne morejo prilagajati. Izključeni so iz kroga, ki

pozna izvorno kodo. Izvorna koda odprtokodne programske opreme je objavljena in na voljo

uporabnikom. Odprta koda je javna, ne lastniška. Ta nova oblika lastnine, ki je v popolnem

nasprotju z običajnim režimom pravic intelektualne lastnine, je podprta s sistemom upravljanja, v

katerega se vključujejo vsi soustvarjalci odprtokodne programske opreme. Temelji na njihovi

motiviranosti za delovanje znotraj takšnega sistema in na pripravljenosti za razvijanje novih

organizacijskih struktur za krepitev sodelovanja (Castells v Pivec 2005, str 1).

Slika 2.1: Arhitektura kompleksnega strežnika levo in kompleksnega odjemalca desno

Vir: Prirejeno po Takada (2012)

6

Iz produkcijskih procesov odprte kode izhajajo zelo veliki in pomembni projekti razvoja sodobne

programske opreme. Najbolj znana sta Apache in Linux, obstaja pa še veliko drugih, saj se praksa

naglo širi v svetu raziskovanja, izobraževanja, institucionalnega razvoja, v poslovnem svetu, v

kar se vključuje vse več korporacij kot so IBM, Google in podobne. Odprta koda uvaja novo,

kooperativno obliko produkcije, ki presega tradicionalne omejitve družbene delitve dela,

temelječe na hierarhiji. Namesto tega uveljavlja odprto mrežo prostovoljnega sodelovanja.

Osnovna platforma za strukturiranost in interakcijo pri ustvarjanju odprte kode je internet. Odprta

koda ni proti-kapitalistična. Obstaja mnogo podjetij, ki prakticirajo odprto kodo in z njo

ustvarjajo dobiček. Drži pa, da je akapitalistična, kar pomeni, da je kompatibilna z drugačnimi

logikami in vrednotami. Predvsem ne potrebuje profitne spodbude za delovanje in ne temelji na

zasebnem prisvajanju izključnih pravic za uporabo in uživanje produktov (Castells v Pivec 2005,

str 1−2).

Odprtokodna programska oprema se praviloma definira s štirimi temeljnimi svobodami (Pivec

2007, str 3):

svoboda 0: neomejena uporaba programa v kakršenkoli namen,

svoboda 1: svoboda preučevanja programa, da bi se naučili, kako deluje in kako bi ga bilo

mogoče prilagoditi lastni potrebi,

svoboda 2: neomejeno razširjanje nespremenjenih kopij,

svoboda 3: neomejeno razširjanje dopolnjenih kopij.

Pravne okvire, v katerih se razširja odprto kodna programska oprema sestavlja nekaj desetin tipov

licenčnih aranžmajev od katerih sta dva najstarejša iz osemdesetih (Pivec 2007, str 4):

licenca GNU/GPL, ki jo je napisal Stallman in velja za najbolj »čisto«,

licenca BSD, ki so jo sestavili v Berkeley Unix in temelji na »copyrightu«.

GNU/GPL in podobne licence so znane kot »copyleft«. Te licence zahtevajo, da produkti, ki

izhajajo iz odprte kode ali jo uporabljajo, tudi sami postanejo odprtokodni. Integracija GPL

licenčne programske opreme v lastniško ni dovoljena. BSD licenca in podobne pa postavljajo

manj stroge pogoje uporabe odprtokodne programske opreme. Integracija v lastniško programsko

7

opremo in prilagajanje brez objave izvorne kode sta dovoljena. Restriktivne licence ščitijo

svobodo razvijalcev, medtem ko se druga skupina osredotoča na svobodo uporabnikov (Mertik

2011, str 71).

Odprtokodna programska oprema je prisotna v informatiki praktično od njenih začetkov in ima

pomembno vlogo v njenem razvoju, zato je presenetljivo, da je o delovanju družbenih skupin, v

katerih nastaja, znanega zelo malo. Michael Weiss in Gabriella Moroiu sta s tega vidika

rekonstruirala projekt Apache in prišla do ugotovitev, ki imajo širši splošni pomen. Odprtokodna

skupnost je skupina razvijalcev in uporabnikov odprtokodne programske opreme, ki delijo

skupne interese v projektih in redno sodelujejo z izmenjavo znanja ter skupaj iščejo rešitve za

odprte probleme. Skupnost deluje po načelih meritokracije, konsistentnosti in notranje

transparentnosti (Pivec 2007, str 7).

Člani skupnosti imajo različne vloge (Pivec 2007, str 7):

projektni vodje,

člani jedra (kreatorji, komunikatorji, drugi sodelavci),

aktivni uporabniki,

pasivni uporabniki.

Večji odprtokodni projekti so sestavljeni iz mnogih podprojektov, ki so včasih kar precej

oddaljeni drug od drugega, a so vseeno soodvisni, zato govorimo o ekologiji skupnosti. Pri

vključevanju sta ključna dva dejavnika: obeležje in vzor. Obeležje lahko pomeni privlačno ime,

duhovita kratica, atraktivna lokacija in podobno, kar pri informatikih vzbudi pozitivno asociacijo

in daje vtis intelektualne prestižnosti. Vzor je praviloma karizmatična vodilna oseba, uspešno

podjetje ali projekt. Pomembna je tudi velikost projekta, saj veliko ljudi pritegne pozornost še

drugih (Pivec 2007, str 7).

8

3. OPIS PROBLEMA IN RAZISKOVALNO VPRAŠANJE

Na primeru procesa sestave lokalne košarice hrane me zanima, katero odprtokodno ogrodje za

sestavo spletnih aplikacij, ki se izvaja v brskalniku, je najbolj primerna izbira za implementacijo

aplikacije.

4. METODOLOGIJA

Kljub kratkemu obdobju od pojava celostnih aplikacijskih ogrodij, ki se izvajajo v brskalniku, se

jih je že pojavilo preveč za podrobno analizo vseh. Sprva sem jih na podlagi popularnosti

njihovih repozitorijev na strani Github izločil šest. Vseh šest se izvaja v brskalniku in so

primarno namenjena gradnji poslovnih aplikacij, kjer delamo s podatki, jih spreminjamo,

brišemo, beremo in dodajamo nove. Ta so Backbone, Angular, Meteor, Ember, Knockout in

Batman.

Graf 4.1: Popularnost ogrodij glede na število uporabnikov, ki spremlja njihove repozitorije

Vir: Github (8. avgust 2013)

9

Najprej sem izločil ogrodje Meteor. Kljub popularnosti ogrodje ni pripravljeno za produkcijo, v

času pisanja te naloge še ni dosegel različice 1.0.

Nato izločim ogrodje Batman zaradi skope dokumentacije in ker uporablja jezik coffeescript, ki

se prevede v javascript. To bi otežilo primerjavo po metrikah kode.

Preostanejo štiri ogrodja: dva minimalistična in fleksibilna Backbone in Knockout ter dve

obsežnejši in celostni ogrodji (Angular in Ember). Ogrodji iz prve skupine sta bolj zreli in

večkrat uporabljeni v poslovnih aplikacijah, ogrodji iz druge skupine pa po drugi strani prinašata

več funkcionalnosti, ki lahko poenostavi razvoj. Glede na to, da želim čim večji del aplikacije

izvajati v brskalniku, sem izbral drugi dve in v raziskavi podrobneje primerjam ogrodji Angular

in Ember.

4.1 Analiza implementacije

V prvem delu primerjalne analize opisujem različna pristopa obeh ogrodij pri implementaciji. V

ta namen pripravim preprosto aplikacijo, ki prikaže seznam košaric. Imena košaric so povezave,

ki ob kliku prikažejo košarico z nekaj izdelki. Poleg košarice je seznam izdelkov, ki jih lahko

dodamo vanjo. Pod njo pa je seštevek izdelkov, teže in cene. Enote aplikacije implementiram in

opišem v ogrodju Angular in nato še v ogrodju Ember ter izpostavim razlike med pristopoma.

Aplikacija je majhna, vendar vsebuje koncepte, ki jih želim primerjati in od katerih pričakujem,

da bodo prikazali razlike med ogrodjema. To so pridobivanje podatkov s strežnika, usmerjanje v

brskalniku, priprava uporabniškega vmesnika iz predlog in podatkov ter upravljanje s podatki in

računanje novih.

4.2 Analiza kode

Po primerjavi implementacije primerjam zapisano kodo obeh aplikacij po osnovnih metrikah, ki

so število vrstic, število imperativnih vrstic, ciklični kompleksnosti in indeksu vzdrževanja.

Ugotoviti želim, ali je aplikacija v katerem izmed ogrodij zapisana na očitno več vrsticah in ali je

katera bolj kompleksna in s tem težja za vzdrževanje. Pravilnost ugotovitev povečam s

10

ponovitvijo enake analize na še eni aplikaciji, implementirani v obeh ogrodjih.

4.3 Analiza skupnosti

Na koncu primerjam še skupnost obeh odprtokodnih ogrodij. Repozitorija gostujeta na strani

Github, iz katerega lahko pridobim statistiko, povezano s številom razvijalcev, ki prispevajo k

projektoma, in številom razvijalcev, ki projekta spremljajo. Ti podatki nakazujejo hitrost in

dolgoročno stabilen razvoj projektov.

Drugi vir statistik je stran Stackoverflow, na kateri razvijalci objavljajo vprašanja in odgovore,

povezane z razvojem programske opreme. Pogosta vprašanja se navezujejo na uporabne dobre

prakse ali reševanje problemov, na katere naleti več razvijalcev. S strani uporabim tri statistike:

število vprašanj, povezanih z ogrodjem, število vprašanj, povezanih z ogrodjem v enem tednu in

v enem dnevu. Ti podatki nakazujejo število razvijalcev, ki posamezno ogrodje uporabljajo za

razvijanje aplikacij.

Zadnja uporabljena statistika v primerjavi je pridobljena iz iskalnika Google, in sicer število

poizvedb povezano z ogrodjema od njune pojavitve. Ta statistika nakazuje, kako uspešno ogrodji

pridobivata pozornost novih razvijalcev.

5. PRIMERJALNA ANALIZA

5.1 Specifikacija najmanjšega izvedljivega produkta (MVP)

Domača stran vsebuje seznam košaric s povezavami na strani oziroma stanji aplikacije, na kateri

košarice urejamo. Ogrodji tu naredita zahtevo na strežnik na naslov /api/baskets in prejmeta

odgovor v obliki JSON, ki vsebuje zbirko košaric, kjer ima vsaka košarica id, opis in zbirko

izdelkov, ki jih košarica privzeto vsebuje. Na podlagi teh podatkov pripravita zgoraj opisani

uporabniški vmesnik.

11

Do drugega stanja aplikacije pridemo, ko izberemo eno izmed košaric. Ta stran je razdeljena na

tri dele. V prvem delu je seznam izdelkov v košarici in je privzeto že napolnjen z nekaj izdelki. Ti

so bili priloženi v zahtevi na /api/baskets in si jih aplikacija zapomni iz prejšnjega stanja.

Aplikacije te izdelke prikaže in doda možnost njihove odstranitve iz košarice. Druga naloga pa je

priprava poročila, ki vsebuje število izdelkov v košarici, njihovo težo in ceno. To poročilo se

mora pravilno osveževati, ko izdelke dodajamo in odstranjujemo.

V drugem delu je prikazan seznam priporočenih izdelkov, ki jih lahko dodamo v košarico. Ta

izdelke aplikacija dobi kot zbirko izdelkov v formatu JSON prek zahteve na /api/suggested.

Naloga aplikacije je prikaz izdelkov s ceno na kilogram in možnostjo dodajanja v košarico. Nad

izdelki je še iskalno polje, s katerim priporočene izdelke filtriramo po imenu.

Tretji del strani prikazuje podrobnosti izdelka iz seznamov v prvem ali drugem delu. Ta del se

prikaže kot posledica klika na ime enega izmed izdelkov in prikaže vse podrobnosti tega izdelka.

Ima tudi gumb s katerim ga zapremo.

Diagram 5.1: Poslovni proces sestave košarice s hrano

Vir: Lokar, lastni prikaz (2014)

12

5.2 Visokonivojski MVP implementiran z Angularjem

Diagram 5.2: Proces sestave košarice implementiran z Angularjem

Vir: Lokar, lastni prikaz (2014)

Slika 5.1: Uporabniški vmesnik aplikacije za sestavo košarice

Vir: Lokar, lastni prikaz (2014)

13

Pri uporabi ogrodja Angular imamo kodo, razdeljeno v module. Kot prikazuje diagram, aplikacija

uporablja pet modulov, pri čemer modul s kontrolerji vsebuje vse kontrolerje, storitveni modul

vsebuje vse storitve in tako naprej. Ta način razporeditve kode v modulih zadostuje za manjše

aplikacije, pri večjih pa je bolj smiselna uporaba več modulov. Ker javascript nima razredov, so

kontrolerji, storitve, filtri in direktive dejansko implementirani kot funkcije.

Vhod v aplikacijo se nahaja v modulu App, ki konfigurira poti (naslove URL) v aplikaciji. Te poti

so povezane s kontrolerji. Aplikacija uporablja štiri kontrolerje, in sicer IndexCtrl, ki omogoči

prikaz seznamov košaric, BasketCtrl, ki omogoči prikaz ene same košarice, prikaz podrobnosti

enega elementa v košarici ter odstranjevanje elementov iz košarice. TotalsCtrl skrbi za prikaz

poročila o vsebini košarice, to je številu izdelkov, teži in skupni ceni. SuggCtrl pa skrbi za prikaz

priporočenih izdelkov in njihovo dodajanje v košarico.

Storitveni modul vsebuje storitve aplikacije, ki komunicirajo s strežnikom in izpostavijo podatke

kontrolerjem. Poleg tega so uporabljene za hranjenje stanja med izvajanjem aplikacije, saj so za

razliko od ostalih komponent instancirane enkrat in obstajajo skozi celotno izvajanje aplikacije.

Baskets storitev zna pridobiti zbirko košaric s strežnika in si jo zapomniti, tako da enake zahteve

ne ponavlja. Zna tudi poiskati eno samo košarico. Suggests pa omogoči pridobitev zbirke

priporočenih izdelkov.

Filters modul vsebuje filtre, ki jih uporabljamo v predlogah. Ti manipulirajo podatke za prikaz v

uporabniškem vmesniku. Aplikacija vsebuje filter, ki pretvori znesek v evre, in filter, ki

kapitalizira prvo črko besede.

Direktive so prav tako kot filtri uporabljene v predlogah in jih uporabljamo za implementacijo

kompleksnejših elementov uporabniškega vmesnika ali ponavljajočih se delov strani. Aplikacija

vsebuje amountInteractive direktivo, uporabljeno za spreminjanje količine izdelkov v košarici.

5.3 Visokonivojski MVP, implementiran z Emberjem

V ember-ju ni ustreznika Angularjevim modulom, elemente aplikacije preprosto dodajamo

14

globalni spremenljivki aplikacije. Med razvojem sem elemente uredil v datoteke tako, da so

kontrolerji, poti, komponente in modeli združeni vsak v svojo datoteko. Ember poskuša biti

objektno usmerjen in oponaša razrede. Objektom doda funkcije, kot sta create in extend, s

katerima lahko nadomestimo dedovanje in instanciranje objektov v jeziku brez razredov.

Poti aplikacije nastavimo s prepisom map funkcije razreda Router. Dodani so še trije razredi

BasketsRoute, BasketRoute in ItemRoute z definirano metodo model, ki nastavi podatkovni model

za uporabo v kontrolerju, povezanem s potjo.

Sledijo kontrolerji, BasktesController nadzoruje prikaz seznama košaric na domači strani

aplikacije. V njem so nastavljena polja, ki določijo vrstni red prikaza. BasketController nadzoruje

prikaz ene košarice, v njem so metode, ki izračunajo celotno število izdelkov v košarici, težo in

ceno. SuggController nadzoruje posamezen priporočen izdelek, ki se zna dodati v košarico in

prikazati ceno. SuggsController nadzoruje priporočene izdelke, njihovo sortiranje in iskanje po

imenu. Zadnji kontroler je ItemController, ki nadzoruje posamezen izdelek v košarici. Ta

Diagram 5.3: Proces sestave košarice implementiran z Emberjem

Vir: Lokar, lastni prikaz (2014)

15

kontroler skrbi za brisanje izdelkov iz košarice, prikaz in zapiranje podrobnosti ter urejanje

količine.

Modeli podobno kot Angularjeve storitve komunicirajo s strežnikom in podatke izpostavijo

kontrolerju. Razlika je v tem, da so Angularjevi podatki tipa Object, tukaj pa imamo dva modela

več, Basket in Item, ki predstavljata podatke. Dostop do njunih polj poteka preko getter in setter

metod, za katere poskrbi ogrodje.

Na koncu sta še dve komponenti - EditCustomView in AmountInteractiveComponent. Prva je

logika, povezana z vnosnim poljem za količino izdelkov v košarici, druga pa je celotna

komponenta količine.

5.4 Analiza implementacije

Za strežnik pri svoji aplikaciji uporabljam Node.js različico 0.10.20 (20. december 2013).

Njegova naloga je zelo preprosta. Streže statične datoteke iz mape public, to so datoteke s

končnicami .js, .css, .html, in odgovarja z .json podatki na dva api naslova, ki sta:

api/baskets: kjer odgovori s košaricami,

api/suggested: kjer odgovori s priporočenimi elementi.

Node.js je seveda popolnoma zamenljiv z drugim strežnikom, nastavljenim za opravljanje zgoraj

navedenih nalog.

Za izvajanje testov Angular aplikacije uporabljam Karma test runner 0.10 (20. december 2013),

za pisanje testov enot Jasmine 1.3.1 (20. december 2013) in za integracijske teste Angular

scenario runner (20. december 2013).

Za testiranje Ember aplikacije uporabljam Qunit 1.12.0 (20. december 2013).

Na koncu potrebujemo še knjižnici obeh ogrodij, ki ju bom primerjal. Za Angular aplikacijo

uporabljam različico 1.2.2 (20. december 2013). Za Ember aplikacijo uporabljam različico 1.2.0

16

(20. december 2013) in še dve knjižnici, ki ju Ember potrebuje to sta jQuery 1.10.2 (20.

december 2013) ter Handlebars 1.1.2 (20. december 2013).

5.4.1 Zagon aplikacije

Z vključenimi knjižnicami lahko zaženemo aplikacijo. V Angularju to storimo z direktivo ng-app,

ki jo vključimo kot atribut poljubnemu elementu strani. V večini primerov bi ga dopisali kar k

html elementu, kar pomeni, da bo aplikacija delovala na celi strani. Lahko pa jo omejimo na del

strani, na primer, če dodajamo funkcionalnost obstoječi strani in želimo uporabiti ogrodje

Angular. Atribut sprejme vrednost, ki je ime aplikacije. Na podlagi tega imena bo Angular naložil

istoimenski modul.

<html ng-app="m-app">

Direktive so zapisane kot html elementi ali atributi elementov. Angular jih med delovanjem

zamenja s standardnimi html elementi in javascript kodo, ki jih brskalnik zna interpretirati.

Moduli v Angularju so kot pričakovano način delitve kode. Sestavljen je iz dveh blokov kode.

Prvi skrbi za konfiguracijo, tukaj registriramo funkcije ter objekte, ki jih bomo pozneje uporabili

prek »vbrizga odvisnosti« (ang. dependency injection). Drugi blok pa je koda, ki se izvede po

tem, ko je modul naložen in konfiguriran. Referenco novega modula dobimo s klicem metode

angular.module, ki sprejme dva argumenta. Prvi je ime module in drugi je array ostalih modulov,

ki jih tudi želimo uporabiti. V aplikaciji mora biti na voljo en modul z enakim imenom, kot smo

ga podali v ng-app, tega bo naložila aplikacija. Spodnja koda prikazuje instanciranje prvega

modula aplikacije, ki je še prazen in tudi ne nalaga drugih modulov.

var app = angular.module('app', []);

S tem je aplikacija zagnana. Angular bo v ozadju začel pripravljati DOM znotraj direktive ng-

app, kar pomeni, da bo zamenjal argumente in elemente, ki so definirani v ogrodju s

standardnimi elementi, ki jih brskalnik zna prikazati. Pripravljen za uporabo je tudi vbrizgalnik

odvisnosti, ki bo naložil zgoraj definirani modul z imenom app.

17

V Emberju ne določimo omejitev aplikacije v html-ju. Kot aplikacijo bo obravnaval celotno stran

in nima dokumentiranega načina za vstavljanje Ember aplikacije v obstoječo stran. Preostane še

instanciranje aplikacije, ki ga opravimo, kot prikazuje spodnja koda.

var App = Ember.Application.create();

Ember je bolj objektno orientiran. Ker javascript nima razredov (ima dedovanje prek prototipov),

so definirali svoje metode, s katerimi ustvarimo razrede in jih instanciramo. Zgornji klic create

metode na aplikacijo torej vrne instanco Ember.Application razreda. Ember aplikacija je s tem

zagnana.

5.4.2 Statični del strani

Aplikacija, ki jo izdelujem, je na eni strani. Imela bo dele strani, ki ostajajo enaki; ti so, na

primer, glava strani in navigacija ter noga strani. Vmesni del z vsebino bo dinamičen. V

Angularju v html vstavimo direktivo ng-view. S tem ogrodju sporočimo, kam naj vstavlja

vsebino.

...

<body>

<header>Ta del je viden skozi celo aplikacijo</header>

<ng-view>

...

Zgornja koda prikaže odstavek v <header> elementu skozi celo aplikacijo, pod njem pa se

vsebina spreminja glede na stanje aplikacije.

V Emberju enako dosežemo z {{outlet}} zaznamkom, ki pa mora biti vstavljen v predlogo

aplikacije (ang. template).

18

<script type="text/x-handlebars">

<header>Ta del je viden skozi celo aplikacijo</header>

{{outlet}}

...

</script>

Ember uporablja handlebars knjižnico za predloge. Handelbars za prikaz vmesnika uporablja

standardni html in ga dopolni z izrazi. Ti so znotraj dvojnih zavitih oklepajev kot outlet izraz

zgoraj. Predloge so vstavljene v spletno stran znotraj script oznak s type atributom, nastavljenim,

kot prikazuje zgornja koda. Drugi atribut je data-template-name, ki unikatno identificira predlogo

in nam omogoči, da jo poiščemo v aplikaciji. Ta atribut zgoraj ni nastavljen, ker v glavni predlogi

aplikacije ni potreben. Predloge so nato interpretirane skupaj s kontekstom, ki določi dejansko

vsebino, ta zamenja izraze v zavitih oklepajih.

5.4.3 Usmerjanje

Aplikacija se zdaj izvaja in prikazuje statični del, ki je enak skozi vsa stanja aplikacije. Naslednja

naloga je nastavitev usmerjevalnika. Usmerjevalnik bo prikazoval različne komponente strani ali

prehajal med stanji, podobno kot prehod med podstranmi na statični strani.

Konkretno v tej aplikaciji bosta implementirani dve poti:

'/': komponenta, ki prikaže seznam košaric

'/košarica/:ime': komponenta, ki prikaže elemente v košarici, dodajanje novih,...

Usmerjevalnika obeh ogrodij poskrbita za spreminjanja url naslova v naslovni vrstici glede na

stanje v aplikaciji. Usmerita na pravilno stran, če je url vnesen ročno, in simulirata delovanje

naprej/nazaj gumbov brskalnika.

V Angularju za usmerjevalnik potrebujemo modul ngRoute, kjer je definirana storitev $route.

Modul je v svoji skripti, ki jo dobimo na Agularjevi spletni strani. Nato ga vključimo v modul

app, kot prikazuje spodnja vrstica.

19

var app = angular.module('app', ['ngRoute']);

Storitev $route je zdaj pripravljena za uporabo. Angularjeve storitve so objekti, instancirani

enkrat, ko so prvič vbrizgani, in nato obstajajo skozi celotno izvajanje aplikacije. Pred uporabo

storitev imenujemo v argumentih funkcije, nato pa jo vbrizgalnik odvisnosti poišče in pripravi za

uporabo.

Za nastavitev poti uporabimo config metodo modula in podamo funkcijo, ki ji bo vbrizgan

$routeProvider objekt, na katerem bosta določeni poti aplikacije. $routeProvider uporablja

sintakso, ki je že domača iz ostalih spletnih ogrodij MVC. When metoda sprejme niz znakov

relativnega url-ja, na katerega odgovori na podlagi konfiguracije v drugem argumentu. Ta je

objekt z definiranim poljem za predlogo in kontroler. Na koncu je še metoda otherwise, ki

preusmeri v primeru ko pot ni sprejel noben prej definiran url vzorec.

app.config(function($routeProvider) {

$routeProvider

.when('/baskets', {

templateUrl: 'index.html',

controller: 'IndexCtrl'

})

.when('/basket/:name', {

templateUrl: 'basket.html',

controller: 'BasketCtrl'

})

.otherwise({

redirectTo: '/'

})

});

V Emberju poti konfiguriramo v map metodi Router objekta. Ta sprejme funkcijo, v kateri

nastavimo poti. Uporabimo lahko route metodo, ki jo pokličemo z imenom poti, in po potrebi

dodamo objekt z več konfiguracije. Druga možnost je metoda resource, ki za razliko od route

sprejme še funkcijo z gnezdenimi poti.

20

App.Router.map(function () {

this.resource('baskets', {path: '/'});

this.resource('basket', {path: '/:basket_id'}, function () {

this.resource('item', {path: '/:item_id'});

});

});

Poleg drugačne sintakse se ogrodji tu razlikujeta pri nastavitvi kontrolerja poti. V Angularju ga

eksplicitno imenujemo kot prikazuje koda zgoraj, v Emberju pa je uporabljen kontroler, ki je

imenovan enako kot pot z dodano končnico Controller.

Ember, kjer je mogoče, uporablja dogovor o poimenovanju namesto neposredne konfiguracije in

na podlagi imen poveže objekte aplikacije. V prvem zgornjem primeru, ko smo na poti '/',

imenovani baskets, bo uporabil BaketsRoute, BasketsController in baskets predlogo.

5.4.4 Pridobivanje podatkov s strežnika

Aplikaciji sta zdaj pripravljeni na usmerjanje v brskalniku, kar pomeni da ne bo treba naložiti

nove strani vsakič, ko se url spremeni. Html predloge in .js datoteke že imamo zapomnjene. Edini

manjkajoči so dejanski podatki, ki jih želimo uporabiti. Te moramo naložiti s strežnika, ko jih

potrebujemo.

V Angularju za to nalogo uporabimo storitve (ang. service). Angular storitve so objekti,

namenjeni izvajanju specifične naloge. Instancirana je enkrat, ko jo prvič uporabimo, in nato

ostane isti objekt skozi celo aplikacijo. Za uporabo storitev preprosto imenujemo kot argument

kontrolerju ali drugi storitvi, nato vbrizgalnik odvisnosti poskrbi, da je storitev na voljo.

Services.factory('Baskets', function ($http) {

var baskets;

var load = function () {

baskets = $http.get('/api/baskets').then(function (response) {

return response.data;

});

21

};

return {

findAll: function () {

if (!baskets) load();

return baskets;

},

find: function (name) {

if (!baskets) load();

return baskets.then(function (data) {

return Helpers.findById(data, name);

});

}

}

});

Storitev Baskets, kot je definirana zgoraj, izpostavi dve metodi. Prva, findAll, vrne obljubo, ki bo

izpolnjena z vsemi košaricami in bo uporabljena za prikaz seznama košaric. Druga, find, pa

vzame ime košarice in vrne obljubo, ki bo izpolnjena s podatki te košarice in bo uporabljena za

prikaz ene same košarice. Za komunikacijo s strežnikom je uporabljena vgrajena $http storitev, ki

pošilja asinhrone zahteve na strežnik in vrne obljubo, izpolnjeno s prejetimi podatki. Na koncu,

ker enaka instanca storitve obstaja čez celo aplikacijo, jo lahko uporabimo za zapomnjenje

podatkov. V tem primeru so košarice shranjene v baskets spremenljivki, in če je ta nastavljena, ne

pošiljamo nove zahteve na strežnik, ampak vrnemo zapomnjene podatke.

V Emberju so podatki zaviti v ember objekte, zato jim moramo najprej nastaviti pripadajoče

razrede. To storimo z dedovanjem Ember.Object razreda, kot je prikazano spodaj.

App.Basket = Ember.Object.extend({

id: null,

desc: '',

items: []

});

App.Item = Ember.Object.extend({

id: null,

title: '',

22

price: 0,

desc: '',

address: '',

city: '',

amount: 0

});

Razreda zgoraj bosta uporabljana za instanciranje košaric in posameznih elementov v košarici. Za

razliko od Emberja tu Angular uporablja navadne javascript objekte in ne potrebuje kode,

primerljive zgornji. Ember pa s svojim pristopom omogoči dedovanje podobno kot v jezikih z

razredi.

Za dejanski prenos podatkov sem pripravil razred Baskets, ki ima enako kot Angularjeva storitev

metodi find in findAll.

App.Baskets = Ember.Object.extend({

findAll: function () {

var baskets = Ember.$.getJSON('/api/baskets');

var success = function (data) {

return data.map(function (item) {

return App.Basket.create({

id: item.id,

desc: item.desc,

items: item.items.map(function (item) {

return App.Item.create(item);

})

});

});

},

return baskets.then(success);

},...

V metodi findAll uporabim metodo getJSON knjižnice jQuery. Za razliko od Angularja tukaj iz

prejetih podatkov instanciram objekte razreda Basket in Item.

23

...find: function (basket_id) {

var basket = this.findAll().then(function (data) {

return data.find(function (item) {

return item.get('id') === basket_id;

});

});

var success = function (data) {

return data;

};

return basket.then(success);

}

V metodi find pa najprej pokličem findAll in nato izločim iskano košarico s priročno metodo find,

ki jo ogrodje doda za uporabo z array-i.

Za razliko od Angularja, pri katerem vbrizgalnik odvisnosti instancira storitev in jo vbrizga ko jo

potrebujemo, tukaj pred uporabo še instanciramo objekt in poskrbimo, da je na voljo. V tem

primeru sem referenco shranil v spremenljivko App.basket, ki je dosegljiva v celi aplikaciji. Še

ena razlika v primerjavi z Angular storitvijo, ki opravlja enako nalogo, je, da sem si tam zapomnil

podatke, ki so prišli s strežnika. Prehod na posamezno košarico zato ni naredil nove zahteve na

strežnik. V Emberju pa lahko podatkovni model podamo s strani s seznamom košaric na stran s

posamezno košarico, zato niti ni treba skrbeti za hranjenje podatkov.

V aplikaciji imam še izdelke, ki jih lahko dodajamo v košarico. Ta del je zelo podoben

pridobivanju podatkov košaric, zato ga ne bom posebej opisal. V Angularju sem pripravil storitev,

v Emberju pa še en razred, ki vsak v svoji aplikaciji opravita zahtevano nalogo.

5.4.5 Kontroler

V prejšnjem delu sem pripravil podatkovni model. Vseboval je podatke ki jih je treba hraniti na

strežniku, saj jih je smiselno trajno shranjevati. Kontroler pa je del aplikacije, ki dostopa do

modela in izpostavi njegove podatke za prikaz v predlogi. Lahko jih tudi dopolni z na novo

24

izračunanimi. Kontroler bo primerjan v aplikaciji na strani s posamezno košarico.

5.4.5.1 Povezava s podatkovnim modelom

Najprej pa je treba kontroler povezati z modelom. V Angularju podatke vbrizgamo, če so ti na

voljo kot storitev.

Controllers.controller('BasketCtrl', function ($scope, $routeParams,

Baskets, Suggests) {...});

Zgornji kontroler je definiran v modulu Controllers, imenovan je BasketCtrl in ima štiri

odvisnosti. Zadnji dve sta Baskets in Suggests, to sta storitvi, ki sem ju opisal v prejšnjem delu.

Prva je vgrajena storitev, ki poskrbi da do podatkov, ki jih želimo prikazati, lahko dostopamo iz

pogleda (ang. view). Druga omogoča dostop do delov url-ja.

Baskets.find($routeParams.name).then(function (data) {

$scope.basket = data;

});

Metoda Baskets.find je znana iz prejšnjih delov. Pokličem jo z imenom košarice, ki ga dobim iz

url naslova. Priprava povezav z vstavljenimi imeni košaric bo opisana pozneje. Pomembno je, da

smo v delu o usmerjanju nastavili naslov baskets/:name. Usmerjevalniku smo z dvopičjem

sporočili, naj sprejme spremenljivi del, imenovan name. Do njega lahko dostopamo s pomočjo

storitve $routeParams, kot je prikazano zgoraj. Ime iz naslova je v podatkih o košaricah unikatni

identifikator, zgornja koda bo zato nastavila spremenljivko basket na podatke o košarici. In

nazadnje, ker je basket nastavljen na $scope storitvi, pomeni, da smo te podatke izpostavili za

dostop na pogledu (ang. view).

V Emberju podatkovni model, ki ga bo kontroler uporabljal, nastavimo že pred kontrolerjem v

route objektu.

25

App.BasketRoute = Ember.Route.extend({

model: function (params) {

return App.baskets.find(params.basket_id);

}

});

Najprej pripravimo BasketRoute razred, ki deduje od vgrajenega Route razreda. Route skrbi za

konfiguracijo, njegove metode se kličejo ko ogrodje izbere pot in pred kontrolerjem. Ime tukaj

sledi dogovoru o poimenovanju, zato ogrodje prepozna, da je ta podrazred Route razreda povezan

z basket potjo. V zgornji kodi je, kot pravijo v terminologiji Emberja nastavljena model kljuka

(ang. model hook), ki bo nastavila podatkovni model za uporabo s kontrolerjem. Še ena

podrobnost v načinu izvajanja zgornje kode je, da Ember v primeru, da je model že nastavljen, ne

pokliče model kljuke. V aplikaciji to pomeni, da pri prehodu s seznama košaric na posamezno

košarico podamo podatkovni model posamezne košarice, in ne izvajamo zgornje kode. Ko pa

dostopamo neposredno na stran posamezne košarice, na primer, če ročno vpišemo naslov, njene

podatke naložimo, kot je opisano. Ember v kontrolerju samodejno izpostavi celotni podatkovni

model za uporabo v delu aplikacije, ki ga bo prikazoval.

5.4.5.2 Izračunani podatki

Izračunani podatki so tisti, ki jih ni smiselno shranjevati v podatkovni bazi, vendar jih vseeno

želimo prikazati. Te bomo pripravili v kontrolerju. V naslednjem primeru spremljamo skupno

vrednost košarice. Ta podatek se bo spreminjal ko dodajamo/odstranjujemo izdelke ali

spreminjamo količino. V Angularju v kontroler imenovan BasketCtrl, dodamo sledečo kodo.

$scope.totalPrice = function () {

if (!$scope.basket) return 0;

return $scope.basket.items.reduce(function (sum, item) {

return sum + item.amount * item.price;

}, 0);

};

Nastavila bo totalPrice spremenljivko na funkcijo, ki vrne vrednost vseh izdelkov v košarici. V

pogled delu aplikacije, lahko uporabimo to funkcijo kot vsako drugo vrednost za prikaz podatkov.

26

Angular tudi sam poskrbi za posodobitev vrednosti, ko se spremeni kateri od uporabljenih

podatkov za njen izračun. V funkciji prva vrstica preveri, ali so podatki nastavljeni, in v

nasprotnem primeru vrne 0. S tem poskrbimo, da funkcija vrne smiselno vrednost tudi, ko

obljuba s podatki o košarici še ni izpolnjena, saj bo Angular začel upodabljati stran, preden

prejme podatke s strežnika. V naslednjih treh vrsticah dostopamo do elementov v košarici, ki so

zapomnjeni v basket.items spremenljivki, in seštejemo vse količine, pomnožene s ceno za

kilogram, kar nam vrne celotno vrednost košarice. V Emberju enako storimo s spodnjo kodo,

dodano v BasketController.

totalPrice: function () {

return this.get('items').reduce(function (total, item) {

return total + item.get('amount') * item.get('price');

}, 0) / 100

}.property('[email protected]')

V Emberjevem pristopu uporabljamo getter-je za dostop do polj objektov in setter-je za njihovo

nastavljanje. Druga razlika je klic metode property nad funkcijo. Z njo Emberju sporočimo, naj

funkcijo jemlje kot izračunano polje. Ko bomo pripravljali pogled, bomo zato lahko navajali

totalPrice kot ostala polja. Zadnja razlika je, da tukaj pretvorimo denarne enote z deljenjem s sto.

Interno v aplikaciji z denarjem ravnam kot s celo številko, da se izognem napakam pri

zaokroževanju, pred prikazom pa jo spremenim v celo številko, kot je prikazano zgoraj. V

Angularju pa obstaja boljše mesto za takšne transformacije, kot bo prikazano pozneje zato tam

številke ne delim.

5.4.5.3 Prikaz podrobnosti

V kontroler spada tudi logika, ki jo uporabljamo le pri prikazu podatkov. Na primeru aplikacije je

to prikaz podrobnosti posameznega izdelka, ko kliknemo na njegovo ime. V Angularju za ta

namen inicializiram spremenljivko, imenovano detailsItem z vrednostjo false.

$scope.detailsItem = false;

Pozneje bom njeno vrednost spremenil na objekt s podatki o elementu, katerega podrobnosti

27

želim prikazati. V pogledu ima Angular možnost pogojnega upodabljanja, znal bo prikazati

objekt s podatki o izbranem elementu ali pa ne bo prikazal ničesar, če bo vrednost nastavljena na

false. Za ta del pa bo poskrbel kontroler. Manjka torej še način nastavljanja vrednost, kar

dosežem s spodnjima dvema funkcijama.

$scope.showDetails = function (id) {

var item = Helpers.findById($scope.basket.items, id)

$scope.detailsItem = item;

};

$scope.closeDetails = function () {

$scope.detailsItem = false;

};

Obe bosta klicani iz pogleda, zato sta definirani v storitvi $scope. Prvo pokličemo skupaj z

unikatnim identifikatorjem elementa. Nato funkcija poišče izbrani element in nastavi detailsItem

na pripadajoči element. Ko se vrednost spremenljivke spremeni, bo Angular samodejno

spremenil tudi njen prikaz v predlogi. Druga funkcija ima še preprostejšo nalogo in le nastavi

detailsItem na vrednost false. Tudi zdaj bo Angular zaznal spremembo vrednosti in skril

predlogo, ki je prikazovala podrobnosti.

V Emberju sem za enako nalogo izkoristil dve lastnosti ogrodja in sicer, da lahko podamo

podatkovni model pri prehodu na novo stran ter da lahko gnezdimo poti znotraj obstoječih. V

delu o usmerjanju sem že dodal gnezdeno pot, imenovano item, na katero ob kliku na ime

elementa preusmerim ter podam njegove podatke. Za skritje podatkov pa preusmerim nazaj na

pot brez elementa. S tem dosežem enako obnašanje, kot je implementirano v Angularju z dodano

prednostjo, da je v Emberjevi aplikaciji prikazani element tudi del url naslova in ta bolj natančno

odraža stanje v aplikaciji. Primer preusmeritve iz pogled dela aplikacije sledi v naslednjem

poglavju.

5.4.5.4 Posodabljanje podatkov

Zadnja pogosta naloga kontrolerja je skrb za posodabljanje podatkov. Tukaj bom primerjal

28

dodajanje elementov v košarico s seznama priporočenih elementov in odstranjevanje elementov v

košarici.

V Angularjev kontroler dodamo funkcijo, ki bo sprejela identifikator elementa, ga poiskala v

priporočenih elementih, ga umaknila iz priporočenih elementov ter ga dodala med elemente v

košarici.

Controllers.controller('SuggsCtrl', function ($scope) {

$scope.add = function (id) {

var item = Helpers.findById($scope.suggs, id);

$scope.suggs = Helpers.removeById($scope.suggs, id);

$scope.basket.items.push(item);

};

});

Tukaj sem funkcijo zapisal v nov kontroler. V Angularju lahko poljubno gnezdimo kontrolerje za

boljšo preglednost, in kot pričakovano, lahko iz SuggsCtrl-ja dostopamo do spremenljivke

basket.items, ki je sicer definirana nivo više. Za odstranjevanje uporabim funkcijo, ki poišče in

odstrani element iz spremenljivke basket.items.

V Emberju funkcij iz kontrolerja v predlogi ne kličemo neposredno z imenom in oklepajem,

ampak uporabimo akcijski pomočnik, kot bo opisano pozneje. Ta akcijski pomočnik pa bo klical

metode, ki so v kontrolerju znotraj objekta actions.

App.SuggController = Ember.ObjectController.extend({

needs: ['basket'],

actions: {

add: function () {

this.get('controllers.basket').get('items')

.addObject(this.get('model'));

this.get('parentController').get('content')

.removeObject(this.get('model'));

}

}

});

29

V Emberju imamo svoj kontroler za vsak priporočen element, imenovan SuggController, in

skupen kontroler vseh elementov, imenovan SuggsController. Za razliko od Angularja tukaj ne

moremo poklicati funkcije z identifikatorjem, zato potrebujemo svoj kontroler za posamezen

element, vendar je to verjetno bolj pregledna zasnova aplikacije. V prvi vrstici v kontrolerju

Emberju sporočimo, da potrebujemo kontroler basket, saj ta vsebuje niz elementov v košarici, v

katero bomo dodali nov element. Nato dodamo metodo add v objekt actions znotraj kontrolerja,

kar jo naredi na voljo za klic iz akcijskega pomočnika v predlogi. V sami metodi add uporabimo

getter-je, kot je prikazano za dostop do reference niza elementov v košarici, in uporabimo

priročno metodo addObject za dodajanje novega elementa. This.get('model') kot pričakovano

vrne podatkovni model objekta, nad katerim smo poklicali metodo. V zadnjih dveh vrsticah

najprej poiščem niz priporočenih elementov, ki je nivo više v SuggsController-ju in nato

odstranim izbrani element.

5.4.6 Uporabniški vmesnik (ang. view layer)

V tem delu uporabimo podatke iz podatkovnega modela in dodano logiko iz kontrolerja ter

zgradimo uporabniški vmesnik, kot ga vidi uporabnik. Obe ogrodji uporabljata predloge, ki so

objete v element script in unikatno imenovane. Angular za prikaz uporabi predlogo, ki jo poišče

na podlagi imena, ki smo ga izbrali pri usmerjanju. Ember predvideva, da smo se držali dogovora

o poimenovanju, in poišče predlogo, imenovano enako kot pot. Pogled bom primerjal na strani,

ki prikazuje eno košarico.

<script type="text/ng-template" id="basket.html">

<script type="text/x-handlebars" data-template-name="basket">

V prvi vrstici odpremo angular predlogo, imenovano basket.html, v drugi vrstici odpremo

handlebars predlogo, imenovano basket, ki jo uporablja Ember.

5.4.6.1 Izrazi

V predlogi uporabljamo standardne elemente html, ogrodji pa dodata še izraze, ki vsebino

30

pripravijo dinamično, in način abstrakcije, ki je v Angularju dosežen z direktivami in v Emberju s

komponentami. Izrazi v obeh ogrodjih so znotraj dvojnih zavitih oklepajev.

<h3>{{id}} košarica</h3>

<h3>{{basket.id}} košarica</h3>

Prvi izraz je vzet iz predloge Emberja, drugi iz predloge Angularja. Sintaktično sta podobna, z

majhno razliko, saj smo v Angularju izpostavili objekt basket, v Emberju pa kontroler privzeto

izpostavi vsa polja svojega podatkovnega modela. Prav tako bosta oba izraza posodobljena v

primeru, da se pripadajoči podatek v kontrolerju spremeni.

Izrazi v Angularju sprejmejo skoraj vsako kodo javascript, vendar je dobra praksa, da v pogledu

ne zapisujemo logike aplikacije. Tri razlike med njimi in javascriptom so, da so izrazi evalvirani

le s spremenljivkami, ki jih izpostavi kontroler ali direktiva, brez globalnih. Ne javljajo napak, če

je vrednost nedefinirana ali vsebuje referenco null. In nazadnje, Angular izrazi ne morejo

vsebovati kontrolnih izjav.

V Emberju ne zapisujemo nikakršne logike neposredno v izraze, vključno s klicem metode.

Namesto tega lahko uporabimo katerega izmed prej definiranih pomočnikov ali napišemo

svojega. Primeri pomočnikov sledijo v nadaljevanju.

5.4.6.2 Iteriranje

V naslednjem koraku iteriramo skozi niz elementov v košarici in jih zapišemo kot vrstice v tabeli.

V Angularju to storimo, kot je prikazano spodaj.

<tr ng-repeat="item in basket.items">

<td>{{item.title}}</td>

</tr>

Ng-repeat je Angularjeva vgrajena direktiva, ki je tu uporabljena kot atribut elementa tr.

Prepoznamo jo po predponi ng. Direktiva bo za vsak element v basket.items ponavljala vrstice od

31

odprtja elementa, na katerem je uporabljena, do zaprtja. Znotraj bo imela svoj lastni nabor

spremenljivk (ang. isolated scope); v tem primeru bo definiran item za vsak element iz košarice.

{{#each item in controller.items itemController="item"}}

<tr><td>{{item.title}}</td></tr>

{{/each}}

V Emberju uporabimo {{#each}} pomočnika, ki je vgrajen v Handlebars. Each pomočniku

najprej sporočimo niz elementov, skozi katere bo iteriral, in ime, ki bo vsebovalo referenco

posameznega elementa znotraj pomočnika. Ta del je enak kot pri Angularju, razlikuje se v drugi

nastavitvi, pri kateri posamezen element povežemo s pripadajočim itemController-jem, ki ga

potrebujemo za upravljanje z elementi. V Angularju zaradi drugačne zasnove to nalogo opravlja

direktiva, ki bo opisana pozneje in BasketCtrl.

5.4.6.3 Filtri

V aplikaciji kot osnovno denarno enoto uporabljam cent, pred izpisom pa želim cente pretvoriti v

evre. V ta namen sem v odseku o kontrolerjih pri Emberju že pretvoril ceno, pri Angularju pa sem

omenil, da obstaja boljše mesto za takšne transformacije. V Emberju ni neposrednega ekvivalenta

filtrom, zato s takšnimi pretvorbami opravimo v kontrolerju.

{{totalPrice() | toEuro}}

V zgornji kodi najprej pokličem totalPrice() metodo, ki vrne ceno v centih, nato s simbolom

»pipe« apliciram filter, ki jo pretvori v evre.

Filters.filter('toEuro', function () {

return function (input) {

return (input / 100);

}

});

Zgornji filter je definiran v svojem modulu Filters. Imenovan je toEuro in je zelo preprosta

funkcija, ki sprejme vrednost ter vrne to vrednost, deljeno s sto. Filtri so tudi popolnoma

32

neodvisni od aplikacije in pripravljeni za uporabo v drugi aplikaciji, takoj ko modul uvozimo. Še

en primer uporabe filtrov je iskanje po seznamu priporočenih elementov. V Angularju to storimo,

kot je prikazano spodaj.

<input type="text" ng-model="search" placeholder="Poišči...">

<tr ng-repeat="sugg in suggs | filter:search">...</tr>

Zgoraj najprej vstavimo input element in mu dodamo direktivo ng-model z vrednostjo search. Ta

bo dodala podatkovni model na $scope za uporabo znotraj kontrolerja. To pomeni, da bo vrednost

elementa input dostopna znotraj kontrolerja pod imenom search in v predlogi, ki jo kontroler

nadzoruje. Nato potrebujemo filter, ki deluje nad nizom podatkov in izloči vse, katerih ime

vsebuje niz znakov vpisan v search polje in tak filter je že definiran v Angularju pod imenom

filter, ločeno z dvopičjem pa mu podamo še polje, kamor bo uporabnik vpisal ime, kot je

prikazano zgoraj. V Emberju za enako nalogo logiko zapišemo v kontroler, najprej pa dodamo

element input.

{{input type="text" value=search placeholder="Poišči..."}}

Uporabljen je pomočnik, ki zgradi polje ter nastavi njegovo vrednost na vrednost search polja,

pridobljeno iz kontrolerja. Ker ogrodje uporablja dvosmerno vezavo podatkov (ang. two way data

binding) bo polje search iz kontrolerja odražalo spremembe, ki jih uporabnik vnese v polje.

App.SuggsController = Ember.ArrayController.extend({

search: '',

content: App.suggs,

filtered: function () {

var that = this;

if (this.search.length === 0) return this.content;

else return this.content.filter(function (item) {

return item.get('title').toLowerCase().indexOf(that.search) >= 0;

})

}.property('search')

});

33

V kontrolerju nastavimo search polje na prazen string. Kasneje bo spremenljivka vsebovala

podatke, ki jih uporabnik vpiše v polje za iskanje. Nato nastavimo izračunano spremenljivko

filtered, ki ji povemo, naj spremlja search polje, in se vnovič izračuna v primeru, da se to polje

spremeni. V funkciji preverimo, ali je polje prazno, in v tem primeru vrnemo celoten seznam. Če

pa je uporabnik vpisal besedo, iteriramo skozi niz elementov in obdržimo le elemente, pri katerih

naslov vsebuje vpisano besedo.

5.4.6.4 Povezave

Za prehod med stanji/stranmi v aplikaciji uporabljamo hiperpovezave. Povezave primerjam pri

pripravi povezav s prve strani s seznamom košaric na strani s posameznimi košaricami. V

Angularju se s povezavami ne dogaja nič posebnega.

<h3><a ng-href="#/basket/{{basket.id}}">{{basket.id}}</a></h3>

Zgoraj pripravimo povezavo s statičnim delom #/basket/ in dinamičnim delom {{basket.id}}. #

znak pred naslovom poskrbi, da se celotna stran ne osveži in prepusti usmerjanje ogrodju.

Dinamičen del je identifikator košarice, na podlagi katerega bo pozneje kontroler povezan s potjo

/basket/:name poiskal pravo košarico. V Emberju pa lahko povezave pošljejo tudi podatkovni

model. Uporabljamo jih tako, kot je prikazano spodaj.

<h3>{{#link-to "basket" basket}}{{basket.id}}{{/link-to}}</h3>

Uporabljen je vgrajen pomočnik link-to, ki sprejme najprej ime poti in nato neobvezno še

podatkovni model. V primeru klika bo ogrodje poiskalo pot basket v usmerjevalniku in

preusmerilo aplikacijo na to pot skupaj s priloženim modelom.

5.4.6.5 Interakcija

Primer interakcije bom opisal v aplikaciji na primeru odstranjevanja artiklov iz košarice. Vsak

izmed elementov, prikazan v tabeli, ima v zadnjem stolpcu gumb, s klikom na katerega ga

odstranimo.

34

<td class="tiny button secondary x" ng-click="removeItem(item.id)">

x

</td>

V Angularju gumbu dodamo direktivo ng-click, ki se pričakovano aktivira ob kliku na gumb x. Za

druge dogodke obstajajo podobne direktive. Vrednost direktive nastavimo na funkcijo, ki smo jo

predhodno definirali v kontrolerju in sprejme identifikator elementa ter ga odstrani iz košarice.

<td {{action "delete"}} class="tiny button secondary x">x</td>

V Emberju uporabimo akcijski pomočnik in mu sporočimo, naj sproži funkcijo delete. Delete ima

tukaj enako vlogo kot v Angularju definirana removeItem funkcija. Za razliko od Angularja pa

smo v Emberju vsakemu elementu nastavili svoj kontroler, zato funkcija ne potrebuje

identifikatorja. Akcijski pomočnik se privzeto odziva na klik, zato dogodka nismo eksplicitno

navedli. Za ostale dogodke bi nastavili še on="imeDogodka".

5.4.7 Direktive in komponente

Z direktivami v Angularju in komponentami v Emberju lahko poenostavimo predlogo z

združevanjem elementov v nov skupen element, ki ga nato ogrodji razširita v standardne

elemente, poznane brskalniku. Z njimi lahko pripravimo nov specifičen jezik za uporabo v

aplikaciji. Poleg združevanja elementov pa direktivam in komponentam lahko pripnemo

obnašanje, definirano z javascriptom. Direktive in komponente bom primerjal v aplikaciji pri

spreminjanju količine posameznega elementa. Vsak element v košarici ima stolpec, v katerem je

zapisana njegova količina v kilogramih. Z dvojnim klikom se količina spremeni v input element,

v katerem uporabnik spremeni količino, nato pa, ko vnosno polje izgubi osredotočenost (ang.

focus) ali ob potrditvi, se polje spet spremeni v normalno stanje, pri čemer prikazuje

posodobljeno količino.

<td class="amount">

<amount-interactive quantity=item.amount>

</td>

35

Zgoraj je prikazana uporaba direktive, imenovane amount-iteractive. Tukaj sem direktivo

uporabil kot element, saj jo lahko razumemo kot nov html element z lastnostmi, opisanimi zgoraj.

Sicer so pogosto uporabljene tudi kot atributi elementov, kot smo videli v prejšnjih primerih z

vgrajenimi direktivami. Z atributom, imenovanem quantity, v direktivo podam količino.

Directives.directive('amountInteractive', function () {

return {

restrict: 'E',

scope: {

quantity: '='

},

templateUrl: 'amount-interactive.html',

link: function (scope, element, attr) {...}

}

});

V zgornji kodi je prikazana priprava direktive z imenom amountIteractive. V htmlju sem imeni

ločil s pomišljajem, v kodi pa z veliko začetnico, vendar bo Angular prepoznal ime, zato ga lahko

zapisujemo na tipičen način za html in javascript. Direktivo definiramo s konfiguracijskim

objektom. Prva nastavljena lastnost restrict bo omejila uporabo na html element. Za uporabo kot

atribut bi to polje nastavili na 'A'. Naslednja nastavitev scope omeji dostop do spremenljivk. V

tem primeru je quantity spremenljivka nastavljena na podano vrednost enako imenovanega

atributa. Znak = pa pomeni, da bo spreminjanje vrednosti vidno zunaj, kot če bi podali referenco.

Če bi želeli podati le trenutno vrednost, bi uporabili znak @. Nastavitev template vsebuje

identifikator predloge, ki v tem primeru vsebuje span element, v katerem izpišem količino in

input element s količino ter css razredom hide, ki ga sprva skrije. In nazadnje v link funkciji

definiramo obnašanje direktive.

var link = function (scope, element, attr) {

var span = element.find('span');

span.on('dblclick', function (event) {

// replace quanity with input field on double click

span.addClass('hide');

input = element.find('input');

input.removeClass('hide');

36

input[0].focus();

// input back to span on enter or blur

var toText = function () {

scope.quantity = Number(input.val());

span.removeClass('hide');

input.addClass('hide');

scope.$apply();

}

input.bind('keyup keypress', function (event) {

if (event.which === 13) toText();

});

input.bind('blur', toText);

});

};

Funkcija link prejme scope objekt direktive, element, zavit v jqLite (jQuery element z manj

funkcij), in objekt argumentov ter pripadajočih vrednosti. Stranski učinek funkcije pa je

spreminjanje DOM-a. V zgornji funkciji najprej pripnemo obravnavanje dvojnega klika na span

element, in sicer ob prejetem dvojnem kliku prikažemo element za vnos podatkov in skrijemo

span s količino. Na vnosno polje pripnemo obravnavanje dveh dogodkov, to sta pritisk enter

tipke in izguba osredotočenosti, ter v obeh primerih nastavimo novo količino, odstranimo vnosno

polje ter vnovič prikažemo span s količino. Na koncu s scope.$apply Angularju sporočimo, da

smo spremenili vrednost in naj posodobi vse izračune, ki jo uporabljajo. S tem je direktiva

zaključena in pripravljena za uporabo kot html element. V Emberju komponento uporabljamo v

sintaksi zavitih oklepajev in ji prav tako podamo količino.

<td class="amount">

{{amount-interactive amount=item.amount}}

</td>

Nato pripravimo predlogo.

37

<script type="text/x-handlebars" template-name="components/amount-interactive">

{{#if editing}}

{{edit-custom action="toggleEdit" type="text" value=amount}}

{{else}}

<span {{action "toggleEdit" on="doubleClick"}}>{{amount}} kg</span>

{{/if}}

</script>

Predlogo moramo imenovati s predpono components/; na ta način bo Ember ugotovil, da je ta

predloga komponenta. Podobno kot direktive v Angularju imajo tudi komponente v Emberju

ločen dostop do spremenljivk (ang. isolated scope), če pa podamo spremenljivko v komponento,

jo lahko ta spreminja in vse spremembe bodo takoj vidne navzven, kar je želeno vedenje v našem

primeru, ko komponenta spreminja količino izdelkov. Med prikazom količine in vnosnim poljem

prestavljam z vgrajenim pomočnikom if/else, za kar potrebujemo tudi nekaj logike, ki jo

definiramo takole:

App.AmountInteractiveComponent = Ember.Component.extend({

editing: false,

actions: {

toggleEdit: function () {

this.set('editing', !this.get('editing'));

}

}

});

Koda komponente deduje od razreda Ember.Component in sledi dogovoru o poimenovanju. Ime

zapišemo z velikimi začetnicami, nujno mora vsebovati vsaj dve besedi in se konča s Component.

V njej nastavimo spremenljivko editing, ki jo uporablja kontrolna izjava v predlogi, in akcijo, ki

spremenljivko prestavlja med obema stanjema. Na koncu pripravimo še pomočnik edit-custom, ki

ga uporabljamo v predlogi kot vnosno polje.

38

App.EditCustomView = Ember.TextField.extend({

didInsertElement: function () {

this.$().focus();

},

focusOut: function () {

this.triggerAction();

},

insertNewline: function () {

this.triggerAction();

}

});

Ember.Handlebars.helper('edit-custom', App.EditCustomView);

Tukaj dedujemo od predpripravljenega vnosnega polja in dodamo nekaj obnašanja v odziv na

dogodke, ki ga pričakujemo od vnosnega polja. Prva funkcija bo sprožena, ko bo element

vstavljen v DOM in mu dodeli osredotočenost. Druga funkcija se sproži, ko element izgubi

poudarek, tretja, ko je pritisnjena nova vrstica (ang. Enter). V obeh primerih element sproži

podano akcijo, ki je v tem primeru toggleEdit. Zadnja vrstica pripravi vnosno polje za uporabo v

predlogah.

5.4.8 Testi enot (ang. unit test)

Testi so del programske opreme, ki zagotavlja, da produkcijski del deluje po specifikacijah in da

se ujamejo napake, povzročene z urejanjem kode. Niso del kode, ki ga aplikacija potrebuje za

delovanje, vseeno pa jih programerji pogosto uporabljajo, saj avtomatizirajo ponavljajoče se

opravilo testiranja.

Pri Angularju poudarjajo pomembnost testiranja in v dokumentaciji vsakemu primeru kode

priložijo primeren test. Tudi ogrodje je zasnovano tako da lahko testiramo vsak modul posebej in

vbrizgamo delujoče odvisnosti. Emberjeva dokumentacija nasprotno ne vsebuje primerov testov

enot ali navodil, kako jih pripraviti. Poskusil sem jih pripraviti na podlagi primerov, ki so jih

objavili uporabniki ogrodja, vendar nisem bil uspešen, zato v nadaljevanju ni primerov testiranja

39

enot v Emberju (sledijo pa integracijski testi v naslednjem poglavju).

Angular uporablja orodje Karma test runner za izvajanje testov in Jasmine za pisanje testov. Z

obema orodjema so testi enot precej berljivi in se zaganjajo ob vsakem shranjevanju datotek,

potrebne pa je kar nekaj konfiguracije, ki je ne bom podrobno opisoval. Uporabil sem Angularjev

seed projekt s priloženimi konfiguracijskimi datotekami in jih prilagodil po potrebi.

describe('Index Controller', function () {

beforeEach(inject(function ($rootScope, $controller, $q, Baskets) {

scope = $rootScope.$new();

var deferred = $q.defer();

deferred.resolve([{id: 1}, {id: 2}]);

spyOn(Baskets, 'findAll').andReturn(deferred.promise);

ctrl = $controller('IndexCtrl', {$scope: scope, Baskets: Baskets});

}));

it('sets baskets', function () {

scope.$apply();

expect(scope.baskets).toEqual([{id: 1}, {id: 2}]);

})

});

V zgornji kodi pripravimo Index kontroler za test in nato preverimo ali pravilno nastavi košarice

z uporabo storitve Baskets. Pred vsakim testom se izvede funkcija beforeEach, v katero

vbrizgamo storitev $rootScope, ki pripravi nov objekt scope za uporabo v kontrolerju, storitev

$controller, ki instancira kontroler za testiranje, storitev $q, uporabljeno za pripravo obljub, in

nazadnje našo storitev Baskets. Kontroler je treba testirati neodvisno od storitve Baskets, zato

prestrežemo klic metode findAll in odgovorimo z obljubo, pripravljeno s pomočjo storitve $q.

Dejanski test se začne s funkcijo it, ki ji podamo opis, ter funkcijo s testom. Najprej pokličemo

scope.$apply, kar izpolni obljubo, nato pa preverimo, da polje s košaricami res vsebuje nastavljen

objekt.

40

describe('Amount Interactive', function () {

var elm, scope, dblclick;

beforeEach(inject(function ($rootScope, $compile) {

elm = angular.element('<amount-interactive quantity=item.amount>');

scope = $rootScope.$new();

scope.item = {amount: 3};

$compile(elm)(scope)

}));

it(...);

});

V primeru testiranja direktive je to najprej treba sestaviti v standardne html elemente in testirati

te. Pred vsakim testom zato najprej pripravimo element, ki vsebuje direktivo za testiranje, in

scope objekt s potrebnimi informacijami. Nato sestavimo element in apliciramo scope.

it('should replace span with input', function () {

var span = elm.find('span');

span[0].dispatchEvent(dblclick);

expect(span.hasClass('hide')).toBe(true);

var input = elm.find('input');

expect(input.length).toBe(1);

});

V testu preverimo, ali je span zamenjan z vnosnim poljem po prejetem dvojnem kliku. Element

poiščemo, sprožimo dogodek in preverimo, da mu je dodan css razred hide. Nato poiščemo

vnosna polja in preverimo, da je dolžina vrnjenega niza točno ena.

5.4.9 Integracijski testi

Integracijski testi (v Angularju imenovani end to end testi) simulirajo uporabnikovo interakcijo in

preverjajo pravilnost odzivanja aplikacije. Testiral bom prehod aplikacije s strani s košaricami na

stran s košarico.

V Angularju uporabimo orodje Angular scenario runner, ki posnema sintakso jasmina, zato so

41

integracijski testi podobni testom enot. Enako kot pri njih je konfiguracija za zagon teh že

pripravljena v seed projektu in je ne bom podrobno opisoval.

describe('Navigation', function() {

it('baskets to basket on link click', function() {

var a = element('.basket-list li a')[0];

a.click();

expect(browser().location().url()).toBe('/basket/' + a.text());

});

});

V zgornjem testu najprej poiščemo prvo povezavo do košarice v DOM-u, nato jo sprožimo in

nazadnje preverimo url naslov trenutne strani, ki mora biti enak /basket/ z dodanim imenom

povezave.

V Emberju sem integracijske teste poganjal v brskalniku s pomočjo knjižnice qunit, uporabljene

tudi za testiranje ogrodja. Najprej je treba pripraviti testno index.html spletno stran s predlogami

in dodanima dvema div elementoma z identifikatorjema qunit ter qunit-fixture, v katera bo testna

knjižnica zapisovala poročila testov. Vključim tudi datoteko qunit in datoteko s testi. Nato

pripravimo aplikacijo za testiranje.

App.rootElement = '#qunit-fixture';

App.setupForTesting();

App.injectTestHelpers();

V prvi vrstici nastavimo element, v katerem bo pripeta aplikacija za potrebe testiranja. Druga in

tretja vrstica sta metodi, vgrajeni v Ember; prva zaustavi pripravljenost aplikacije dokler ni test

pripravljen za izvajanje, druga nastavi priročne funkcije v globalno okolje.

module("Navigation", {

setup: function() {

App.reset();

}

});

42

V zgornji kodi nastavimo modul navigation s setup metodo, ki se izvede pred vsakim testom, ki

sledi modulu. V tem primeru moramo le ponastaviti aplikacijo.

test('basket to baskets', function () {

visit('/').then(function () {

a.click('.basket-list li a: first').then(function () {

equal(path(), 'basket', 'Redirect to /:basket_name');

});

});

});

V tem testu začnemo na domači strani. Ko je pripravljena, poiščemo prvo povezavo košarice in jo

kliknemo. Nato preverimo, da je pot res spremenjena na pot basket.

5.4.10 Razlike

Angular aplikacijo lahko omejimo na del strani in celo izvajamo več aplikacij na eni

strani, Ember deluje nad celo stranjo.

Ember je bolj objektno usmerjen, dedovanje prek prototipov v javascriptu prekrije z

razredi. Za dostop in nastavitev polj objektov uporablja getter in setter metode.

Dele aplikacije v Angularju poimenujemo poljubno in jih nato povežemo s konfiguracijo,

v Emberju pa veljajo pravila o poimenovanju, ki se jih je treba držati. Ta pravila so vzeta

iz uveljavljenega ogrodja rails. Z njihovim upoštevanjem se izognemo konfiguraciji,

poleg tega s standardnim poimenovanjem aplikacija postane bolj razumljiva.

Ember se zdi precej nepopustljiv pri sestavljanju aplikacije. Arhitektura je osredotočena

na url naslov, ki bo v Ember aplikaciji vedno hranil stanje aplikacije. Pred kodiranjem je

zato dobro določiti naslove v aplikaciji, njihova gnezdenja in z njimi povezane vire.

Ostale dele preprosto dopišemo kot narekuje konvencija. V Angularju lahko sledimo

enako sistematičnemu pristopu, dovoljuje pa tudi bolj fleksibilen pristop. Pozneje lahko

kodo preprosto urejamo zaradi ohlapne povezanosti komponent v ogrodju.

Angular filtri so fleksibilen in priročen način manipuliranja podatkov pred prikazom. V

Emberju nimajo ekvivalenta.

43

Poudarek na testiranju aplikacije je nedvomno večji pri Angularju. Dokumentacija pri njih

vsebuje primere testov, razvili so orodje, ki teste poganja, in pripravili začetni projekt s

potrebno konfiguracijo za pisanje in poganjanje testov. Pri Emberju je dokumentacija

testiranja skopa z eno stranjo namenjeno integracijskim testom, testi enot pa so

popolnoma prepuščeni razvijalcu.

5.5 Analiza kode

V analizi kode primerjam javascript kodo obeh aplikacij in kodo todoMVC projekta,

implementiranega v obeh ogrodjih. TodoMVC je namenjen kot pomoč razvijalcem pri izbiri

javascript ogrodja ali knjižnice za razvoj spletne aplikacije. V analizi sem uporabil kodo

aplikacije za spremljanje opravil, zgrajeno z uporabo angular in ember ogrodja.

Kodo primerjam po šestih parametrih, za analizo uporabljam orodje jscomplexity (20. december

2013). Prvi parameter je preprosto število vrstic kode, manj vrstic načeloma pomeni manj časa za

razvoj in vzdrževanje aplikacije. Drugi parameter je število imperativnih izjav; ta pokazatelj je

lahko bolj natančen, saj več izjav v eni vrstici nanj ne vpliva. Tretji pokazatelj kompleksnosti je

število parametrov, ki jih funkcije sprejmejo. Četrti parameter je ciklična kompleksnost, kot jo je

definiral Thomas J. McCabe in je število različnih poti skozi kodo. Preprosta koda ima nizko

ciklično kompleksnost. Peti parameter, gostota ciklične kompleksnosti, je ciklična kompleksnost,

izražena kot del imperativnih izjav. Pokazatelj sta predlagala Geoffrey Gill in Chris Kemerer.

Zadnji pokazatelj, indeks vzdrževanja, je bolj kompleksen. Najprej za vsako funkcijo izračunamo

tri mere kompleksnosti, kot jih je definiral Maurice Halstead (Jscomplexity, 20. december 2013).

Prva mera je težavnost:

(št. različnih operatorjev / 2) * (št. operandov / št. različnih operandov)

Drugo mero je imenoval prostornina:

(št. operatorjev + št. operandov) * log2(št. različnih operatorjev + št. različnih

operandov)

44

Tretja mera je trud:

težavnost * prostornina

Z mero truda in prej poznanimi pokazatelji sta Paul Oman in Jack Hagemeister definirala indeks

vzdrževanja, ki je izračunan za celotno aplikacijo kot:

171 -

(3.42 * ln(povprečje truda)) -

(0.23 * ln(povprečje ciklične kompleksnosti)) -

(16.2 * ln(povprečje števila imperativnih izjav))

Vrednosti indeksa so od negativne neskončnosti do 171. Višja vrednost pomeni lažje vzdržljiv

program, vrednost 65 pa je meja, pod katero je program lahko težaven za vzdrževanje

(Jscomplexity, 20. december 2013).

Število vrstic javascript kode je nižje z uporabo ogrodja Angular, v obeh primerih je z

Angularjem potrebno zapisati 8 % manj vrstic. Ta razlika je precej majhna, še posebej glede na

to, da je brez uporabe kakršnega koli ogrodja todo projekt zapisan na več kot štirikrat toliko

vrsticah kot z uporabo ogrodja. Število imperativnih izjav je podobno kot število vrstic nekoliko

niže z uporabo ogrodja Angular.

45

Tabela 5.1: Pokazatelji kompleksnosti kode

Ogrodje Število vrstic Število

imperativnih

izjav

Število

parametrov

Ciklična

kompleksnost

Gostota

ciklične

kompleksnosti

Indeks

vzdrževanja

Angular 216 108 38 8 7% 140

Ember 234 135 21 3 2% 147

Todo projekt

Angular 162 75 27 10 13% 136

Ember 176 99 4 7 7% 141

Samo js 785 323 62 51 16% 122

Vir: Lokar, lastna raziskava (2013) in Todo projekt (27. december 2013)

Število parametrov, podanih funkcijam, je nižje z uporabo Emberja. Za to sem našel dva vzroka.

Prvi je precejšna uporaba vzorca vbrizga odvisnosti v Angularju, kjer odvisnosti podamo kot

parameter v funkcijo in s tem višamo tudi ta kazalnik kompleksnosti, po drugi strani pa je kodo,

zapisano na tak način lahko testirati in urejati. Drugi vzrok je objektna orientiranost Emberja, kjer

je bolj verjetno, da bomo kodo zapisali kot metodo, v kateri bo objekt, nad katerim smo metodo

poklicali na voljo in ga ni treba eksplicitno podati. Oba vzroka sta posledica različnega pristopa

ogrodij, višja kompleksnost kazalnika pri Angularju pa je nepomembna glede na večjo

fleksibilnost, omogočeno s takšnim pristopom.

Ciklična kompleksnost je višja z uporabo Angularja. Pri podrobnejšem pregledu sem našel

največjo razliko pri treh funkcijah, ki izračunajo ceno košarice, število izdelkov in težo. V

Angularju v teh funkcijah preverim, ali so podatki, povezani s košarico, nastavljeni, in jih nato

izračunam, v Emberju to preverjanje ni potrebno. Ta dodatna kompleksnost izvira iz načina

delovanja ogrodja, Ember pri nastavljanju poti počaka na asinhrone podatke in nadaljuje v

kontroler šele, ko je obljuba izpolnjena, Angular za razliko takoj začne s prikazom uporabniškega

vmesnika, zato v prej naštetih treh funkcijah preverimo, ali so podatki že na voljo, in vrnemo

smiselni rezultat, tudi če niso. Kot pokazatelj nakazuje, je koda Angular aplikacije res bolj

46

kompleksna v treh funkcijah, vendar z namenom hitrejšega prikaza uporabniškega vmesnika.

Indeks vzdrževanja kode je približno enak v obeh ogrodjih, z vrednostjo 140 v Angularju in 147

v Emberju. Podoben rezultat je dosežen tudi z analizo kode projekta Todo.

5.6 Analiza skupnosti

Skupnost uporabnikov je vitalen del vsakega projekta, saj so to ljudje, ki ogrodje uporabljajo in

ga razvijajo. Poleg tega skupnost odprtokodnega projekta javlja popravke napak v projektu,

sporoča potrebe po novih funkcionalnostih in ponuja vir razvijalcev, ki so lahko rekrutirani za

delo na projektu. In nazadnje več uporabnikov olajša iskanje pomoči.

Za prvo oceno skupnosti obeh ogrodij sem uporabil Googlovo poročilo iskanja po ključnih

besedah.

Vir: Google trendi (18. avgust 2013)

V poročilu nisem uporabil ključnih besed Angular in Ember, ker imata obe pomen nepovezan s

spletnimi aplikacijami, in ju nadomestil s poizvedbami, dopolnjenimi z .js in JS (poizvedba ni

občutljiva na velike črke). Prve poizvedbe za Ember se pojavijo v začetku 2012, za Angular sredi

leta 2012. Poizvedba, ki izstopa, je angularJS, in iz katere lahko sklepamo, da Angular ustvarja

precej več zanimanja in stalno narašča od pojava ogrodja.

Graf 5.1: Iskanje po ključnih besedah obeh ogrodij

Graf 5.2: Iskanje po ključnih besedah. (vir: www.google.com/trends)

47

Github je priljubljena spletna stran, gosti repozitorije in povezuje razvijalce za delo na projektu.

Kot nakazuje ime, stran uporablja git sistem za nadzor različic programa. Obe ogrodji Angular in

Ember uporabljata Github. Na podstraneh obeh projektov najdemo nekaj statistik, iz katerih

lahko ugotavljamo aktivnost razvoja projekta. Prva statistika je število razvijalcev, ki je

prispevalo k projektu s popravki kode in katerih popravek je bil sprejet v glavno vejo projekta.

Druga statistika je število razvijalcev, ki spremlja projekt, kar pomeni, da prejemajo vsa

obvestila, povezana s projektom. Tretja statistika »zvezda« so razvijalci, ki želijo pokazati

podporo projektu, vendar ne prejmejo obvestil o dogajanju. Zadnja statistika je število projektov,

odcepljenih iz originalnega projekta za samostojno nadaljnje razvijanje.

Tabela 5.2: Število razvijalcev, ki repozitoriju projektov prispeva, ga spremlja, ga je označilo z

zvezdo ali ga je odcepilo

Prispevalo Spremlja Zvezda Odcepilo

Angular 569 1924 18415 5235

Ember 294 785 8981 1876

Vir: Github (20. december 2013)

Po vseh navedenih statistikah ima angular bolj aktiven razvoj in približno dvakrat večjo skupnost

razvijalcev.

Stackoverflow je najbolj popularna skupnost razvijalcev, v kateri si ti med seboj pomagajo, ko se

zatakne. Uporabnik postavi vprašanje in nato počaka na odgovor nekoga, ki pozna rešitev, ali

pogosto le poišče že obstoječ odgovor v primeru, da je nekdo že naletel na enak problem. Stran je

tako ogromna baza rešitev problemov, na katere so naleteli uporabniki.

48

Tabela 5.3: Število vprašanj glede ogrodij postavljenih v enem dnevu, tednu in do zdaj

Zaznamek Vseh vprašanj Vprašanj danes Vprašanj ta teden

Angular angularjs 20384 81 418

Ember ember.js 7262 12 73

Vir: Stackoverflow (20. december 2013)

Vprašanja na strani so organizirana z zaznamki. Največja zaznamka za ogrodji, ki ju primerjam,

sta angularjs za ogrodje Angular in ember.js za ogrodje Ember. Pod prvim zaznamkom ogrodje

Angular je skupno postavljenih 20384 vprašanj, pod drugim zaznamkom ogrodje Ember pa je

7262 vprašanj. Vse tri statistike tudi tu nakazujejo večjo aktivnost uporabnikov ogrodje Angular.

6. ZAKLJUČEK

V iskanju najbolj primernega ogrodja za izdelavo spletne aplikacije za povezovanje lokalnih

ponudnikov hrane z dodatno omejitvijo, da se to ogrodje izvaja na strani odjemalca, sem na prvi

izziv naletel, ko sem ugotovil, da je teh ogrodij preprosto preveč za primerjavo. Število sem

zmanjšal na podlagi popularnosti ogrodij in raziskavo začel najprej s šestimi MVC ogrodji. Nato

sem izločil dve najbolj primerni za dejansko uporabo glede na tip aplikacije, ki jo gradim.

Izbrani ogrodji Ember in Angular sem primerjal najprej na primeru implementacije minimalnega

smiselnega produkta (MVP). Ugotovil sem, da sta si ogrodji presenetljivo podobni, tudi če

nekatere dele imenujeta različno, ali pa na prvi pogled izgledajo drugače, a v osnovi še vedno

opravljajo enako nalogo. Tako v Angularju najdemo direktive in v Emberju komponente, oboje

pa je namenjeno zapisu ponavljajočih ali kompleksnih elementov uporabniškega vmesnika.

Podobno Angularjeve storitve v večini primerov opravljajo nalogo, ki je v ostalih ogrodjih

zapisana v modelih.

Naletel sem tudi na kar nekaj razlik, ki niso boljše ali slabše v enem ogrodju. Te so stvar

49

odločitve o zasnovi ogrodja in preferenc razvijalcev. Emberjevi razvijalci so se odločili

posnemati razrede, s čimer želijo ogrodje narediti domače razvijalcem z ozadjem v objektno

orientiranih jezikih, pri Anguarju pa sprejemajo idiomatičen javascript. Z arhitekturnega vidika

Ember zahteva načrtovanje, osredotočeno na url, ki bo zvesto odražal stanje aplikacije in

načeloma vodi v jasno in predvidljivo sestavo aplikacije, Angular pa se zdi bolj fleksibilen; z

njim bi na primer hitreje sestavil prototip.

V analizi implementacije sem odkril še tri vidike, v katerih je Angular boljše ogrodje kot Ember.

Prvi dve razliki sta manjši, in sicer: Angular aplikacijo lahko omejimo na del strani in celo

poganjamo več aplikacij hkrati na eni strani, vsebuje priročne filtre, ki manipulirajo s podatki

pred izpisom v uporabniški vmesnik. S tem sprostijo kontroler in omogočijo lažje deljenje kode

med aplikacijami. Tretja razlika, ki se mi zdi pomembnejša, je Angularjeva naklonjenost

testiranju aplikacije. Začetni projekt ogrodja že vsebuje konfiguracijo in orodja, potrebna za

poganjanje testov. Blestijo pa tudi pri dokumentaciji, pri kateri je vsakemu relevantnemu koščku

kode priložen še primer testa, ki pravilnost delovanja te kode preverja. Pri Emberju je v času

pisanja raziskave dokumentacija testiranja vsebovala le en kratek dokument s področja

integracijskih testov in nič glede testov enot. Zdi pa se tudi, da če dopolnijo dokumentacijo,

Ember aplikacije ne bodo enako preproste za testiranje kot Angular aplikacije, ki obsežno

uporabljajo vbrizg odvisnosti. Ta razlika je lahko odločilna za veliko razvijalcev, ki želijo

garancijo dobro testirane aplikacije v jeziku brez pomoči prevajalnika in statičnih tipov.

V drugem delu analize sem primerjal kodo obeh aplikacij in še enega projekta, zapisanega v obeh

ogrodjih, po metrikah kode, kot so število vrstic, ciklična kompleksnost in indeks vzdrževanja.

Kodi aplikacij z uporabo obeh ogrodij sta bili enakovredni brez očitnih razlik.

V primerjavi skupnosti se vnovič pokaže večja razlika med obema ogrodjema. Angular ima okoli

dvakrat več razvijalcev, ki prispevajo k projektu ali ga spremljajo. Na stackoverflow-u je skoraj

trikrat več vprašanj, povezanih z Angular ogrodjem. V iskalniku Google po poizvedbah Angular

ustvarja mnogo več zanimanja. Te statistike nakazujejo, da se bo ogrodje Angular hitreje in dlje

časa razvijalo ter je bolj dolgoročna varna možnost za gradnjo aplikacije.

50

Na podlagi raziskave ugotavljam, da je Angular bolj primerno ogrodje, glede na to, da je pri

odprtokodnih orodjih močna skupnost ključnega pomena. Drugi razlog je dobra podpora

testiranju, ki je zelo dobrodošla še posebej pri jeziku, kot je javascript, in uporabi

neuveljavljenega ogrodja, pri čemer se ne moremo zanašati na dobre prakse, ki se razvijejo z leti

uporabe.

Očitna pomanjkljivost raziskave je primerjava na velikih aplikacijah, torej, kako se ogrodji

obneseta na velikosti produkcijske aplikacije; kateremu ogrodju predstavlja velika aplikacija

manj težav in ali je sploh smiselno seliti večjo aplikacijo na stran odjemalca.

51

7. LITERATURA IN VIRI

1. ANGULARJS. Dostopno prek: www.angularjs.org (20. 12. 2013).

2. ANGULAR SCENARIO RUNNER. Dostopno prek:

https://code.angularjs.org/1.2.2/docs/guide/dev_guide.e2e-testing (20. 12. 2013).

3. APPWARD, BERT (2012) Field Guide to Web Applications, e-knjiga. Dostopno prek:

http://www.html5rocks.com/webappfieldguide/ (13. 8. 2013).

4. BACKBONE.JS. Dostopno prek: www.backbonejs.org (16. 8. 2013).

5. BATMAN.JS. Dostopno prek: www.batmanjs.org (16. 8. 2013).

6. EMBER. Dostopno prek: www.emberjs.com (20. 12. 2013).

7. FLANAGAN, DAVID (2011) JavaScript The Defnitive Guide.6th Edition. O'Reilly,

Sebastopol.

8. GARRETT, JESSE JAMES (2005) Ajax: A new approach to web applications. Dostopno

prek: http://www.adaptivepath.com/ideas/ajax-new-approach-web-applications/ (30. 12.

2013).

9. GIAMPIETRO, MARINA (2013) Twenty years of a free, open web. Dostopno prek:

http://home.web.cern.ch/about/updates/2013/04/twenty-years-free-open-web (30. 12. 2013).

10. GITHUB. Dostopno prek: www.github.com (8. 8. 2013).

11. GOOGLE THRENDS. Dostopno prek: http://www.google.com/trends (18. 8. 2013).

12. HANDLEBARS. Dostopno prek: http://www.handlebarsjs.com/ (20. 12. 2013).

13. HEMPTON, GORDON (2012) The Top 10 Javascript MVC Frameworks Reviewed.

Dostopno prek: http://codebrief.com/2012/01/the-top-10-javascript-mvc-frameworks-

reviewed/ (2. 1. 2014).

14. HTML. Dostopno prek: http://www.w3.org/community/webed/wiki/HTML (30. 12. 2013).

15. JASMINE. Dostopno prek: http://pivotal.github.io/jasmine1.3.1 (20. 12. 2013).

16. JSCOMPLEXITY. Dostopno prek: http://jscomplexity.org/ (20. 12. 2013).

52

53

17. JQUERY. Dostopno prek: http://jquery.com/ (20. 12. 2013 ).

18. KARMA RUNNER. Dostopno prek: http://karma-runner.github.io/0.10 (20. 12. 2013).

19. KNOCKOUT. Dostopno prek: www.knockoutjs.com (21. 8. 2013).

20. MERTIK, MATEJ (2011) A look at the state of open source use in Slovenia (Freeing Slovenian

organizations). Innovative Issues and Approaches in Social Sciences, januar 2011, str. 68-75.

Dostopno prek: http://www.iiass.com/pdf/IIASS-2011-no1-art03.pdf (7. 7. 2014).

21. METEOR. Dostopno prek: www.meteor.com (16. 8. 2013).

22. O'LUANAIGH, CIAN (2014) World Wide Web born at CERN 25 years ago. Dostopno prek:

http://home.web.cern.ch/about/updates/2014/03/world-wide-web-born-cern-25-years-ago (5. 7.

2014).

23. OSMANI, ADDY (2012) Journey Through The JavaScript MVC Jungle. Dostopno prek:

http://www.smashingmagazine.com/2012/07/27/journey-through-the-javascript-mvc-jungle/ (2. 1.

2014).

24. PIVEC, FRANCI (2005) Politična ekonomija odprte kode, povzel po Manuel Castells (2005)

Inovacije, informacijska tehnologija in kultura svobode. Dostopno prek:

http://www.coks.si/images/c/c4/Iprok_clanek_Politicna_ekonomija_OK.pdf (5. 7. 2014).

25. PIVEC, FRANCI (2007) Informatika in odprta koda. Dostopno prek:

www.coks.si/images/a/a7/Informatika_in_odprta_koda.pdf (7. 7. 2014).

26. PIVEC, FRANCI (2009) Odprta koda v luči Marxove teorije produkcije. Dostopno prek:

http://www.coks.si/images/8/89/IPROKMarxinOKPO.pdf (5. 7. 2014).

27. PRASAD, GANESH, RAJAT, TANEJA IN TODANKAR, VIKRANT (2007) Life above the

Service tier. Dostopno prek: http://www.smart-soft.com/downloads/articles/Life-above-the-

Service-Tier-v1_1.pdf (16. 8. 2013).

28. SOFEA, AJAX, Full-JAX and the Death of Half-JAX. Dostopno prek: http://www.smart-

soft.com/downloads/articles/sofea.html (16. 8. 2013).

29. STACKOVERFLOW. Dostopno prek: www.stackoverflow.com (7. 7. 2014).

54

55

30. STEFANOV, STOYAN (2008) Object-Oriented JavaScript. Birmingham: Packt Publishing Ltd.

31. TAKADA, MIKITO (2012) Single page apps in depth, e-knjiga. Dostopno prek:

www.singlepageappbook.com (13. 8. 2013).

32. TODO PROJEKT. Dostopno prek: http://todomvc.com/ (27. 12. 2013).

33. QUNIT. Dostopno prek: http://qunitjs.com/ (8. 7. 2014).

34. ZAKAS, NICHOLAS C. (2012) Professional JavaScript for Web Developers. 3rd Edition.

John Wiley & Sons, Inc.