Javascript per applicazioni complesse - Lo Stretto digitale

Post on 06-Jul-2015

855 views 0 download

description

Mentre ogni giorno di più crescono e si fanno sempre più complessi gli ambiti nei quali Javascript si propone (e spesso impone) come strumento di sviluppo, viene da chiedersi se (e quando) si avvererà la legge di Atwood per la quale "ogni applicazione che può essere scritta in Javascript, sarà necessariamente scritta in Javascript". Nell'attesa di scoprirlo meglio prepararsi con vecchi e nuovi patterns e best practices che ci consentono di realizzare software di qualità con uno dei linguaggi più duttili e trasversali di sempre. Presentazione realizzata nell'ambito del progetto "Lo Stretto Digitale"

Transcript of Javascript per applicazioni complesse - Lo Stretto digitale

LO STRETTO DIGITALESUMMER TALKS 2013

MESSINA - TORRE DEGLI INGLESI C/O HORCYNUS ORCA - 23/07/2013

JAVASCRIPT PERAPPLICAZIONI

COMPLESSEDESIGN PATTERNS & BEST PRACTICES

/ / Giuseppe PIZZIMENTI @gpizzimenti @strettodigitale

JAVA..CHE?Cos'era ed a cosa serviva Javascript ...fino a 5 minuti

(informatici) fa...

ALCUNI FATTI SU JAVASCRIPT...Sviluppato da una sola persona ( ) in 10 giorniSintassi come il CInterpretato come BasicDinamico come PythonFunzionale come SchemeAd oggetti ...ma senza classi! (come Perl)...ed ha Java nel nome!

@BrendanEich

https://www.destroyallsoftware.com/talks/wat

...ED ALCUNI, ALTRI, FATTI...

OGGETTI IN JAVA

