SlideShare a Scribd company logo
Responsible DI
(Ditch the frameworks!)
@KenScambler
MYOB
Spring / Guice / Dagger 2
Problems with DI frameworks
• Cognitive overheard, confusing semantics
• Smear application-level responsibility everywhere
• Makes it too easy to not think about responsibilities
• Makes it harder to reason about code in isolation
• Throws tech at a problem that shouldn’t exist
What problems do DI frameworks solve
• “Factories aren’t fun”
• “Think of Guice’s @Inject
as the new new”
Guice Dagger 2
• “App assembly can be 100KLOC”
• ”Replace FactoryFactory classes”
• “Swapping dependencies for
testing”
Spring
• “Initialisation ordering”
ApplicationContext,
BeanFactory, container,
beans, configuration
metadata,
BeanDefinitionReader,
autowiring
Spring Guice
@Inject, module, AbstractModule,
injector, scopes, providers, linked
bindings, instance bindings, provider
bindings, constructor bindings,
untargetted bindings, built-in bindings,
scopes, injection points
Dagger 2
module, provider, @Inject,
@Provides, bindings,
component, Lazy, injector,
builder, code gen, qualifier,
component provision methods,
@Reusable scope
Actual problem
Need to pass arguments to things
Actual solution
Pass arguments to things
More constructively:
Actual problem
• Of the arguments we need to pass, some are selected once for the application
and never changed. It would be bad to select them over and over again
Actual solution
• Only one place should know that it is in an ”application”
• Wire up the things that never change here
• Use good software engineering to reduce the number of things
1.
Dependencies
from scratch
Case study – Video Rental API
Video Search
Controller
Payment
Controller
Video
Searcher
Payments
Payments
Gateway
Rental
Controller
Rentals
Video Repo
Video DB
Analytics
Logging
3rd Party
What if there were no objects?
handleVideoSearch
Request
handlePayment
Request
findByName
findSimilar
charge
transferFrom
Account
handleRental
Request
rentVideo
runVideoQuery
record
Debug,
warn,
error
public class Rentals {
public static
Receipt rentVideo(Video v, VideoStore store, Customer c) {
store.decrementStock(vid);
Payments.charge(c.getCreditCard(), v.getPrice());
List<Movie> recommendations =
VideoSearcher.findSimilar(v);
Logger.debug(LogMessages.VIDEO_RENTED);
return new Receipt(v.getId(), c.getId(), recommendations);
}
}
public class Rentals {
public static
Receipt rentVideo(Video v, VideoStore store, Customer c) {
store.decrementStock(vid);
Payments.charge(c.getCreditCard(), v.getPrice());
List<Movie> recommendations =
VideoSearcher.findSimilar(v);
Logger.debug(LogMessages.VIDEO_RENTED);
return new Receipt(v.getId(), c.getId(), recommendations);
}
}
handleVideoSearch
Request
handlePayment
Request
findByName
charge
transferFrom
Account
handleRental
Request
rentVideo
runVideoQuery(DB)
record
Debug,
warn,
error
findSimilar
I need a DB!
handleVideoSearch
Request
handlePayment
Request
charge
transferFrom
Account
handleRental
Request
rentVideo
runVideoQuery(DB)
record
Debug,
warn,
error
findByName
(DB)
findSimilar
(DB)
handlePayment
Request
charge
handleRental
Request
runVideoQuery(DB)
record
Debug,
warn,
error
findByName
(DB)
findSimilar
(DB)
handleVideoSearch
Request (DB)
rentVideo
(DB)
transferFrom
Account
handlePayment
Request
charge
transferFrom
Account
runVideoQuery(DB)
record
Debug,
warn,
error
findByName
(DB)
findSimilar
(DB)
handleVideoSearch
Request (DB)
rentVideo
(DB)
handleRental
Request (DB)
handlePayment
Request
charge
runVideoQuery(DB)
record
Debug,
warn,
error
findByName
(DB)
findSimilar
(DB)
handleVideoSearch
Request (DB)
rentVideo
(DB)
handleRental
Request (DB)
transferFrom
Account(PG)
I need a
payment
gateway!
handlePayment
Request
charge(PG)
runVideoQuery(DB)
record
Debug,
warn,
error
findByName
(DB)
findSimilar
(DB)
handleVideoSearch
Request (DB)
rentVideo
(DB)
handleRental
Request (DB)
transferFrom
Account(PG)
charge(PG)
runVideoQuery(DB)
record
Debug,
warn,
error
findByName
(DB)
findSimilar
(DB)
handleVideoSearch
Request (DB)
rentVideo
(DB, PG)
handleRental
Request (DB)
transferFrom
Account(PG)
handlePayment
Request (PG)
handleVideoSearch
Request (DB)
handlePayment
Request (PG)
findByName
(DB)
charge(PG)
transferFrom
Account(PG)
handleRental
Request (DB, PG)
rentVideo
(DB, PG)
runVideoQuery(DB)
record
Debug,
warn,
error
findSimilar
(DB)
Trickling up is very, very bad
1. Punches through abstraction layers
2. Changes ripple
3. Same arguments must be supplied many times to many places, but
for only one reason
Objects = 1
handleVideoSearch
Request
handlePayment
Request
charge
transferFrom
Account
handleRental
Request
rentVideo
record
Debug,
warn,
error
Video Repo
Video DB
findByName findSimilar
Objects = 2
handleVideoSearch
Request
handlePayment
Request
charge
transferFrom
Account
handleRental
Request
rentVideo
record
Debug,
warn,
error
Video Repo
Video DB
Video
Searcher
Objects = 4
handlePayment
Request
charge
transferFrom
Account
handleRental
Request
record
Debug,
warn,
error
Video Repo
Video DB
Video
Searcher
Rentals
Video Search
Controller
Objects = 5
handlePayment
Request
charge
transferFrom
Account
record
Debug,
warn,
error
Video Repo
Video DB
Video
Searcher
Rentals
Video Search
Controller
Rental
Controller
Objects = 7
handlePayment
Request
charge
transferFrom
Account
Video Repo
Video DB
Video
Searcher
Rentals
Video Search
Controller
Rental
Controller
Analytics
Logging
Objects = 8
handlePayment
Request
charge
Video Repo
Video DB
Video
Searcher
Rentals
Video Search
Controller
Rental
Controller
Analytics
Logging
Payments
Gateway
3rd Party
Objects = 9
handlePayment
Request
Video Repo
Video DB
Video
Searcher
Rentals
Video Search
Controller
Rental
Controller
Analytics
Logging
Payments
Gateway
3rd Party
Payments
Objects = 10
Video Repo
Video DB
Video
Searcher
Rentals
Video Search
Controller
Rental
Controller
Analytics
Logging
Payments
Gateway
3rd Party
Payments
Payment
Controller
Object creep is real!
…but isn’t that ok?
We’re writing OO software,
after all
Video
Searcher
Rentals
Logging
Payments
public class Rentals {
private final VideoSearcher search;
private final Payments p;
private final Logger log;
// Obvious constructor
public Receipt rentVideo(Video v, VideoStore store, Customer c) {
store.decrementStock(vid);
p.charge(c.getCreditCard(), v.getPrice());
List<Movie> recommendations = search.findSimilar(v);
log.debug(LogMessages.VIDEO_RENTED);
return new Receipt(v.getId(), c.getId(), recommendations);
}
}
Rentals
- rentVideo
“Coathanger object”: just exists to
hang the functionality on
Rentals
- rentVideo
VideoSearcher
Payments
Logger
Rentals
- rentVideo
Payments
Logger
VideoSearcher
VideoRepo
- findSimilar
• Hiding functionality in objects isn’t free
• Inhibits composition & reuse
• Can we reduce the number of objects we
use?
2.
Bleeding
responsibilities
The place where the wiring happens
var logger = LoggingFramework.newLogger();
var analytics = MediaBubbleMonkeyAnalytics.create();
var conn = new SpecificDatabaseConnection(connString);
var videoRepo = new VideoRepo(conn);
var videoSearcher = new VideoSearcher(videoRepo);
var gateway = new PaymentsGateway(url);
var payments = new Payments(gateway);
var rentals = new Rentals(videoSearcher, payments);
var videoSearchController = new
VideoSearchController(videoSearcher);
var rentalSearchController = new
RentalSearchController(rentals);
var paymentsController = new PaymentsController(payments);
Some people say “yeah, I
can manage it myself”… but
in an Android application,
we had 3000 LOC. In a large
server-side app, it flushes
out to about 100k LOC.
Greg Kick, Dagger 2 author
(Google)
“I know I am in an application, and what it is for”
var logger = LoggingFramework.newLogger();
var analytics = MediaBubbleMonkeyAnalytics.create();
var conn = new SpecificDatabaseConnection(connString);
var videoRepo = new VideoRepo(conn);
var videoSearcher = new VideoSearcher(videoRepo);
var gateway = new PaymentsGateway(url);
var payments = new Payments(gateway);
var rentals = new Rentals(videoSearcher, payments);
var videoSearchController = new
VideoSearchController(videoSearcher);
var rentalSearchController = new
RentalSearchController(rentals);
var paymentsController = new PaymentsController(payments);
DI frameworks help reduce code in that one spot
….but:
“I know I’m in an application” is smooshed
everywhere
public class Rentals {
private final VideoSearcher search;
private final Payments p;
private final Logger log;
public Rentals(VideoSearcher search, Payments p, Logger log) {
this.search = search;
this.p = p;
this.log = log;
}
public Receipt rentVideo(Video v, VideoStore store, Customer c) {
...
}
}
public class Rentals {
private final VideoSearcher search;
private final Payments p;
private final Logger log;
public Rentals(VideoSearcher search, Payments p, Logger log) {
this.search = search;
this.p = p;
this.log = log;
}
public Receipt rentVideo(Video v, VideoStore store, Customer c) {
...
}
}
Who am I? What do I
exist for?
What is the problem
that makes me say
“Aha! I’ll use Rentals
to solve it”
*** MOST IMPORTANT SLIDE IN THE WHOLE TALK ***
Programmer
public class Rentals {
...
public Receipt rentVideo(Video v, VideoStore store,
Customer c) {
...
}
}
Use me if you want
to rent a video.
public class Rentals {
...
public Receipt rentVideo(Video v, VideoStore store,
Customer c) {
...
}
}
What’s that you say,
I’m in an “app”? I
have no idea what
this means
public class Rentals {
private final VideoSearcher search;
private final Payments p;
private final Logger log;
public Rentals(VideoSearcher search, Payments p, Logger log) {
this.search = search;
this.p = p;
this.log = log;
}
public Receipt rentVideo(Video v, VideoStore store, Customer c) {
...
}
}
I don’t care in the
slightest which
VideoSearcher,
Payments or Logger
we use
@Component(“Bob”)
public class Rentals {
private final VideoSearcher search;
private final Payments p;
private final Logger log;
@Autowired
public Rentals(VideoSearcher search, Payments p, Logger log) {
this.search = search;
this.p = p;
this.log = log;
}
public Receipt rentVideo(Video v, VideoStore store, Customer c) {
...
}
}
But…
@Component(“Bob”)
public class Rentals {
private final VideoSearcher search;
private final Payments p;
private final Logger log;
@Autowired
public Rentals(VideoSearcher search, Payments p, Logger log) {
this.search = search;
this.p = p;
this.log = log;
}
public Receipt rentVideo(Video v, VideoStore store, Customer c) {
...
}
}
There’s only one true
Rentals. Create THE
Rentals for the whole app
to use. They can call it
“Bob”.
@Component(“Bob”)
public class Rentals {
private final VideoSearcher search;
private final Payments p;
private final Logger log;
@Autowired
public Rentals(VideoSearcher search, Payments p, Logger log) {
this.search = search;
this.p = p;
this.log = log;
}
public Receipt rentVideo(Video v, VideoStore store, Customer c) {
...
}
}
I want THE VideoSearcher, THE
Payments, and THE Log
defined for the app.
interface
VideoSearcher
class
LocalDbSearcher
class
InternetSearcher
interface
Payments
class
CreditCardPayments
class
BankPayments
class
HashMapSearcher
@Component(“Bob”)
public class Rentals {
private final VideoSearcher search;
private final Payments p;
private final Logger log;
@Autowired
public Rentals(@Qualifier(“internetSearch”) VideoSearcher search,
@Qualifier(“creditPayments”) Payments p,
@Qualifier(“log4J”) Logger log) {
this.search = search;
this.p = p;
this.log = log;
}
public Receipt rentVideo(Video v, VideoStore store, Customer c) {
...
}
}
I want a really really specific
VideoSearcher, Payments, and
Log that we get from a global
register somewhere.
I don’t care in the
slightest which
VideoSearcher,
Payments or Logger
we use
?????
public class Rentals {
public Receipt rentVideo(Video v, VideoStore store,
Customer c) {
store.decrementStock(vid);
p.charge(c.getCreditCard(), v.getRentalPrice());
List<Movie> recommendations = search.findSimilar(v);
log.debug(LogMessages.VIDEO_RENTED);
return new Receipt(v.getId(), c.getId(),
recommendations);
}
}
Use me if you
want to rent a
video.
THEREFORE:
1.
2.
3.
4.
Test that we can rent a video:
For some valid VideoSearcher, Payments, and Logger
1. Check the VideoStore got decremented
2. Check the Payments was charged
3. Check the logger received a LogMessages.VIDEO_RENTED message
4. Check our receipt has the expected data, including the expected
recommended videos
ALIGNS WITH OUR PURPOSE
public class RentalsTest {
VideoSearcher search = new FixedResultsSearcher(...);
Payments p = new InMemoryPayments();
InMemoryLogger log = new InMemoryLogger();
@Test
public void stockGetsDecremented() {
var rentals = new Rentals(search, p, log);
var store = new InMemoryVideoStore();
var video = new Video(“Weekend at Bernies”, Price.cents(250));
rentals.rentVideo(video, store.put(video,2), new Customer(...));
assertEquals(1, store.count(video));
}
...
}
public class Rentals {
private final StuffThatHappensFirst firstStuff;
...
@Autowired
public Rentals(@Qualifier(“decrementAndPayStuff”) StuffThatHappensFirst
firstStuff,
VideoSearcher search, Logger log) {
...
}
public Receipt rentVideo(Video v, VideoStore store, Customer c) {
firstStuff.doIt(store);
List<Movie> recommendations = search.findSimilar(v);
log.debug(“Video rented!”);
return new Receipt(v.getId(), c.getId(), recommendations);
}
}
Class responsibility has bled into the app!!!
3.
How to make less things
that need wiring?
There is nothing wrong with “new”
1 + 4 * 5
1.add(4.mult(5))
new Adder().add(1,
new Multiplier().mult(4,5))
class Multiplier {
private final
Adder adder = new Adder();
public int mult(int a, int b) {
int tot = 0;
for (int i = 0; i < a; i++)
tot = adder.add(tot,b);
return tot;
}
}
class Multiplier {
private final Adder adder;
public Multiplier(Adder a) {
adder = a;
}
public int mult(int a, int b) {
...
}
}
class Multiplier {
private final
Adder adder = new Adder();
public int mult(int a, int b) {
...
}
}
Who am I? What do I
exist for?
class Multiplier {
private final
Adder adder = new Adder();
public int mult(int a, int b) {
...
}
}
The point is:
Multiply 2 ints
into a resulting
int
Tool that
helps us do
our job
class Multiplier {
private final Adder adder;
public Multiplier(Adder a) {
adder = a;
}
public int mult(int a, int b) {
...
}
}
We do not care in
the slightest how
the ints get
combined
class Multiplier {
private final Adder adder;
public Multiplier(Adder a) {
adder = a;
}
public int mult(int a, int b) {
...
}
}
I exist to …
perform an action
on ints a given
number of times?
class GstPrice {
private final Price untaxed;
private final GstPolicy policy =
new GstPolicy();
public GstPrice(Price untaxed) {
this.untaxed = untaxed;
}
... // arithmetic, rounding, display, etc
}
class GstPrice {
private final Price untaxed;
private final GstPolicy policy =
new GstPolicy();
public GstPrice(Price untaxed) {
this.untaxed = untaxed;
}
... // arithmetic, rounding, display, etc
}
I exist to provide a
price that has
provably had GST
applied
class GstPrice {
private final Price untaxed;
private final GstPolicy policy =
new GstPolicy();
public GstPrice(Price untaxed) {
this.untaxed = untaxed;
}
... // arithmetic, rounding, display, etc
}
This is a tool I
need to do the
job. GST is the
point
class GstPrice {
private final Price untaxed;
private final GstPolicy policy =
new GstPolicy();
public GstPrice(Price untaxed) {
this.untaxed = untaxed;
}
... // arithmetic, rounding, display, etc
}
I do not care in
the slightest
which untaxed
price I am dealing
with
class TaxedPrice {
private final Price untaxed;
private final TaxPolicy policy;
public TaxedPrice(Price untaxed,
TaxPolicy policy) {
this.untaxed = untaxed;
}
... // arithmetic, rounding, display, etc
}
I do not care in
the slightest
which untaxed
price or tax policy
I am dealing with
// Mostly we don’t want to vary the policy,
so...
class TaxedPriceFactory {
private final TaxPolicy policy;
// ...Obvious constructor
public
TaxedPrice newTaxedPrice(Price untaxed) {
return new TaxedPrice(untaxed, policy);
}
}
• Don’t lazily turn every field into a
dependency; it increases
complexity and object creep.
• Think hard about responsibilities.
• Use new if it supports our reason
for existing.
4.
Dependencies
ain’t free
public class Rentals {
private final VideoSearcher search;
private final Payments p;
private final Logger log;
@Autowired
public Rentals(VideoSearcher search, Payments p, Logger log) {
...
}
public Receipt rentVideo(Video v, VideoStore store, Customer c) {
... // Uses search, p & log
}
}
public class Rentals {
private final VideoSearcher search;
private final Payments p;
private final Logger log;
private final PopcornMachine p;
@Autowired
public Rentals(VideoSearcher search, Payments p, Logger log, PopcornMachine p) {
...
}
public Receipt rentVideo(Video v, VideoStore store, Customer c) {
... // Uses search, p & log
}
public Receipt rentVideoWithPopcornDeal(Video v, VideoStore store, Customer c) { ... }
}
rentVideo
rentVideo
rentVideoWithPopcornDeal
Getters and setters
• This is how a codebase goes to
hell
• Each dependency makes reuse,
extension, reasoning & testing
harder
• Frameworks make it too easy to
pretend it’s free
5.
“Setter injection”
is malpractice
public class Rentals {
private VideoSearcher search;
private Payments p;
private Logger log;
public Rentals() {}
public void setVideoSearcher(VideoSearcher v) {...}
public void setPayments(Payments p) {...}
public void setLogger(Logger log) {...}
public Receipt rentVideo(Video v, VideoStore store,
Customer c) {... }
}
Programmer
UsageConstruction
- setVideoSearcher
- setPayments
- setLogger
- rentVideo
Totally different concerns!
Buy stuffSupply
Programmer
Usage
- rentVideointerface Rentals {
Receipt rentVideo(...)
}
• “Setter injection” is a bad idea
• Public interfaces confuses usage & creation
concerns
• Nobody ever wants all that at once
• Mutable, uncertain – what order did things
happen in?
• Frameworks make “setter injection” too easy &
practical
6.
Making
coathanger
objects
disappear
public class Payments {
private final Gateway gateway;
public Payments(Gateway gateway) {...}
public Receipt charge(Price price) {...}
}
public class Payments {
public static
Receipt charge(Price price, Gateway gateway) {
...
}
}
public class Payments {
public static
Function<Gateway, Receipt> charge(Price price) {
...
}
}
public class Payments {
public static
NeedsGateway<Receipt> charge(Price price) {
...
}
}
Required flexibility is now
built in to return type; no
coathanger object required
charge(Price.cents(250)).flatMap(
price -> doSomethingElse(price).map(
result -> result.toString()));
• “If only I had a Price, this is what I would totally
do with it"
• “Monadic style”
• Popular with functional programmers
• Maybe not so practical in Java
NeedsGateway<FinalResult> program;
FinalResult result =
program.actuallyRun(actualGateway);
Objects = 4 (just the IO points)
handleVideoSearch
Request
handlePayment
Request
charge
handleRental
Request
rentVideo
Video Repo
Video DB
findByName findSimilar
Gateway
Analytics
Logging
The problem has
vanished! There’s almost
nothing left to wire
Conclusion
• Passing arguments to things is not very hard
• Wiring together applications is not very hard
• Having a central “I am the application” place and thinking hard about
responsibilities gives you what you want
• DI frameworks are too complex, not necessary, and lead programmers
and teams toward sloppy design habits.

