SlideShare une entreprise Scribd logo
1  sur  99
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.

Contenu connexe

Tendances

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 2017Colin 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 2014Matthias Noback
 
A reviravolta do desenvolvimento web
A reviravolta do desenvolvimento webA reviravolta do desenvolvimento web
A reviravolta do desenvolvimento webWallace Reis
 
PSGI and Plack from first principles
PSGI and Plack from first principlesPSGI and Plack from first principles
PSGI and Plack from first principlesPerl Careers
 
Java & low latency applications
Java & low latency applicationsJava & low latency applications
Java & low latency applicationsRuslan Shevchenko
 
An Introduction to Windows PowerShell
An Introduction to Windows PowerShellAn Introduction to Windows PowerShell
An Introduction to Windows PowerShellDale 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 DounarMinsk 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 OmuraPreferred 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 persistencebaccigalupi
 
Conscious Decoupling - Lone Star PHP
Conscious Decoupling - Lone Star PHPConscious Decoupling - Lone Star PHP
Conscious Decoupling - Lone Star PHPCiaranMcNulty
 
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 DevelopersMarcin Chwedziak
 

Tendances (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
 

Similaire à 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 SDKHorea Porutiu
 
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 serverPloneFoundation
 
Dropwizard with MongoDB and Google Cloud
Dropwizard with MongoDB and Google CloudDropwizard with MongoDB and Google Cloud
Dropwizard with MongoDB and Google CloudYun 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 - AppSphere16AppDynamics
 
springtraning-7024840-phpapp01.pdf
springtraning-7024840-phpapp01.pdfspringtraning-7024840-phpapp01.pdf
springtraning-7024840-phpapp01.pdfBruceLee275640
 
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 HerokuSalesforce Developers
 
Unit Testing for Great Justice
Unit Testing for Great JusticeUnit Testing for Great Justice
Unit Testing for Great JusticeDomenic Denicola
 
Comet from JavaOne 2008
Comet from JavaOne 2008Comet from JavaOne 2008
Comet from JavaOne 2008Joe Walker
 
Jenkins vs. AWS CodePipeline
Jenkins vs. AWS CodePipelineJenkins vs. AWS CodePipeline
Jenkins vs. AWS CodePipelineSteffen 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 2016Sergey Polischook
 
Seeding a Tree in a Gherkin
Seeding a Tree in a GherkinSeeding a Tree in a Gherkin
Seeding a Tree in a GherkinPaul 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 environmentsalexandru 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 FoundryJoshua Long
 

Similaire à 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
 

Plus de kenbot

Grow your own tech leads
Grow your own tech leadsGrow your own tech leads
Grow your own tech leadskenbot
 
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 compositionalitykenbot
 
FP adoption at REA
FP adoption at REAFP adoption at REA
FP adoption at REAkenbot
 
Lenses for the masses - introducing Goggles
Lenses for the masses - introducing GogglesLenses for the masses - introducing Goggles
Lenses for the masses - introducing Goggleskenbot
 
Good functional programming is good programming
Good functional programming is good programmingGood functional programming is good programming
Good functional programming is good programmingkenbot
 
Data made out of functions
Data made out of functionsData made out of functions
Data made out of functionskenbot
 
Imagine a world without mocks
Imagine a world without mocksImagine a world without mocks
Imagine a world without mockskenbot
 
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 REAkenbot
 
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 beginnerskenbot
 
The disaster of mutable state
The disaster of mutable stateThe disaster of mutable state
The disaster of mutable statekenbot
 
Running Free with the Monads
Running Free with the MonadsRunning Free with the Monads
Running Free with the Monadskenbot
 

Plus de 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
 

Dernier

Unveiling the Future: Sylius 2.0 New Features
Unveiling the Future: Sylius 2.0 New FeaturesUnveiling the Future: Sylius 2.0 New Features
Unveiling the Future: Sylius 2.0 New FeaturesŁukasz Chruściel
 
React Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief UtamaReact Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief UtamaHanief Utama
 
Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...
Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...
Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...OnePlan Solutions
 
Post Quantum Cryptography – The Impact on Identity
Post Quantum Cryptography – The Impact on IdentityPost Quantum Cryptography – The Impact on Identity
Post Quantum Cryptography – The Impact on Identityteam-WIBU
 
Implementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with AzureImplementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with AzureDinusha Kumarasiri
 
Taming Distributed Systems: Key Insights from Wix's Large-Scale Experience - ...
Taming Distributed Systems: Key Insights from Wix's Large-Scale Experience - ...Taming Distributed Systems: Key Insights from Wix's Large-Scale Experience - ...
Taming Distributed Systems: Key Insights from Wix's Large-Scale Experience - ...Natan Silnitsky
 
Comparing Linux OS Image Update Models - EOSS 2024.pdf
Comparing Linux OS Image Update Models - EOSS 2024.pdfComparing Linux OS Image Update Models - EOSS 2024.pdf
Comparing Linux OS Image Update Models - EOSS 2024.pdfDrew Moseley
 
Powering Real-Time Decisions with Continuous Data Streams
Powering Real-Time Decisions with Continuous Data StreamsPowering Real-Time Decisions with Continuous Data Streams
Powering Real-Time Decisions with Continuous Data StreamsSafe Software
 
Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)
Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)
Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)jennyeacort
 
