Modularno programiranje sa ES6

Karakteristike ES6 modula

es6 modul

Sa novom verzijom JavaScript-a ES6 dolazi integrisana podrška za modularno programiranje.

  • Podržava module koji se smeštaju u datoteke – jedan modul po datoteci
  • Moduli su jedinstveni primerci, svaki modul se izvršava samo jednom (singleton model).
  • ES6 moduli mogu da rade i sinhrono i asihrono.
  • Podržava “cyclic dependencies”.
  • Sintaksa je još kompaktnija od CommonJS
  • ES moduli imaju statičku strukturu. Pošto je struktura modula nepromenjiva, često je dovoljno da se pregleda kod i shvati šta se gde importuje. Ovo nije slučaj kod dinamičke strukture, gde je često potrebno da se kod izvrši da bi se videlo šta se importuje. Eventualne greške mogu da se nadju i u vreme kompajliranja (sa modul bundler-om), jer se sve radnje vezane za import i export modula odredjuju u tom trenutku.
  • Svi uvezeni elementi su nepromenjivi iz modula koji importuje. Svaka operacija dodeljivanja vrednosti uveženom elementu bi prouzrokovala grešku (TypeError).
  • ES6 se ne pravi kopiju svojstva već deli vezu na to svojstvo. Ovo važi čak i za deljenje primitivnih svojstava (“broj” ili “string”). U narednom primeru vidimo da ukoliko matični modul promeni vrednost deljenog svojstva (promena je izvršena metodom iz matičnog modula!), modul koji je importovao to svojsto “vidi” tu promenu.
    PRIMER
    proracun.js

    main.js

    Importujemo sve elemente koji su eksportovani iz modula “proracun.js”

    Ako bi se sada koristila promenjiva “brojač” u nekom “trećem” modulu imala bi vrednost 2.

Continue reading…


Modularno programiranje – eksterna sintaksa (AMD & CommonJS)

Uvod

Externe sintakse nisu JavaScript biblioteke, već odgovarajuće specifikacije i konvencije za definisanje modula. Eksterna sintaksa može da se koristi jedino uz pomoć modul loader-a koji joj “udahnu život”. Ako modul loader podržava sintaksu to znači da unutar sebe sadrži ugradjene metode koje su prethodno zamišljene da se koriste kroz odredjenu sintaksu.
Prednost korišćenja ovih eksternih sintaksi u odnosu na native ES5 modul patern je ta što ne zagadjuje globalni domen nazivima modula i što je omogućen rad dependencies menadžera.

  • Asynchronous Module Definition (AMD) kao što mu i samo ime kaže, podržava asihrono učitavanje modula što je pogodno za rad sa modulima u browser-u.
  • CommonJS učitava module sinhrono i zbog toga se najčešće koristi za rad sa modulima na serverskoj strani u okruženju node.js. Iako nije planiran za rad u browser-u, uz pomoć “modul bundler-a” je moguće da prilagoditi CommonJS radu u browser-u.
  • Universal module definition (UMD) je kompatibilan i sa AMD i sa CommonJS definicijom i koristi se uglavnom ukoliko ima potrebe da se isti modul učitava na serveru i u browser-u.

OBJAŠNJENJE:
CommonJS, AMD ili UMD nisu JavaScript biblioteke. To su organizacije za standardizaciju, kao što je ECMA (definiše specifikaciju jezika za JavaScript) ili W3C (definiše JavaScript web API, kao što su DOM ili DOM događaji). Cilj CommonJS ili AMD sintaksi je definisanje API-ja za rad sa modulima.

Continue reading…


Modularno programiranje sa ES5

Uvod

es5

ES5 verzija JavaScript-a nema podršku za module, ali bez obzira na to je moguće držeći se odredjenih principa napraviti aplikacije u maniru modularnog programiranja. Module sa svojim enkapsuliranim kodom kreiramo koristeći “Immediately-Invoked Function Expressions” ili sa konstruktor funkcijom. API modula koji treba da bude javan jednostavno vratimo unutar funkcije sa rezervisanom reči return. Ovo je jednostavan šablon i može se primeniti bilo gde bez dodatnih biblioteka. U okviru jednog fajla je moguće definisati više modula.

Pored navedenih prednosti ovaj pristup ipak ima i svojih mana:

  • “zagadjivanje” globalnog domena nazivima modula, mada je body modula skriven korišćenjem funkcija (IIFE) u lokalni domen.
  • “ručno” odredjivanje redosleda učitavanja modula a redosled učitavanja modula može biti prilično komplikovan kod velikih i kompleksnih aplikacija.
  • nije moguće asihrono učitavanje

Ovi šabloni nisu savršeni i imaju svoje mane ali bez obzira na mane, kod je razumljiviji jer je bolje organizovan.

IIFE – Immediately-Invoked Function Expressions

Definicija