More Related Content

What's hot

Rise of the Machines: PHP and IoT - ZendCon 2017
Rise of the Machines: PHP and IoT - ZendCon 2017Rise of the Machines: PHP and IoT - ZendCon 2017
Rise of the Machines: PHP and IoT - ZendCon 2017
Colin O'Dell
 
High Quality Symfony Bundles tutorial - Dutch PHP Conference 2014
High Quality Symfony Bundles tutorial - Dutch PHP Conference 2014High Quality Symfony Bundles tutorial - Dutch PHP Conference 2014
High Quality Symfony Bundles tutorial - Dutch PHP Conference 2014
Matthias Noback
 
A reviravolta do desenvolvimento web
A reviravolta do desenvolvimento webA reviravolta do desenvolvimento web
A reviravolta do desenvolvimento web
Wallace Reis
 
PSGI and Plack from first principles
PSGI and Plack from first principlesPSGI and Plack from first principles
PSGI and Plack from first principles
Perl Careers
 
Java & low latency applications
Java & low latency applicationsJava & low latency applications
Java & low latency applications
Ruslan Shevchenko
 
An Introduction to Windows PowerShell
An Introduction to Windows PowerShellAn Introduction to Windows PowerShell
An Introduction to Windows PowerShell
Dale Lane
 
