Nyheder i JavaScript – Frontend-udvikling – AngularJS "to the resque"



Nyheder i JavaScript – Frontend-udvikling – AngularJS "to the resque"

0 0


appacademy_presentation_nyheder_i_javascript_2014

Presentation (revealjs based slideshow) for talk: "Nyheder i JavaScript".

On Github askarby / appacademy_presentation_nyheder_i_javascript_2014

Nyheder i JavaScript

Udvikling i JavaScript på en hensigtsmæssig og tidssvarende måde

Udarbejdet af Anders Bruhn Skarby / @askarby for App Academy

Før vi går i gang

Om mig

Navn Anders Skarby Erfaring 10 års indenfor software og webudvikling Derudover er jeg passioneret programmør Slutteligt er jeg doven og utålmodig (vi vender tilbage til dette)

Aftenens program

Frontend-udvikling med AngularJS Backend-udvikling med Express / NodeJS Udviklingsværktøjer (Gulp og Yeoman)

Fremgangsmåde

En blanding af slide-deck

Live-kodning (tags i git)

Dialog frem og tilbage

Frontend-udvikling

med AngularJS

Hvor vi kradser i overfladen på AngularJS og lærer om de mest basale principper - lige akkurat nok til at komme igang.

En lille test

Hvad gør denne applikation?

HTML burde være nok

<html>
    <head>...</head>
    <body>
        <div id="container1">
            <ul></ul>
            <button id="btn1"><button/>
        </div>
        <div id="container2">
            <input id="inp1"/>
            <textarea id="edt1"><textarea/>
            <button id="btn2"><button/>
        </div>
        ...
    </body>
</html>

Et unfair spørgsmål

... jeg viser ikke hele koden

Det behøver jeg heller ikke

... her er de vigtige dele

