cbdw2014 - dependency injection: wiring up for the future

54
CBDW.3 Dependency Injection Wiring up for the future

Upload: ortus-solutions-corp

Post on 26-May-2015

157 views

Category:

Technology


1 download

DESCRIPTION

In this session we will cover the basics of DI (Dependency Injection), why you need it in your object oriented toolbox, and the theory behind DI. We will then venture into how to apply DI principles into our applications using WireBox and look at the features and benefits of WireBox.

TRANSCRIPT

Page 1: CBDW2014 - Dependency Injection: Wiring Up for the Future

CBDW.3Dependency InjectionWiring up for the future

Page 2: CBDW2014 - Dependency Injection: Wiring Up for the Future

The Obligatory Who Am Husband

Dad

Coach

Youth Leader

Co-Owner of Computer Know How

Member of TEAM ColdBox

Open CFML Foundation Board

Page 3: CBDW2014 - Dependency Injection: Wiring Up for the Future

What is Dependency Injection?Dependency injection is a software design

pattern in which one or more dependencies (or services) are injected, or passed by reference, into a dependent object (or client) and are made part of the client's state. The pattern separates the creation of a client's dependencies from its own behavior, which allows program designs to be loosely coupled and to follow the dependency inversion and single responsibility principles. It directly contrasts the service locator pattern, which allows clients to know about the system they use to find dependencies. The term was coined by Martin Fowler

Page 4: CBDW2014 - Dependency Injection: Wiring Up for the Future

Mr Smarty Pants

Page 5: CBDW2014 - Dependency Injection: Wiring Up for the Future

What is Dependency Injection?Dependency injection is a software design

pattern in which one or more dependencies (or services) are injected, or passed by reference, into a dependent object (or client) and are made part of the client's state. The pattern separates the creation of a client's dependencies from its own behavior, which allows program designs to be loosely coupled and to follow the dependency inversion and single responsibility principles. It directly contrasts the service locator pattern, which allows clients to know about the system they use to find dependencies. The term was coined by Martin Fowler

Page 6: CBDW2014 - Dependency Injection: Wiring Up for the Future

What is the problem?

We are now working with lots of objects! An object may depend on other objects These objects might also depend on other objects An object without its dependencies cannot function This composite system -> Object Graph !

A B C D

Page 7: CBDW2014 - Dependency Injection: Wiring Up for the Future

What is the problem?

!

Start by seeing objects as services An object is a client (dependency,dependent) of another object Objects have identity and responsibilities to accomplish specific tasks Modeling = Decompose services/functionality into object

!

A B C D

DI = Reliably + Efficiently building object graphs, strategies and patterns.

Page 8: CBDW2014 - Dependency Injection: Wiring Up for the Future

PRE-DI Evolution

Page 9: CBDW2014 - Dependency Injection: Wiring Up for the Future

Editor

Spell Checker

Manual

PRE-DI Evolution

Page 10: CBDW2014 - Dependency Injection: Wiring Up for the Future

component{!! function init(){!! ! variables.spellChecker = new SpellChecker();! !! }! !}

How do I change Languages? How do I isolate it?

What if I need this in another object?

What if this has more dependencies?

What if those dependencies have more

dependencies?

Getting Confused?

PRE-DI EvolutionHow do I test this?

Page 11: CBDW2014 - Dependency Injection: Wiring Up for the Future

Editor

Spell Checker

Manual

Editor

English Spell

Checker

Spanish Spell

Checker

Constructor/Setter

PRE-DI Evolution

Page 12: CBDW2014 - Dependency Injection: Wiring Up for the Future

component{!function init(ISpellChecker checker){!

spellChecker = arguments.checker;!cacheData = {};!return this;!!

}! !}!!component{!

function init(){!cacheData = {};!!return this;!

}!function setSpellChecker(ISpellChecker checker){!

variables.spellChecker = arguments.checker;!}! !

}

Editor

English Spell

Checker

Spanish Spell

Checker

I can change languages!

Who creates checker?

What if I need this in another object?

What if this has more dependencies?

What about my instance data?

Dang it! More Problems!

PRE-DI Evolution

Page 13: CBDW2014 - Dependency Injection: Wiring Up for the Future

PRE-DI EvolutionEditor