HTTP Middlewares in PHP by Eugene Dounar
HTTP Middlewares in PHP by Eugene DounarHTTP Middlewares in PHP by Eugene Dounar
HTTP Middlewares in PHP by Eugene Dounar
Minsk PHP User Group
 
SPIFFE Meetup Tokyo #2 - Attestation Internals in SPIRE - Shingo Omura
SPIFFE Meetup Tokyo #2 - Attestation Internals in SPIRE - Shingo OmuraSPIFFE Meetup Tokyo #2 - Attestation Internals in SPIRE - Shingo Omura
SPIFFE Meetup Tokyo #2 - Attestation Internals in SPIRE - Shingo Omura
Preferred Networks
 
A cool, clear drink of Ruby object persistence
A cool, clear drink of  Ruby object persistenceA cool, clear drink of  Ruby object persistence
A cool, clear drink of Ruby object persistence
baccigalupi
 
Conscious Decoupling - Lone Star PHP
Conscious Decoupling - Lone Star PHPConscious Decoupling - Lone Star PHP
Conscious Decoupling - Lone Star PHP
CiaranMcNulty
 
Effective Doctrine2: Performance Tips for Symfony2 Developers
Effective Doctrine2: Performance Tips for Symfony2 DevelopersEffective Doctrine2: Performance Tips for Symfony2 Developers
Effective Doctrine2: Performance Tips for Symfony2 Developers
Marcin Chwedziak
 

