Slide 1

Slide 1 text

Construindo uma arquitetura modularizada com Angular 1

Slide 2

Slide 2 text

Talysson @talyssonoc talyssonoc.github.io Codeminer42

Slide 3

Slide 3 text

Angular O início

Slide 4

Slide 4 text

No content

Slide 5

Slide 5 text

No content

Slide 6

Slide 6 text

No content

Slide 7

Slide 7 text

Angular A verdade

Slide 8

Slide 8 text

Código escrito de maneira incorreta (influenciado até pela documentação) Culpar o framework antes de entender a causa

Slide 9

Slide 9 text

É possível ter uma aplicação Angular organizada e performática?

Slide 10

Slide 10 text

Sim

Slide 11

Slide 11 text

Sim Mas não vem de graça

Slide 12

Slide 12 text

Angular The React right way

Slide 13

Slide 13 text

Arquitetura

Slide 14

Slide 14 text

Arquitetura ➔ Sem $scope; ➔ Baseada em componentes/diretivas; ➔ Roteamento de componentes; ➔ Utilizar JavaScript moderno; ➔ Lógica e fetching em services/factories; ➔ Fluxo único de dados; ➔ Organização por conceitos.

Slide 15

Slide 15 text

Eliminando o $scope ➔ O $scope não deve ser usado como se fosse o controller; ➔ Prejudica o isolamento; ➔ Efeito de mudanças difícil de prever; ➔ Passagem explícita de dados em vez de usar herança de $scope.

Slide 16

Slide 16 text

angular.module('blogApp', []) .controller('BlogCtrl', function($scope, $http) { $http.get('/api/posts') .then(function(posts) { $scope.posts = posts; }); });
  • {{ post.title }}
Antes Eliminando o $scope

Slide 17

Slide 17 text

angular.module('blogApp', []) .controller('BlogCtrl', function($http) { var ctrl = this; $http.get('/api/posts') .then(function(posts) { ctrl.posts = posts; }); });
  • {{ post.title }}
Depois Eliminando o $scope

Slide 18

Slide 18 text

Tudo é um componente ➔ Facilmente reutilizáveis; ➔ Promovem isolamento; ➔ Removem o uso de ng-controller.

Slide 19

Slide 19 text

angular.module('blogApp', []) .controller('BlogCtrl', function($http) { var ctrl = this; $http.get('/api/posts') .then(function(posts) { ctrl.posts = posts; }); });
  • {{ post.title }}
Antes Tudo é um componente

Slide 20

Slide 20 text

Depois Tudo é um componente

Slide 21

Slide 21 text

angular.module('blogApp', []) .directive('postsList', function() { return { restrict: 'E', scope: {}, controllerAs: '$ctrl', controller: function PostsList($http) { var $ctrl = this; $http.get('/api/posts') .then(function(posts) { $ctrl.posts = posts; }); }, template: '...' }; }); angular.module('blogApp', []) .component('postsList', { controller: function PostsList($http) { var $ctrl = this; $http.get('/api/posts') .then(function(posts) { $ctrl.posts = posts; }); }, template: '...' }); < 1.5 1.5+ Tudo é um componente

Slide 22

Slide 22 text

angular.module('blogApp', []) .directive('postTitle', function() { return { restrict: 'E', scope: {}, bindToController: { post: '=' }, controllerAs: '$ctrl', controller: function PostTitle() {}, template: '...' }; }); angular.module('blogApp', []) .component('postTitle', bindings: { post: '=' }, template: '...' }); < 1.5 1.5+ Tudo é um componente

Slide 23

Slide 23 text

Rotas para componentes ➔ Até páginas são componentes; ➔ Centraliza controller e template de rotas; ➔ Melhor manutenibilidade das rotas; ➔ Ajuda a prevenir reuso de controllers; ➔ Utilizar o ui-router.

Slide 24

Slide 24 text

import uiRouter from 'angular-ui-router'; angular.module('blogApp', [uiRouter]) .config(($stateProvider) => { $stateProvider .state('posts', { url: '/posts', controller: 'PostsController', controllerAs: '$ctrl', template: '...' }); }); Antes Rotas para componentes

