AMD, BDD, e o Javali

Preview:

DESCRIPTION

Saiba como manter seu JavaScript modular, testado e automatizado, utilizando algumas ferramentas como: RequireJS, Mocha e GruntJS. - Rupy Brazil 2013

Citation preview

AMD, BDD e o Javali

"PROGRAMMING IS ACRAFT NOT SCIENCE OR

ENGINEERING"John Graham Cumming

É uma combinação de habilidades e experiência expressada pormeio de ferramentas, o artersão escolhe suas ferramentas

específicas e aprende a usá-las para criar sua arte.

GIVEN THAT IT'S A CRAFT THEN IT'S NOT HARD TO SEE THAT:experience matterstools matterintuition matters

AMDAsynchronous Module Definition!

REQUIRE JS

O RequireJS surgiu em setembro de 2009, com a proposta de serum carregador de módulos para javascript.

Hoje ele gerencia as dependências do seu programa

O PROBLEMA: ESCREVER CÓDIGO MODULAR.

MODULARIZAÇÃO VS ACOPLAMENTOAcoplamento:

Gera dependênciaDificulta o crescimento

Não simpatiza com TDD|BDDDificulta entendimento do código

Impossibilita reutilizaçãoGera propagação de mudanças

MODULARIZAÇÃO VS ACOPLAMENTOModularização:

Menos dependênciasFácil evolução

Facilidade na hora de testarSimples de ler

Facilidade de reutilizaçãoLiberdade para alterações

ENTÃO EU SÓ CONSIGO ESCREVER JAVASCRIPT MODULAR SEEU USAR UMA BIBLIOTECA? NÃO!

ENTÃO PORQUE REQUIREJS?

AMD IS NOT THEANSWER

Tom Dale

Many HTTP Requests!Too Much CeremonyThe alternative!

PLEASE, SHOW ME THE CODE!

define(['jquery'], function ($) { function PhotoGallery () { this.thumbs = $('.gallery-thumb'); this.highlights = $('.gallery-highlight'); this.activePhoto = $('.gallery-highlight.on'); this.thumbs.on('mouseenter', $.proxy(this.onThumbHover, this)); } PhotoGallery.prototype.onThumbHover = function (ev) { var $currentTarget = $(ev.currentTarget), index = $currentTarget.attr('data-index'); this.activePhoto.removeClass('on'); this.activePhoto = $(this.highlights[index]); this.activePhoto.addClass('on'); } return PhotoGallery; });

define([ 'jquery'], function ($) { 'use strict'; $.fn.expandContent = function () { this.each(function(key, element){ var $element = $(element), content, styleClass; $element.click(function(event){ event.preventDefault(); content = $element.attr('data-content'); $element.removeClass('clickable'); var $content = $(content); $content.show(); })

}) }});

require.config({ baseUrl: "scripts/" shim: { "backbone": { deps: ["underscore", "jquery"], exports: "Backbone" } }, paths: { "mout": "../vendor/mout/src", "text": "../vendor/requirejs-text/text", "hbars": "../vendor/requirejs-handlebars/hbars", "jquery": "../vendor/jquery/jquery", "facebook": "https://connect.facebook.net/pt_BR/all", "leaflet": "http://cdn.leafletjs.com/leaflet-0.6.4/leaflet" }});

define([ 'hbars!securityBundle/templates/user/card', 'jquery'], function (template, $) { 'use strict'; return function (container, user, player) { var $container = $(container); Handlebars.registerHelper( 'getPlayerPointsPercent', $.proxy(player.getPointsPercent, player) ); Handlebars.registerHelper( 'getUserFirstName', $.proxy(user.getFirstName, user) ); $container.html( template({ 'user': user, 'player': player }) ); };});

BDDBehavior-driven development

Desenvolvimento orientado ao comportamento

TDDPor onde começar?

O que testar? O que não testar?

BDD!Tests are Specs

O teste pode ser a sua documentação.A palavra should te mantém no foco do teste.O nome do teste ajuda quando o teste falha.O should te faz questionar a premissa do teste.Qual a proxima coisa mais importante que o seu sistema nãofaz ainda?

"O BDD EVOLUIU DE PRÁTICA ÁGEIS"Como um [X]Eu quero [Y]Para que [Z]

Dado algum contexto inicial.Quando algum evento ocorrer.Então verificar os resultados.

MOCHA

UM FRAMEWORK DE TESTES JAVASCRIPT (NODE.JS EBROWSER) PARA SIMPLIFICAR TESTES ASSÍNCRONOS

POR ONDE COMEÇAR

Você precisa escolher uma biblioteca de asserts:

should.jsexpect.jschaibetter-assert

Show me the code!describe('Array', function() { describe('#indexOf()', function(){ it('should return -1 when the value is not present', function(){ assert.equal(-1, [1,2,3].indexOf(5)); assert.equal(-1, [1,2,3].indexOf(0)); }) })});