What's hot (11)

Rise of the Machines: PHP and IoT - ZendCon 2017
Rise of the Machines: PHP and IoT - ZendCon 2017Rise of the Machines: PHP and IoT - ZendCon 2017
Rise of the Machines: PHP and IoT - ZendCon 2017
 
High Quality Symfony Bundles tutorial - Dutch PHP Conference 2014
High Quality Symfony Bundles tutorial - Dutch PHP Conference 2014High Quality Symfony Bundles tutorial - Dutch PHP Conference 2014
High Quality Symfony Bundles tutorial - Dutch PHP Conference 2014
 
A reviravolta do desenvolvimento web
A reviravolta do desenvolvimento webA reviravolta do desenvolvimento web
A reviravolta do desenvolvimento web
 
PSGI and Plack from first principles
PSGI and Plack from first principlesPSGI and Plack from first principles
PSGI and Plack from first principles
 
Java & low latency applications
Java & low latency applicationsJava & low latency applications
Java & low latency applications
 
An Introduction to Windows PowerShell
An Introduction to Windows PowerShellAn Introduction to Windows PowerShell
An Introduction to Windows PowerShell
 
HTTP Middlewares in PHP by Eugene Dounar
HTTP Middlewares in PHP by Eugene DounarHTTP Middlewares in PHP by Eugene Dounar
HTTP Middlewares in PHP by Eugene Dounar
 
