Arquitecturas Para La Reutilización en JavaScript

43
Javier Vélez Reyes @javiervelezreye www.javiervelezreyes.com Arquitecturas Para La Reu/lización en JavaScript Programación Orientada a Componentes Mayo 2016

Transcript of Arquitecturas Para La Reutilización en JavaScript

JavierVélezReyes@javiervelezreye

www.javiervelezreyes.com

ArquitecturasParaLaReu/lizaciónenJavaScript

ProgramaciónOrientadaaComponentes

Mayo2016

@javiervelezreye2

AutorArquitecturasParaLaReu<lizaciónEnJavaScript

LicenciadoporlaUPMdesdeelaño2001ydoctoreninformá<caporlaUNEDdesdeelaño2009,Javierconjugasuslaborescomoprofesore inves<gador con la consultoría y la formación técnica paraempresa. Su línea de trabajo actual se centra en la innovación ydesarrollodetecnologíasparalaWeb.Ademásrealizaac<vidadesdeevangelización y divulgación en diversas comunidades IT y escoordinadordevariosgruposdeámbitolocalcomoNodeJSMadridoMadridJS.FormapartedelprogramaPolymerPolytechnicSpeakeryesmentordelcapítulodeMadriddeNodeSchool.

SobreMí

[email protected]

@javiervelezreye

linkedin.com/in/javiervelezreyes

gplus.to/javiervelezreyes

jvelez77

javiervelezreyes

youtube.com/user/javiervelezreyes www.javiervelezreyes.com

JavierVélezReyes@javiervelezreye

[email protected]

1Introducción§  QuéeslaReu<lización§  ElFracasodelaReu<lización§  HaciaunaVerdaderaReu<lización§  ArquitecturasparalaReu<lización

Introd

ucción

Arqu

itecturasParaLaReu

/lizaciónEn

JavaScrip

t

@javiervelezreye4

IntroducciónArquitecturasParaLaReu<lizaciónEnJavaScript

Lareu<lizacióndecódigoeselprocesoporelcualla creación de nuevos sistemas se realiza a par<rde artefactos previamente elaborados con elánimo de reducir costes, <empos y esfuerzos dedesarrollo.

Lareu<lizacióncomoahorrodecostesQuéeslaReu<lización

@javiervelezreye5

IntroducciónArquitecturasParaLaReu<lizaciónEnJavaScript

Reu<lizaciónenel<empoyenelespacioQuéeslaReu<lización

Reu<lización

Tiempo

IOS

Web

Java

GWT

Android

Espacio

JS

Se requieren mecanismos deestandarización que alcancen laabstracción necesaria para crearesfuerzos de desarrollo agnósBcosdetecnología

WriteOnceRunEverywhere

Angular

React

Polymer

WriteOnceRunWheneverSerequierencriteriosdediseñoquepermitan construir soEware quesupere los dictámenes de latecnologíaenusooenhype

@javiervelezreye6

IntroducciónArquitecturasParaLaReu<lizaciónEnJavaScript

Lastensionesdelareu<lizaciónElFracasodelaReu<lización

Reu<lización

Abstracción Acoplamiento

Granularidad Cuál debe ser el nivel adecuadodegranularidad en el diseño de cadaartefacto para maximizar susoportunidadesdereuBlización

A qué nivel de abstracción debediseñarse cada artefacto paramaximizarsureuBlización

Cuál debe ser la relación de cadaartefacto con los demás artefactosde la vecindad para maximizar sureuBlización

@javiervelezreye7

IntroducciónArquitecturasParaLaReu<lizaciónEnJavaScript

Lasreu<lizacióndesdelaabstracciónElFracasodelaReu<lización

var filterReduce = function (data, fn, gn, b) { return data .filter (fn) .reduce (gn, b); }; var adults = filterReduce (users, function (user) { return user.age > 18; }, function (user) { return 1; }, 0);

filter

reduce

[...]

d

fn

gn

PF.AbstraccióncentradaenlaTarea

Reu<lizaciónrestringidaatareasSe consigue reuBlizar el esquemaalgorítmico para disBntas tareaspero siempre se aplica sobre losmismosBposdedatos

Vehicle Tester

Car Truck

Tester.check = function (v) { v.start (); assert (v.started, true); v.stop (); assert (v.started, false); };

start () stop ()

check ()

OOP.AbstraccióncentradaendatosReu<lizaciónrestringidaavariantes

Se consigue reuBlizar el esquemadelTestersóloenelmarcodefinidopor los objetos de la jerarquía deherenciaqueparBcipanconéste

Tarea

Datos

PF