English Spell

Checker

Spanish Spell

Checker

Constructor/Setter

Pros: We can test We can use different spell checkers

Cons: Up to you to build dependencies Need to know the entire object graph of every object Use object in other locations (NOT DRY) Violates encapsulation

!

Page 14: CBDW2014 - Dependency Injection: Wiring Up for the Future

DI EvolutionEditor

Spell Checker

Manual

Editor

English Spell

Checker

Spanish Spell

Checker

Via Constructor

Client Factory ObjectXBuildRequests

Factory Patterns

Page 15: CBDW2014 - Dependency Injection: Wiring Up for the Future

component{!function init(ISpellChecker checker){!

spellChecker = arguments.checker;!cacheData = {};!return this;!!

}! !}!!component name=”EditorFactory”{!

function init(MailerFactory mailerFactory){!variables.mailerFactory = arguments.mailerFactory;!return this;!

}!function Editor newEnglishEditor(){!

var e = new Editor( new EnglishSpellChecker() );!e.setAddressBook( new AddressBook() );!e.setMailer( mailerFactory.newEnglishMailer() );!return e;!

}!function Editor newSpanishEditor(){!var e = new Editor( new SpanishSpellChecker() );!e.setAddressBook( new AddressBook() );!e.setMailer( mailerFactory.newSpanishMailer() );!return e;!

} !function Editor newGermanEditor(){}!!

}

PRE-DI EvolutionI can change languages!

Clean Separation of construction code

How many factories do I need?

All clients need factories?

Who builds the factory?

Creation gets verbose for new

variations

Dang it! More Problems!

What about persistence?

Page 16: CBDW2014 - Dependency Injection: Wiring Up for the Future

PRE-DI EvolutionPros:

Factory creates and assembles objects The client code remains clean and cohesive No more repetitive code, we have achieved reusability Encapsulation is maintained as client no longer build objects but request them

Cons: Our Factory becomes difficult to test as Editors are created and recreated Persistence is not achieved The factory must exist in every client that needs it The factory must implement every variation of what it produces The factory code will get messy and repetitive over time !

Client Factory ObjectXBuildRequests

Factory

Page 17: CBDW2014 - Dependency Injection: Wiring Up for the Future

DI EvolutionEditor

Spell Checker

Manual

Editor

English Spell

Checker

Spanish Spell

Checker

Via Constructor

Client Factory ObjectXBuildRequests

Custom Object Factory

Injector

Client

produces

Object XWith

dependencieswith

Dependency Injection

NOT A SILVER BULLET, BUT ALMOST!

Page 18: CBDW2014 - Dependency Injection: Wiring Up for the Future

DI BasicsAs we apply OO, we need object management Replace manual/boilerplate object creation and/or object factories No more createObject() or new() to avoid coupling and be DRY Abstract object dependencies Dependencies = Objects, Settings, Data, Etc. Manage object persistence for you

component{!! function init(){!! ! variables.spellChecker = new SpellChecker();!!! }! !}

Editor

English Spell

Checker

Spanish Spell

Checker

How do I change Languages? How do I isolate it? What if I need this in

another object?

What if this has more dependencies?

What if those dependencies have more

dependencies?How do I test this?

Page 19: CBDW2014 - Dependency Injection: Wiring Up for the Future

createObject/new() is evil

Your objects are MINE!!

Page 20: CBDW2014 - Dependency Injection: Wiring Up for the Future

DI Basics

Ask Injector for objects by named keys Injector manages object persistence for you -> Scoping Dependency Discovery

Introspection (Annotations+Methods+Arguments) Configuration (XML or Programmatic)

Injector Autowires = Automatic resolving and injecting of dependencies Dependency Injection Idioms:

Constructor arguments Setters/Methods Mixins (CFProperty) Injector)

Annotated)Code)

Class)Introspection)

Application)

Configuration)XML)or)

Programmatic)

Page 21: CBDW2014 - Dependency Injection: Wiring Up for the Future

DI IDIOMS// Constructor!function init(service){! variables.service = arguments.service;! return init;!}!

// CF Property Injection!property name=“service” inject;!property name=“service” inject=”id:CoolService”;!property name=“log” inject=”logbox:logger:{this}”;!