SPIFFE Meetup Tokyo #2 - Attestation Internals in SPIRE - Shingo Omura
SPIFFE Meetup Tokyo #2 - Attestation Internals in SPIRE - Shingo OmuraSPIFFE Meetup Tokyo #2 - Attestation Internals in SPIRE - Shingo Omura
SPIFFE Meetup Tokyo #2 - Attestation Internals in SPIRE - Shingo Omura
 
A cool, clear drink of Ruby object persistence
A cool, clear drink of  Ruby object persistenceA cool, clear drink of  Ruby object persistence
A cool, clear drink of Ruby object persistence
 
Conscious Decoupling - Lone Star PHP
Conscious Decoupling - Lone Star PHPConscious Decoupling - Lone Star PHP
Conscious Decoupling - Lone Star PHP
 
Effective Doctrine2: Performance Tips for Symfony2 Developers
Effective Doctrine2: Performance Tips for Symfony2 DevelopersEffective Doctrine2: Performance Tips for Symfony2 Developers
Effective Doctrine2: Performance Tips for Symfony2 Developers
 

Similar to Responsible DI: Ditch the Frameworks

Developing applications with Hyperledger Fabric SDK
Developing applications with Hyperledger Fabric SDKDeveloping applications with Hyperledger Fabric SDK
Developing applications with Hyperledger Fabric SDK
Horea Porutiu
 
Hexagonal architecture
Hexagonal architectureHexagonal architecture
Hexagonal architecture
Alessandro Minoccheri
 
Acercándonos a la Programación Funcional a través de la Arquitectura Hexag...
Acercándonos a la Programación Funcional a través de la Arquitectura Hexag...Acercándonos a la Programación Funcional a través de la Arquitectura Hexag...
Acercándonos a la Programación Funcional a través de la Arquitectura Hexag...
CodelyTV
 
Pyruvate, a reasonably fast, non-blocking, multithreaded WSGI server
Pyruvate, a reasonably fast, non-blocking, multithreaded WSGI serverPyruvate, a reasonably fast, non-blocking, multithreaded WSGI server
Pyruvate, a reasonably fast, non-blocking, multithreaded WSGI server
PloneFoundation
 
Dropwizard with MongoDB and Google Cloud
Dropwizard with MongoDB and Google CloudDropwizard with MongoDB and Google Cloud
Dropwizard with MongoDB and Google Cloud
Yun Zhi Lin
 
Getting More Out of the Node.js, PHP, and Python Agents - AppSphere16
Getting More Out of the Node.js, PHP, and Python Agents - AppSphere16Getting More Out of the Node.js, PHP, and Python Agents - AppSphere16
Getting More Out of the Node.js, PHP, and Python Agents - AppSphere16
AppDynamics
 
How to debug IoT Agents
How to debug IoT AgentsHow to debug IoT Agents
How to debug IoT Agents
Fernando Lopez Aguilar
 
springtraning-7024840-phpapp01.pdf
springtraning-7024840-phpapp01.pdfspringtraning-7024840-phpapp01.pdf
springtraning-7024840-phpapp01.pdf
BruceLee275640
 
Rapid Prototyping Chatter with a PHP/Hack Canvas App on Heroku
Rapid Prototyping Chatter with a PHP/Hack Canvas App on HerokuRapid Prototyping Chatter with a PHP/Hack Canvas App on Heroku
Rapid Prototyping Chatter with a PHP/Hack Canvas App on Heroku
Salesforce Developers
 
Unit Testing for Great Justice
Unit Testing for Great JusticeUnit Testing for Great Justice
Unit Testing for Great Justice
Domenic Denicola
 
Comet from JavaOne 2008
Comet from JavaOne 2008Comet from JavaOne 2008
Comet from JavaOne 2008
Joe Walker
 
Jenkins vs. AWS CodePipeline
Jenkins vs. AWS CodePipelineJenkins vs. AWS CodePipeline
Jenkins vs. AWS CodePipeline
Steffen Gebert
 
Orchestrating the execution of workflows for media streaming service and even...
Orchestrating the execution of workflows for media streaming service and even...Orchestrating the execution of workflows for media streaming service and even...
Orchestrating the execution of workflows for media streaming service and even...
Shuen-Huei Guan
 
Behat internals for advanced usage. Symfony Camp 2016
Behat internals for advanced usage. Symfony Camp 2016Behat internals for advanced usage. Symfony Camp 2016
Behat internals for advanced usage. Symfony Camp 2016
Sergey Polischook
 
Seeding a Tree in a Gherkin
Seeding a Tree in a GherkinSeeding a Tree in a Gherkin
Seeding a Tree in a Gherkin
Paul Rohorzka
 
BlackHat EU 2012 - Zhenhua Liu - Breeding Sandworms: How To Fuzz Your Way Out...
BlackHat EU 2012 - Zhenhua Liu - Breeding Sandworms: How To Fuzz Your Way Out...BlackHat EU 2012 - Zhenhua Liu - Breeding Sandworms: How To Fuzz Your Way Out...
BlackHat EU 2012 - Zhenhua Liu - Breeding Sandworms: How To Fuzz Your Way Out...
MindShare_kk
 
Creating Scalable JVM/Java Apps on Heroku
Creating Scalable JVM/Java Apps on HerokuCreating Scalable JVM/Java Apps on Heroku
Creating Scalable JVM/Java Apps on HerokuJoe Kutner
 
Jenkins vs. AWS CodePipeline (AWS User Group Berlin)
Jenkins vs. AWS CodePipeline (AWS User Group Berlin)Jenkins vs. AWS CodePipeline (AWS User Group Berlin)
Jenkins vs. AWS CodePipeline (AWS User Group Berlin)
Steffen Gebert
 
