Slide 1

Slide 1 text

Building DSLs with JavaScript and CoffeeScript Dave Mosher @dmosher [email protected]

Slide 2

Slide 2 text

Goals: Theory + Practical Examples What is a DSL? As a web developer, why should I care? What practical ways can I apply this knowledge?

Slide 3

Slide 3 text

Domain Specific Language “Small languages, focused around a specific aspect of a software system” ~ Martin Fowler http://martinfowler.com/books/dsl.html

Slide 4

Slide 4 text

Characteristics “You can't build a whole program with a DSL” ~ Martin Fowler http://martinfowler.com/books/dsl.html

Slide 5

Slide 5 text

Characteristics External vs Internal

Slide 6

Slide 6 text

External “language that's parsed independently of the host general purpose language” http://martinfowler.com/books/dsl.html

Slide 7

Slide 7 text

External - CSS ruleset : selector [ ‘,’ S* selector ]* ‘{‘ S* declaration [ ‘;’ S*declaration ]* ‘}’ S* ; selector : simple_selector [ combinator selector | S+ [ combinator? selector ]? ]? ; simple_selector : element_name [ HASH | class | attrib | pseudo ]* | [ HASH | class | attrib | pseudo ]+ ; class : ‘.’ IDENT ; element_name : IDENT | ‘*’ ; attrib : ‘[‘ S* IDENT S* [ [ ‘=’ | INCLUDES | DASHMATCH ] S* [ IDENT | STRING ] S* ‘]’ ; pseudo : ‘:’ [ IDENT | FUNCTION S* [IDENT S*] ‘)’ ] ;

Slide 8

Slide 8 text

Internal “form of API in a host general purpose language” http://martinfowler.com/books/dsl.html

Slide 9

Slide 9 text

Internal “fluent interface” http://martinfowler.com/books/dsl.html

Slide 10

Slide 10 text

Internal - Procedural Code http://martinfowler.com/bliki/FluentInterface.html function makeNormal(Customer customer) { Order o1 = new Order(); customer.addOrder(o1); OrderLine line1 = new OrderLine(1, Product.find("widget")); o1.addLine(line1); OrderLine line2 = new OrderLine(2, Product.find("pants")); o1.addLine(line2); OrderLine line3 = new OrderLine(3, Product.find("cows")); o1.addLine(line3); line2.setSkippable(true); o1.setRush(true); }

Slide 11

Slide 11 text

Internal - Fluent Interface http://martinfowler.com/bliki/FluentInterface.html function makeFluent(Customer customer) { customer.newOrder() .with(1, "widget") .with(2, "pants").skippable() .with(3, "cows") .priorityRush(); }

Slide 12

Slide 12 text

In the Browser JavaScript

Slide 13

Slide 13 text

A Question of Value “I use to say, ‘I can bend space and time with .toString() and .eval()…

Slide 14

Slide 14 text

A Question of Value “I’ve come to realize that it’s generally better to not bend space and time in JavaScript.” ~ Marak Squires

Slide 15

Slide 15 text

In the Browser Does the host language support meta programming?

Slide 16

Slide 16 text

Meta Programming Support define_method method_missing eval assignment** Proxies* eval *ES6 coming soon™ ** Object.defineProperty in some cases

Slide 17

Slide 17 text

What’s a realistic approach to building a DSL in JavaScript?

Slide 18

Slide 18 text

Realistic DSLs in JavaScript Focus on the benefits not the terminology

Slide 19

Slide 19 text

Realistic DSLs in JavaScript Reduce cognitive load Improve understanding Reveal intent

Slide 20

Slide 20 text

Focus Areas 1. convention over configuration 2. meaningful semantics 3. fluent interfaces 4. extensions to libraries 5. abstractions

Slide 21

Slide 21 text

Realistic DSLs in JavaScript Convention over Configuration

Slide 22

Slide 22 text

Namespacing window.app = { views: { config: {}, }, … } // myView.js app = app || {}; app.views = app.views || {}; app.views.myView = {};

Slide 23