Slide 25

Slide 25 text

import uiRouter from 'angular-ui-router'; angular.module('blogApp', [uiRouter]) .config(($stateProvider) => { $stateProvider .state('posts', { url: '/posts', template: '' }); }); import uiRouter from 'angular-ui-router'; angular.module('blogApp', [uiRouter]) .config(($stateProvider) => { $stateProvider .state('posts', { url: '/posts', component: 'postsList' }); }); ui-router < 1.0 ui-router 1.0+ Depois Rotas para componentes

Slide 26

Slide 26 text

JavaScript moderno ➔ Classes e métodos em vez de funções e closures; ➔ Arrow-functions em vez de salvar o this em uma variável; ➔ npm em vez de Bower; ➔ Loaders (Webpack) ou transforms (Browserify) em vez de escrever o template em uma string.

Slide 27

Slide 27 text

import template from './postsList.html'; angular.module('blogApp', []) .component('postsList', { controller: class PostsList { constructor($http) { $http.get('/api/posts') .then((posts) => { this.posts = posts; }); } }, template: template }); angular.module('blogApp', []) .component('postsList', { controller: function PostsList($http) { var $ctrl = this; $http.get('/api/posts') .then(function(posts) { $ctrl.posts = posts; }); }, template: '...' }); Antes Depois JavaScript moderno

Slide 28

Slide 28 text

Dados, lógica e regras de negócio ➔ Lógica e consultas isolados em factories; ➔ Criação de models para data-fetching; ➔ Angular Restmod.

Slide 29

Slide 29 text

Dados, lógica e regras de negócio import template from './postsList.html'; angular.module('blogApp', []) .component('postsList', { controller: class PostsList { constructor($http) { $http.get('/api/posts') .then((posts) => { this.posts = posts; }); } }, template: template }); Antes

Slide 30

Slide 30 text

Dados, lógica e regras de negócio import template from './postsList.html'; angular.module('blogApp', []) .component('postsList', { controller: class PostsList { constructor(Post) { Post.findAll() .then((posts) => { this.posts = posts; }); } }, template: template }); angular.module('blogApp') .factory('Post', function($http) { return { findAll() { return $http.get('/api/posts'); } }; }); Depois

Slide 31

Slide 31 text

Dados, lógica e regras de negócio angular.module('blogApp') .factory('Post', function($http) { return { findAll() { return $http.get('/api/posts'); } }; }); angular.module('blogApp') .factory('Post', function($http) { class Post { static findAll() { return $http .get('/api/posts') .then((posts) => { return posts.map((p) => { return new Post(p); }); }); } } return Post; }); Depois Antes

Slide 32

Slide 32 text

Dados, lógica e regras de negócio angular.module('blogApp') .factory('Post', function($http) { class Post { static findAll() { return $http .get('/api/posts') .then((posts) => { return posts.map((p) => { return new Post(p); }); }); } } return Post; }); angular.module('blogApp') .factory('Post', function(restmod) { return restmod.model('/api/posts'); }); Depois Antes Angular Restmod

Slide 33

Slide 33 text

Fluxo único de dados ➔ Melhora a previsibilidade das mudanças; ➔ Favorece imutabilidade; ➔ Maior escalabilidade do front-end; ➔ Fácil de encontrar bugs; ➔ One-way data binding entre componentes; ➔ Data down, callbacks/events up.

Slide 34

Slide 34 text

Fluxo único de dados import template from './postTitle.html' angular.module('blogApp', []) .component('postTitle', bindings: { post: '=' }, controller: class PostTitle { renamePost(name) { this.post.name = name; } }, template: template }); Antes

Slide 35

Slide 35 text

Fluxo único de dados angular.module('blogApp', []) .component('postTitle', bindings: { post: '<', onRenamePost: '&' }, controller: class PostTitle { renamePost(name) { this.onRenamePost({ param1: this.post, param2: name }); } }, template: ... }); Depois

Slide 36

Slide 36 text