Ahmed Motair CV April 2024 (Senior SW Developer)
Ahmed Motair CV April 2024 (Senior SW Developer)Ahmed Motair CV April 2024 (Senior SW Developer)
Ahmed Motair CV April 2024 (Senior SW Developer)Ahmed Mater
 
Software Project Health Check: Best Practices and Techniques for Your Product...
Software Project Health Check: Best Practices and Techniques for Your Product...Software Project Health Check: Best Practices and Techniques for Your Product...
Software Project Health Check: Best Practices and Techniques for Your Product...Velvetech LLC
 
Balasore Best It Company|| Top 10 IT Company || Balasore Software company Odisha
Balasore Best It Company|| Top 10 IT Company || Balasore Software company OdishaBalasore Best It Company|| Top 10 IT Company || Balasore Software company Odisha
Balasore Best It Company|| Top 10 IT Company || Balasore Software company Odishasmiwainfosol
 
Large Language Models for Test Case Evolution and Repair
Large Language Models for Test Case Evolution and RepairLarge Language Models for Test Case Evolution and Repair
Large Language Models for Test Case Evolution and RepairLionel Briand
 
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...OnePlan Solutions
 
20240415 [Container Plumbing Days] Usernetes Gen2 - Kubernetes in Rootless Do...
20240415 [Container Plumbing Days] Usernetes Gen2 - Kubernetes in Rootless Do...20240415 [Container Plumbing Days] Usernetes Gen2 - Kubernetes in Rootless Do...
20240415 [Container Plumbing Days] Usernetes Gen2 - Kubernetes in Rootless Do...Akihiro Suda
 
MYjobs Presentation Django-based project
MYjobs Presentation Django-based projectMYjobs Presentation Django-based project
MYjobs Presentation Django-based projectAnoyGreter
 
SensoDat: Simulation-based Sensor Dataset of Self-driving Cars
SensoDat: Simulation-based Sensor Dataset of Self-driving CarsSensoDat: Simulation-based Sensor Dataset of Self-driving Cars
SensoDat: Simulation-based Sensor Dataset of Self-driving CarsChristian Birchler
 
Sending Calendar Invites on SES and Calendarsnack.pdf
Sending Calendar Invites on SES and Calendarsnack.pdfSending Calendar Invites on SES and Calendarsnack.pdf
Sending Calendar Invites on SES and Calendarsnack.pdf31events.com
 
Catch the Wave: SAP Event-Driven and Data Streaming for the Intelligence Ente...
Catch the Wave: SAP Event-Driven and Data Streaming for the Intelligence Ente...Catch the Wave: SAP Event-Driven and Data Streaming for the Intelligence Ente...
Catch the Wave: SAP Event-Driven and Data Streaming for the Intelligence Ente...confluent
 
UI5ers live - Custom Controls wrapping 3rd-party libs.pptx
UI5ers live - Custom Controls wrapping 3rd-party libs.pptxUI5ers live - Custom Controls wrapping 3rd-party libs.pptx
UI5ers live - Custom Controls wrapping 3rd-party libs.pptxAndreas Kunz
 

Dernier (20)

Unveiling the Future: Sylius 2.0 New Features
Unveiling the Future: Sylius 2.0 New FeaturesUnveiling the Future: Sylius 2.0 New Features
Unveiling the Future: Sylius 2.0 New Features
 
React Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief UtamaReact Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief Utama
 
Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...
Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...
Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...
 
Post Quantum Cryptography – The Impact on Identity
Post Quantum Cryptography – The Impact on IdentityPost Quantum Cryptography – The Impact on Identity
Post Quantum Cryptography – The Impact on Identity
 
Implementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with AzureImplementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with Azure
 
Taming Distributed Systems: Key Insights from Wix's Large-Scale Experience - ...
Taming Distributed Systems: Key Insights from Wix's Large-Scale Experience - ...Taming Distributed Systems: Key Insights from Wix's Large-Scale Experience - ...
Taming Distributed Systems: Key Insights from Wix's Large-Scale Experience - ...
 
Comparing Linux OS Image Update Models - EOSS 2024.pdf
Comparing Linux OS Image Update Models - EOSS 2024.pdfComparing Linux OS Image Update Models - EOSS 2024.pdf
Comparing Linux OS Image Update Models - EOSS 2024.pdf
 
Powering Real-Time Decisions with Continuous Data Streams
Powering Real-Time Decisions with Continuous Data StreamsPowering Real-Time Decisions with Continuous Data Streams
Powering Real-Time Decisions with Continuous Data Streams
 
Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)
Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)
Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)
 
Ahmed Motair CV April 2024 (Senior SW Developer)
Ahmed Motair CV April 2024 (Senior SW Developer)Ahmed Motair CV April 2024 (Senior SW Developer)
Ahmed Motair CV April 2024 (Senior SW Developer)
 
Software Project Health Check: Best Practices and Techniques for Your Product...
Software Project Health Check: Best Practices and Techniques for Your Product...Software Project Health Check: Best Practices and Techniques for Your Product...
Software Project Health Check: Best Practices and Techniques for Your Product...
 
Balasore Best It Company|| Top 10 IT Company || Balasore Software company Odisha
Balasore Best It Company|| Top 10 IT Company || Balasore Software company OdishaBalasore Best It Company|| Top 10 IT Company || Balasore Software company Odisha
Balasore Best It Company|| Top 10 IT Company || Balasore Software company Odisha
 
Large Language Models for Test Case Evolution and Repair
Large Language Models for Test Case Evolution and RepairLarge Language Models for Test Case Evolution and Repair
Large Language Models for Test Case Evolution and Repair
 
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
 
20240415 [Container Plumbing Days] Usernetes Gen2 - Kubernetes in Rootless Do...
20240415 [Container Plumbing Days] Usernetes Gen2 - Kubernetes in Rootless Do...20240415 [Container Plumbing Days] Usernetes Gen2 - Kubernetes in Rootless Do...
20240415 [Container Plumbing Days] Usernetes Gen2 - Kubernetes in Rootless Do...
 
MYjobs Presentation Django-based project
MYjobs Presentation Django-based projectMYjobs Presentation Django-based project
MYjobs Presentation Django-based project
 
SensoDat: Simulation-based Sensor Dataset of Self-driving Cars
SensoDat: Simulation-based Sensor Dataset of Self-driving CarsSensoDat: Simulation-based Sensor Dataset of Self-driving Cars
SensoDat: Simulation-based Sensor Dataset of Self-driving Cars
 
Sending Calendar Invites on SES and Calendarsnack.pdf
Sending Calendar Invites on SES and Calendarsnack.pdfSending Calendar Invites on SES and Calendarsnack.pdf
Sending Calendar Invites on SES and Calendarsnack.pdf
 
Catch the Wave: SAP Event-Driven and Data Streaming for the Intelligence Ente...
Catch the Wave: SAP Event-Driven and Data Streaming for the Intelligence Ente...Catch the Wave: SAP Event-Driven and Data Streaming for the Intelligence Ente...
Catch the Wave: SAP Event-Driven and Data Streaming for the Intelligence Ente...
 
UI5ers live - Custom Controls wrapping 3rd-party libs.pptx
UI5ers live - Custom Controls wrapping 3rd-party libs.pptxUI5ers live - Custom Controls wrapping 3rd-party libs.pptx
UI5ers live - Custom Controls wrapping 3rd-party libs.pptx
 

Responsible DI: Ditch the Frameworks