Slide 23 text

Extend.js + Namespacing extend(‘app.views.config’, {…});

Slide 24

Slide 24 text

Realistic DSLs in JavaScript Meaningful Semantics

Slide 25

Slide 25 text

Meaningful Semantics window.alert; adjective noun verb idiom

Slide 26

Slide 26 text

Meaningful Semantics window.notify = window.alert; notify(‘semantics improved’); verb

Slide 27

Slide 27 text

Meaningful Semantics extend ‘app.views.home’, class HomeView extends Backbone.View overloaded semantics

Slide 28

Slide 28 text

Meaningful Semantics def(‘app.views.home’, Backbone.View.extend({…}); def ‘app.views.home’, class HomeView extends Backbone.View improved semantics window.def = window.extend;

Slide 29

Slide 29 text

Realistic DSLs in JavaScript Fluent Interfaces

Slide 30

Slide 30 text

Fluent Interfaces (Mocha) (5).should.be.exactly(5).and.be.a.Number;

Slide 31

Slide 31 text

Method Chaining: Not Fluency // underscore var childrenOf = function(rootId) { return _(navItems).chain().where({parentId: rootId, hidden:false}).map(function(child) { return { title: child.label, url: child.url, ordinal: child.sequence, state: child.name }; }).sortBy(function(child) { return child.ordinal; }).value(); }; // lodash var childrenOf = function(rootId) { return _(navItems).where({parentId: rootId, hidden:false}).map(function(child) { return { title: child.label, url: child.url, ordinal: child.sequence, state: child.name }; }).sortBy(function(child) { return child.ordinal; }); };

Slide 32

Slide 32 text

Procedural Code http://martinfowler.com/bliki/FluentInterface.html function makeNormal(Customer customer) { Order o1 = new Order(); customer.addOrder(o1); OrderLine line1 = new OrderLine(1, Product.find("widget")); o1.addLine(line1); OrderLine line2 = new OrderLine(2, Product.find("pants")); o1.addLine(line2); OrderLine line3 = new OrderLine(3, Product.find("cows")); o1.addLine(line3); line2.setSkippable(true); o1.setRush(true); }

Slide 33

Slide 33 text

Fluent Interface http://martinfowler.com/bliki/FluentInterface.html function makeFluent(Customer customer) { customer.newOrder() .with(1, "widget") .with(2, "pants").skippable() .with(3, "cows") .priorityRush(); }

Slide 34

Slide 34 text

Cost of Implementation “The price of this fluency is more effort, both in thinking and in the API construction itself. Coming up with a nice fluent API requires a good bit of thought.” ~ Martin Fowler http://martinfowler.com/bliki/FluentInterface.html

Slide 35

Slide 35 text

Realistic DSLs in JavaScript Extensions to Libraries

Slide 36

Slide 36 text

Backbone + Fixins.SuperView class MyView extends Backbone.Fixins.SuperView renderJQueryAccordion: -> https://github.com/testdouble/backbone-fixins

Slide 37

Slide 37 text

ng - Automatic Template Resolution

Slide 38

Slide 38 text

Realistic DSLs in JavaScript Abstractions

Slide 39

Slide 39 text

Web Components

Date:

$(‘#datepicker’).datepicker();

Slide 40

Slide 40 text

jQuery + CSS Selector Paradigm $(‘#header > nav li:nth-child(2)’); document.querySelectorAll(…);

Slide 41

Slide 41 text

ng - custom element directives

Slide 42

Slide 42 text

Recap 1. convention over configuration 2. meaningful semantics 3. fluent interfaces 4. extensions to libraries 5. abstractions

Slide 43

Slide 43 text

Values to keep in mind 1. reduce cognitive load 2. improve understanding 3. reveal intent

Slide 44

Slide 44 text

Final Thoughts Be pragmatic Be aware of complexity Be cost-averse

Slide 45

Slide 45 text

Questions?

Slide 46

Slide 46 text

Thanks for coming! Dave Mosher @dmosher [email protected] bitly.com/bundles/dmosher/8