OOP

@javiervelezreye8

IntroducciónArquitecturasParaLaReu<lizaciónEnJavaScript

Lasreu<lizacióndesdeelacoplamientoElFracasodelaReu<lización

return data .filter (fn) .fn .reduce (gn, b);

reduce

Acoplamientoadatos

var y = fn(x); return gn(y);

y

y

fn

filter

[...]

[...] fn gn

Acoplamientoa<po Acoplamientoaaridad

hn( gn( fn(x) ) ); 1

fn

gn

hn 1

Acoplamientoa<empo Acoplamientoacardinalidad Acoplamientoavolumen

A B

A

B

b.m(x)

b.send('m', x);

A B

A

B bus

b.m(x)

b.send('m', x);

B B

B B

A B b.m(x,y,z)

A B b.m({ x : x, y : y, z : z })

@javiervelezreye9

IntroducciónArquitecturasParaLaReu<lizaciónEnJavaScript

Lasreu<lizacióndesdelagranularidadElFracasodelaReu<lización

Granu

larid

ad

-+

FeatureOrientedPrograming

ObjectOrientedPrograming

ServiceOrientedProgramingArtefacto

Repository

find () add (e) remove (e)

Servicio

Stack

push() pop()

Objeto

Composición

Delegación

A B

Reu<lización

-+

Orquestación

A B

O

Arquitectura

Capas

Colaboración

A B

C

Contribución

Core

Ext

Identifiable

getId () setId ()

Feature Parciales

Exts

cores

@javiervelezreye10

IntroducciónArquitecturasParaLaReu<lizaciónEnJavaScript

Lareu<lizaciónporDiseñoHaciaunaVerdaderaReu<lización

Tiempo

Requ

isito

s

Reu<lizaciónporrefactorización

Tiempo

Requ

isito

s

Reu<lizaciónpordiseño

ElagilismomalentendidoSedesesBmacualquieracBvidaddeanálisisyencadacadasprintsedasoluciónexactaalasdemandasdelcliente sin atender a los costes delrepivotaje

ElagilismobienentendidoSe dedican esfuerzos de análisisdirigidos a inferir la tendenciaevoluBva del soEware de maneraque pueda orientarse el desarrolloparaminimizarcostesderepivotaje

@javiervelezreye11

IntroducciónArquitecturasParaLaReu<lizaciónEnJavaScript

Arquitecturasclásicasreu<lizables

EnBdadesdeProyecto ContextoArquitectónicodeUso

ProyectoA

ProyectoBReu<lizaciónexternaLa capacidad de reuBlización entreproyectos se ve compromeBda porelconjuntoderequisitosespecíficosimpuestosaniveldecadaproyecto

Reu<lizacióninternaLacapacidaddereuBlizacióninternaen un proyecto se ve limitada a unpequeño conjunto de contextosarquitectónicos de uso donde cadaartefacto se puede usar de formasemánBcamenteequivalente

HaciaunaVerdaderaReu<lización

A B C

D E

A

B

C

D

E A

B

A' F G

@javiervelezreye12

IntroducciónArquitecturasParaLaReu<lizaciónEnJavaScript

usa

Componentes Meta-programas

Proyecto

crea

ProgramaciónOrientadaaComponentesArquitecturasparalaReu<lización

usa

EnBdadesdeProyecto

+

NiveldeProyecto

NiveldeDominioRasgosreu<lizables

Componentescomorasgosparciales que implementarcaracterísBcasreuBlizables

Meta-programas comoesquemas de composiciónreuBlizables de aplicabili-dadrecurrente

Esquemasdecomposición

En<dadesagnós<casEnBdades que capturan elcore del negocio de formaagnósBcaalusode rasgosadiBvos

ProyectogeneradoaparBrde especificaciones dep r o y e c t o y d om i n i oreduciendo esfuerzos dedesarrollo

Códigogenerado

@javiervelezreye13

IntroducciónArquitecturasParaLaReu<lizaciónEnJavaScript

usa

Componentes Meta-programas

ProyectoA

crea

Arquitecturasparalareu<lizaciónenelespacioArquitecturasparalaReu<lización

usa

EnBdadesdeProyecto

+

ProyectoB

NiveldeProyecto

NiveldeDominio

DisBntos proyectos se adaptan alas necesidades de cliente porcomposicióndediferentesrasgosparciales

Ges<óndelaconfiguración

@javiervelezreye14

IntroducciónArquitecturasParaLaReu<lizaciónEnJavaScript

Arquitecturasparalareu<lizaciónenel<empoArquitecturasparalaReu<lización

usa