Fluxo único de dados
Depois angular.module('blogApp', []) .component('postsList', { controller: class PostsList { constructor(Post) { ... } renamePost(post, name) { this.posts .$find(post.id) .$update({ title: name }); } }, template: ... });

Slide 37

Slide 37 text

Fluxo único de dados ➔ Usar uma modelagem mais robusta em aplicações maiores; ➔ ng-redux; ➔ flux-angular; ➔ Solução própria.

Slide 38

Slide 38 text

Fluxo único de dados angular.module('blogApp', []) .factory('dispatcher', ($rootScope) => { return { on(...args) { $rootScope.$on(...args); }, emit(...args) { $rootScope.$emit(...args); } }; }); Dispatcher próprio

Slide 39

Slide 39 text

Organização por conceitos ➔ A organização tradicional não modulariza corretamente por conceitos; ➔ O codebase não escala bem; ➔ Confusão na hora de decidir onde colocar um certo arquivo.

Slide 40

Slide 40 text

Organização por conceitos /app /components /commentContent /postsList /postTitle /factories /commentsService /notificationsService /models /Comment /Post Antes

Slide 41

Slide 41 text

Organização por conceitos /app /posts /postsList /postsTitle /Post /comments /commentContent /commentsService /Comment /notifications /notificationsService Depois

Slide 42

Slide 42 text

Performance

Slide 43

Slide 43 text

Performance ➔ Diminuir tempo do $digest; ➔ Evitar filtros na view; ➔ Deixar ng-repeat mais rápido; ➔ Remover checagens desnecessárias; ➔ Usar ng-model-options quando possível.

Slide 44

Slide 44 text

Diminuir tempo do $digest ➔ $digest é o loop de checagens de alterações; ➔ Quanto mais rápido, menor o tempo de atualização da view; ➔ Remover reprocessamentos da view.

Slide 45

Slide 45 text

Diminuir tempo do $digest angular.module('blogApp', []) .component('postsList', { controller: class PostsList { constructor(Post) { ... } postsFor(category) { return this.posts .filter((p) => { return p.category === category; }); } } }); Antes

Slide 46

Slide 46 text

Diminuir tempo do $digest angular.module('blogApp', []) .component('postsList', { controller: class PostsList { constructor(Post, category) { this.categoryPosts = this .postsFor(category); } postsFor(category) { return this.posts .filter((p) => { return p.category === category; }); } } }); Depois

Slide 47

Slide 47 text

Evitar filtros na view ➔ Mesmo problema das expressões na view; ➔ Filtro é reprocessado todo $digest; ➔ Mover o uso do filtro para o controller.

Slide 48

Slide 48 text

Evitar filtros na view

{{ $ctrl.post.title }} {{ $ctrl.post.date| date }}

Antes

Slide 49

Slide 49 text

Evitar filtros na view

{{ $ctrl.post.title }} {{ $ctrl.postDate }}

Depois angular.module('blogApp', []) .component('postTitle', bindings: { post: '<' }, controller: class PostTitle { constructor($filter) { const date = $filter('date')(this.post.date); this.postDate = date; } } });

Slide 50

Slide 50 text

ng-repeat mais rápido ➔ Cooperar com a checagem de duplicações do Angular; ➔ Todo item deve ter um identificador único; ➔ Também se aplica ao ng-options.

Slide 51

Slide 51 text

ng-repeat mais rápido
Antes

Slide 52

Slide 52 text

ng-repeat mais rápido
Depois

Slide 53

Slide 53 text

Remover checagens desnecessárias ➔ Remover o dirty-checking de valores que não mudarão; ➔ Diminui a quantidade de verificações do $digest; ➔ Operador de one-time binding; ➔ Pode ser aplicado à qualquer expressão; ➔ Ganho de desempenho porém deve ser pensado onde será usado.

Slide 54

Slide 54 text

Remover checagens desnecessárias

{{ $ctrl.post.title }} {{ $ctrl.postDate }}

Antes

Slide 55

Slide 55 text

Remover checagens desnecessárias

{{:: $ctrl.post.title }} {{:: $ctrl.postDate }}