<html>
    <head>
        <script src="..." />
        <script>...</script>
        ...
    </head>
    <body>
        <script src="..." />
        <script src="..." />
        <script>...<(script>
        <script>...</script>
        ...
    </body>
</html>

Det er knap så godt

Fordi:

  • Vi har ingen ide om hvad der foregår
  • Koden er baseret på id / class-selectors i .js-filer
  • .js-filerne kan importere andre .js-filer
  • Det er ikke til at vedligeholde

AngularJS "to the resque"

Nyt HTML

<html>
    <head>...</head>
    <body ng-app="notepad" ng-controller="MainCtrl as main">
        <notelist id="container1">
            <ul>
                <li ng-repeat="note in notes">{{note.title}}</li>
            </ul>
            <button id="btn1" ng-click="main.createNewNote()"><button/>
        </notelist>
        <editor id="container2">
            <input id="inp1" ng-model="note.title"/>
            <textarea id="edt1" ng-model="note.content"><textarea/>
            <button id="btn2" ng-click="main.save()">Save note<button/>
        </editor>
        ...
    </body>
</html>

Hvad vi fik var

  • Nye og custom:
    • Elementer
    • Attributter
  • Som resulterer i:
    • Markup der forklarer applikationens opførsel

AngularJS giver os

  • Et MVC framework
  • Databinding
  • Direktiver (Directives)
  • Dependency injection
  • Testbar kode

MVC Framework

  • Vores Model er et JavaScript-objekt
  • Vores Controller er en JavaScript-funktion
  • Vores View er HTML

MVC Framework - Forsat

Controlleren er mest interessant

angular.controller('MainCtrl', function ($scope) {
    $scope.friend = 'Bob';
});

Databinding

En del af HTML

<input type="text" ng-model="friend" />
<div>Vores ven hedder {{friend}}</div>

Direktiver

Element: <spinner /> Attribut: <div content-editable>Data</div> Class: <div class="blink">1994 calling!</div>

Dependency Injection

angular.controller('MainCtrl', function ($scope, StorageService) {
    $scope.friend = 'Bob';
    this.save = function () { StorageService.save($scope.friend); };
});
angular.service('StorageService', function ($http) {
    this.saveFriend = function (friend) {
        // ... Use $http service ...
    };
});

Testbar kode

  • Unit testing - nemt med Dependency Injection
  • Protractor til End-to-End testing
    • WebDriverJS
    • Selenium

Tid til en demo!

Fordi det er begrænset hvor interessante slides er.

Backend-udvikling

med Express og NodeJS

Hvor vi kradser i overfladen på Express og NodeJS, og lærer lige akkurat nok til at skrive en backend til vores frontend.

Hvad er NodeJS

  • Chrome's V8 JavaScript-motor
  • Sammenkoblet med C-libraries

Hvilke fordele er der?

Vi tager dem lige en for en...

Hurtig, event-dreven arkitektur

Ét event-loop, der kører i V8-motoren, som så spørger ud til eksterne C-libraries, får svar igen når event-loopet kører forbi og modulet har et svar klar. → Non-blocking I/O.

Ufattelig hurtigt til I/O - uden at skabe unødvendig load!

Samme sprog på frontend og backend

Man kan som webudvikler ikke udelukke sig selv fra hverken frontend eller backend

  • Ingen skift af kontekst
  • Ingen skel imellem teams
  • Fortolket sprog → Hurtig feedback

Modularitet

Moduler eksporteres med module.exports:

module.exports = function messenger(name) {
    return {
        sayHello: function () {
            console.log('Hello ' + name);
        },
        sayBye: function () {
            console.log('Goodbye ' + name);
        }
    }
};

Modularitet - Import

Som så kan importeres vha. require

var messenger = require('./messenger.js');
messenger('Anders').sayHello();
messenger('Anders').sayBye();

Modularitet - Manifest

En manifest-fil per modul, denne hedder package.json, skrevet i JSON

{ 
  "name" : "some-library",
  "main" : "./lib/some-lib.js" 
}

Modularitet - NPM

  • De facto pakke-manager til node
  • npm install "pakkenavn"
  • npm install "pakkenavn" --save
  • Pakker findes vha. NPM repository www.npmjs.org
  • Mange pakker / libraries

Modularitet - Look-up mekanisme

  • require('util'); Core module
  • require('custom') samme folder (.js, .json, .node)
  • require('./custom.js') filen custom.js i samme folder
  • require('/home/user/module.js') absolut sti

Modularitet - Mere lookup

Hvis ikke argument til require('...') findes i core modules, eller i /, ./ eller ../ - så tjekkes der i parent-folderen (med tilføjet node_modules)

Modularitet - Opsummering

  • Simpel
  • Fleksibel
  • Mange tilgængelige libraries

Hvad er ulemperne?

Dem tager vi også lige, en for en...

Dynamisk programmeringssprog

Hvis du skal bruge etstatisk skrevet sprog til modellering af kompleks forretningslogik, skal du nok lede andetsteds.

Tunge beregninger

  • Arkitekturen målrettet mod at levere effektiv, asynkron I/O, på én enkelt tråd
  • Tråd i en beregning i 10 sekunder → Dårlig performance!
  • Workaround child_proces-modul (fork ny js-script eksekvering)
  • Workaround Web workers (flere implementationer i npm)
  • Bedre løsning Vælg et andet sprog til beregninger, udstil vha. REST og brug disse fra NodeJS

Multi-core CPU D.I.Y.

  • NodeJS kører kun med én enkelt tråd → det skalerer ikke
  • Skalerer ikke til mange requests
  • Manuel proxy / load balancer config foran NodeJS (nginx / Apache httpd)
  • PM2 (process manager for Node, med indbygget load balancer)

Flying wedge anti-pattern

Callback-baserede API'er

function processData(initial) {
    this.outer(initial, function (err, data) {
        // Work with data...
    });
}

Mere anti-pattern

function processData(initial) {
  this.outer(initial, function (err, data1) {
    data1.inner(function (err, data2) {
      data2.nested(function (err, data3) {
        data3.errrmagerd(data2, data3, function (err, data4) {
          // etc.
        });
      });
    });
  });
}

Løsning: Brug promises

Simpel NodeJS webserver

Eksempel taget fra NodeJS' website

var http = require('http');
http.createServer(function (req, res) {
  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.end('Hello World\n');
}).listen(1337, '127.0.0.1');
console.log('Server running at http://127.0.0.1:1337/');

Der er dog et problem

Vi skal selv inspicere req-objektet for informationer om URL, HTTP Method etc, ved bare 2 URL'er bliver det ulæseligt!

Grimmere end grimt

var http = require('http');
http.createServer(function (req, res) {
  if (req.method === 'GET' && req.url === '/') { 
    res.writeHead(200, {'Content-Type': 'text/plain'});
    res.end('Hello World\n');
  } else if (req.method === 'GET' && req.url === '/other') {
    res.writeHead(200, {'Content-Type': 'text/plain'});
    res.end('Hello Universe\n');
  }
}).listen(1337, '127.0.0.1');
console.log('Server running at http://127.0.0.1:1337/');

Løsningen på vores problem

Brug Express frameworket, og lav læsbar kode!

var express = require('express');
var app = express();
app.get('/', function (req, res) {
  res.send('Hello World');
});
app.get('/other', function (req, res) {
  res.send('Hello Universe');
});
var server = app.listen(1337, function () {
  console.log('Example app listening at http:/127.0.0.1:1337/');
});

Flere muligheder

  • Middleware
  • Serve statiske resourcer
  • Templating engines (MVC)

Tid til endnu en demo!

Lad os kode en backend til vores post-it frontend.

Udviklingsværktøjer

om Gulp og Yeoman

Hvor vi lærer at bruge Gulp som et byggeværktøj, da vi ved at vores tid er dyrebar og at automatisering at repetative opgaver er alfa-omega.

Gulp

Der er 2 primære byggeværktøjer i JavaScript

  • Grunt
    • Konfiguration af byggemiljø (brug af plugins)
    • Uoverskueligt (synes jeg)
  • Gulp
    • Koder sit byggemiljø (læsbar scripting + plugins)
    • Overskueligt og fleksibelt (synes jeg)
    • Alt er streams
    • Parallel eksekvering

Gulp - Vores mål

Skal "bygge" vores frontend - "bygge" som i:

  • Kombinere JavaScript filer
  • Obfuskering af JavaScript
  • Minificering af CSS og HTML

Gulp - Eksempel

  • gulpfile.js - eksekveres med kommandoen gulp
  • usemin plugin - parser kommentarer i HTML-filer

Yeoman

"Jeg er doven" - brug Yeoman, sammen med gulp og bower.

npm install -g yo gulp bower
npm install -g generator-gulp-angular
yo gulp-angular
gulp serve

Nyttige links

(opsamlet fra slides i denne præsentation)

Spørgsmål?

Udarbejdet af Anders Bruhn Skarby / @askarby

I samarbejde med App Academy