Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Code Reusability in Angular

Code Reusability in Angular

The presentation illustrates how we can achieve code reuse through different practices in our AngularJS applications.
In its first chapter it introduce some foundational concepts in the object-oriented programming.
In its second part it illustrates how we can take advantage of the standard JavaScript inheritance patterns in our AngularJS components.
The third part of the presentation, introduces the concept of cross-cutting concerns and how we can modularize them using aspect-oriented programming.

This talk was presented at Angular Berlin.

Minko Gechev

June 10, 2015
Tweet

More Decks by Minko Gechev

Other Decks in Programming

Transcript

  1. Minko Gechev github.com/mgechev twitter.com/mgechev { "job": "Freelancer", "hobbies": [ "open

    source", "blogging", "teaching", "sports" ], "communityEvents": [ "SofiaJS", "BeerJS Sofia" ] }
  2. GRASP • Low Coupling • High Cohesion • Controller •

    Creator • Indirection • Information Expert • Polymorphism • Protected Variations • Pure Fabrication
  3. GRASP • Low Coupling • High Cohesion • Controller •

    Creator • Indirection • Information Expert • Polymorphism • Protected Variations • Pure Fabrication
  4. – Wikipedia “In software engineering, coupling is the manner and

    degree of interdependence between software modules” Coupling
  5. function Parent(age) { this.age = age; } Parent.prototype.getAge = function

    () { return this.age; }; function Child(name, age) { Parent.call(this, age); this.name = name; } Child.prototype = Object.create(Parent.prototype); Child.prototype.getName = function () { return this.name; };
  6. function Parent function Child object object prototype prototype __proto__ __proto__

    new  Child("",  42).getAge(); new  Child("",  42)
  7. new  Child("",  42) function Parent function Child object object prototype

    prototype __proto__ __proto__ new  Child("",  42).getAge();
  8. function Parent function Child object object prototype prototype __proto__ __proto__

    new  Child("",  42) new  Child("",  42).getAge();
  9. function Parent function Child object object prototype prototype __proto__ __proto__

    new  Child("",  42) new  Child("",  42).getAge();
  10. function Parent function Child object object prototype prototype __proto__ __proto__

    new  Child("",  42) new  Child("",  42).getAge(); 42
  11. var Parent = { age: 42, getAge: function () {

    return this.age; } }; var Child = Object.create(Parent); Child.name = 'foobar'; Child.getName = function () { return this.name; };
  12. var myModule = angular.module(...); myModule.directive('directiveName', function factory(injectables) { var directiveDefinitionObject

    = { // ... controller: function($scope, $element, $attrs, $transclude, otherInjectables) { ... }, // ... compile: function compile(tElement, tAttrs, transclude) { return { pre: function preLink(scope, iElement, iAttrs, controller) { ... }, post: function postLink(scope, iElement, iAttrs, controller) { ... } } // or // return function postLink( ... ) { ... } }, // or // link: { // pre: function preLink(scope, iElement, iAttrs, controller) { ... }, // post: function postLink(scope, iElement, iAttrs, controller) { ... } // } // or // link: function postLink( ... ) { ... } }; return directiveDefinitionObject; }); Directive Definition
  13. angular.extend module.controller('ChildCtrl', function ($scope, $controller) { // Initialize the super

    class and extend it. angular.extend(this, $controller('ParentCtrl', { $scope: $scope })); });
  14. Classical Inheritance function BaseCtrl($scope, $location, ...) { $scope.keyupHadler = function

    () { // body... }; $scope.answer = 42; } BaseCtrl.prototype.clickHelper = function () { // body... }; function SectionCtrl($scope, $location) { BaseCtrl.call(this, $scope, $location); $scope.clickHandler = function () { this.clickHelper(); }.bind(this); } SectionCtrl.prototype = Object.create(BaseCtrl.prototype); //Register SectionCtrl as AngularJS controller myModule.controller('SectionCtrl', SectionCtrl);
  15. Classical Inheritance function BaseCtrl($scope, $location, ...) { $scope.keyupHadler = function

    () { // body... }; $scope.answer = 42; } BaseCtrl.prototype.clickHelper = function () { // body... }; function SectionCtrl($scope, $location) { BaseCtrl.call(this, $scope, $location); $scope.clickHandler = function () { this.clickHelper(); }.bind(this); } SectionCtrl.prototype = Object.create(BaseCtrl.prototype); //Register SectionCtrl as AngularJS controller myModule.controller('SectionCtrl', SectionCtrl);
  16. Classical Inheritance function BaseCtrl($scope, $location, ...) { $scope.keyupHadler = function

    () { // body... }; $scope.answer = 42; } BaseCtrl.prototype.clickHelper = function () { // body... }; function SectionCtrl($scope, $location) { BaseCtrl.call(this, $scope, $location); $scope.clickHandler = function () { this.clickHelper(); }.bind(this); } SectionCtrl.prototype = Object.create(BaseCtrl.prototype); //Register SectionCtrl as AngularJS controller myModule.controller('SectionCtrl', SectionCtrl);
  17. Classical Inheritance function BaseCtrl($scope, $location, ...) { $scope.keyupHadler = function

    () { // body... }; $scope.answer = 42; } BaseCtrl.prototype.clickHelper = function () { // body... }; function SectionCtrl($scope, $location) { BaseCtrl.call(this, $scope, $location); $scope.clickHandler = function () { this.clickHelper(); }.bind(this); } SectionCtrl.prototype = Object.create(BaseCtrl.prototype); //Register SectionCtrl as AngularJS controller myModule.controller('SectionCtrl', SectionCtrl);
  18. Controller as Syntax function BaseCtrl($location, ...) { } BaseCtrl.prototype.clickHelper =

    function () { // body... }; function SectionCtrl($location) { BaseCtrl.call(this, $location); } SectionCtrl.prototype = Object.create(BaseCtrl.prototype); SectionCtrl.prototype.clickHandler = function () { this.clickHelper(); // body ... }; //Register SectionCtrl as AngularJS controller myModule.controller('SectionCtrl', SectionCtrl);
  19. Controller as Syntax function BaseCtrl($location, ...) { } BaseCtrl.prototype.clickHelper =

    function () { // body... }; function SectionCtrl($location) { BaseCtrl.call(this, $location); } SectionCtrl.prototype = Object.create(BaseCtrl.prototype); SectionCtrl.prototype.clickHandler = function () { this.clickHelper(); // body ... }; //Register SectionCtrl as AngularJS controller myModule.controller('SectionCtrl', SectionCtrl);
  20. Controller as Syntax function BaseCtrl($location, ...) { } BaseCtrl.prototype.clickHelper =

    function () { // body... }; function SectionCtrl($location) { BaseCtrl.call(this, $location); } SectionCtrl.prototype = Object.create(BaseCtrl.prototype); SectionCtrl.prototype.clickHandler = function () { this.clickHelper(); // body ... }; //Register SectionCtrl as AngularJS controller myModule.controller('SectionCtrl', SectionCtrl);
  21. Controller as Syntax function BaseCtrl($location, ...) { } BaseCtrl.prototype.clickHelper =

    function () { // body... }; function SectionCtrl($location) { BaseCtrl.call(this, $location); } SectionCtrl.prototype = Object.create(BaseCtrl.prototype); SectionCtrl.prototype.clickHandler = function () { this.clickHelper(); // body ... }; //Register SectionCtrl as AngularJS controller myModule.controller('SectionCtrl', SectionCtrl);
  22. Controller as Syntax <section ng-controller="SectionCtrl"> <button ng-click="clickHandler()"> Click me! </button>

    <button ng-click="clickHelper()"> You can click here as well! </button> </section>
  23. module.factory inheritance var Collection = (function () { var totalItems

    = 0; return { add: function (item) { // body }, remove: function (item) { // body } }; }()); var ArticleCollection = Object.create(Collection); ArticleCollection._items = []; module.factory('ArticleCollection', function ($http) { ArticleCollection.fetchAll = function () { $http.get('/articles') .then(function () { // ... }); }; return ArticleCollection; });
  24. module.factory inheritance var Collection = (function () { var totalItems

    = 0; return { add: function (item) { // body }, remove: function (item) { // body } }; }()); var ArticleCollection = Object.create(Collection); ArticleCollection._items = []; module.factory('ArticleCollection', function ($http) { ArticleCollection.fetchAll = function () { $http.get('/articles') .then(function () { // ... }); }; return ArticleCollection; });
  25. module.factory inheritance var Collection = (function () { var totalItems

    = 0; return { add: function (item) { // body }, remove: function (item) { // body } }; }()); var ArticleCollection = Object.create(Collection); ArticleCollection._items = []; module.factory('ArticleCollection', function ($http) { ArticleCollection.fetchAll = function () { $http.get('/articles') .then(function () { // ... }); }; return ArticleCollection; });
  26. module.factory inheritance function CollectionFactory($log) { return { // API };

    } module.factory('Collection', CollectionFactory); function ArticleCollectionFactory(Collection, $http) { var ArticleCollection = Object.create(Collection); ArticleCollection._items = []; ArticleCollection.fetchAll = function () { $http.get('/articles') .then(function () { // ... }); }; return ArticleCollection; } module.factory('ArticleCollection', ArticleCollectionFactory);
  27. module.factory inheritance function CollectionFactory($log) { return { // API };

    } module.factory('Collection', CollectionFactory); function ArticleCollectionFactory(Collection, $http) { var ArticleCollection = Object.create(Collection); ArticleCollection._items = []; ArticleCollection.fetchAll = function () { $http.get('/articles') .then(function () { // ... }); }; return ArticleCollection; } module.factory('ArticleCollection', ArticleCollectionFactory);
  28. module.factory inheritance function CollectionFactory($log) { return { // API };

    } module.factory('Collection', CollectionFactory); function ArticleCollectionFactory(Collection, $http) { var ArticleCollection = Object.create(Collection); ArticleCollection._items = []; ArticleCollection.fetchAll = function () { $http.get('/articles') .then(function () { // ... }); }; return ArticleCollection; } module.factory('ArticleCollection', ArticleCollectionFactory);
  29. module.factory inheritance function CollectionFactory($log) { return { // API };

    } function ArticleCollectionFactory($injector, $http) { var Collection = $injector.invoke(CollectionFactory); var ArticleCollection = Object.create(Collection); ArticleCollection._items = []; ArticleCollection.fetchAll = function () { $http.get('/articles') .then(function () { // ... }); }; return ArticleCollection; } module.factory('ArticleCollection', ArticleCollectionFactory);
  30. module.factory inheritance function CollectionFactory($log) { return { // API };

    } function ArticleCollectionFactory($injector, $http) { var Collection = $injector.invoke(CollectionFactory); var ArticleCollection = Object.create(Collection); ArticleCollection._items = []; ArticleCollection.fetchAll = function () { $http.get('/articles') .then(function () { // ... }); }; return ArticleCollection; } module.factory('ArticleCollection', ArticleCollectionFactory);
  31. module.service inheritance function Media($http) { // ... } Media.prototype.fetch =

    function () { // ... }; Media.$inject = ['$http']; function Video($http, CODECS) { Media.call(this, $http); } Video.prototype = Object.create(Media.prototype); Video.prototype.getScreenshot = function (time) { // ... }; Video.$inject = ['$http', 'CODECS']; angular.module('demo').service('Media', Media); angular.module('demo').service('Video', Video); angular.module('demo').value('CODECS', […]);
  32. module.service inheritance function Media($http) { // ... } Media.prototype.fetch =

    function () { // ... }; Media.$inject = ['$http']; function Video($http, CODECS) { Media.call(this, $http); } Video.prototype = Object.create(Media.prototype); Video.prototype.getScreenshot = function (time) { // ... }; Video.$inject = ['$http', 'CODECS']; angular.module('demo').service('Media', Media); angular.module('demo').service('Video', Video); angular.module('demo').value('CODECS', […]);
  33. module.service inheritance function Media($http) { // ... } Media.prototype.fetch =

    function () { // ... }; Media.$inject = ['$http']; function Video($http, CODECS) { Media.call(this, $http); } Video.prototype = Object.create(Media.prototype); Video.prototype.getScreenshot = function (time) { // ... }; Video.$inject = ['$http', 'CODECS']; angular.module('demo').service('Media', Media); angular.module('demo').service('Video', Video); angular.module('demo').value('CODECS', […]);
  34. module.service inheritance function Media($http) { // ... } Media.prototype.fetch =

    function () { // ... }; Media.$inject = ['$http']; function Video($http, CODECS) { Media.call(this, $http); } Video.prototype = Object.create(Media.prototype); Video.prototype.getScreenshot = function (time) { // ... }; Video.$inject = ['$http', 'CODECS']; angular.module('demo').service('Media', Media); angular.module('demo').service('Video', Video); angular.module('demo').value('CODECS', […]);
  35. module.service inheritance function Media($http) { // ... } Media.prototype.fetch =

    function () { // ... }; Media.$inject = ['$http']; function Video($http, CODECS) { Media.call(this, $http); } Video.prototype = Object.create(Media.prototype); Video.prototype.getScreenshot = function (time) { // ... }; Video.$inject = ['$http', 'CODECS']; angular.module('demo').service('Media', Media); angular.module('demo').service('Video', Video); angular.module('demo').value('CODECS', […]);
  36. Logging module.factory('ArticleCollection', function ($log, $resource) { return { getArticle: function

    (id) { $log.log('getArticle called with', arguments); try { // body... } catch (e) { $log.error('getArticle threw an error', e); } finally { $log.log('getArticle execution completed'); } }, getArticles: function () {}, removeArticle: function (id) {}, updateArticle: function (id, article) {} }; });
  37. Logging module.factory('ArticleCollection', function ($log, $resource) { return { getArticle: function

    (id) { $log.log('getArticle called with', arguments); try { // body... } catch (e) { $log.error('getArticle threw an error', e); } finally { $log.log('getArticle execution completed'); } }, getArticles: function () { $log.log('getArticles called with', arguments); try { // body... } catch (e) { $log.error('getArticles threw an error', e); } finally { $log.log('getArticles execution completed'); } }, removeArticle: function (id) { $log.log('removeArticle called with', arguments); try { // body... } catch (e) { $log.error('removeArticle threw an error', e); } finally { $log.log('removeArticle execution completed'); } }, updateArticle: function (id, article) { $log.log('updateArticle called with', arguments); try { // body... } catch (e) { $log.error('updateArticle threw an error', e); } finally { $log.log('updateArticle execution completed'); } } }; });
  38. Logging & Authorization module.factory('ArticleCollection', function ($log, $resource, Authorization) { return

    { getArticle: function (id) { $log.log('getArticle called with', arguments); try { Authorization.authorize(); // body... } catch (e) { $log.error('getArticle threw an error', e); } finally { $log.log('getArticle execution completed'); } }, getArticles: function () { $log.log('getArticles called with', arguments); try { Authorization.authorize(); // body... } catch (e) { $log.error('getArticles threw an error', e); } finally { $log.log('getArticles execution completed'); } }, removeArticle: function (id) { $log.log('removeArticle called with', arguments); try { Authorization.authorize(); // body... } catch (e) { $log.error('removeArticle threw an error', e); } finally { $log.log('removeArticle execution completed'); } }, updateArticle: function (id, article) { $log.log('updateArticle called with', arguments); try { Authorization.authorize(); // body... } catch (e) { $log.error('updateArticle threw an error', e); } finally { $log.log('updateArticle execution completed'); } } }; });
  39. Logging & Authorization module.factory('ArticleCollection', function ($log, $resource, Authorization) { return

    { getArticle: function (id) { $log.log('getArticle called with', arguments); try { Authorization.authorize(); // body... } catch (e) { $log.error('getArticle threw an error', e); } finally { $log.log('getArticle execution completed'); } }, getArticles: function () { $log.log('getArticles called with', arguments); try { Authorization.authorize(); // body... } catch (e) { $log.error('getArticles threw an error', e); } finally { $log.log('getArticles execution completed'); } }, removeArticle: function (id) { $log.log('removeArticle called with', arguments); try { Authorization.authorize(); // body... } catch (e) { $log.error('removeArticle threw an error', e); } finally { $log.log('removeArticle execution completed'); } }, updateArticle: function (id, article) { $log.log('updateArticle called with', arguments); try { Authorization.authorize(); // body... } catch (e) { $log.error('updateArticle threw an error', e); } finally { $log.log('updateArticle execution completed'); } } }; });
  40. Logging & Authorization module.factory('ArticleCollection', function ($log, $resource, Authorization) { return

    { getArticle: function (id) { $log.log('getArticle called with', arguments); try { Authorization.authorize(); // body... } catch (e) { $log.error('getArticle threw an error', e); } finally { $log.log('getArticle execution completed'); } }, getArticles: function () { $log.log('getArticles called with', arguments); try { Authorization.authorize(); // body... } catch (e) { $log.error('getArticles threw an error', e); } finally { $log.log('getArticles execution completed'); } }, removeArticle: function (id) { $log.log('removeArticle called with', arguments); try { Authorization.authorize(); // body... } catch (e) { $log.error('removeArticle threw an error', e); } finally { $log.log('removeArticle execution completed'); } }, updateArticle: function (id, article) { $log.log('updateArticle called with', arguments); try { Authorization.authorize(); // body... } catch (e) { $log.error('updateArticle threw an error', e); } finally { $log.log('updateArticle execution completed'); } } }; });
  41. Logging & Authorization module.factory('ArticleCollection', function ($log, $resource, Authorization) { return

    { getArticle: function (id) { $log.log('getArticle called with', arguments); try { Authorization.authorize(); // body... } catch (e) { $log.error('getArticle threw an error', e); } finally { $log.log('getArticle execution completed'); } }, getArticles: function () { $log.log('getArticles called with', arguments); try { Authorization.authorize(); // body... } catch (e) { $log.error('getArticles threw an error', e); } finally { $log.log('getArticles execution completed'); } }, removeArticle: function (id) { $log.log('removeArticle called with', arguments); try { Authorization.authorize(); // body... } catch (e) { $log.error('removeArticle threw an error', e); } finally { $log.log('removeArticle execution completed'); } }, updateArticle: function (id, article) { $log.log('updateArticle called with', arguments); try { Authorization.authorize(); // body... } catch (e) { $log.error('updateArticle threw an error', e); } finally { $log.log('updateArticle execution completed'); } } }; });
  42. Logging & Authorization module.factory('ArticleCollection', function ($log, $resource, Authorization) { return

    { getArticle: function (id) { $log.log('getArticle called with', arguments); try { Authorization.authorize(); // body... } catch (e) { $log.error('getArticle threw an error', e); } finally { $log.log('getArticle execution completed'); } }, getArticles: function () { $log.log('getArticles called with', arguments); try { Authorization.authorize(); // body... } catch (e) { $log.error('getArticles threw an error', e); } finally { $log.log('getArticles execution completed'); } }, removeArticle: function (id) { $log.log('removeArticle called with', arguments); try { Authorization.authorize(); // body... } catch (e) { $log.error('removeArticle threw an error', e); } finally { $log.log('removeArticle execution completed'); } }, updateArticle: function (id, article) { $log.log('updateArticle called with', arguments); try { Authorization.authorize(); // body... } catch (e) { $log.error('updateArticle threw an error', e); } finally { $log.log('updateArticle execution completed'); } } }; });
  43. cross-cutting concerns module.factory('ArticleCollection', function ($resource) { return { getArticle: function

    (id) { // body... }, getArticles: function () { // body... }, removeArticle: function (id) { // body... }, updateArticle: function (id, article) { // body... } }; });
  44. Aspect definition module.config(function ($provide, executeProvider) { executeProvider.annotate($provide, { ArticleCollection: [{

    jointPoint: executeProvider.AROUND, advice: 'aroundLogger', methodPattern: /.*/ }, { jointPoint: executeProvider.ON_THROW, advice: 'onThowAdvice', methodPattern: /.*/ }] }); });
  45. module.config(function ($provide, executeProvider) { executeProvider.annotate($provide, { ArticleCollection: [{ jointPoint: executeProvider.AROUND,

    advice: 'aroundLogger', methodPattern: /.*/ }, { jointPoint: executeProvider.ON_THROW, advice: 'onThowAdvice', methodPattern: /.*/ }] }); }); Aspect definition
  46. module.config(function ($provide, executeProvider) { executeProvider.annotate($provide, { ArticleCollection: [{ jointPoint: executeProvider.AROUND,

    advice: 'aroundLogger', methodPattern: /.*/ }, { jointPoint: executeProvider.ON_THROW, advice: 'onThowAdvice', methodPattern: /.*/ }] }); }); Aspect definition
  47. module.config(function ($provide, executeProvider) { executeProvider.annotate($provide, { ArticleCollection: [{ jointPoint: executeProvider.AROUND,

    advice: 'aroundLogger', methodPattern: /.*/ }, { jointPoint: executeProvider.ON_THROW, advice: 'onThowAdvice', methodPattern: /.*/ }] }); }); Aspect definition
  48. module.config(function ($provide, executeProvider) { executeProvider.annotate($provide, { ArticleCollection: [{ jointPoint: executeProvider.AROUND,

    advice: 'aroundLogger', methodPattern: /.*/ }, { jointPoint: executeProvider.ON_THROW, advice: 'onThowAdvice', methodPattern: /.*/ }] }); }); Aspect definition
  49. – Wikipedia “In computing, aspect-oriented programming (AOP) is a patented

    programming paradigm that aims to increase modularity by allowing the separation of cross-cutting concerns.”
  50. – Wikipedia “In computing, aspect-oriented programming (AOP) is a patented

    programming paradigm that aims to increase modularity by allowing the separation of cross-cutting concerns.”
  51. Logging & Authorization module.factory('ArticleCollection', function ($log, $resource, Authorization) { return

    { getArticle: function (id) { $log.log('getArticle called with', arguments); try { Authorization.authorize(); // body... } catch (e) { $log.error('getArticle threw an error', e); } finally { $log.log('getArticle execution completed'); } }, getArticles: function () { $log.log('getArticles called with', arguments); try { Authorization.authorize(); // body... } catch (e) { $log.error('getArticles threw an error', e); } finally { $log.log('getArticles execution completed'); } }, removeArticle: function (id) { $log.log('removeArticle called with', arguments); try { Authorization.authorize(); // body... } catch (e) { $log.error('removeArticle threw an error', e); } finally { $log.log('removeArticle execution completed'); } }, updateArticle: function (id, article) { $log.log('updateArticle called with', arguments); try { Authorization.authorize(); // body... } catch (e) { $log.error('updateArticle threw an error', e); } finally { $log.log('updateArticle execution completed'); } } }; });
  52. export default class ArticleCollection { getArticle(id) { logger.log('getArticle called with',

    arguments); try { Authorization.authorize(); // body... } catch (e) { logger.error('getArticle threw an error', e); } finally { logger.log('getArticle execution completed'); } } getArticles() { logger.log('getArticles called with', arguments); try { Authorization.authorize(); // body... } catch (e) { logger.error('getArticles threw an error', e); } finally { logger.log('getArticles execution completed'); } } removeArticle(id) { logger.log('removeArticle called with', arguments); try { Authorization.authorize(); // body... } catch (e) { logger.error('removeArticle threw an error', e); } finally { logger.log('removeArticle execution completed'); } } updateArticle(id, article) { logger.log('updateArticle called with', arguments); try { Authorization.authorize(); // body... } catch (e) { logger.error('updateArticle threw an error', e); } finally { logger.log('updateArticle execution completed'); } } }
  53. @Wove export default class ArticleCollection { getArticle(id) { logger.log('getArticle called

    with', arguments); try { Authorization.authorize(); // body... } catch (e) { logger.error('getArticle threw an error', e); } finally { logger.log('getArticle execution completed'); } } getArticles() { logger.log('getArticles called with', arguments); try { Authorization.authorize(); // body... } catch (e) { logger.error('getArticles threw an error', e); } finally { logger.log('getArticles execution completed'); } } removeArticle(id) { logger.log('removeArticle called with', arguments); try { Authorization.authorize(); // body... } catch (e) { logger.error('removeArticle threw an error', e); } finally { logger.log('removeArticle execution completed'); } } updateArticle(id, article) { logger.log('updateArticle called with', arguments); try { Authorization.authorize(); // body... } catch (e) { logger.error('updateArticle threw an error', e); } finally { logger.log('updateArticle execution completed'); } } }
  54. Angular 2 Service @Wove export default class ArticleCollection { getArticle(id)

    { // body... } getArticles() { // body... } removeArticle(id) { // body... } updateArticle(id, article) { // body... } }
  55. Angular 2 Service @Wove export default class ArticleCollection { getArticle(id)

    { // body... } getArticles() { // body... } removeArticle(id) { // body... } updateArticle(id, article) { // body... } }
  56. AOP.js Aspect @Aspect class LoggingAspect { @Before(/.*/, /.*/) before(args) {

    console.log(`${args.name} called with ${args.args}`); } @After(/.*/, /.*/) after(args) { console.log(`${args.name} execution completed`); } @OnThow(/.*/, /.*/) errorHandler(args) { console.error(`${args.name} threw an error`, args.error); } }
  57. AOP.js Aspect @Aspect class LoggingAspect { @Before(/.*/, /.*/) before(args) {

    console.log(`${args.name} called with ${args.args}`); } @After(/.*/, /.*/) after(args) { console.log(`${args.name} execution completed`); } @OnThow(/.*/, /.*/) errorHandler(args) { console.error(`${args.name} threw an error`, args.error); } }
  58. AOP.js Aspect @Aspect class LoggingAspect { @Before(/.*/, /.*/) before(args) {

    console.log(`${args.name} called with ${args.args}`); } @After(/.*/, /.*/) after(args) { console.log(`${args.name} execution completed`); } @OnThow(/.*/, /.*/) errorHandler(args) { console.error(`${args.name} threw an error`, args.error); } }
  59. AOP.js Aspect @Aspect class LoggingAspect { @Before(/.*/, /.*/) before(args) {

    console.log(`${args.name} called with ${args.args}`); } @After(/.*/, /.*/) after(args) { console.log(`${args.name} execution completed`); } @OnThow(/.*/, /.*/) errorHandler(args) { console.error(`${args.name} threw an error`, args.error); } }
  60. References • AngularJS Inheritance Patterns • Aspect-Oriented Programming • Aspect-Oriented

    Programming in AngularJS • SOLID • GRASP • aop.js • ECMAScript 7 Decorators • Object-Oriented Analysis and Design