Depois

Slide 56

Slide 56 text

Remover checagens desnecessárias

{{:: $ctrl.post.title }} {{:: $ctrl.postDate }}

Depois

Slide 57

Slide 57 text

Remover checagens desnecessárias

{{$ctrl.post.title }} {{:: $ctrl.postDate }}

Depois

Slide 58

Slide 58 text

Usar ng-model-options ➔ Nem sempre uma mudança precisa ser checada o tempo todo; ➔ Permite postergar checagem ou checar somente quando certo evento ocorre.

Slide 59

Slide 59 text

Usar ng-model-options Preview:

{{ $ctrl.post.title }}

Antes

Slide 60

Slide 60 text

Usar ng-model-options Preview:

{{ $ctrl.post.title }}

Depois

Slide 61

Slide 61 text

Usar ng-model-options Preview:

{{ $ctrl.post.title }}

Depois

Slide 62

Slide 62 text

Boas práticas

Slide 63

Slide 63 text

Boas práticas ➔ Combinar construtor com $onInit em componentes; ➔ Melhorar expressividade na view; ➔ Favorecer factories à services; ➔ Ferramentas para desenvolvedores; ➔ Siga um styleguide.

Slide 64

Slide 64 text

Combinar construtor com $onInit ➔ Utilizar corretamente o ciclo de vida dos componentes; ➔ $onInit é chamado quando todos os controllers foram instanciados e o bindings feitos; ➔ Usar construtor somente para dependency-injection.

Slide 65

Slide 65 text

Combinar construtor com $onInit angular.module('blogApp', []) .component('postsList', { controller: class PostsList { constructor(Post) { Post.findAll() .then((posts) => { this.posts = posts; }); } }, template: ... }); angular.module('blogApp', []) .component('postsList', { controller: class PostsList { constructor(Post) { this.Post = Post; } $onInit() { this.Post.findAll() .then((posts) => { this.posts = posts; }); } }, template: ... }); Depois Antes

Slide 66

Slide 66 text

Melhorar expressividade da view ➔ Identação do template; ➔ Manter eventos expressos na view em vez de usar função link; ➔ Ordenação de atributos das tags para maior clareza.

Slide 67

Slide 67 text

Melhorar expressividade da view Identação

Slide 68

Slide 68 text

Melhorar expressividade da view Preview:

{{ $ctrl.post.title }}

Evento na view

Slide 69

Slide 69 text

Melhorar expressividade da view
  • {{ ctg.name }}
  • {{ ctg.name }}
Antes Depois Ordem das props

Slide 70

Slide 70 text

➔ Services são apenas wrappers para factories; ➔ Factories são mais versáteis e dão mais liberdade; ➔ É possível fazer tudo que um service faz com uma factory. Substituindo services por factories

Slide 71

Slide 71 text

Substituindo services por factories function service(name, constructor) { return factory(name, [ '$injector', function($injector) { return $injector .instantiate(constructor); } ]); }

Slide 72

Slide 72 text

angular.module('someModule') .service('ThingService', function() { // isso vai ser instanciado // como uma classe // this aponta para a instância }); angular.module('someModule') .factory('Thing', function() { // isso vai ser simplesmente retornado }); Substituindo services por factories

Slide 73

Slide 73 text

➔ AngularJS Batarang; ➔ Angular watchers; ➔ ng-inspector for AngularJS; ➔ Todos são para Google Chrome. Ferramentas para desenvolvedores

Slide 74

Slide 74 text

➔ Styleguide do John Papa está desatualizado; ➔ Prefira o styleguide do Todd Motto. Siga um styleguide

Slide 75

Slide 75 text

No content

Slide 76

Slide 76 text

“ Don’t Rewrite, React! - Ryan Florence

Slide 77

Slide 77 text

Obrigado! Talysson @talyssonoc talyssonoc.github.io

Slide 78

Slide 78 text

Be a miner! [email protected]

Slide 79

Slide 79 text

➔ Angular ui-router ➔ Restmod ➔ Styleguide Todd Motto Links