Common primitives in Docker environments
Common primitives in Docker environmentsCommon primitives in Docker environments
Common primitives in Docker environments
alexandru giurgiu
 
Spring in the Cloud - using Spring with Cloud Foundry
Spring in the Cloud - using Spring with Cloud FoundrySpring in the Cloud - using Spring with Cloud Foundry
Spring in the Cloud - using Spring with Cloud Foundry
Joshua Long
 

Similar to Responsible DI: Ditch the Frameworks (20)

Developing applications with Hyperledger Fabric SDK
Developing applications with Hyperledger Fabric SDKDeveloping applications with Hyperledger Fabric SDK
Developing applications with Hyperledger Fabric SDK
 
Hexagonal architecture
Hexagonal architectureHexagonal architecture
Hexagonal architecture
 
Acercándonos a la Programación Funcional a través de la Arquitectura Hexag...
Acercándonos a la Programación Funcional a través de la Arquitectura Hexag...Acercándonos a la Programación Funcional a través de la Arquitectura Hexag...
Acercándonos a la Programación Funcional a través de la Arquitectura Hexag...
 
Pyruvate, a reasonably fast, non-blocking, multithreaded WSGI server
Pyruvate, a reasonably fast, non-blocking, multithreaded WSGI serverPyruvate, a reasonably fast, non-blocking, multithreaded WSGI server
Pyruvate, a reasonably fast, non-blocking, multithreaded WSGI server
 
Dropwizard with MongoDB and Google Cloud
Dropwizard with MongoDB and Google CloudDropwizard with MongoDB and Google Cloud
Dropwizard with MongoDB and Google Cloud
 
Getting More Out of the Node.js, PHP, and Python Agents - AppSphere16
Getting More Out of the Node.js, PHP, and Python Agents - AppSphere16Getting More Out of the Node.js, PHP, and Python Agents - AppSphere16
Getting More Out of the Node.js, PHP, and Python Agents - AppSphere16
 
How to debug IoT Agents
How to debug IoT AgentsHow to debug IoT Agents
How to debug IoT Agents
 
springtraning-7024840-phpapp01.pdf
springtraning-7024840-phpapp01.pdfspringtraning-7024840-phpapp01.pdf
springtraning-7024840-phpapp01.pdf
 
Rapid Prototyping Chatter with a PHP/Hack Canvas App on Heroku
Rapid Prototyping Chatter with a PHP/Hack Canvas App on HerokuRapid Prototyping Chatter with a PHP/Hack Canvas App on Heroku
Rapid Prototyping Chatter with a PHP/Hack Canvas App on Heroku
 
Unit Testing for Great Justice
Unit Testing for Great JusticeUnit Testing for Great Justice
Unit Testing for Great Justice
 
Comet from JavaOne 2008
Comet from JavaOne 2008Comet from JavaOne 2008
Comet from JavaOne 2008
 
Jenkins vs. AWS CodePipeline
Jenkins vs. AWS CodePipelineJenkins vs. AWS CodePipeline
Jenkins vs. AWS CodePipeline
 
Orchestrating the execution of workflows for media streaming service and even...
Orchestrating the execution of workflows for media streaming service and even...Orchestrating the execution of workflows for media streaming service and even...
Orchestrating the execution of workflows for media streaming service and even...
 
Behat internals for advanced usage. Symfony Camp 2016
Behat internals for advanced usage. Symfony Camp 2016Behat internals for advanced usage. Symfony Camp 2016
Behat internals for advanced usage. Symfony Camp 2016
 
Seeding a Tree in a Gherkin
Seeding a Tree in a GherkinSeeding a Tree in a Gherkin
Seeding a Tree in a Gherkin
 
BlackHat EU 2012 - Zhenhua Liu - Breeding Sandworms: How To Fuzz Your Way Out...
BlackHat EU 2012 - Zhenhua Liu - Breeding Sandworms: How To Fuzz Your Way Out...BlackHat EU 2012 - Zhenhua Liu - Breeding Sandworms: How To Fuzz Your Way Out...
BlackHat EU 2012 - Zhenhua Liu - Breeding Sandworms: How To Fuzz Your Way Out...
 
Creating Scalable JVM/Java Apps on Heroku
Creating Scalable JVM/Java Apps on HerokuCreating Scalable JVM/Java Apps on Heroku
Creating Scalable JVM/Java Apps on Heroku
 
Jenkins vs. AWS CodePipeline (AWS User Group Berlin)
Jenkins vs. AWS CodePipeline (AWS User Group Berlin)Jenkins vs. AWS CodePipeline (AWS User Group Berlin)
Jenkins vs. AWS CodePipeline (AWS User Group Berlin)
 
Common primitives in Docker environments
Common primitives in Docker environmentsCommon primitives in Docker environments
Common primitives in Docker environments
 
Spring in the Cloud - using Spring with Cloud Foundry
Spring in the Cloud - using Spring with Cloud FoundrySpring in the Cloud - using Spring with Cloud Foundry
Spring in the Cloud - using Spring with Cloud Foundry
 

More from kenbot

Grow your own tech leads
Grow your own tech leadsGrow your own tech leads
Grow your own tech leads
kenbot
 
Applied category theory: the emerging science of compositionality
Applied category theory: the emerging science of compositionalityApplied category theory: the emerging science of compositionality
Applied category theory: the emerging science of compositionality
kenbot
 
FP adoption at REA
FP adoption at REAFP adoption at REA
FP adoption at REA
kenbot
 
Lenses for the masses - introducing Goggles
Lenses for the masses - introducing GogglesLenses for the masses - introducing Goggles
Lenses for the masses - introducing Goggles
kenbot
 
Good functional programming is good programming
Good functional programming is good programmingGood functional programming is good programming
Good functional programming is good programming
kenbot
 
Data made out of functions
Data made out of functionsData made out of functions
Data made out of functions
kenbot
 
Imagine a world without mocks
Imagine a world without mocksImagine a world without mocks
Imagine a world without mocks
kenbot
 
2 Years of Real World FP at REA
2 Years of Real World FP at REA2 Years of Real World FP at REA
2 Years of Real World FP at REA
kenbot
 