require([ 'modules/photo-gallery/main'], function (PhotoGallery){ 'use strict'; function createDomScope () { var i = 0, l = 5, dl, dt, dd; dl = document.createElement('dl'); for (i = 0; i < l; i += 1) { var dt = document.createElement('dt'); dt.className += 'gallery-highlight'; if (i == 0) { dt.className += ' on'; } dl.appendChild(dt); } for (i = 0; i < l; i += 1) { var dd = document.createElement('dd'); dd.className += 'gallery-thumb'; dd.setAttribute('data-index', i); dl.appendChild(dd); } return dl; } describe('Photo Gallery', function () { var photoGallery, domScope, testArea, $thumbs, $highlights, $activeHighlight, i, l, dataIndex; before(function () { domScope = createDomScope(); testArea = document.getElementById('testArea'); testArea.appendChild(domScope); photoGallery = new PhotoGallery();

O seu SpecRunner:< body>< link href="../bower_components/mocha/mocha.css" rel="stylesheet" media="screen" />< script src="../bower_components/requirejs/require.js">< script src="../bower_components/mocha/mocha.js">< script src="../bower_components/expect/expect.js">

Rodando seus testes:< script type="text/javascript"> var specs = [ 'specs/module.spec', 'specs/component.spec', 'specs/feature.spec' ]; require.config({ ... }); mocha.setup('bdd'); require( specs, function () { mocha.run() });< /script>< /body>

O RESULTADO NO NAVEGADOR:

O RESULTADO NO TERMINAL:

GRUNTJS

O GRUNT É UM GERENCIADOR DE TAREFAS FRONT-END FEITOEM JAVASCRIPT.

TAREFAS DA ROTINA DO DESENVOLVIMENTO FRONTEND

TestarMinificarConcatenarCompilar...

PORQUE ESCOLHER O GRUNT?A comunidade do grunt é enorme e cresce a cada dia, já são

centenas de plugins do grunt que fazem praticamente tudo quevocê precisa.

npm install -g grunt-cli

sudo npm install -g grunt-cli

INSTALANDO O GRUNTJS

OU

npm init

npm install grunt --save-dev.

Configurando o GruntJS

{ "name": "reveal.js", "version": "2.6.0-dev", "description": "The HTML Presentation Framework", "homepage": "http://lab.hakim.se/reveal-js", "subdomain": "revealjs", "scripts": { "test": "grunt test", "start": "" }, "author": { "name": "Hakim El Hattab", "email": "hakim.elhattab@gmail.com", "web": "http://hakim.se" }, "repository": { "type": "git", "url": "git://github.com/hakimel/reveal.js.git" }, "engines": { "node": "~0.8.0" }, "dependencies": { "socket.io": "~0.9.13" }, "devDependencies": { "grunt-contrib-qunit": "~0.2.2", "grunt-contrib-jshint": "~0.6.4", "grunt": "~0.4.0" }, "licenses": [

O PACKAGE.JSON

module.exports = function (grunt) { 'use strict'; grunt.initConfig({ pkg: grunt.file.readJSON('package.json'), requirejs: grunt.file.readJSON('config/requirejs.json'), compass: grunt.file.readJSON('config/compass.json'), watch: grunt.file.readJSON('config/watch.json'), uglify: grunt.file.readJSON('config/uglify.json'), csslint: grunt.file.readJSON('config/csslint.json'), jshint: grunt.file.readJSON('config/jshint.json'), connect: grunt.file.readJSON('config/connect.json'), mocha: grunt.file.readJSON('config/mocha.json'), shell: grunt.file.readJSON('config/shell.json'), release: grunt.file.readJSON('config/release.json') });

require('matchdep').filter('grunt-*').forEach(grunt.loadNpmTasks);

grunt.registerTask('build', ['compass', 'requirejs']); grunt.registerTask('test', ['mocha']);};

O GRUNTFILE.JS

{ "test": { "src": ["test/SpecRunner.html"], "options": { "run": false, "reporter": "Spec" } }}

GRUNT MOCHA

{ "server": { "options": { "port": 9001, "hostname": "*", "keepalive": true } }}

GRUNT CONNECT

{ "compile" : { "options" : { "baseUrl": "src/js/", "name": "filename", "paths": { "templates": "../templates/", "Handlebars": "../../bower_components/handlebars/handlebars", "text": "../../bower_components/requirejs-text/text", "hbars": "../../bower_components/requirejs-handlebars/hbars" }, "shim": { "Handlebars": { "exports": "Handlebars" }, "jquery": { "exports": "jQuery" } }, "out": "public/js/main.min.js", "optimize": "uglify2" } }}

GRUNT REQUIREJS

"I'M NOT YOUNG ENOUGH TO KNOWEVERYTHING"

John Graham Cumming

RAFAEL LYRAfront end developer at apontador.com

github: twitter: linkedin:

rafaellyra@rafaellyra

br.linkedin.com/in/rafaellyra/