// Setters!function setService(service) inject=”service”{! variables.service = arguments.service;!}!

Page 22: CBDW2014 - Dependency Injection: Wiring Up for the Future

DI Golden Rule #1Instead of pulling your dependencies in, you opt to receive them from someplace and you don’t care where they come from. Instead of pull you push Hollywood principle -> IoC = Inversion of Control

Don’t call us; we’ll call you!

Page 23: CBDW2014 - Dependency Injection: Wiring Up for the Future

DI BenefitsBest parts of the evolution Testability and Mockability (Yes, that’s a word!) Can enable object state or persistence Loose Coupling

Objects don’t know about their dependencies Easily switch dependencies

DRY principles Removes code clutter and write less boilerplate code Ability to dynamically influence objects: AOP, Mixins, More

Applications become tolerant to rapid structural and behavioral change

Page 24: CBDW2014 - Dependency Injection: Wiring Up for the Future

What is WireBox?“A next generation conventions based dependency injection

and AOP framework for ColdFusion”

“Build objects the MACHO way!”

Page 25: CBDW2014 - Dependency Injection: Wiring Up for the Future

FeaturesDocumentation & Professional Services

Annotation driven DI

0 configuration or programmatic configuration mode (NO XML)

More than CFCs

Persistence scopes: singleton, session, request, cache, etc.

Integrated logging and debugging

Object Life Cycle Events

Automatic CF Scope registration

!

Application*Scope*

Injector*

Page 26: CBDW2014 - Dependency Injection: Wiring Up for the Future

Installationbox install wirebox1

2 Relax and start coding!

Page 27: CBDW2014 - Dependency Injection: Wiring Up for the Future

InstallationDownload ColdBox or Standalone

http://coldbox.org/download 1

2

3 Relax and start coding!

If standalone, drop in the webroot as wirebox or create a wirebox mapping

Page 28: CBDW2014 - Dependency Injection: Wiring Up for the Future

WireBox Universe

Injector)

Scopes)

Binder)

LogBox)

DSL)Builders)

Parent)Injector)

Events)

AOP

Page 29: CBDW2014 - Dependency Injection: Wiring Up for the Future

WireBox Injector

Creates and wires all objects for you getInstance(‘named key or path’)

injector = new wirebox.system.ioc.Injector();!injector = new wirebox.system.ioc.Injector(binder=”path.to.Binder”, !

properties={prop1=val1,prop2=val2});!!obj = injector.getInstance(“model.path.Service”);!!obj2 = injector.getInstance(“NamedKey”);

Page 30: CBDW2014 - Dependency Injection: Wiring Up for the Future

Creation Styles

Explicit Mappings

getInstance('path.to.object')

path.to.object

createObject()

getInstance('MyService')

path.to.object

Binder

Lookup Key

Create Resolved Path

Implicit Mappings Scan Locations

getInstance('MyService')

Scan Location

1

Scan Location

2

Scan Location

3

scan

scan

scan

Page 31: CBDW2014 - Dependency Injection: Wiring Up for the Future

Configuration Binder

Simple CFC Configure()

Define WireBox Settings Define Object Mappings

Mapping DSL

component extends=”wirebox.system.ioc.config.Binder”{!!

configure(){!!

}!}

Page 32: CBDW2014 - Dependency Injection: Wiring Up for the Future

Mapping DSLUsed by concatenating calls to itself, returns the binder always Very readable bursts of logic:

map(“Luis”).toJava(“cool.Java.App”).into(this.SCOPES.SESSION); Extend it!

component extends=”wirebox.system.ioc.config.Binder”{!!

configure(){!!map(“Luis”).toJava(“cool.java.Service”) .asSingleton() .asEagerInit();!!

}!!}!

Page 33: CBDW2014 - Dependency Injection: Wiring Up for the Future

More than CFCsType Description

CFC ColdFusion Component

JAVA Any Java object

WEBSERVICE Any WSDL

RSS Any RSS or Atom feed

DSL Any registered or core injection DSL string

CONSTANT Any value

FACTORY Any other mapped object

PROVIDER A registered provider object

Page 34: CBDW2014 - Dependency Injection: Wiring Up for the Future