IIFE (izgovara se “ifi”) je function expression koja se izvršava odmah nakon stvaranja. Kreira se tako što “deklaraciju funkcije” obavijemo sa parom zagrada i tako napravimo “function expression”. Razlog za transformaciju “deklarisane funkcije” u “function expression”, je taj što deklarisana funkcija ne može biti odmah pozvana u istoj naredbi dok function expression može.

Nakon pravljenja function expression u istoj naredbi dodamo još jedan par zagrada i tako odmah pozovemo funkciju.

Privatnost podataka unutar IIFE

IIFE se koristi za modularni patern programiranja jer sav kod unutar ovakve funkcije ostaje privatan, što se vidi u narednom primeru.

Prosledjivanje promenjivih u IIFE

Globalne promenjive se mogu proslediti unutar funkcije, pri pozivanju funkcije kao argument te funkcije:

jQuery biblioteka takodje koristi ovaj pristup da bi prosledila promenjivu:

Vraćanje podataka

Sa IIFE možemo da izaberemo koje podatke želimo da zadržimo kao privatne a koje podatke želimo da objavimo. Javno dostupni će biti oni delovi koda koji se vrate sa rezervisanom reči return. Pomenutim načinom možemo u globalni namespace proslediti sve tipove podataka. U sledećem primeru vraćamo promenjivu a samim tim je činimo je globalno vidljivom:

možemo vratiti funkciju

Ili možemo vratiti ceo objekat

Revealing module pattern

Najčešće nije potrebno vratit ceo objekat već je dovoljno otkriti javnosti samo neke delove koda, što se primenjuje kroz “Revealing module pattern”. Sa ovim principom možemo da izberemo koje metode želimo da budu privatne a koje da budu javne i dostupne ostalim modulima.

IIFE + Singleton šablon

izgled aplikacije

Opšte

U softverskom inžinjerstvu singleton (srp. unikatni) šablon programiranja je zasnovan na principu da svaki objekat (klasa) ima SAMO JEDNU INSTANCU, uz uslov da pristup toj instanci bude globalno dostupan. U JavaScript-u je to moguće dodeljivanjem IIFE globalnoj promenjivoj. U modulima se “otkrivaju” metode koje želimo da budu globalno dostupne prateći “Revealing module pattern”. Sa je IIFE se pravi lokalni scope i sprečava se zagadjivanje globalnog domena, ali naziv svakog modula postaje deo globalnog domena i može doći u koliziju sa nekom externom bibliotekom ukoliko njena promenjiva ima isto ime.

Praktična primena u aplikaciji

index.html

Ovaj fajl čini osnovu aplikacije i služi kao view za prikupljanje podataka od korisnika i vraćanje razultata. Obratiti pažnju na deo koji je zadužen za učitavnje modula, jer redosled učitavanja modula zavisi od funkcionalnosti aplikacije. Ovo je najteži deo za programera naručito kod velikih i kompleksnih aplikacija. U ovom primeru se prvo učitava “unos.js” jer se njegove metode koriste i u okviru “proracun.js” i “app.js”, dok se skripta “proracun.js” učitava odmah za njom ali pre “app.js” jer je njena metoda sastavni deo “app.js”.

unos.js

proracun.js

app.js

Konstruktor šablon

Opšte

Konstruktor šablon omogućava pravljenje više instanci na osnovu konstruktorske funkcije. Izmene koda u odnosu na prethodni šablon su male. Telo funkcije ostaje nepromenjeno dok se prilagodjavaju samo sledeće stvari:

  • Naziv promenjive kojoj se dodeljuje funkcija treba da počinje sa velikim početnim slovom, da bi se zadovoljila konvencija
  • IIFE se transformiše u običnu funkciju, brisanjem zagrada koje odmah pozivaju funkciju jer je standardna konstruktorska funkcija planirana da se poziva samo sa rezervisanom reči “new”
  • Unutar modula koji potražuje metodu iz drugog modula potrebno je instancirati novi objekat, da bi bila dostupna njegova metoda.

Praktična primena u aplikaciji

unos.js

Ovaj modul ne koristi metode iz drugih modula, pa su izmene vezane samo za ukidanje zagrada za pozivanje funkcije.

proracun.js

Unutar ovog modula je potrebno da se instancira novi “Unos” objekat.

app.js

Unutar ovog modula je potrebno da se instancira novi “Unos” i “Proracun” objekat.



Uvod u modularno programiranje

Karakteristike modularnog programiranja

modularno programiranje kocka

Modularni koncept programiranja je trenutno jedan od najzastupljenijih koncepata u modernom programiranju sa Javascript-om. Zasniva se na razbijanju jedne velike aplikacije na manje, enkapsulirane, nezavisne delove koda – module. Cilj modularnosti jeste da se smanji kompleksnost prema principu “podeli pa vladaj”. Najznačajnije prednosti modularnog programiranja su:

  • preglednija i razumljivija aplikacija
  • lakše kontrolisanje domena promenjivih
  • sprečeno “zagadjenje globalnog domena”
  • ponovna upotrebljivost koda
  • mogućnost rada na istom projektu više različitih timova ili programera koji rade odvojene manje zadatke.
  • lakše debagovanje