Componentes Meta-programas

ProyectoA

NiveldeProyecto

NiveldeDominio

usa

EnBdadesdeProyecto

+

ProyectoA'

EjecuciónenelBempo

El sistema reacciona adaptán-dose a las nuevas condicionesambientalesquedetectaencadamomento

Evoluciónadapta<va

@javiervelezreye15

usa

Componentes Meta-programas

Proyecto

creausa

EnBdadesdeProyecto

+

NiveldeProyecto

NiveldeDominio

IntroducciónArquitecturasParaLaReu<lizaciónEnJavaScript

Enlaprác<ca.DesdeFront…

OOPDelegaciónHerencia

Abstracción

PFO.SuperiorClausuras

AdiciónExtensiónIntercesiónDelegación

Composición

ArquitecturasparalaReu<lización

@javiervelezreye16

Isomorfismo

IntroducciónArquitecturasParaLaReu<lizaciónEnJavaScript

Enlaprác<ca.DesdeBack…ArquitecturasparalaReu<lización

Front-end Back-endNegocio Integración

A.Arquitecturasdirigidasporprocesos

Igualmente los datos expuestosen forma de APIWeb se alineande forma isomorfa con lasenBdadesdenegocio

Loscomponentesdefrontofrecen un modelo deinteracciónparaelaccesoa las cadenas de valorofrecidasdesdeelback

El negocio se codifica en forma decomponentes que son proxies de loscomponentes de front y controladores dedatos de acuerdo a una aproximaciónisomorfa

@javiervelezreye17

Isomorfismo

IntroducciónArquitecturasParaLaReu<lizaciónEnJavaScript

Enlaprác<ca.DesdeBack…ArquitecturasparalaReu<lización

Front-end Back-end

B.Arquitecturasdirigidaspordatos

En este caso los componentessubsumen las responsabilidadesde control sobre la arquitecturade datos subyacente y operancomo gateways de datos delnegocio

La API Web expone todas lascapacidades del negocio enformade recursosdedatosparaquepuedanserexploradas

JavierVélezReyes@javiervelezreye

[email protected]

2ArquitecturasParaLaReu/lización§  TécnicasdeComposiciónenJavaScript§  ArquitecturasdeMixins&Traits§  ArquitecturasdeSubjects&Roles§  ArquitecturasdeAspectos&Filtros

Arqu

itecturasParaLaReu

/lización

Arqu

itecturasParaLaReu

/lizaciónEn

JavaScrip

t

@javiervelezreye19

ArquitecturasParaLaReu<lizaciónArquitecturasParaLaReu<lizaciónEnJavaScript

TécnicasdeComposiciónIntroducción

Adición

var core = { x : 1, y : 2, }; core = Object.assign ({}, { p : function () { return this.x; }, q : function () { return this.y; } });

Extensión

class A { p() {...}, q() {...} } class B extends A { m() {...} }

Intercesión

var core = { p: function () {...} }; var fn = core.p; var gn = function () {...}; core.p = function (...args) { gn.apply (this, args); return fn.apply (this, args); };

Early

Binding

LateBinding

Delegación

var core = { d : ext, x : 3, p : function () { return this.x; }, q : function () { return this.d.m(x); } }; var ext = { m: function (n) { return 2*n; }};

var core = { x : 1, p : function () { return this.x; }, }) var ext = { x : 2}; core.p = core.p.bind (ext)

A Bm()

this

@javiervelezreye20

ArquitecturasParaLaReu<lizaciónArquitecturasParaLaReu<lizaciónEnJavaScript

DescripciónGeneralArquitecturasdeMixins

Componente.Mixin

UnMixinesunaabstraccióndedatosparcial reu<lizable que puedecontribuirseacualquierclasebase

state

autonomíaadaptación

abstracción

stateextensibilidadreversibilidad

Core

Arquitectura

Unmodelodeextensionespormixinsmueveunaarquitecturadedatosconagnos<cismo de las en<dades denegociosobrelasqueopereA B

X Y

Losmixinsmuevenlaarquitectura

Abstraccionesdedatosdelnegocio

ReuBlizaciónendisBntosproyectos ProyectoA

ProyectoB

@javiervelezreye21

ArquitecturasParaLaReu<lizaciónArquitecturasParaLaReu<lizaciónEnJavaScript

ImplementaciónI.ComposiciónporAdiciónArquitecturasdeMixins

TécnicadeComposición

La técnica habitual aplica composición adi<vasobre los mixins. Lamentablemente estasoluciónnofuncionaencontextosdeherencia

A

M

state

state

DesdeelCódigo