!// RSS Integration With Caching.!map("googleNews")!! .toRSS("http://news.google.com/news?pz=1&ned=us&hl=en&topic=h&num=3&output=rss")!! .asEagerInit()!! .inCacheBox(timeout=20,lastAccessTimeout=30,provider="default",key="google-news");! !// Java Integration with init arguments!map("Buffer").!! toJava("java.lang.StringBuffer").!! initArg(value="500",javaCast="long");!! !// Java integration with initWith() custom arguments and your own casting.!map("Buffer").!! toJava("java.lang.StringBuffer").!! initWith( javaCast("long",500) );!!// Constant!map("MyEmail").!! toConsant("[email protected]");!!// Factory Methods!map("FunkyEpresso").!! toFactorymethod(factory="SecurityServic",method=”getEspresso”).!! methodArg(name=”funkyLevel”,value=”45”);!!// Property injections!map("SecurityService")!! .to("model.security.SecurityService")!! .in(this.SCOPES.SERVER)!! .property(name="userService", ref="UserService", scope="instance")!! .property(name="logger", dsl="LogBox:root", scope="instance")!! .property(name="cache", dsl="CacheBox:Default", scope="instance")!! .property(name="maxHits", value=20, scope="instance"!

Page 35: CBDW2014 - Dependency Injection: Wiring Up for the Future

What about persistence?

Page 36: CBDW2014 - Dependency Injection: Wiring Up for the Future

Scoping by Mapping// map google news!map(“GoogleNews”)!