Tipovi sintakse

U zavisnosti od verzije JavaScripta postoje različiti pristupi problemu i različite sintakse koje omogućavaju modularno programiranje:

Native ES5 sintaksa

U vreme pisanja JavaScripta, modularno programiranje nije bilo planirano kao način programiranja, tako da JavaScript sve do ES6 (ES2015) verzije nema podršku za module. U okviru native ES5 se koriste razni šabloni (eng. patern) koji imaju sličnosti sa modularnim programiranjem ali nemaju baš sve karakteristike “čistokrvnog modularnog šablona”.
Pročitajte više o native ES5 sintaksi u članku Modularno programiranje sa ES5.

ES5 sa externim bibliotekama

Upravo zbog nedostatka podrške za module u ES5 su kreirane externe syntax-e koje jeziku daju nedostajuću syntax-u:

  • CommonJS Modules
  • Asynchronous Module Definition (AMD)
  • Universal modul definition (UMD)

Pročitajete više o sardnji ES5 sa externim bibliotekama u članku Modularno programiranje – eksterna sintaksa (AMD & CommonJS).

ES6 modules sintaksa

Uz ES6 stiže podrška za modularni sistem ugradjena i u sam jezik – ECMAScript 6 modules. Nova syntax-a još uvek nije podržana od strane browser-a, pa je potrebno koristi Babel ili TypeScript da bi se transpilovala u ES5.
Pogledajte više o novoj ES6 modules sintaksi u članku Modularno programiranje sa ES6.

Modul loaders i bundlers

Ukoliko se odlučimo za modularni način programiranja aplikacije, susrećemo se sa problemom organizovanja učitavanja modula i modula od kojih oni zavise tzv. dependencies. Modul loaders i bundlers su nepohodna podrška programeru za jednostavniji i efikasniji rad sa modulima.

Modul loaders

“Modul loaders” omogućavaju dinamičko učitavanje modula pazeći na raspored učitavanja. Najpoznatiji modul loader-i su:

  • RequireJS – implementira AMD modularni sistem.
  • SystemJS – je univerzalni loader i može učitavati module u bilo kom popularnom formatu (CommonJS, UMD, AMD, ES6). Najčešće se koristi zajedno sa jsmp.io koji je više od običnog package manager-a, pa može transpilovati ES6 kao i TypeScript ili CoffeeScript.

Šta su CommonJS, AMD i UMD?

  • Asynchronous Module Definition (AMD) kao što mu i samo ime kaže, podržava asihrono učitavanje modula što je pogodno za rad sa modulima u browser-u.
  • CommonJS učitava module sinhrono i zbog toga se najčešće koristi za rad sa modulima na serverskoj strani u okruženju node.js. Iako nije planiran za rad u browser-u, uz pomoć “modul bundler-a” je moguće da prilagoditi CommonJS radu u browser-u.
  • Universal module definition (UMD) je kompatibilan i sa AMD i sa CommonJS definicijom i koristi se uglavnom ukoliko ima potrebe da se isti modul učitava na serveru i u browser-u.

Više p ovome pogledajte u članku Modularno programiranje – eksterna sintaksa (AMD & CommonJS)

Module bundlers

“Modul bundlers” rešavaju problem tako što kompajliraju sve module u jedan fajl prema odredjenom redu pazeći da neki modul koji je zavisnost drugome bude učitan na vreme. Najpoznatiji modul bundler-i:

  • Browserify – implementira CommonJS i u browser okruženju. Može da se nadogradjuje raznim plugin-ima i uz pomoć task runner-a (Gulp ili Grunt) može da završi različite poslove.
  • Webpack – može učitavati module u bilo kom popularnom formatu (CommonJS, UMD, AMD, ES6), dolazi kao jedan paket i nisu mu potrebni dodatni plugin. Pored učitavanja modula može da izvrši posao transpilovanja ES6(Typescript) u ES5 kao i transpilovanje SASS-a u CSS.

Zaključak

Izbor tipa podrške za rad sa modulima najviše zavisi od same aplikacije. Stoga ukoliko se aplikacija sastoji od manjeg broja većih modula, smatra se da je bolji izbor “modul loader”, dok se smatra da je “modul bundler” pogodniji ukoliko se aplikacija sastoji od većeg broja manjih modula. U svakom slučaju najsigurnije je isprobati oba tipa pa videti koji daje bolje rezultate.

Popularnost alata za rad sa modulima tokom zadnjih par godina se može proučiti na grafikonu google trends. Na osnovu grafikona se zaključuje da postoji ogromno interesovanje za Webpack kao predstavnika modul bundler-a, dok kod predstavnika modul load-era je vidljiv rast popularnosti SystemJS-a.