Your data structures are made of maths!
Your data structures are made of maths!Your data structures are made of maths!
Your data structures are made of maths!
kenbot
 
Category theory for beginners
Category theory for beginnersCategory theory for beginners
Category theory for beginners
kenbot
 
The disaster of mutable state
The disaster of mutable stateThe disaster of mutable state
The disaster of mutable state
kenbot
 
Running Free with the Monads
Running Free with the MonadsRunning Free with the Monads
Running Free with the Monads
kenbot
 

More from kenbot (12)

Grow your own tech leads
Grow your own tech leadsGrow your own tech leads
Grow your own tech leads
 
Applied category theory: the emerging science of compositionality
Applied category theory: the emerging science of compositionalityApplied category theory: the emerging science of compositionality
Applied category theory: the emerging science of compositionality
 
FP adoption at REA
FP adoption at REAFP adoption at REA
FP adoption at REA
 
Lenses for the masses - introducing Goggles
Lenses for the masses - introducing GogglesLenses for the masses - introducing Goggles
Lenses for the masses - introducing Goggles
 
Good functional programming is good programming
Good functional programming is good programmingGood functional programming is good programming
Good functional programming is good programming
 
Data made out of functions
Data made out of functionsData made out of functions
Data made out of functions
 
Imagine a world without mocks
Imagine a world without mocksImagine a world without mocks
Imagine a world without mocks
 
2 Years of Real World FP at REA
2 Years of Real World FP at REA2 Years of Real World FP at REA
2 Years of Real World FP at REA
 
Your data structures are made of maths!
Your data structures are made of maths!Your data structures are made of maths!
Your data structures are made of maths!
 
Category theory for beginners
Category theory for beginnersCategory theory for beginners
Category theory for beginners
 
The disaster of mutable state
The disaster of mutable stateThe disaster of mutable state
The disaster of mutable state
 
Running Free with the Monads
Running Free with the MonadsRunning Free with the Monads
Running Free with the Monads
 

Recently uploaded

Pro Unity Game Development with C-sharp Book
Pro Unity Game Development with C-sharp BookPro Unity Game Development with C-sharp Book
Pro Unity Game Development with C-sharp Book
abdulrafaychaudhry
 
Quarkus Hidden and Forbidden Extensions
Quarkus Hidden and Forbidden ExtensionsQuarkus Hidden and Forbidden Extensions
Quarkus Hidden and Forbidden Extensions
Max Andersen
 
Exploring Innovations in Data Repository Solutions - Insights from the U.S. G...
Exploring Innovations in Data Repository Solutions - Insights from the U.S. G...Exploring Innovations in Data Repository Solutions - Insights from the U.S. G...
Exploring Innovations in Data Repository Solutions - Insights from the U.S. G...
Globus
 
Webinar: Salesforce Document Management 2.0 - Smarter, Faster, Better
Webinar: Salesforce Document Management 2.0 - Smarter, Faster, BetterWebinar: Salesforce Document Management 2.0 - Smarter, Faster, Better
Webinar: Salesforce Document Management 2.0 - Smarter, Faster, Better
XfilesPro
 
A Sighting of filterA in Typelevel Rite of Passage
A Sighting of filterA in Typelevel Rite of PassageA Sighting of filterA in Typelevel Rite of Passage
A Sighting of filterA in Typelevel Rite of Passage
Philip Schwarz
 
May Marketo Masterclass, London MUG May 22 2024.pdf
May Marketo Masterclass, London MUG May 22 2024.pdfMay Marketo Masterclass, London MUG May 22 2024.pdf
May Marketo Masterclass, London MUG May 22 2024.pdf
Adele Miller
 
Introduction to Pygame (Lecture 7 Python Game Development)
Introduction to Pygame (Lecture 7 Python Game Development)Introduction to Pygame (Lecture 7 Python Game Development)
Introduction to Pygame (Lecture 7 Python Game Development)
abdulrafaychaudhry
 
Enhancing Research Orchestration Capabilities at ORNL.pdf
Enhancing Research Orchestration Capabilities at ORNL.pdfEnhancing Research Orchestration Capabilities at ORNL.pdf
Enhancing Research Orchestration Capabilities at ORNL.pdf
Globus
 
How Recreation Management Software Can Streamline Your Operations.pptx
How Recreation Management Software Can Streamline Your Operations.pptxHow Recreation Management Software Can Streamline Your Operations.pptx
How Recreation Management Software Can Streamline Your Operations.pptx
wottaspaceseo
 
Navigating the Metaverse: A Journey into Virtual Evolution"
Navigating the Metaverse: A Journey into Virtual Evolution"Navigating the Metaverse: A Journey into Virtual Evolution"
Navigating the Metaverse: A Journey into Virtual Evolution"
Donna Lenk
 
Understanding Globus Data Transfers with NetSage
Understanding Globus Data Transfers with NetSageUnderstanding Globus Data Transfers with NetSage
Understanding Globus Data Transfers with NetSage
Globus
 
Prosigns: Transforming Business with Tailored Technology Solutions
Prosigns: Transforming Business with Tailored Technology SolutionsProsigns: Transforming Business with Tailored Technology Solutions
Prosigns: Transforming Business with Tailored Technology Solutions
Prosigns
 
Cyaniclab : Software Development Agency Portfolio.pdf
Cyaniclab : Software Development Agency Portfolio.pdfCyaniclab : Software Development Agency Portfolio.pdf
Cyaniclab : Software Development Agency Portfolio.pdf
Cyanic lab
 
Top 7 Unique WhatsApp API Benefits | Saudi Arabia
Top 7 Unique WhatsApp API Benefits | Saudi ArabiaTop 7 Unique WhatsApp API Benefits | Saudi Arabia
Top 7 Unique WhatsApp API Benefits | Saudi Arabia
Yara Milbes
 
Lecture 1 Introduction to games development
Lecture 1 Introduction to games developmentLecture 1 Introduction to games development
Lecture 1 Introduction to games development
abdulrafaychaudhry
 
Innovating Inference - Remote Triggering of Large Language Models on HPC Clus...
Innovating Inference - Remote Triggering of Large Language Models on HPC Clus...Innovating Inference - Remote Triggering of Large Language Models on HPC Clus...
Innovating Inference - Remote Triggering of Large Language Models on HPC Clus...
Globus
 