Para garan<zar la ausencia decolisiones entre estados demixins ycoresseencapsulaelestadodecadamixin. La colisión de métodos debeprevenirseconposi<vasdeexclusiónoreescritura

mp.Mixin = function (ext) { return function (core) { var ctx = Object.create (null); var keys = Object.getOwnPropertyNames(ext); var mix = Object.assign({}, core); ctx.self = mix; keys.forEach (function (key) { if (typeof(ext[key]) === 'function') mix[key] = ext[key].bind(ctx); else ctx[key] = ext[key]; }); if (mix.init) mix.init.call(mix); return mix; }; }; var A = {...}; var MixinId = mp.Mixin({ id : 0, getId : function () { return this.id; }, setId : function (id) { this.id = id; } }); var B = MixinId(A);

p() q()

x() y()

Existenciapotencialde

colisiones

Seencapsulaelestadoparaevitarcolisiones

Laherenciademixinsoclasesconmixinsnofunciona

+

@javiervelezreye22

ArquitecturasParaLaReu<lizaciónArquitecturasParaLaReu<lizaciónEnJavaScript

ImplementaciónII.ComposiciónporExtensiónArquitecturasdeMixins

TécnicadeComposición

La técnica de composición porextensiónman<enelaindependenciademixins,posibilita la reversibilidad,u<liza late binding y funciona encontextosdeherencia

A

A with M M

B

DesdeelCódigo

Los mixins ahora son funciones quecontribuyen a una clase con nuevasabstracciones de datos. Losproblemas de colisión potencial demétodosseman<enen

