Slide 1

Slide 1 text

Applying the Adapter Pattern to Analytics ember-metrics ɾ D O C K YA R D ɾ

Slide 2

Slide 2 text

ohai dere

Slide 3

Slide 3 text

Lauren Tan DockYard Señorita Developer

Slide 4

Slide 4 text

How many of you have apps in production?

Slide 5

Slide 5 text

No content

Slide 6

Slide 6 text

No content

Slide 7

Slide 7 text

No content

Slide 8

Slide 8 text

ga('send', 'event', 'button', 'click', 'nav buttons', 4);

Slide 9

Slide 9 text

mixpanel.track('Clicked Nav Button', { value: 4 });

Slide 10

Slide 10 text

_kmq.push(['record', 'Clicked Nav Button', { value: 4 }]);

Slide 11

Slide 11 text

Slide 12

Slide 12 text

No content

Slide 13

Slide 13 text

y not

Slide 14

Slide 14 text

Ember.get(this, 'metrics').trackEvent({ name: 'Clicked nav button', category: 'Button', action: 'click', label: 'Nav buttons', value: 4 }); One API, do all the things

Slide 15

Slide 15 text

No content

Slide 16

Slide 16 text

I. What is the Adapter Pattern? II. Creating the Ember Metrics Addon III. Adapters and Blueprints

Slide 17

Slide 17 text

I. What is the Adapter Pattern? II. Creating the Ember Metrics Addon III. Adapters and Blueprints

Slide 18

Slide 18 text

Adapters in Finance http://jsbin.com/xawopi/edit?js,output

Slide 19

Slide 19 text

Acme Co wants to borrow $13,000

Slide 20

Slide 20 text

class Borrower { constructor(name, bank) { this.name = name; this.bank = bank; } loan(amount) { this.bank.lendTo(this, amount); // bank lends money to borrower } }

Slide 21

Slide 21 text

Milton has $10,000 Bill has $5,000 Michael has $5,000

Slide 22

Slide 22 text

class Lender { constructor(name, bank) { this.name = name; this.bank = bank; } deposit(amount) { this.bank.borrowFrom(this, amount); // bank borrows money from lender } }

Slide 23

Slide 23 text

Borrows from Lends from Adapter Client Adaptee

Slide 24

Slide 24 text

const piggyBank = new Bank(); const michael = new Lender('Michael Bolton', piggyBank); const milton = new Lender('Milton Waddams', piggyBank); const bill = new Lender('Bill Lumbergh', piggyBank); const acmeCo = new Borrower('Acme Co', piggyBank); michael.deposit(5000); milton.deposit(10000); bill.deposit(5000); console.log(piggyBank.cash()); // 20000 acmeCo.loan(13000); console.log(acmeCo.report()); // -13000 console.log(piggyBank.cash()); // 7000

Slide 25

Slide 25 text

The bank is the interface between lenders and borrowers

Slide 26

Slide 26 text

I. What is the Adapter Pattern? II. Creating the Ember Metrics Addon III.Adapters and Blueprints

Slide 27

Slide 27 text

$ ember install ember-metrics

Slide 28

Slide 28 text

module.exports = function(environment) { var ENV = { metricsAdapters: [ { name: 'GoogleAnalytics', config: { id: 'UA-XXXX-Y' } }, { name: 'Mixpanel', config: { token: 'xxx' } } ] } }

Slide 29

Slide 29 text

import Ember from 'ember'; export default Ember.Route.extend({ metrics: inject.service(), activate() { this._trackPage(); }, _trackPage() { run.scheduleOnce('afterRender', this, () => { const page = document.location.href; const title = this.routeName; get(this, 'metrics').trackPage({ page, title }); }); } });

Slide 30

Slide 30 text

// only invokes the `trackPage` method on the `GoogleAnalyticsAdapter` metrics.trackPage('GoogleAnalytics', { title: 'My Awesome App' });

Slide 31

Slide 31 text

No content

Slide 32

Slide 32 text

Creating the Addon

Slide 33

Slide 33 text

Accessing App Config

Slide 34

Slide 34 text

import config from '../config/environment'; export function initialize(_container, application) { const { metricsAdapters = {} } = config; application.register('config:metrics', metricsAdapters, { instantiate: false }); application.inject('service:metrics', 'metricsAdapters', 'config:metrics'); } export default { name: 'metrics', initialize };

Slide 35

Slide 35 text

Metrics Service

Slide 36

Slide 36 text

import Ember from 'ember'; export default Ember.Service.extend({ _adapters: {}, init() { const adapters = Ember.getWithDefault(this, 'metricsAdapters', Ember.A()); this.activateAdapters(adapters); }, activateAdapters(adapterOptions = []) { // 1. activates adapters and adds them to internal cache // 2. is idempotent } });

Slide 37

Slide 37 text

No content

Slide 38

Slide 38 text

import Ember from 'ember'; export default Ember.Route.extend({ metrics: Ember.inject.service(), afterModel(model) { const metrics = Ember.get(this, 'metrics'); const id = Ember.get(model, 'googleAnalyticsKey'); metrics.activateAdapters([ { name: 'GoogleAnalytics', config: { id } } ]); } });

Slide 39

Slide 39 text

_activateAdapter(adapterOption = {}) { const metrics = this; const { name, config } = adapterOption; const Adapter = this._lookupAdapter(name); return Adapter.create({ metrics, config }); }

Slide 40

Slide 40 text

Leveraging the Container and Resolver

Slide 41

Slide 41 text

const path = 'ember-metrics@metrics-adapters:google-analytics'; const GoogleAnalyticsAdapter = container.lookupFactory(path);

Slide 42

Slide 42 text

Service Interface

Slide 43

Slide 43 text

identify(...args) { this.invoke('identify', ...args); }, alias(...args) { this.invoke('alias', ...args); }, trackEvent(...args) { this.invoke('trackEvent', ...args); }, trackPage(...args) { this.invoke('trackPage', ...args); }

Slide 44

Slide 44 text

invoke(methodName, ...args) { const adaptersObj = Ember.get(this, '_adapters'); const adapterNames = Object.keys(adaptersObj); const adapters = adapterNames.map((adapterName) => { return Ember.get(adaptersObj, adapterName); }); if (args.length > 1) { let [ adapterName, options ] = args; const adapter = Ember.get(adaptersObj, adapterName); adapter[methodName](options); } else { adapters.forEach((adapter) => adapter[methodName](...args)); } }

Slide 45

Slide 45 text

I. What is the Adapter Pattern? II. Creating the Ember Metrics Addon III. Adapters and Blueprints

Slide 46

Slide 46 text

$ ember generate metrics-adapter foo-bar

Slide 47

Slide 47 text

import Ember from 'ember'; export default Ember.Object.extend({ init() { Ember.assert(`[ember-metrics] ${this.toString()} must implement the init hook!`); }, willDestroy() { Ember.assert(`[ember-metrics] ${this.toString()} must implement the willDestroy hook!`); }, metrics: null, config: null, identify: Ember.K, trackEvent: Ember.K, trackPage: Ember.K, alias: Ember.K });

Slide 48

Slide 48 text

import Ember from 'ember'; import BaseAdapter from './base'; export default BaseAdapter.extend({ init() { // setup library and API key }, trackEvent(options = {}) { // tracks event }, trackPage(options = {}) { // tracks pageview }, willDestroy() { // tearsdown library } });

Slide 49

Slide 49 text

I. What is the Adapter Pattern? II. Creating the Ember Metrics Addon III. Adapters and Blueprints

Slide 50

Slide 50 text

thx