SlideShare a Scribd company logo
Testable JavaScript
Architecting Your Application for
Testability
Mark Ethan Trostler
Google Inc.
twitter: @zzoass
mark@zzo.com
Loose
Coupling
Tight
Focus
No
Surprises
What Is Testability?
Minimal
Tedium
Swap
Implementations
Work/Test in
Parallel
Interfaces not Implementation
Write Tests
Once
Interfaces not Implementation
var UserRepository = {
get: function(id) {}
, save: function(user) {}
, getAll: function() {}
, edit: function(id, user) {}
, delete: function(id) {}
, query: function(query) {}
};
Interfaces not Implementation
function test(repo) {
var id = 99, user = { id: id, ... };
repo.save(user);
expect(repo.get(id)).toEqual(user);
}
Test the interface
Interfaces not Implementation
var UserRepoRedis = function(host, port, opt) {
this.redis = redis.createClient({ ... });
};
UserRepoRedis.prototype =
Object.create(UserRepo);
UserRepoRedis.prototype.save =
function(user) { ... };
Interfaces not Implementation
• Object is interface - no initialization
• Implementation has constructor with
injected dependencies
• Prototype is Object.create(Interface)
• Override with prototype functions
Interfaces not Implementation
function test(repo) {
var user = { ... };
repo.save(user);
expect(repo.get(id)).toEqual(user);
}
var repo = new UserRepoRedis(host, port, opt);
test(repo);
Test the interface
Interfaces not Implementation
var UserRepoS3 = function(key, secret, bucket) {
this.s3 = knox.createClient({...});
};
UserRepoS3.prototype = Object.create(UserRepo);
UserRepoS3.prototype.save =
function(user) { ... }
Interfaces not Implementation
function test(repo) {
var id = 99, user = { id: id, ... };
repo.save(user);
expect(repo.get(id)).toEqual(user);
}
var repo = new UserRepoS3(key, secret, bucket);
test(repo);
Test the interface
Single Responsibility Principle
Every interface should have a single
responsibility, and that responsibility
should be entirely encapsulated by
the interface.
Responsibility = Reason To Change
Interface Segregation Principle
No object should be forced
to depend on methods it
does not use.
Interface Pattern
• Single Responsibility Principle
• Match Sets with Gets
• More Smaller / Fewer Bigger
• Interface Segregation Principle
• Test and Program to Interface Only
Using Interfaces
You've created nice interfaces - use them
wisely!
// DO NOT DO THIS!
var UserController = function() {
this.userRepo = new UserRepoRedis();
};
Using Interfaces
You've created nice interfaces - use them
wisely!
// DO THIS - Inject the dependencies!
var UserController = function(userRepo) {
this.userRepo = userRepo;
};
Liskov Substitution Principle
Any objects that implement
an interface can be used
interchangeably
Constructor Injection
All dependencies should be injected into your
object's constructor*.
•  Make dependencies explicit
•  Loose coupling
•  Cannot instantiate a non-usable Object
* Except:
•  runtime dependencies
•  objects with a shorter lifetime
Instantiating Implementations
So do all dependees need to provide fully
initialized objects to their dependents when
instantiating them?
NO - THEY DO NOT INSTANTIATE THEM!
Object Creation vs. Object Use
•  ensures a loosely coupled system
•  ensures testability
Object Creation vs. Object Use
creation
Happens one time at the Composition Root.
All Objects* are created/wired together at
this time
•  startup
•  Request
use
Happens all the time throughout the application
Object Creation
What creates the objects?
Forces specification of dependencies and
their lifespan
•  DIY DI
•  wire.js / cujojs
•  Inverted
•  Intravenous
•  AngularJS
whole lotta others...
Cross-Cutting Concerns
What about the crap I might need?
•  Logging
•  Auditing
•  Profiling
•  Security
•  Caching
•  ....
"Cross-cutting concerns"
Cross-Cutting Concerns
// DO NOT DO THIS:
UserRepoRedis = function(...) {
this.redis = ...
this.logger = new Logger(); // or Logger.get()
this.profiler = new Profiler(); // or Profiler.get()
};
•  tightly coupled to Logger & Profiler
implementations
•  PITA to test
Cross-Cutting Concerns
// DO NOT DO THIS:
UserRepoRedis = function(..., logger, profiler) {
this.redis = ...
this.logger = logger;
this.profiler = profiler;
};
Injection - so looks good BUT violating SRP!
Cross-Cutting Concerns
// DO NOT DO THIS:
UserRepoRedis.prototype.save =
function(user) {
logger.log('Saving user: ' + user);
profiler.startProfiling('saveUser');
... do redis/actual save user stuff ...
profiler.stopProfiling('saveUser');
logger.log('that took: ' + (start - end));
};
Cross-Cutting Concerns
•  Keep different functionality separate
•  Single Responsibility Principle
•  Interface Segregation Principle
var LoggerFile = function(file) { // Implementation
this.file = file;
}
LoggerFile.prototype = Object.create(Logger);
LoggerFile.prototype.log = function(msg) {
this.file.write(msg);
};
Logging Interface and Implementation
var Logger = { // Interface
log: function(msg) {}
, getLastLog: function() {} // get it out!
};
Mixin method - quick aside...
// Composition not inheritance
var MIXIN = function(base, extendme) {
var prop;
for (prop in base) {
if (typeof base[prop] === 'function'
&& !extendme[prop]) {
extendme[prop] = base[prop].bind(base);
}
}
};
Decorator
var UserRepoLogger = function(repo, logger) {
this.innerRepo = repo;
this.logger = logger;
MIXIN(repo, this); // Mixin repo's methods
};
UserRepoLogger.prototype.save =
function(user) {
this.logger.log('Saving user: ' + user);
return this.innerRepo.save(user);
};
Decorator
// UserRepoLogger will Intercept save
// all other methods will fall thru to
// UserRepoRedis
// This userRepo implements the UserRepo
// interface therefore can be used anywhere
var userRepo =
new UserRepoLogger(
new UserRepoRedis()
, new LoggerFile()
);
var ProfilerTime = function() { this.profiles = {}; };
ProfilerTime.prototype = Object.create(Profiler);
ProfilerTime.prototype.start = function(id) {
this.profiles[id] = new Date().getTimestamp();
};
ProfilerTime.prototype.stop = function(id) { ... };
....
Profile Interface and Implementation
var Profiler = { // Interface
start: function(id) {}
, stop: function(id) {}
, getProfile: function(id) {} // get it out!
};
Decorator
var UserRepoProfiler = function(repo, profiler) {
this.innerRepo = repo;
this.profiler = profiler;
MIXIN(repo, this); // Mixin repo's methods
};
UserRepoProfiler.prototype.save = f(user) {
this.profiler.start('save user');
this.innerRepo.save(user);
this.profiler.stop('save user');
Intercept
var redisRepo = new UserRepoRedis();
var profiler = new ProfilerTime();
var logger = new LoggerFile();
// Profiling UserRepo
var userRepoProf =
new UserRepoProfiler(redisRepo, profiler);
// Logging Profiling UserRepo
var userRepo =
new UserRepoLogger(userRepoProf, logger);
Testing Decorators
Create the Decorator and Test the Interface:
function testUserRepoLogger(repo) {
var id = 99, user = { id: id, ... },
loggerMock = new LoggerMock(),
testRepo =
new UserRepoLogger(repo, loggerMock);
testRepo.save(user);
// verify loggerMock
}
Testing Decorators
var repo = new UserRepoMock();
var logger = new LoggerMock();
var profiler = new ProfileMock();
var userRepo = new UserRepoProfile(
new UserRepoLogger(repo, logger), profiler);
// test UserRepo interface
testRepo(userRepo);
// verify logger and profiler mocks
Decorator Pattern
•  Constructor accepts 'inner' Object of the
same type and any other necessary
dependencies.
•  Mixin with 'inner' Object to get default
behavior for non-decorated methods.
•  Decorate necessary interface methods and
(optionally) delegate to 'inner' Object.
var FindMatchesDistance = f(userRepo) { ... };
FindMatchesDistance.prototype =
Object.create(FindMatches);
var FindMatchesActivites = f(userRepo) { ... };
var FindMatchesLikes = f(userRepo) { ... };
Runtime/Short-lived Dependencies
var FindMatches = {
matches: function(userid) {}
};
Runtime/Short-lived Dependencies
// User Controller needs a findMatches
// implementation - but which one???
var UserController = function(findMatches, ...) {
....
}
Inject all three?? What if I make more? What if
other classes need a dynamic findMatch
implementation?
var FindMatchFactoryImp = function(repo) {
this.repo = repo;
};
FindMatchFactoryImpl.prototype =
Object.create(FindMatchFactory);
Runtime/Short-lived Dependencies
var FindMatchFactory = {
getMatchImplementation: function(type) {}
};
Runtime/Short-lived Dependencies
getMatchImplementation = function(type) {
switch(type) {
case 'likes':
return new FindMatchesLikes(this.repo);
break;
....
default:
return new FindMatchesActivites(this.repo);
}
};
Runtime/Short-lived Dependencies
var UserController = function(findMatchFactory) {
this.findMatchFactory = findMatchFactory;
};
UserController.prototype = Object.create(Controller);
UserController.prototype.findMatches = function(type, uid) {
var matcher =
this.findMatchFactory.getMatchImplementation(type);
return matcher.matches(uid);
};
Testing Abstract Factories
var matchTypes = [
{ name: 'likes', type: FindMatchesLikes }
, ....
];
test(findMatchFactory) {
matchTypes.forEach(function(type) {
expect(
findMatchFactory
.getMatchImplementation(type.name)
.toEqual(type.type);
});
}
Mocking Abstract Factories
var TestFactoryImpl = function(expectedType, mockMatch) {
this.expectedType = expectedType;
this.mockMach = mockMatch;
};
TestFactoryImpl.prototype = Object.create(FindMatchFactory);
TestFactoryImpl.prototype.getMatchImplementation(type) {
expect(type).toEqual(this.expectedType);
return this.mockMatch;
};
Abstract Factory Pattern
•  Abstract factory translates runtime
parameter -> Dependency
•  Factory implementation created at
Composition Root along with everything
else
•  Inject factory implementation into the
Constructor for runtime dependencies
•  Object uses injected factory to get
Dependency providing Runtime Value
Testable JavaScript
•  Composition not Inheritance (impl. lock-in)
•  Program and Test to Interfaces / Interfaces are
the API
•  Create lots of small Single Responsibility
Interfaces
•  Decorate and Intercept Cross-Cutting Concerns
•  Constructor Inject all Dependencies
•  Inject Abstract Factory for run-time
Dependencies
Ensuring Testability

More Related Content

What's hot

Javascript Prototype Visualized
Javascript Prototype VisualizedJavascript Prototype Visualized
Javascript Prototype Visualized
军 沈
 
Javascript basics for automation testing
Javascript  basics for automation testingJavascript  basics for automation testing
Javascript basics for automation testing
Vikas Thange
 
Annotation Processing - Demystifying Java's Dark Arts
Annotation Processing - Demystifying Java's Dark ArtsAnnotation Processing - Demystifying Java's Dark Arts
Annotation Processing - Demystifying Java's Dark Arts
James Kirkbride
 
Javascript closures
Javascript closures Javascript closures
Javascript closures
VNG
 
Spring boot
Spring bootSpring boot
Javascript basic course
Javascript basic courseJavascript basic course
Javascript basic courseTran Khoa
 
JavaScript Basics and Best Practices - CC FE & UX
JavaScript Basics and Best Practices - CC FE & UXJavaScript Basics and Best Practices - CC FE & UX
JavaScript Basics and Best Practices - CC FE & UX
JWORKS powered by Ordina
 
JavaScript Programming
JavaScript ProgrammingJavaScript Programming
JavaScript Programming
Sehwan Noh
 
Object Oriented Programming in JavaScript
Object Oriented Programming in JavaScriptObject Oriented Programming in JavaScript
Object Oriented Programming in JavaScriptzand3rs
 
EMF Tips n Tricks
EMF Tips n TricksEMF Tips n Tricks
EMF Tips n Tricks
Kaniska Mandal
 
A Deeper look into Javascript Basics
A Deeper look into Javascript BasicsA Deeper look into Javascript Basics
A Deeper look into Javascript Basics
Mindfire Solutions
 
Making Java more dynamic: runtime code generation for the JVM
Making Java more dynamic: runtime code generation for the JVMMaking Java more dynamic: runtime code generation for the JVM
Making Java more dynamic: runtime code generation for the JVM
Rafael Winterhalter
 
JavaScript - From Birth To Closure
JavaScript - From Birth To ClosureJavaScript - From Birth To Closure
JavaScript - From Birth To Closure
Robert Nyman
 
The JavaScript Programming Language
The JavaScript Programming LanguageThe JavaScript Programming Language
The JavaScript Programming Language
Raghavan Mohan
 
Maintainable JavaScript 2011
Maintainable JavaScript 2011Maintainable JavaScript 2011
Maintainable JavaScript 2011
Nicholas Zakas
 
Advanced javascript
Advanced javascriptAdvanced javascript
Advanced javascript
Doeun KOCH
 
Bytecode manipulation with Javassist and ASM
Bytecode manipulation with Javassist and ASMBytecode manipulation with Javassist and ASM
Bytecode manipulation with Javassist and ASM
ashleypuls
 
Design pattern is_everywhere_by_saurabh_sharma
Design pattern is_everywhere_by_saurabh_sharmaDesign pattern is_everywhere_by_saurabh_sharma
Design pattern is_everywhere_by_saurabh_sharma
Saurabh Sharma
 

What's hot (20)

Javascript Prototype Visualized
Javascript Prototype VisualizedJavascript Prototype Visualized
Javascript Prototype Visualized
 
Javascript basics for automation testing
Javascript  basics for automation testingJavascript  basics for automation testing
Javascript basics for automation testing
 
Annotation Processing - Demystifying Java's Dark Arts
Annotation Processing - Demystifying Java's Dark ArtsAnnotation Processing - Demystifying Java's Dark Arts
Annotation Processing - Demystifying Java's Dark Arts
 
Javascript closures
Javascript closures Javascript closures
Javascript closures
 
Spring boot
Spring bootSpring boot
Spring boot
 
Javascript
JavascriptJavascript
Javascript
 
Javascript basic course
Javascript basic courseJavascript basic course
Javascript basic course
 
JavaScript Basics and Best Practices - CC FE & UX
JavaScript Basics and Best Practices - CC FE & UXJavaScript Basics and Best Practices - CC FE & UX
JavaScript Basics and Best Practices - CC FE & UX
 
JavaScript Programming
JavaScript ProgrammingJavaScript Programming
JavaScript Programming
 
Object Oriented Programming in JavaScript
Object Oriented Programming in JavaScriptObject Oriented Programming in JavaScript
Object Oriented Programming in JavaScript
 
EMF Tips n Tricks
EMF Tips n TricksEMF Tips n Tricks
EMF Tips n Tricks
 
A Deeper look into Javascript Basics
A Deeper look into Javascript BasicsA Deeper look into Javascript Basics
A Deeper look into Javascript Basics
 
Making Java more dynamic: runtime code generation for the JVM
Making Java more dynamic: runtime code generation for the JVMMaking Java more dynamic: runtime code generation for the JVM
Making Java more dynamic: runtime code generation for the JVM
 
JavaScript - From Birth To Closure
JavaScript - From Birth To ClosureJavaScript - From Birth To Closure
JavaScript - From Birth To Closure
 
The JavaScript Programming Language
The JavaScript Programming LanguageThe JavaScript Programming Language
The JavaScript Programming Language
 
Maintainable JavaScript 2011
Maintainable JavaScript 2011Maintainable JavaScript 2011
Maintainable JavaScript 2011
 
Advanced javascript
Advanced javascriptAdvanced javascript
Advanced javascript
 
Core concepts-javascript
Core concepts-javascriptCore concepts-javascript
Core concepts-javascript
 
Bytecode manipulation with Javassist and ASM
Bytecode manipulation with Javassist and ASMBytecode manipulation with Javassist and ASM
Bytecode manipulation with Javassist and ASM
 
Design pattern is_everywhere_by_saurabh_sharma
Design pattern is_everywhere_by_saurabh_sharmaDesign pattern is_everywhere_by_saurabh_sharma
Design pattern is_everywhere_by_saurabh_sharma
 

Similar to Testable JavaScript: Application Architecture

Build Web Apps using Node.js
Build Web Apps using Node.jsBuild Web Apps using Node.js
Build Web Apps using Node.js
davidchubbs
 
Intro To JavaScript Unit Testing - Ran Mizrahi
Intro To JavaScript Unit Testing - Ran MizrahiIntro To JavaScript Unit Testing - Ran Mizrahi
Intro To JavaScript Unit Testing - Ran MizrahiRan Mizrahi
 
Android best practices
Android best practicesAndroid best practices
Android best practices
Jose Manuel Ortega Candel
 
Annotation Processing
Annotation ProcessingAnnotation Processing
Annotation Processing
Jintin Lin
 
JavaScript Growing Up
JavaScript Growing UpJavaScript Growing Up
JavaScript Growing UpDavid Padbury
 
Dev fest kyoto_2021-flutter_test
Dev fest kyoto_2021-flutter_testDev fest kyoto_2021-flutter_test
Dev fest kyoto_2021-flutter_test
Masanori Kato
 
2. Design patterns. part #2
2. Design patterns. part #22. Design patterns. part #2
2. Design patterns. part #2
Leonid Maslov
 
Ember.js - A JavaScript framework for creating ambitious web applications
Ember.js - A JavaScript framework for creating ambitious web applications  Ember.js - A JavaScript framework for creating ambitious web applications
Ember.js - A JavaScript framework for creating ambitious web applications
Juliana Lucena
 
TypeScript for Java Developers
TypeScript for Java DevelopersTypeScript for Java Developers
TypeScript for Java Developers
Yakov Fain
 
Concurrency and Thread-Safe Data Processing in Background Tasks
Concurrency and Thread-Safe Data Processing in Background TasksConcurrency and Thread-Safe Data Processing in Background Tasks
Concurrency and Thread-Safe Data Processing in Background TasksWO Community
 
Workshop 23: ReactJS, React & Redux testing
Workshop 23: ReactJS, React & Redux testingWorkshop 23: ReactJS, React & Redux testing
Workshop 23: ReactJS, React & Redux testing
Visual Engineering
 
Annotation processing tool
Annotation processing toolAnnotation processing tool
Annotation processing tool
Andrzej Ludwikowski
 
Grails unit testing
Grails unit testingGrails unit testing
Grails unit testing
pleeps
 
JDD 2016 - Grzegorz Rozniecki - Java 8 What Could Possibly Go Wrong
JDD 2016 - Grzegorz Rozniecki - Java 8 What Could Possibly Go WrongJDD 2016 - Grzegorz Rozniecki - Java 8 What Could Possibly Go Wrong
JDD 2016 - Grzegorz Rozniecki - Java 8 What Could Possibly Go Wrong
PROIDEA
 
Lambda Chops - Recipes for Simpler, More Expressive Code
Lambda Chops - Recipes for Simpler, More Expressive CodeLambda Chops - Recipes for Simpler, More Expressive Code
Lambda Chops - Recipes for Simpler, More Expressive Code
Ian Robertson
 
OpenWebBeans and DeltaSpike at ApacheCon
OpenWebBeans and DeltaSpike at ApacheConOpenWebBeans and DeltaSpike at ApacheCon
OpenWebBeans and DeltaSpike at ApacheCon
os890
 
How and why i roll my own node.js framework
How and why i roll my own node.js frameworkHow and why i roll my own node.js framework
How and why i roll my own node.js frameworkBen Lin
 
ES6 metaprogramming unleashed
ES6 metaprogramming unleashedES6 metaprogramming unleashed
ES6 metaprogramming unleashed
Javier Arias Losada
 
What's Coming in Spring 3.0
What's Coming in Spring 3.0What's Coming in Spring 3.0
What's Coming in Spring 3.0
Matt Raible
 
TWINS: OOP and FP - Warburton
TWINS: OOP and FP - WarburtonTWINS: OOP and FP - Warburton
TWINS: OOP and FP - Warburton
Codemotion
 

Similar to Testable JavaScript: Application Architecture (20)

Build Web Apps using Node.js
Build Web Apps using Node.jsBuild Web Apps using Node.js
Build Web Apps using Node.js
 
Intro To JavaScript Unit Testing - Ran Mizrahi
Intro To JavaScript Unit Testing - Ran MizrahiIntro To JavaScript Unit Testing - Ran Mizrahi
Intro To JavaScript Unit Testing - Ran Mizrahi
 
Android best practices
Android best practicesAndroid best practices
Android best practices
 
Annotation Processing
Annotation ProcessingAnnotation Processing
Annotation Processing
 
JavaScript Growing Up
JavaScript Growing UpJavaScript Growing Up
JavaScript Growing Up
 
Dev fest kyoto_2021-flutter_test
Dev fest kyoto_2021-flutter_testDev fest kyoto_2021-flutter_test
Dev fest kyoto_2021-flutter_test
 
2. Design patterns. part #2
2. Design patterns. part #22. Design patterns. part #2
2. Design patterns. part #2
 
Ember.js - A JavaScript framework for creating ambitious web applications
Ember.js - A JavaScript framework for creating ambitious web applications  Ember.js - A JavaScript framework for creating ambitious web applications
Ember.js - A JavaScript framework for creating ambitious web applications
 
TypeScript for Java Developers
TypeScript for Java DevelopersTypeScript for Java Developers
TypeScript for Java Developers
 
Concurrency and Thread-Safe Data Processing in Background Tasks
Concurrency and Thread-Safe Data Processing in Background TasksConcurrency and Thread-Safe Data Processing in Background Tasks
Concurrency and Thread-Safe Data Processing in Background Tasks
 
Workshop 23: ReactJS, React & Redux testing
Workshop 23: ReactJS, React & Redux testingWorkshop 23: ReactJS, React & Redux testing
Workshop 23: ReactJS, React & Redux testing
 
Annotation processing tool
Annotation processing toolAnnotation processing tool
Annotation processing tool
 
Grails unit testing
Grails unit testingGrails unit testing
Grails unit testing
 
JDD 2016 - Grzegorz Rozniecki - Java 8 What Could Possibly Go Wrong
JDD 2016 - Grzegorz Rozniecki - Java 8 What Could Possibly Go WrongJDD 2016 - Grzegorz Rozniecki - Java 8 What Could Possibly Go Wrong
JDD 2016 - Grzegorz Rozniecki - Java 8 What Could Possibly Go Wrong
 
Lambda Chops - Recipes for Simpler, More Expressive Code
Lambda Chops - Recipes for Simpler, More Expressive CodeLambda Chops - Recipes for Simpler, More Expressive Code
Lambda Chops - Recipes for Simpler, More Expressive Code
 
OpenWebBeans and DeltaSpike at ApacheCon
OpenWebBeans and DeltaSpike at ApacheConOpenWebBeans and DeltaSpike at ApacheCon
OpenWebBeans and DeltaSpike at ApacheCon
 
How and why i roll my own node.js framework
How and why i roll my own node.js frameworkHow and why i roll my own node.js framework
How and why i roll my own node.js framework
 
ES6 metaprogramming unleashed
ES6 metaprogramming unleashedES6 metaprogramming unleashed
ES6 metaprogramming unleashed
 
What's Coming in Spring 3.0
What's Coming in Spring 3.0What's Coming in Spring 3.0
What's Coming in Spring 3.0
 
TWINS: OOP and FP - Warburton
TWINS: OOP and FP - WarburtonTWINS: OOP and FP - Warburton
TWINS: OOP and FP - Warburton
 

Recently uploaded

GraphSummit Singapore | Neo4j Product Vision & Roadmap - Q2 2024
GraphSummit Singapore | Neo4j Product Vision & Roadmap - Q2 2024GraphSummit Singapore | Neo4j Product Vision & Roadmap - Q2 2024
GraphSummit Singapore | Neo4j Product Vision & Roadmap - Q2 2024
Neo4j
 
20240609 QFM020 Irresponsible AI Reading List May 2024
20240609 QFM020 Irresponsible AI Reading List May 202420240609 QFM020 Irresponsible AI Reading List May 2024
20240609 QFM020 Irresponsible AI Reading List May 2024
Matthew Sinclair
 
DevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA ConnectDevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA Connect
Kari Kakkonen
 
Climate Impact of Software Testing at Nordic Testing Days
Climate Impact of Software Testing at Nordic Testing DaysClimate Impact of Software Testing at Nordic Testing Days
Climate Impact of Software Testing at Nordic Testing Days
Kari Kakkonen
 
zkStudyClub - Reef: Fast Succinct Non-Interactive Zero-Knowledge Regex Proofs
zkStudyClub - Reef: Fast Succinct Non-Interactive Zero-Knowledge Regex ProofszkStudyClub - Reef: Fast Succinct Non-Interactive Zero-Knowledge Regex Proofs
zkStudyClub - Reef: Fast Succinct Non-Interactive Zero-Knowledge Regex Proofs
Alex Pruden
 
Video Streaming: Then, Now, and in the Future
Video Streaming: Then, Now, and in the FutureVideo Streaming: Then, Now, and in the Future
Video Streaming: Then, Now, and in the Future
Alpen-Adria-Universität
 
Observability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdf
Observability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdfObservability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdf
Observability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdf
Paige Cruz
 
Uni Systems Copilot event_05062024_C.Vlachos.pdf
Uni Systems Copilot event_05062024_C.Vlachos.pdfUni Systems Copilot event_05062024_C.Vlachos.pdf
Uni Systems Copilot event_05062024_C.Vlachos.pdf
Uni Systems S.M.S.A.
 
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
James Anderson
 
The Art of the Pitch: WordPress Relationships and Sales
The Art of the Pitch: WordPress Relationships and SalesThe Art of the Pitch: WordPress Relationships and Sales
The Art of the Pitch: WordPress Relationships and Sales
Laura Byrne
 
20240605 QFM017 Machine Intelligence Reading List May 2024
20240605 QFM017 Machine Intelligence Reading List May 202420240605 QFM017 Machine Intelligence Reading List May 2024
20240605 QFM017 Machine Intelligence Reading List May 2024
Matthew Sinclair
 
GraphSummit Singapore | The Future of Agility: Supercharging Digital Transfor...
GraphSummit Singapore | The Future of Agility: Supercharging Digital Transfor...GraphSummit Singapore | The Future of Agility: Supercharging Digital Transfor...
GraphSummit Singapore | The Future of Agility: Supercharging Digital Transfor...
Neo4j
 
UiPath Test Automation using UiPath Test Suite series, part 5
UiPath Test Automation using UiPath Test Suite series, part 5UiPath Test Automation using UiPath Test Suite series, part 5
UiPath Test Automation using UiPath Test Suite series, part 5
DianaGray10
 
Removing Uninteresting Bytes in Software Fuzzing
Removing Uninteresting Bytes in Software FuzzingRemoving Uninteresting Bytes in Software Fuzzing
Removing Uninteresting Bytes in Software Fuzzing
Aftab Hussain
 
Mind map of terminologies used in context of Generative AI
Mind map of terminologies used in context of Generative AIMind map of terminologies used in context of Generative AI
Mind map of terminologies used in context of Generative AI
Kumud Singh
 
Introduction to CHERI technology - Cybersecurity
Introduction to CHERI technology - CybersecurityIntroduction to CHERI technology - Cybersecurity
Introduction to CHERI technology - Cybersecurity
mikeeftimakis1
 
A tale of scale & speed: How the US Navy is enabling software delivery from l...
A tale of scale & speed: How the US Navy is enabling software delivery from l...A tale of scale & speed: How the US Navy is enabling software delivery from l...
A tale of scale & speed: How the US Navy is enabling software delivery from l...
sonjaschweigert1
 
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
DanBrown980551
 
PCI PIN Basics Webinar from the Controlcase Team
PCI PIN Basics Webinar from the Controlcase TeamPCI PIN Basics Webinar from the Controlcase Team
PCI PIN Basics Webinar from the Controlcase Team
ControlCase
 
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdfFIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance
 

Recently uploaded (20)

GraphSummit Singapore | Neo4j Product Vision & Roadmap - Q2 2024
GraphSummit Singapore | Neo4j Product Vision & Roadmap - Q2 2024GraphSummit Singapore | Neo4j Product Vision & Roadmap - Q2 2024
GraphSummit Singapore | Neo4j Product Vision & Roadmap - Q2 2024
 
20240609 QFM020 Irresponsible AI Reading List May 2024
20240609 QFM020 Irresponsible AI Reading List May 202420240609 QFM020 Irresponsible AI Reading List May 2024
20240609 QFM020 Irresponsible AI Reading List May 2024
 
DevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA ConnectDevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA Connect
 
Climate Impact of Software Testing at Nordic Testing Days
Climate Impact of Software Testing at Nordic Testing DaysClimate Impact of Software Testing at Nordic Testing Days
Climate Impact of Software Testing at Nordic Testing Days
 
zkStudyClub - Reef: Fast Succinct Non-Interactive Zero-Knowledge Regex Proofs
zkStudyClub - Reef: Fast Succinct Non-Interactive Zero-Knowledge Regex ProofszkStudyClub - Reef: Fast Succinct Non-Interactive Zero-Knowledge Regex Proofs
zkStudyClub - Reef: Fast Succinct Non-Interactive Zero-Knowledge Regex Proofs
 
Video Streaming: Then, Now, and in the Future
Video Streaming: Then, Now, and in the FutureVideo Streaming: Then, Now, and in the Future
Video Streaming: Then, Now, and in the Future
 
Observability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdf
Observability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdfObservability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdf
Observability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdf
 
Uni Systems Copilot event_05062024_C.Vlachos.pdf
Uni Systems Copilot event_05062024_C.Vlachos.pdfUni Systems Copilot event_05062024_C.Vlachos.pdf
Uni Systems Copilot event_05062024_C.Vlachos.pdf
 
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
 
The Art of the Pitch: WordPress Relationships and Sales
The Art of the Pitch: WordPress Relationships and SalesThe Art of the Pitch: WordPress Relationships and Sales
The Art of the Pitch: WordPress Relationships and Sales
 
20240605 QFM017 Machine Intelligence Reading List May 2024
20240605 QFM017 Machine Intelligence Reading List May 202420240605 QFM017 Machine Intelligence Reading List May 2024
20240605 QFM017 Machine Intelligence Reading List May 2024
 
GraphSummit Singapore | The Future of Agility: Supercharging Digital Transfor...
GraphSummit Singapore | The Future of Agility: Supercharging Digital Transfor...GraphSummit Singapore | The Future of Agility: Supercharging Digital Transfor...
GraphSummit Singapore | The Future of Agility: Supercharging Digital Transfor...
 
UiPath Test Automation using UiPath Test Suite series, part 5
UiPath Test Automation using UiPath Test Suite series, part 5UiPath Test Automation using UiPath Test Suite series, part 5
UiPath Test Automation using UiPath Test Suite series, part 5
 
Removing Uninteresting Bytes in Software Fuzzing
Removing Uninteresting Bytes in Software FuzzingRemoving Uninteresting Bytes in Software Fuzzing
Removing Uninteresting Bytes in Software Fuzzing
 
Mind map of terminologies used in context of Generative AI
Mind map of terminologies used in context of Generative AIMind map of terminologies used in context of Generative AI
Mind map of terminologies used in context of Generative AI
 
Introduction to CHERI technology - Cybersecurity
Introduction to CHERI technology - CybersecurityIntroduction to CHERI technology - Cybersecurity
Introduction to CHERI technology - Cybersecurity
 
A tale of scale & speed: How the US Navy is enabling software delivery from l...
A tale of scale & speed: How the US Navy is enabling software delivery from l...A tale of scale & speed: How the US Navy is enabling software delivery from l...
A tale of scale & speed: How the US Navy is enabling software delivery from l...
 
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
 
PCI PIN Basics Webinar from the Controlcase Team
PCI PIN Basics Webinar from the Controlcase TeamPCI PIN Basics Webinar from the Controlcase Team
PCI PIN Basics Webinar from the Controlcase Team
 
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdfFIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
 

Testable JavaScript: Application Architecture

  • 1. Testable JavaScript Architecting Your Application for Testability Mark Ethan Trostler Google Inc. twitter: @zzoass mark@zzo.com
  • 3.
  • 5. Interfaces not Implementation var UserRepository = { get: function(id) {} , save: function(user) {} , getAll: function() {} , edit: function(id, user) {} , delete: function(id) {} , query: function(query) {} };
  • 6. Interfaces not Implementation function test(repo) { var id = 99, user = { id: id, ... }; repo.save(user); expect(repo.get(id)).toEqual(user); } Test the interface
  • 7. Interfaces not Implementation var UserRepoRedis = function(host, port, opt) { this.redis = redis.createClient({ ... }); }; UserRepoRedis.prototype = Object.create(UserRepo); UserRepoRedis.prototype.save = function(user) { ... };
  • 8. Interfaces not Implementation • Object is interface - no initialization • Implementation has constructor with injected dependencies • Prototype is Object.create(Interface) • Override with prototype functions
  • 9. Interfaces not Implementation function test(repo) { var user = { ... }; repo.save(user); expect(repo.get(id)).toEqual(user); } var repo = new UserRepoRedis(host, port, opt); test(repo); Test the interface
  • 10. Interfaces not Implementation var UserRepoS3 = function(key, secret, bucket) { this.s3 = knox.createClient({...}); }; UserRepoS3.prototype = Object.create(UserRepo); UserRepoS3.prototype.save = function(user) { ... }
  • 11. Interfaces not Implementation function test(repo) { var id = 99, user = { id: id, ... }; repo.save(user); expect(repo.get(id)).toEqual(user); } var repo = new UserRepoS3(key, secret, bucket); test(repo); Test the interface
  • 12. Single Responsibility Principle Every interface should have a single responsibility, and that responsibility should be entirely encapsulated by the interface. Responsibility = Reason To Change
  • 13. Interface Segregation Principle No object should be forced to depend on methods it does not use.
  • 14. Interface Pattern • Single Responsibility Principle • Match Sets with Gets • More Smaller / Fewer Bigger • Interface Segregation Principle • Test and Program to Interface Only
  • 15. Using Interfaces You've created nice interfaces - use them wisely! // DO NOT DO THIS! var UserController = function() { this.userRepo = new UserRepoRedis(); };
  • 16. Using Interfaces You've created nice interfaces - use them wisely! // DO THIS - Inject the dependencies! var UserController = function(userRepo) { this.userRepo = userRepo; };
  • 17. Liskov Substitution Principle Any objects that implement an interface can be used interchangeably
  • 18. Constructor Injection All dependencies should be injected into your object's constructor*. •  Make dependencies explicit •  Loose coupling •  Cannot instantiate a non-usable Object * Except: •  runtime dependencies •  objects with a shorter lifetime
  • 19. Instantiating Implementations So do all dependees need to provide fully initialized objects to their dependents when instantiating them? NO - THEY DO NOT INSTANTIATE THEM! Object Creation vs. Object Use •  ensures a loosely coupled system •  ensures testability
  • 20. Object Creation vs. Object Use creation Happens one time at the Composition Root. All Objects* are created/wired together at this time •  startup •  Request use Happens all the time throughout the application
  • 21. Object Creation What creates the objects? Forces specification of dependencies and their lifespan •  DIY DI •  wire.js / cujojs •  Inverted •  Intravenous •  AngularJS whole lotta others...
  • 22. Cross-Cutting Concerns What about the crap I might need? •  Logging •  Auditing •  Profiling •  Security •  Caching •  .... "Cross-cutting concerns"
  • 23. Cross-Cutting Concerns // DO NOT DO THIS: UserRepoRedis = function(...) { this.redis = ... this.logger = new Logger(); // or Logger.get() this.profiler = new Profiler(); // or Profiler.get() }; •  tightly coupled to Logger & Profiler implementations •  PITA to test
  • 24. Cross-Cutting Concerns // DO NOT DO THIS: UserRepoRedis = function(..., logger, profiler) { this.redis = ... this.logger = logger; this.profiler = profiler; }; Injection - so looks good BUT violating SRP!
  • 25. Cross-Cutting Concerns // DO NOT DO THIS: UserRepoRedis.prototype.save = function(user) { logger.log('Saving user: ' + user); profiler.startProfiling('saveUser'); ... do redis/actual save user stuff ... profiler.stopProfiling('saveUser'); logger.log('that took: ' + (start - end)); };
  • 26. Cross-Cutting Concerns •  Keep different functionality separate •  Single Responsibility Principle •  Interface Segregation Principle
  • 27. var LoggerFile = function(file) { // Implementation this.file = file; } LoggerFile.prototype = Object.create(Logger); LoggerFile.prototype.log = function(msg) { this.file.write(msg); }; Logging Interface and Implementation var Logger = { // Interface log: function(msg) {} , getLastLog: function() {} // get it out! };
  • 28. Mixin method - quick aside... // Composition not inheritance var MIXIN = function(base, extendme) { var prop; for (prop in base) { if (typeof base[prop] === 'function' && !extendme[prop]) { extendme[prop] = base[prop].bind(base); } } };
  • 29. Decorator var UserRepoLogger = function(repo, logger) { this.innerRepo = repo; this.logger = logger; MIXIN(repo, this); // Mixin repo's methods }; UserRepoLogger.prototype.save = function(user) { this.logger.log('Saving user: ' + user); return this.innerRepo.save(user); };
  • 30. Decorator // UserRepoLogger will Intercept save // all other methods will fall thru to // UserRepoRedis // This userRepo implements the UserRepo // interface therefore can be used anywhere var userRepo = new UserRepoLogger( new UserRepoRedis() , new LoggerFile() );
  • 31. var ProfilerTime = function() { this.profiles = {}; }; ProfilerTime.prototype = Object.create(Profiler); ProfilerTime.prototype.start = function(id) { this.profiles[id] = new Date().getTimestamp(); }; ProfilerTime.prototype.stop = function(id) { ... }; .... Profile Interface and Implementation var Profiler = { // Interface start: function(id) {} , stop: function(id) {} , getProfile: function(id) {} // get it out! };
  • 32. Decorator var UserRepoProfiler = function(repo, profiler) { this.innerRepo = repo; this.profiler = profiler; MIXIN(repo, this); // Mixin repo's methods }; UserRepoProfiler.prototype.save = f(user) { this.profiler.start('save user'); this.innerRepo.save(user); this.profiler.stop('save user');
  • 33. Intercept var redisRepo = new UserRepoRedis(); var profiler = new ProfilerTime(); var logger = new LoggerFile(); // Profiling UserRepo var userRepoProf = new UserRepoProfiler(redisRepo, profiler); // Logging Profiling UserRepo var userRepo = new UserRepoLogger(userRepoProf, logger);
  • 34. Testing Decorators Create the Decorator and Test the Interface: function testUserRepoLogger(repo) { var id = 99, user = { id: id, ... }, loggerMock = new LoggerMock(), testRepo = new UserRepoLogger(repo, loggerMock); testRepo.save(user); // verify loggerMock }
  • 35. Testing Decorators var repo = new UserRepoMock(); var logger = new LoggerMock(); var profiler = new ProfileMock(); var userRepo = new UserRepoProfile( new UserRepoLogger(repo, logger), profiler); // test UserRepo interface testRepo(userRepo); // verify logger and profiler mocks
  • 36. Decorator Pattern •  Constructor accepts 'inner' Object of the same type and any other necessary dependencies. •  Mixin with 'inner' Object to get default behavior for non-decorated methods. •  Decorate necessary interface methods and (optionally) delegate to 'inner' Object.
  • 37. var FindMatchesDistance = f(userRepo) { ... }; FindMatchesDistance.prototype = Object.create(FindMatches); var FindMatchesActivites = f(userRepo) { ... }; var FindMatchesLikes = f(userRepo) { ... }; Runtime/Short-lived Dependencies var FindMatches = { matches: function(userid) {} };
  • 38. Runtime/Short-lived Dependencies // User Controller needs a findMatches // implementation - but which one??? var UserController = function(findMatches, ...) { .... } Inject all three?? What if I make more? What if other classes need a dynamic findMatch implementation?
  • 39. var FindMatchFactoryImp = function(repo) { this.repo = repo; }; FindMatchFactoryImpl.prototype = Object.create(FindMatchFactory); Runtime/Short-lived Dependencies var FindMatchFactory = { getMatchImplementation: function(type) {} };
  • 40. Runtime/Short-lived Dependencies getMatchImplementation = function(type) { switch(type) { case 'likes': return new FindMatchesLikes(this.repo); break; .... default: return new FindMatchesActivites(this.repo); } };
  • 41. Runtime/Short-lived Dependencies var UserController = function(findMatchFactory) { this.findMatchFactory = findMatchFactory; }; UserController.prototype = Object.create(Controller); UserController.prototype.findMatches = function(type, uid) { var matcher = this.findMatchFactory.getMatchImplementation(type); return matcher.matches(uid); };
  • 42. Testing Abstract Factories var matchTypes = [ { name: 'likes', type: FindMatchesLikes } , .... ]; test(findMatchFactory) { matchTypes.forEach(function(type) { expect( findMatchFactory .getMatchImplementation(type.name) .toEqual(type.type); }); }
  • 43. Mocking Abstract Factories var TestFactoryImpl = function(expectedType, mockMatch) { this.expectedType = expectedType; this.mockMach = mockMatch; }; TestFactoryImpl.prototype = Object.create(FindMatchFactory); TestFactoryImpl.prototype.getMatchImplementation(type) { expect(type).toEqual(this.expectedType); return this.mockMatch; };
  • 44. Abstract Factory Pattern •  Abstract factory translates runtime parameter -> Dependency •  Factory implementation created at Composition Root along with everything else •  Inject factory implementation into the Constructor for runtime dependencies •  Object uses injected factory to get Dependency providing Runtime Value
  • 45. Testable JavaScript •  Composition not Inheritance (impl. lock-in) •  Program and Test to Interfaces / Interfaces are the API •  Create lots of small Single Responsibility Interfaces •  Decorate and Intercept Cross-Cutting Concerns •  Constructor Inject all Dependencies •  Inject Abstract Factory for run-time Dependencies