let MixinId = function (cls) { return class extends cls { constructor() { super(); this.id = 0; } getId() { return this.id; } setId(id) { this.id = id; } }; class A { ... } Let AM = MixinId(A);

Cadamixinseseparaenuna

nuevaclase

Contribucióndelmixin

Losmixinssebuscanascendentementeloquefomentaoperarconlatebinding

@javiervelezreye23

ArquitecturasParaLaReu<lizaciónArquitecturasParaLaReu<lizaciónEnJavaScript

EjemploArquitecturasdeMixins

Ejemplo

Unasolucióndemixinsmueveunaarquitecturaparasoportar la valoración social de una colección deproductosvinculadosauncliente

var allScore = function (aProduct, social) { var score = 0; var product = aProduct; while (product) { var social = product[social]; while (social) { score = score + getScore(social) social = social.next(); } product = product.next(); } return score; } var getScore = function (social) { return !social.children ? social.score() : social.children.reduce (function (c) { return getScore(c) + c.score(); }, 0); }

EllibroseexBendeacardinalidadmúlBple

SeexBendeelcomentarioparaconverBrloenuna

enBdadvalorable

parent

children

Book

MIndex

back() next()

Comment

MIndex

back() next() back

next

back

next

MChilds

children() parent()

MScore

like() dislike() score()

User

@javiervelezreye24

ArquitecturasParaLaReu<lizaciónArquitecturasParaLaReu<lizaciónEnJavaScript

DescripciónGeneralArquitecturasdeTraits

Componente.Trait

UnTraitesunaabstracciónfuncionalparcialquecontribuyeconunacolec-ción de capacidades. No <enenestadoyseapoyaenlaexistenciadeciertos métodos requeridos en elcore

autonomíaencapsulación

dependenciafuncional

Core

extensibilidad

Arquitectura

En este caso la arquitectura denegocio debe proporcionar métodosque permitan a los Traits operarconvenientemente.A B

X Y

LosTraitsrequierenmétodosdeanclajeparamoverlaarquitectura

Abstraccionesdedatosdelnegocio

ReuBlizaciónendisBntosproyectos

ProyectoA

ProyectoB

@javiervelezreye25

ArquitecturasParaLaReu<lizaciónArquitecturasParaLaReu<lizaciónEnJavaScript

Implementación.ComposiciónporAdición&RecontextualizaciónArquitecturasdeTraits

TécnicadeComposición

La composición por adición es sencilla pero suponeoperar en early binding. Los Traits se definen como sipertenecieranalcore,loquerequierecontextualización

DesdeelCódigo

Cada método dentro del Trait secontextualizareasignandoelvalordelpunterothis.Seasumequeunrasgono puede contener otra cosa másquemétodos

mp.Trait = function (ext){ return function (core) { var keys = Object.getOwnPropertyNames(ext); var trait = Object.assign({}, core); keys.forEach (function (key) { if (typeof(ext[key]) === 'function') trait[key] = ext[key].bind(core); }); return trait; }; }; var TEnumerable = pm.Trait ({ map : function (fn) { var result = []; this.forEach (function (e) { result.push (fn(e)); }); return result; }, reduce: function (rn, b) { ... }, filter: function (pn) { ... } });

+

p() q() x() y()

r()

this

Contextualización

ComposiciónadiBva

@javiervelezreye26

ArquitecturasParaLaReu<lizaciónArquitecturasParaLaReu<lizaciónEnJavaScript

EjemploArquitecturasdeTraits

Ejemplo

Extendiendo el ejemplo anterior queremossaber el coste de la cesta de libros y lavaloraciónsocialdelamisma.

User Book

var cost = function (user, type) { return user.book .filter (function (book) { return type ? book.type === type : true; }) .reduce (function (price, book) { return price + book.price; }, 0); }; var score = function (user) { return user.book .reduce (function (score, book) { return score + book.comment .reduce (function (score, comment) { return score + comment.score(); }, 0); }); };

type price

TEnumerable

map(fn) reduce(rn, b) filter(pn)

forEach

MScore

like() dislike() score()

Comment

ElMixinMIndexproporcionaforEachloquepermite

incorporarTEnumerable

MIndex

back() next() back

next

MIndex

back() next() back

next

TEnumerable

map(fn) reduce(rn, b) filter(pn)

forEach

@javiervelezreye27

ArquitecturasParaLaReu<lizaciónArquitecturasParaLaReu<lizaciónEnJavaScript

DescripciónGeneralArquitecturasdeSubjects

Componente.Subject

UnSubjectesunaproyecciónsubje<vadeunmodelode negocio preparada para ser u<lizada por undeterminadocolec<vodedesarrolladoresdentrodelproyecto.

Arquitectura

Lasarquitecturassubje<vaspermitencontemplarunmismomodelodesdeperspec<vas contrapuestas lo quepermite simplificar el desarrollo enproyectosgrandesycomplejos

Plant Tree

nest ()

WithInsect WithNectar

feed()

Tree

HardWood SoftWood

cheerypine

Object

mapledandelionSBird

SWoodsman

Core

SA

SB autonomía

dependenciafuncional

ProyecciónsubjeBva

@javiervelezreye28

ArquitecturasParaLaReu<lizaciónArquitecturasParaLaReu<lizaciónEnJavaScript

Implementación.ComposiciónporDelegaciónArquitecturasdeSubjects

TécnicadeComposición

Se aplica composición por delegación de manera quecada Subject se mantenga como una proyecciónsimplificada cuyos métodos terminan invocando almodelorealsubyacente. Core

SA

SB

p()

q()

r() x() y()

m() n()

métodorequerido

delegacióncontratosubjeBvo

DesdeelCódigo

Para definir un Subject, se propor-cionaunadescripcióndelosmétodosque contendrá. Esto genera unafunción que permite ac<var elSubjectsobreunconjuntodeobjetos

mp.Subject = function (cfg) { return function (...objs) { return Object.keys(cfg) .reduce (function (subject, key) { var method = cfg[key]; var target = objs[cfg[key].target]; var feature = typeof (method) === 'function' ? method : target[method]; subject[key] = typeof (feature) === 'function' ? feature.bind(target) : feature; return subject; }, {}); }; class A { foo() {...}, bar() {...} } class B { baz() {...}, qux() {...} } var S1 = mp.Subject({ p: {method: 'foo', target: 0} q: {method: 'qux', target: 1} }); var s = S1 (new A(), new B());

@javiervelezreye29

ArquitecturasParaLaReu<lizaciónArquitecturasParaLaReu<lizaciónEnJavaScript

EjemploArquitecturasdeSubjects

Ejemplo

En este caso realizamos dos proyeccionessubje<vas para los departamentos defidelizaciónyventas

var SLoyalty = mp.Subject({ title : {method: 'title', target: 0}, author : {method: 'author', target: 0}, comments : {method: 'forEach', target: 0}, score : {method: function () { this.reduce(function (score, comment){ return score + comment.score(); }, 0); }, target: 0} }); var SSales = mp.Subject({ price : {method: 'price', target: 1}, owner : {method: 'getId', target: 0}, others : {method: 'forEach', target: 0} }); var user = ... var loyalty = SLoyalty (user.book); var sales = SSales (user, user.book);

User Book

title() author() type() price()

forEach

MScore

like() dislike() score()

Comment

MIndex

back() next() back

next

MIndex

back() next() back

next

forEach

MId

getId() setId(id)

@javiervelezreye30

ArquitecturasParaLaReu<lizaciónArquitecturasParaLaReu<lizaciónEnJavaScript

DescripciónGeneralArquitecturasdeRoles

Componente.Role

Un Rol encapsula un perfil de acceso a una en<dadqueofreceunaformaparcialyrestringidadeexplotarlascapacidadesfuncionalesqueestaen<dadofrece

Core

Ra

Rb autonomíarolesdeacceso

Rc

unicidad

state

state

state

dinamismo

estadomulBplicidad

Arquitectura

Lasarquitecturasderolespermitenmodelarmuchomáscómodamentelosproblemasdeges<ónderecursosconunaspolí<casdeaccesocomplicadas.AdiferenciadelosSubjects, en este <po de arquitec<tas cada rolproporciona métodos propios y un estado interno quedebeinstanciarse

A B

C

a1

a2

a1

b2

a2

c1

Admin

Guest

User

@javiervelezreye31

ArquitecturasParaLaReu<lizaciónArquitecturasParaLaReu<lizaciónEnJavaScript

Implementación.ComposiciónporDelegación&ContextualizaciónArquitecturasdeRoles

TécnicadeComposición

Se aplica composición por delegación y contextualiza-ción. Cada Role <ene un estado interno con variablesprimadasyunareferenciaselfalcore.Deestamanerasesolucionalaesquizofreniadeobjetos

Core

Ra

Rb

p()

q()

r() x() y()

m() n()

state

state

this

this

self

Accesoexplícitoacore

Contextualizacióninterna

Capacidadesderol

Capacidadesdecore

DesdeelCódigo

La función de definición de un Role recibe elcore y los métodos. Ésta contextualiza losmétodos sobre un contexto privado ctx paraencapsular el estado e incluye una referenciaself al core. Se requiereuna función init parainicializarelRoleenlainstanciación

mp.Role = function (core, cfg) { return function (...args) { var ctx = Object.create (null); ctx.self = core; var role = Object.keys (cfg) .reduce (function (role, key) { role[key] = cfg[key].bind(ctx); return role; }, {}); if (role.init) role.init(args); return role; }; }; var core = { add (x, y) { return x + y; } } var RA = mp.Role (core, { init : function (x) { this.x = x; }, inc : function () { this.self.add (this.x, 1); }, }) var rA1 = RA (1); var rA2 = RA (2);

@javiervelezreye32

ArquitecturasParaLaReu<lizaciónArquitecturasParaLaReu<lizaciónEnJavaScript

EjemploArquitecturasdeRoles

Ejemplo

Sobre el servicio de acceso a la API Webdefinimosunecosistemaderolesparaoperarporclienteconunestadointerno

var RReadOnly = mp.Role (core, { get: function (id) { return this.self.get(id); }, all: function (k) { return this.self.getAll(k); } }); var RMax = mp.Role (core, { init: function (max) { this.max = max; this.n = 0; }, get: function (id) { return this.self.get(id); }, add: function (e) { if (this.n < this.max) { this.self.add(e); this.n++; } else console.log ('Error - [%s,%j]', k, e); }, reset: function () { this.n = 0; } });

Resource

get(id) getAll() add(book) remove(book)

a2 a2

ro1

RReadOnly

a2 a2

rm1

RMax

var roBooks1 = RReadOnly (); var roBooks2 = RReadOnly (); var roBooks3 = RReadOnly (); ...

var rmaxBooks1 = RMax (1000); var rmaxBooks2 = RMax (500); var rmaxBooks3 = RMax (2500); ...

uri='/books'

@javiervelezreye33

ArquitecturasParaLaReu<lizaciónArquitecturasParaLaReu<lizaciónEnJavaScript

DescripciónGeneralArquitecturasdeAspectos

Componente.Aspecto

Un aspecto es una proyección parcial de lasresponsabilidades funcionales que debe cubrir unaabstracción para dar respuesta a los requisitos denegocio

Core autonomía

métodosdelcore

dinamismo

Decoraciónporaspectos

Arquitectura

Lasarquitecturasdeaspectospermitendescomponerlosproblemasenproyeccionesortogonalesqueresultandegran reu<lización potencial al poder contribuirse deforma inmediata a dis<ntas en<dades de negocio. Sonaspectos cpicamente el control de acceso, laconcurrencia, la distribu<vidad, la trazabilidad, etc. Elentrelazado de aspectos conforma el código final delaplica<vo

Logeable Accesible Traceable

Cores

Aspects

A

B

interwovenC

@javiervelezreye34

ArquitecturasParaLaReu<lizaciónArquitecturasParaLaReu<lizaciónEnJavaScript

Implementación.IntercesiónArquitecturasdeAspectos

TécnicadeComposición

La creación de arquitecturas basadas en aspectosentrelazados u<liza técnicas de intercesión sobrefunciones y atributos. En JavaScript la intercesión defunciones puede aplicarse repe<damente sobre unmismocore,ladeatributosno

Core

q()

q() Intercesion:before

q()

Intercesion:before

q()

Intercesion:aEer

DesdeelCódigo.Definición

Cada aspecto sedefine a par<r deun advice,función que supone una decoración sobre unmétodo del core, y un punto de croscudng,momento en el cual el decorador debe serinvocado.

var aspect = mp.Aspect ({ p: { when : 'before' | 'after', advice : function () { ... }, q: { when : 'before' | 'after', advice : function () { ... } }); aspect (coreA); aspect (coreB); aspect (coreC);

@javiervelezreye35

ArquitecturasParaLaReu<lizaciónArquitecturasParaLaReu<lizaciónEnJavaScript

ImplementaciónI.IntercesiónEstá<caArquitecturasdeAspectos

DesdeelCódigo.IntercesiónEstá<ca

La implementación más sencilla consiste enaplicar intercesión directamente sobre losmétodos del core. Para ello inicialmente espreciso incluir en la librería los métodosauxiliaresendecoracióndebeforeyaeer.

mp.before = function before (core, key, ext) { var fn = core[key]; core[key] = function (...args) { ext.apply (this, args); return fn.apply (this, args); }; }; mp.after = function after (core, key, ext) { var fn = core[key]; core[key] = function (...args) { var r = fn.apply (this, args); ext.apply (this, [...args, r]); return r; }; };

métodosauxiliaresdeintercesión

mp.Aspect = function (ext){ return function (core){ var keys = Object.getOwnPropertyNames(ext); keys.forEach (function (key) { var m = ext[key]; mp[m.when](core, key, m.advice); }); }; }; Ladecoraciónoperaen

earlybindingconloqueladecoraciónnoesdinámicanireversible

@javiervelezreye36

ArquitecturasParaLaReu<lizaciónArquitecturasParaLaReu<lizaciónEnJavaScript

ImplementaciónII.IntercesiónDinámicaArquitecturasdeAspectos

DesdeelCódigo.IntercesiónDinámica

EnestecasovamosaaprovecharqueenJScadafunción es un objeto para incluir propiedadesdeintercesiónenlasquedelegar

mp.Aspect = function (ext){ return function (core) { var keys= Object.getOwnPropertyNames (ext); keys.forEach (function (key) { if (!core[key].isAdvisable) mp.advisable (core, key); var m = ext[key]; core[key][m.when](m.advice); }); }; }; Ahoraladecoraciónoperaen

latebindingconloqueladecoraciónesdinámicayreversiblepormodificacióndelosatributosbeforesyaEers

Métodosinternosdesoportealaintercesióndinámica

mp.advisable = function (core, key) { var fn = core[key]; core[key] = function (...args) { core[key].befores.forEach (function (fn) { fn.apply (this, args); }); var r = core[key].body.apply (this, args); core[key].afters.forEach (function (fn) { fn.apply (this, [...args, r]); }); return r; }; core[key].isAdvisable = true; core[key].befores = []; core[key].body = fn; core[key].afters = []; core[key].before = function (fn) { this.befores.unshift (fn); }; core[key].after = function (fn) { this.afters.push (fn); }; };

@javiervelezreye37

ArquitecturasParaLaReu<lizaciónArquitecturasParaLaReu<lizaciónEnJavaScript

EjemploArquitecturasdeAspectos

Ejemplo

Supongamos que queremos idearunaarquitecturaquepersista todaslas en<dades en memoria en unabasededatosde formaautomá<caencuantosedetectencambios

var books = { data : {}, find : function (id) { return this.data[id]; }, add : function (book) { this.data[book.id] = book; } };

Books

find (id) add (book)

var Atraceable = mp.Aspect ({ add: { when: 'before', advice: function (item) { console.log ('Adding', book); } }, find: { when: 'after', advice: function (id) { console.log ('Finding', id); } } }); Atraceable (books);

ATraceable

find (id) add (book)

find:beforeadd:before

var ACheckeable = mp.Aspect ({ add: { when: 'before', advice: function (item) { if (!item || !item.id) throw 'Invalid Type'; } } }); ACheckeable (books);

ACheckeable

add (book)

add:before

var AStorable = mp.Aspect ({ add: { when: 'after', advice: function (item) { db.save (item.id, item); } } }); AStorable (books);

AStorable

add (book)

add:aEer

@javiervelezreye38

ArquitecturasParaLaReu<lizaciónArquitecturasParaLaReu<lizaciónEnJavaScript

DescripciónGeneralArquitecturasdeObjectFilters

Componente.ObjectFilter

Un filtro es un componente con la capacidad demodificar la ges<ónnaturalde invocacionesparaundeterminado método de manera qué ésta puedadelegarseenotraen<dadinternaoexterna

Core

state

filtrosenbefore

delegaciónexterna

delegacióninterna

autonomía

filtrosenaEer

Arquitectura

Las arquitectura de filtros permiten alterar dinámica-mente la ges<ón de losmensajes de invocación que sereciben sobre cada uno de los métodos de uncomponente de core. Esto permite aplicar polí<cas deintervencióndeformatransparente

Ext1 Ext2 Ext3

Filters

A

B

C

@javiervelezreye39

ArquitecturasParaLaReu<lizaciónArquitecturasParaLaReu<lizaciónEnJavaScript

Implementación.Intercesión&DelegaciónArquitecturasdeObjectFilters

TécnicadeComposición

En este caso se aplica intercesión para poderintervenir la respuesta de cada método con unalógica de dispatching que delegue hacia dis<ntosobjetosinternosoexternos

p()

statepn

delegaciónfiltrodedelegaciónconestado

IntercesiónbeforeoaEer

DesdeelCódigo.Definición

Cadafiltro determina quémétodos intervenirycualeslalógicadeintervenciónquehayqueaplicar antes o después del método paradelegarenotrocomponente

var filter = mp.Filter ({ init : function () { ... }, p : { when : 'before' | 'after', guard : function () { ... }, do : function () { ... } }, q : { when : 'before' | 'after', guard : function () { ... }, do : function () { ... } } }); filter (coreA); filter (coreB); filter (coreC);

@javiervelezreye40

ArquitecturasParaLaReu<lizaciónArquitecturasParaLaReu<lizaciónEnJavaScript

ImplementaciónI.Intercesión&DelegaciónArquitecturasdeAspectos

DesdeelCódigo.IntercesiónDinámica

Demaneramuysimilaralcasoanterioraplicamosintercesióndinámica. La diferencia aquí es que ejecutamos cada filtrosólosisecumplelacondicióndeguarda

mp.Filter = function (ext){ return function (core){ return function (...args) { var ctx = Object.create(null); ctx.self = core; var keys = Object.getOwnPropertyNames (ext); keys.forEach (function (key) { if (typeof (ext[key]) === 'object'){ if (!core[key].isAdvisable) mp.advisable (core, key); var m = ext[key]; core[key][m.when](function (params){ if (!m.guard || m.guard && m.guard.apply(ctx, [...params, ...args])) m.do.apply (ctx, [...params, ...args]) }); } if (ext.init) ext.init.apply(ctx, args); }); }; }; };

Secompruebalacondicióndeguarda

Secreauncontextoparamantenerelestado

Seinicializaelestadodecadafiltro

DadoquecadafiltroBeneaccesoalcorepuedeoperarconelo

comunicarseatravésdeesquemasdememoriacomparBda

@javiervelezreye41

ArquitecturasParaLaReu<lizaciónArquitecturasParaLaReu<lizaciónEnJavaScript

EjemploArquitecturasdeAspectos

Ejemplo

Finalmente, supongamos en este úl<mo casoquequeremosimplementarlógicadeshardingsobrelabasededatosdistribuidadelibros

Books

find (id) add (book) find

find

find

add

addadd

DB3

DB1

DB2

shard1

shard2

shard3

var Books = { find : function (id) { return this.data; }, add : function (book) {} } var shardBooks = FShard (books); shardBooks (0, 3, db0); shardBooks (1, 3, db1); shardBooks (2, 3, db2);

var FShard = mp.Filter ({ init : function (idx, max, db) { this.idx = idx; this.max = max; this.db = db; }, find : { when : 'before', guard : function (id) { return id % this.max === this.idx; }, do : function (e) { this.self.data = this.db.get (e.id, e); } }, add : { when : 'before', do : function (e) { this.db.set (e.id, e); } } });

@javiervelezreye42

PreguntasArquitecturasParaLaReu<lizaciónEnJavaScript

www.javiervelezreyes.com

ProgramaciónOrientadaaComponentes

ArquitecturasParaLaReu<lizaciónEnJavaScript

JavierVélezReyes@javiervelezreye

www.javiervelezreyes.com

ArquitecturasParaLaReu/lizaciónenJavaScript

ProgramaciónOrientadaaComponentes

Mayo2016