public class Point { private int x = 0; private int y = 0; //constructor public Point(int a, int b) { x = a; y = b; } public int sumXY() { return x+y; } }

Point origin = new Point(23, 94); out.print(origin.sumXY());

OGGETTI IN JAVASCRIPT

var point = {};

point.x = 23;point.y = 94;

point.sumXY = function() { return this.x + this.y;

};

alert(point.sumXY());

INSTALLAZIONE

AGGIORNAMENTO

SVILUPPO

...INTANTO, LÀ FUORI...

LA LEGGE DI ATWOODCos'è ed a cosa serve Javascript ...ora!

“any application that can be written inJavaScript, will eventually be written in

JavaScript”

Jeff Atwood, 17/07/2007

http://www.codinghorror.com/blog/2007/07/the-principle-of-least-power.html

FACCIAMO UN PÒ D'ORDINE..

NAMESPACING

var coord = 0;

.

.

. var showCoord = function() {

var coord = 1; alert(coord);

};

var myApp = {};

myApp.coord = 0;

myApp.data.coords.x = 0;

myApp.utils.geo.setCoords = function(x,y){

myApp.data.coords.x = x; myApp.data.coords.y = y;

}; ;

myApp.utils.geo.setCoords(10,10);

//Flyweight;

myApp.utils.geo.processCoords(myApp.data.coords);

myApp.utils.geo.processCoords = function(coords){

process(coords.x,coords.y);

}; ;

IIFE & REVEALING MODULE

//IIFE: Immediately invoked Function Expression

(function() { // scope}());

// Revealing Module Pattern

var myApp.utils.geo = (function() { //private var x = 0, y = 0, set = function(coordx,coordy) { x = coordx; y = coordy; }; // public return { setCoords: set };}());

myApp.utils.geo.setCoords(10,10);

REQUIRE.JSHTTP://REQUIREJS.ORG/

// File Name: utils/geo.js // per convenzione , il nome del modulo è quello del filedefine( [ "underscore", "jquery" ], // dipendenze function( _, $ ) { /* Callback : i parametri corrispondono alle dipendenze richieste */ . . . // public return { setCoords: set };});

require( [ "utils/geo" ], function( geo ) { geo.setCoords(10,10); });

<script src="./libs/require.min.js" data-main="./js/main"></script>

/* main.js */ require.config({ paths: { "jquery": "../libs/jquery.min", "underscore": "../libs/underscore.min" }, shim: { // Underscore.js non è un modulo AMD underscore: { exports: "_" } }});

L'IMPORTANZA DEL DIALOGO

$('div#coords li').each(function(el) { var $el = $(el); $el.on('click', function(e) { var jsonUrl = "myData.jsp?id=" + $el.attr("id"); $.get(jsonUrl, function(data) { $(el).text(data.result); }) });});

MEDIATOR

var myApp = {};

myApp.mediator = $({});

myApp.mediator.on("myApp:loadData", function(e,id) { var jsonUrl = "myData.jsp?id=" + id; $.get(jsonUrl, function(data) { myApp.mediator.trigger('myApp:dataLoaded', data, id); }) })

myApp.mediator.on("myApp:dataLoaded", function(e, data, id) { $('div#coords').find('li[id="' + id+ '"]'.text(data.result); })

$('div#coords li').on("click", function(e) { myApp.mediator.trigger('myApp:loadData',$(e.currentTarget).attr("id")); })

DIVIDIAMOCI I COMPITI

[ { "id":"1", "title":"Code Complete", "author":"Steve McConnell" }, { "id":"2", "title":"JavaScript: The Good Parts", "author":"Douglas Crockford" }, { "id":"3", "title":"The Mythical Man-Month", "author":"Fred Brooks" }]

TEMPLATE

UNDERSCORE.JSHTTP://UNDERSCOREJS.ORG/

// Template<script id="tmpl-books" type="text/template">

</script>

<ul> <% for (var i = 0; i < books.length; i++) { %> <% var book = books[i]; %> <li> <em><%= book.title %></em> di <%= book.author %> </li> <% } %> </ul>

var tmplMarkup = $('#tmpl-books').html();

var compiledTmpl = _.template(tmplMarkup, { books : data });

$('#target').html(compiledTmpl);

<ul> <li><em>Code Complete</em> di Steve McConnell</li> <li><em>JavaScript: The Good Parts</em> di Douglas Crockford</li> <li><em>The Mythical Man-Month</em> di Fred Brooks</li></ul>

MVC ED I SUOI FRATELLI

MODEL : Rappresenta i dati e la logica utile per recuperarlie manipolarli

VIEW : Visualizza i dati e interagisce con il fruitore

CONTROLLER : Riceve i comandi del fruitore e li attuamodificando lo stato degli altri due componenti

BACKBONE.JSHTTP://BACKBONEJS.ORG/

JSON

[ { "id":"1", "title":"Code Complete", "author":"Steve McConnell" }, { "id":"2", "title":"JavaScript: The Good Parts", "author":"Douglas Crockford" }, { "id":"3", "title":"The Mythical Man-Month", "author":"Fred Brooks" }]

MODEL

myLib.models.libro = Backbone.Model.extend({ defaults: { id: _.uniqueId(), title: null, author: null }});

COLLECTION

myLib.collections.libri = Backbone.Collection.extend({ url: myLib.settings.urls.services.libri , model: myLib.models.libro, , sortField: 'id' // default , comparator: function(item) { return item.get(this.sortField); } , sortByField: function(fieldName) { this.sortField = fieldName; this.sort(); } });

"VIEW"

myLib.views.libri = Backbone.View.extend({ template: myLib.templates.libri,

initialize: function() { var _this = this; _.bindAll( _this, "render" , "openBook"); this.listenTo(this.collection,"sort",this.render); }, events: { "click .libro": 'openBook' } , render: function() { var html = this.template({ books: this.collection.toJSON() }); this.$el.find( ".main" ).html( html ); }, openBook: function(e) { document.location.href="#libro:" + $(e.currentTarget()).attr("data-id"); } });

TEMPLATE

myLib.templates.libri = _.template([ '<ul>', '<% for (var i = 0; i < books.length; i++) { %>', '<% var book = books[i]; %>', '<li>', '<em><a href="myPage?id=<%= book.id %>" class="roll"><span data-title="', '<%= book.title %>">', '<%= book.title %></span></a></em>', ' di <%= book.author %>', '</li>', '<% } %>', '</ul>'].join(''));

"CONTROLLER"

myLib.modules.libri = function(ns){ var _main = function(opts) { var membri = new ns.collections.libri(); membri.fetch({success: function(){_render(membri,opts)}}), }; var _render = function(data,opts) { if (options && options.sort) membri.sortByField(options.sort); else membri.sortByField("title"); var libriView = new ns.views.libri({ collection: data, el: $("div.container") }); libriView.render(); }; return { run: function(opts){_main(opts);} }; }(myLib);

ROUTER

myLib.router = Backbone.Router.extend({ routes: { "/libri/sort:p_sort": "showBooks" } , showBooks: function(p_sort) { myLib.modules.libri.run(p_sort); } });

..ANCORA NON M'È CHIARO...

( )http://eloquentjavascript.net/ @marijnjh

( )

http://www.addyosmani.com/resources/essentialjsdesignpatterns/book/@addyosmani

( )

http://addyosmani.github.io/backbone-fundamentals/@addyosmani

THAT'S ALL FOLKS!LO STRETTO DIGITALE - SUMMER TALKS 2013 - #LOSTRETTODIGITALE