.toRSS(“http://news.google.com/news?output=rss”)!

.asEagerInit()!

.inCacheBox(timeout=”30”,lastAccessTimeout=10);!!// Wire up java objects!map(“SecurityService”)!

.toJava(“org.company.SecurityService)!

.asSingleton()!

.setter(name=”userService”,ref=”userService”);!map(“UserService”)!

.asSingleton()!

.toJava(“org.company.UserService”);!!

// request based objects!map(“SearchCriteria”)!

.to(“model.search.Criteria”)!

.into(this.SCOPES.REQUEST);!!// session based objects!map(“UserPreferences”)!

.to(“model.user.Preferences”)!

.into(this.SCOPES.SESSION);

Page 37: CBDW2014 - Dependency Injection: Wiring Up for the Future

Scoping by Annotation

component{}!!component singleton{}!!component scope=”session”{}!!component scope=”request”{}!!component cache cacheTimeout=”30”{}!!component cachebox=”ehCache” cacheTimeout=”30”{}

Page 38: CBDW2014 - Dependency Injection: Wiring Up for the Future

Injection Styles

Page 39: CBDW2014 - Dependency Injection: Wiring Up for the Future

Style Pros Cons

Annotations

Documentable

Better visibility

Rapid Workflows

Just Metadata!

Can pollute code Some call intrusive Unusable on compiled code

ConfigurationCompiled/Legacy Code Multiple configurations per object Visible Object Map

Tedious Slower workflow Lower visibility

Dependencies, Scope, Names?

Page 40: CBDW2014 - Dependency Injection: Wiring Up for the Future

Injection AnnotationUse one annotation: inject

Tells the Injector what to inject Concatenated strings separated by “:” First section is called DSL namespace inject=”id:MyService”, inject=”coldbox:plugin:Logger”

Namespace Description

ID-Model-Empty Mapped references by key

WireBox WireBox related objects: parent injectors, binder, properties, scopes

CacheBox CacheBox related objects: caches, cache keys, etc

Provider Object Providers

LogBox LogBox related objects: loggers, root loggers

ColdBox ColdBox related objects: interceptors, entity services, etc

Custom Your own live annotations

Page 41: CBDW2014 - Dependency Injection: Wiring Up for the Future

Annotations

// CF Property Injection!property name=“service” inject;!property name=“service” inject=”id:CoolService”;!property name=“log” inject=”logbox:logger:{this}”;!!// Constructor!function init(service inject){! variables.service = arguments.service;! return init;!}!!// Setter!function setService(service) inject{! variables.service = arguments.service;!}!

Page 42: CBDW2014 - Dependency Injection: Wiring Up for the Future

CFC Annotations@autowire = boolean [true] @alias = list of know names for this CFC @eagerInit [false] @threadSafe [false] @scope = valid scope @singleton @cachebox = cache provider [default] @cache [default] @cacheTimeout = minutes @cacheLastAccessTimeout = minutes @parent = parent ID @mixins = A list of UDF templates to mixin

Page 43: CBDW2014 - Dependency Injection: Wiring Up for the Future

Method ConventionsIf the following method signatures are found, we call them for you!

Injector Awareness setBeanFactory() setInjector()

ColdBox Awareness setColdBox()

onDIComplete()

Page 44: CBDW2014 - Dependency Injection: Wiring Up for the Future

Event Model

Announce events throughout injector and object life cycles Create simple CFC listeners or enhanced ColdBox interceptors Modify CFCs, metadata, etc Extend WireBox-CacheBox YOUR WAY!

component{!!

configure(injector,properties){}!!afterInstanceCreation(interceptData){!

var target = arguments.interceptData.target; target.$formatdate = variables.formatDate;!

}!!

function formatDate(){}!}!

Page 45: CBDW2014 - Dependency Injection: Wiring Up for the Future

What about AOP?

AOP?

Page 46: CBDW2014 - Dependency Injection: Wiring Up for the Future

WireBox AOPFull AOP support for

before, after and around advices

Goals

Fast

Simple

Matching Power

Reusability

1 Listener called “Mixer” to activate it

Service

Transaction Aspect

Logging Aspect

wirebox.listeners = [!{ class=”wirebox.system.aop.Mixer” }!

];!

Page 47: CBDW2014 - Dependency Injection: Wiring Up for the Future

Why AOPcomponent name="UserService"{!! !! function save(){!! !! log.info("method save() called with arguments: #serializeJSON(arguments)#");!! !! transaction {!! // do some work here!! }!! !! log.info("Save completed successfully!");!! }!}!

Target

Logging concerns: before and after our code executes

Transaction concerns: around our code

What if we have 50 methods like this?

How do we move these cross cutting concerns into a more reusable layer?

Page 48: CBDW2014 - Dependency Injection: Wiring Up for the Future

How it works?1. We can identify our target CFC 2. Identify the methods to change 3. AOP framework can proxy our methods

User Service save()

Transaction Aspect

Logging Aspect

Page 49: CBDW2014 - Dependency Injection: Wiring Up for the Future

AOP The WireBox Way

component implements=”wirebox.system.aop.MethodInterceptor”{!!

function invokeMethod(invocation){ !

transaction{!var results = invocation.proceed();!

}!!if( !isNull(results) ){!

return results;!}!

!}!

}!

Write an Aspect

Page 50: CBDW2014 - Dependency Injection: Wiring Up for the Future

AOP The WireBox Way

// Map an aspect (it can have any dependency)!mapAspect(“TransactionAspect”).to(“model.aspects.TransactionAspect”);!!!

Map the aspect

Bind to targets// Bind the aspects!bindAspect(classes=match().any(), methods=match().annotatedWith(“transactional”),! aspects=”TransactionAspect”);!

Page 51: CBDW2014 - Dependency Injection: Wiring Up for the Future

AOP

Matchers any() annotatedWith(annotation,value) isInstanceOf() regex() mappings(list or single) methods(list or single) returns(type) and(), or()

Page 52: CBDW2014 - Dependency Injection: Wiring Up for the Future

AOP The WireBox Way

!/**!* @classMatcher any!* @methodMatcher annotatedWith(transactional)!*/ component implements=”wirebox.system.aop.MethodInterceptor”{!!

function invokeMethod(invocation){ !

transaction{!var results = invocation.proceed();!

}!!if( !isNull(results) ){!

return results;!}!

!}!

}!

Self Binding Aspects

Page 53: CBDW2014 - Dependency Injection: Wiring Up for the Future

Source: https://github.com/ColdBox/coldbox-platform Get WireBox: http://www.coldbox.org/download Documentation: http://wiki.coldbox.org/wiki/WireBox.cfm Google Group: http://groups.google.com/group/coldbox

E-mail: [email protected] Blog: http://www.compknowhow.com Twitter/Skype/League of Legends: gratzc GTalk: [email protected]

More Info

Contact Info

Page 54: CBDW2014 - Dependency Injection: Wiring Up for the Future

Thanks!

Q & A