arquitecturas para la reutilización en javascript
TRANSCRIPT
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í
@javiervelezreye
linkedin.com/in/javiervelezreyes
gplus.to/javiervelezreyes
jvelez77
javiervelezreyes
youtube.com/user/javiervelezreyes www.javiervelezreyes.com
JavierVélezReyes@javiervelezreye
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
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