Custom Healthcare Software for Managing Chronic Conditions and Remote Patient...
Custom Healthcare Software for Managing Chronic Conditions and Remote Patient...Custom Healthcare Software for Managing Chronic Conditions and Remote Patient...
Custom Healthcare Software for Managing Chronic Conditions and Remote Patient...
Mind IT Systems
 
Globus Compute wth IRI Workflows - GlobusWorld 2024
Globus Compute wth IRI Workflows - GlobusWorld 2024Globus Compute wth IRI Workflows - GlobusWorld 2024
Globus Compute wth IRI Workflows - GlobusWorld 2024
Globus
 
First Steps with Globus Compute Multi-User Endpoints
First Steps with Globus Compute Multi-User EndpointsFirst Steps with Globus Compute Multi-User Endpoints
First Steps with Globus Compute Multi-User Endpoints
Globus
 
Graphic Design Crash Course for beginners
Graphic Design Crash Course for beginnersGraphic Design Crash Course for beginners
Graphic Design Crash Course for beginners
e20449
 

Recently uploaded (20)

Pro Unity Game Development with C-sharp Book
Pro Unity Game Development with C-sharp BookPro Unity Game Development with C-sharp Book
Pro Unity Game Development with C-sharp Book
 
Quarkus Hidden and Forbidden Extensions
Quarkus Hidden and Forbidden ExtensionsQuarkus Hidden and Forbidden Extensions
Quarkus Hidden and Forbidden Extensions
 
Exploring Innovations in Data Repository Solutions - Insights from the U.S. G...
Exploring Innovations in Data Repository Solutions - Insights from the U.S. G...Exploring Innovations in Data Repository Solutions - Insights from the U.S. G...
Exploring Innovations in Data Repository Solutions - Insights from the U.S. G...
 
Webinar: Salesforce Document Management 2.0 - Smarter, Faster, Better
Webinar: Salesforce Document Management 2.0 - Smarter, Faster, BetterWebinar: Salesforce Document Management 2.0 - Smarter, Faster, Better
Webinar: Salesforce Document Management 2.0 - Smarter, Faster, Better
 
A Sighting of filterA in Typelevel Rite of Passage
A Sighting of filterA in Typelevel Rite of PassageA Sighting of filterA in Typelevel Rite of Passage
A Sighting of filterA in Typelevel Rite of Passage
 
May Marketo Masterclass, London MUG May 22 2024.pdf
May Marketo Masterclass, London MUG May 22 2024.pdfMay Marketo Masterclass, London MUG May 22 2024.pdf
May Marketo Masterclass, London MUG May 22 2024.pdf
 
Introduction to Pygame (Lecture 7 Python Game Development)
Introduction to Pygame (Lecture 7 Python Game Development)Introduction to Pygame (Lecture 7 Python Game Development)
Introduction to Pygame (Lecture 7 Python Game Development)
 
Enhancing Research Orchestration Capabilities at ORNL.pdf
Enhancing Research Orchestration Capabilities at ORNL.pdfEnhancing Research Orchestration Capabilities at ORNL.pdf
Enhancing Research Orchestration Capabilities at ORNL.pdf
 
How Recreation Management Software Can Streamline Your Operations.pptx
How Recreation Management Software Can Streamline Your Operations.pptxHow Recreation Management Software Can Streamline Your Operations.pptx
How Recreation Management Software Can Streamline Your Operations.pptx
 
Navigating the Metaverse: A Journey into Virtual Evolution"
Navigating the Metaverse: A Journey into Virtual Evolution"Navigating the Metaverse: A Journey into Virtual Evolution"
Navigating the Metaverse: A Journey into Virtual Evolution"
 
Understanding Globus Data Transfers with NetSage
Understanding Globus Data Transfers with NetSageUnderstanding Globus Data Transfers with NetSage
Understanding Globus Data Transfers with NetSage
 
Prosigns: Transforming Business with Tailored Technology Solutions
Prosigns: Transforming Business with Tailored Technology SolutionsProsigns: Transforming Business with Tailored Technology Solutions
Prosigns: Transforming Business with Tailored Technology Solutions
 
Cyaniclab : Software Development Agency Portfolio.pdf
Cyaniclab : Software Development Agency Portfolio.pdfCyaniclab : Software Development Agency Portfolio.pdf
Cyaniclab : Software Development Agency Portfolio.pdf
 
Top 7 Unique WhatsApp API Benefits | Saudi Arabia
Top 7 Unique WhatsApp API Benefits | Saudi ArabiaTop 7 Unique WhatsApp API Benefits | Saudi Arabia
Top 7 Unique WhatsApp API Benefits | Saudi Arabia
 
Lecture 1 Introduction to games development
Lecture 1 Introduction to games developmentLecture 1 Introduction to games development
Lecture 1 Introduction to games development
 
Innovating Inference - Remote Triggering of Large Language Models on HPC Clus...
Innovating Inference - Remote Triggering of Large Language Models on HPC Clus...Innovating Inference - Remote Triggering of Large Language Models on HPC Clus...
Innovating Inference - Remote Triggering of Large Language Models on HPC Clus...
 
Custom Healthcare Software for Managing Chronic Conditions and Remote Patient...
Custom Healthcare Software for Managing Chronic Conditions and Remote Patient...Custom Healthcare Software for Managing Chronic Conditions and Remote Patient...
Custom Healthcare Software for Managing Chronic Conditions and Remote Patient...
 
Globus Compute wth IRI Workflows - GlobusWorld 2024
Globus Compute wth IRI Workflows - GlobusWorld 2024Globus Compute wth IRI Workflows - GlobusWorld 2024
Globus Compute wth IRI Workflows - GlobusWorld 2024
 
First Steps with Globus Compute Multi-User Endpoints
First Steps with Globus Compute Multi-User EndpointsFirst Steps with Globus Compute Multi-User Endpoints
First Steps with Globus Compute Multi-User Endpoints
 
Graphic Design Crash Course for beginners
Graphic Design Crash Course for beginnersGraphic Design Crash Course for beginners
Graphic Design Crash Course for beginners
 

Responsible DI: Ditch the Frameworks