El enfoque adecuado
#LaunchpadBCN
Diciembre 2014
Gonzalo Ruiz de Villa Suárez
CoFounder @adesis
Google Developer Expert in Angular
+GonzaloRuizdeVilla
@gruizdevilla
Dirigir la atención o el interés hacia un asunto o problema desde unos supuestos previos, para tratar de resolverlo acertadamente.
Porque queremos utilizar el enfoque adecuado para resolver cada problema.
Reduce la distracción, centrando tu atención en elementos concretos.
Testing unitario
Testing e2e
Inyección de dependencias
Automatización
Estructura del proyecto
Módulos y bower
Encontrando el enfoque adecuado:
La importancia del primer test.
beforeEach(inject(function($filter) {
items = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'];
str = "tuvwxyz";
number = 100.045;
limitTo = $filter('limitTo');
}));
it('should return the first X items when X is positive', function() {
expect(limitTo(items, 3)).toEqual(['a', 'b', 'c']);
expect(limitTo(items, '3')).toEqual(['a', 'b', 'c']);
expect(limitTo(str, 3)).toEqual("tuv");
expect(limitTo(str, '3')).toEqual("tuv");
expect(limitTo(number, 3)).toEqual("100");
expect(limitTo(number, '3')).toEqual("100");
});
it('should filter results', function() {
element(by.model('user')).sendKeys('jacksparrow');
element(by.css(':button')).click();
expect(element.all(by.repeater('task in tasks')).count()).toEqual(10);
element(by.model('filterText')).sendKeys('groceries');
expect(element.all(by.repeater('task in tasks')).count()).toEqual(1);
});
module.controller("MyController", function ($scope, myService){
myService
.doSomething()
.then(function (value){
$scope.value = value;
});
});
var FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m;
var FN_ARG_SPLIT = /,/;
fn.toString()
.match(FN_ARGS)
.split(FN_ARG_SPLIT)
someModule.controller('MyController', ['$scope', 'greeter', function($scope, myService) {
// ...
}]);
Notación de array
Anotación mediante propiedad $inject
var MyController = function($scope, myService) {
// ...
}
MyController.$inject = ['$scope', 'myService'];
someModule.controller('MyController', MyController);
Porque lo repetitivo distrae y nos hace perder el foco.
Broccoli
gulp.js
Grunt
* "Puff, estoy hasta arriba, ya lo haré cuando termine esta entrega"
No te obsesiones con automatizar todo al principio y después tampoco seas "vago"* para automatizar lo que te haga perder tiempo.
y simplifica la automatización, refactorización, el rediseño, etc.
Se me olvida configurar y se me olvida lo configurado...
...y lo prefiero así.
https://github.com/angular/angular-seed
Cada vez van a ser más "opinionated" sobre la estructura del código.
Una convención bien seguida se cambia muy rápido.
La mezcla de convenciones no es una convención.
Gestiona las partes independientes de forma independiente.
Utiliza repositorios independientes para cada parte.
angular.module('myApp', ['miModule1', 'miModule2', 'miModule3'])
https://github.com/ck86/main-bower-files
Todo lo anterior multiplica la potencia de
Separación de responsabilidades.
.signup(ng-controller="SignupCtrl")
form(name="signupForm" ng-show="state = 'START'")
h1 Sign up
label User
input(ng-model="signup.user", required)
label Name
input(ng-model="signup.name", required)
button(
ng-disabled="signup_form.$invalid",
ng-click="createAccount()") Create account
div(ng-show="state == 'LOADING'") Creating account
div(ng-show="estado == 'CREATED'") Account {{signup.user}} created!
module.controller('SignupCtrl', function ($scope, signupService){
$scope.state = "START";
$scope.createAccount = function(){
$scope.state = "LOADING";
signupService.signup($scope.signup).then(function(){
$scope.state = "CREATED";
});
}
});
Encapsulando la lógica de negocio.
module.service('matrixSrv', function () {
this.transpose = function (matrix) {
return matrix[0].map(function(col, i) {
return matrix.map(function(row) {
return row[i]
});
});
};
});
module.service('signupService', function ($http){
this.singup = function (data) {
return $http.post('/api/signup', data);
};
});
pie-chart(data="populations")
Al adaptarnos a la filosofía AngularJS, seguimos manteniendo el foco sobre cada elemento.
ngModule.directive('usernameAvailable', function(signupService) {
return {
require : 'ngModel',
link : function($scope, element, attrs, ngModel) {
ngModel.$asyncValidators.usernameAvailable = signupService.usernameAvailable;
};
}
}
});
input(ng-model="signup.user", required, username-available)
Las directivas permiten definir el comportamiento de un nuevo elemento. Aumentamos la semántica.
Las directivas permiten decorar elementos y hacer composición de funcionalidad de forma transversal.
ul
li(ng-repeat="lineas in pedido.lineas | reverse")
.description {{linea.description}}
.ammount {{ pedido.ammount | ammount }}
p Total ammount: {{ pedido.ammount | ammount }}
Centraliza la definición de transformaciones de salida habituales. Los filtros no modifican el modelo.
module.filter('ammount', function() {
return function(ammount) {
return ammount.currencyCode + ' ' + ammount.quantity
})
})