jazoon'13 - paul brauner - a backend developer meets the web: my dart experience
DESCRIPTION
http://guide13.jazoon.com/#/submissions/124TRANSCRIPT
My Dart ExperiencePaul Brauner
|
• PhD in Logic / Types
• Postdoc in Languages
• Now at Google
|
About Me
• PhD in Logic / Types
• Postdoc in Languages
• Now at Google
|
About Me
• PhD in Logic / Types
• Postdoc in Languages
• Now at Google
|
About Me
map f (x:xs) = f x : map f xs
for (x <- xs) f(x)
• PhD in Logic / Types
• Postdoc in Languages
• Now at Google
|
About Me
map f (x:xs) = f x : map f xs
for (x <- xs) f(x)
|
Dart Contributor
• Writing backends
• Writing background jobs (mapreduce)
• Mostly Java, C++
|
My Work Involves
• Code navigation, completion, static errors
• Libraries / Modules
• Generated documentation
• Reasonable performance
|
I Take for Granted
|
I ♥ the Web Platform
|
I ♥ the Web Platform
|
I Web Development *
* except for fast edit-refresh cycle, that's awesome
|
> [] + {}[object Object]> {} + []0> {} + {}NaN
WAT (h/t Gary Bernhardt)
|
WAT - Reloaded
var x = "top-level";function foo() { if (true) { var x = "inside-if"; } console.log(x);}foo();
|
WAT - Reloaded
var x = "top-level";function foo() { if (true) { var x = "inside-if"; } console.log(x);}foo();
inside-if
|
Libraries?
|
Libraries?
|
Libraries?
|
Linker?
|
Linker?
|
Web Development?
|
• Language and Libraries
• Tools
• Virtual Machine
• Compiles to Javascript
|
Dart
|
Targets All Browsers
.dart
|
Targets All Browsers
.dart
Virtual Machine
edit/refresh
|
Targets All Browsers
.dart
Virtual Machine
dart2js
.js
edit/refresh deploy
• CoffeScript & Friends: only improve syntax
• Closure: structure but same semantics
• GWT: good but slow edit/refresh cycle (fixed in
upcoming version!)
|
Alternatives
• Semantics
• Structure
• Fast edit/refresh cycle
|
Dart
|
Dart in a Nutshell
class Point {
double x, y;
Point(this.x, this.x);
toString() => "($x, $y)";}
|
Dart in a Nutshell
class Point {
double x, y;
Point(this.x, this.x);
toString() => "($x, $y)";}
Class-based
|
Dart in a Nutshell
class Point {
double x, y;
Point(this.x, this.x);
toString() => "($x, $y)";}
Class-based
Optionally typed
|
Dart in a Nutshell
class Point {
double x, y;
Point(this.x, this.x);
toString() => "($x, $y)";}
Class-based
Optionally typed
Terse syntax
|
Dart in a Nutshell
class Point {
double x, y;
Point(this.x, this.x);
toString() => "($x, $y)";}
Class-based
Optionally typed
Terse syntax
|
Dart in a Nutshell
class Point {
double x, y;
Point(this.x, this.x);
toString() => "($x, $y)";}
Class-based
Optionally typed
Terse syntax
|
Clean Unsurprising Semantics
• Only true is truthy
• There is no undefined, only null
• No type coercion with ==, +
|
Clean Semantics - Examples
|
Clean Semantics – Missing Getter
"hello".missing // ??
|
Clean Semantics – Missing Getter
"hello".missing // ??
Class 'String' has no instance getter 'missing'.
NoSuchMethodError : method not found: 'missing'Receiver: "hello"Arguments: []
|
Clean Semantics – Index out of Range
[][42] // ??
|
Clean Semantics – Index out of Range
[][42] // ??
RangeError: 42
|
Clean Semantics – Variable Scope
var x = "top-level";void foo() { if (true) { var x = "inside-if"; } print(x);}void main() { foo(); } // ??
|
Clean Semantics – Variable Scope
var x = "top-level";void foo() { if (true) { var x = "inside-if"; } print(x);}void main() { foo(); } // ??
top-level
|
Clean Semantics – Scope of this
class App {
App(button) { button.onClick.listen((e) => this.foo()); }
foo() { … }}
|
Structure
|
Structure - Libraries
library game;import 'dart:math';
class Game { … }play(Game game) { … }
_secret(Game game) { … }
Module system
|
Structure - Libraries
library game;import 'dart:math';
class Game { … }play(Game game) { … }
_secret(Game game) { … }
Module system
Scoped definitions
|
Structure - Libraries
library game;import 'dart:math';
class Game { … }play(Game game) { … }
_secret(Game game) { … }
Module system
Scoped definitions
Private definition
|
Structure - Packages
name: parsers version: 0.13.6
dependencies: persistent: '>=0.7.0 <0.8.0' dev_dependencies: unittest: any
• Optional types
• Mixins (class A extends B with C)
• Method cascades (foo..bar(1)..baz(2))
• Future proof APIs
|
Towards a Better Language
• Optional types
• Mixins (class A extends B with C)
• Method cascades (foo..bar(1)..baz(2))
• Future proof APIs
|
Towards a Better Language
|
Future Proof APIs
class Point { // now polar coordinates double angle, radius; Point(this.angle, this.radius);
… }
How do we prevent clients from breaking?
|
Future Proof APIs
class Point { // now polar coordinates
get x => … set x(value) => …
operator [](int index) => …
toString([bool asJson]) => … }
|
Future Proof APIs
class Point { // now polar coordinates
get x => … set x(value) => …
operator [](int index) => …
toString([bool asJson]) => … }
Getters / Setters
|
Future Proof APIs
class Point { // now polar coordinates
get x => … set x(value) => …
operator [](int index) => …
toString([bool asJson]) => … }
Getters / Setters
Operator overriding
|
Future Proof APIs
class Point { // now polar coordinates
get x => … set x(value) => …
operator [](int index) => …
toString([bool asJson]) => … }
Getters / Setters
Operator overriding
Optional arguments
|
Future Proof APIs
class Point { // now polar coordinates
factory Point(x, y) { return new Point.polar(…); }
Point.polar(angle, radius) { … }}
Factoryconstructors
|
Future Proof APIs
class Point { // now polar coordinates
factory Point(x, y) { return new Point.polar(…); }
Point.polar(angle, radius) { … }}
Factoryconstructors
Named constructors
• Modern, consistent library (collections, typed
HTML bindings, futures, streams, ...)
• JS interoperability
• Server-side programming
|
Not Just a Language
|
Flip It!
|
Flip It!
Snappy UIOffline playing
|
Flip It!
Snappy UIOffline playing
Validation required
|
Code Reuse
class Board { Board.decode(str) { … } String encode() { … } bool validate() { … }}
common.dart server.dart
client.dart
import
import
|
3rd Party Libraries
Bootstrap for Dart
Google APIs client libs
OAuth2 authentication
PostgreSQL driver
Web Server
Clientside routing
|
3rd Party Libraries
|
Can I Have my Reader Now?
|
Can I Have my Reader Now?
• "Widgets" are a bunch of nested divs
• Unique IDs leak all over the place
• CSS leaks to parents / children
|
The Problem with HTML
• "Widgets" are a bunch of nested divs
• Unique IDs leak all over the place
• CSS leaks to parents / children
|
The Problem with HTML
• "Widgets" are a bunch of nested divs
• Unique IDs leak all over the place
• CSS leaks to parents / children
|
The Problem with HTML
|
MVC Boilerplateclass Model { StreamController _onCurrentBoardChanged = new StreamController(); StreamController _onPreviousBoardChanged = new StreamController(); StreamController _onCurrentPathChanged = new StreamController(); StreamController _onPreviousPathChanged = new StreamController(); StreamController _onStateChanged = new StreamController(); StreamController _onUserInfoChanged = new StreamController(); StreamController _onSignInStatusChanged = new StreamController();
void _initStreams() { onCurrentBoardChanged = _onCurrentBoardChanged.stream.asBroadcastStream(); onPreviousBoardChanged = _onPreviousBoardChanged.stream.asBroadcastStream(); onCurrentPathChanged = _onCurrentPathChanged.stream.asBroadcastStream(); onPreviousPathChanged = _onPreviousPathChanged.stream.asBroadcastStream(); onStateChanged = _onStateChanged.stream.asBroadcastStream(); onUserInfoChanged = _onUserInfoChanged.stream.asBroadcastStream(); onSignInStatusChanged = _onSignInStatusChanged.stream.asBroadcastStream(); }
void _currentBoardChanged() { _onCurrentBoardChanged.add(null); }
… }
|
Web Components
|
Web Components
<messages> <message> <subject> Please fill out the TPS report </subject> <sent>2012-10-03</sent> <summary> I'm going to have to ask you to come in... </summary> </message> <message> <subject> Reminder: fill out that TPS report! </subject> <sent>2012-10-04</sent> <summary> It's been 24 hours... </summary> </message> ...</messages>
|
Custom Elements
<custom-element>
Structure Behavior Styles
<div> <input> <p> <span></span> </p></div>
tag.verifyAccount();<style> p { color: red; }</style>
|
Reusability
Custom Element
HTML Page HTML Page HTML Page
import import import
• Based on emerging web standards
• Browser vendors interested
• Already partially implemented!
|
Future Proof
|
|
Polymer: Web Components Today
Polymer.dart
|
Custom Element Declaration
<polymer-element name="my-message">
</polymer-element>
|
Custom Element Declaration
<polymer-element name="my-message"> <template>
<div id="frame"> <b>Subject: </b><content select=".subject"></content> <content select="p"></content> </div> </template>
</polymer-element>
Structure
|
Custom Element Declaration
<polymer-element name="my-message"> <template> <style> #frame { border: 1px solid black; } </style>
<div id="frame"> <b>Subject: </b><content select=".subject"></content> <content select="p"></content> </div> </template>
</polymer-element>
Structure
Style
|
Custom Element Declaration
<polymer-element name="my-message"> <template> <style> #frame { border: 1px solid black; } </style>
<div id="frame"> <b>Subject: </b><content select=".subject"></content> <content select="p"></content> </div> </template>
<script type="application/dart" src="my_message.dart"></script></polymer-element>
Behavior
Structure
Style
|
Custom Element Instantiation
<head> <link rel="import" href="my_message.html"> </head>
Import
|
Custom Element Instantiation
<head> <link rel="import" href="my_message.html"> </head>
<body>
<my-message> <span class="subject">Hello</span> <p>How are you?</p> </my-message> </body>
Import
Instantiation
|
Custom Element Instantiation
<head> <link rel="import" href="my_message.html"> </head>
<body> <div id="frame">This won't be framed</div> <my-message> <span class="subject">Hello</span> <p>How are you?</p> </my-message> </body>
Encapsulation
Import
Instantiation
|
Custom Element Instantiation
|
Custom Element Instantiation<my-message> <span class="subject">Hello</span> <p>How are you?</p></my-message>
|
Custom Element Instantiation<my-message> <span class="subject">Hello</span> <p>How are you?</p></my-message>
<div id="frame"> <b>Subject: </b><content select=".subject"></content> <content select="p"></content></div>
|
Custom Element Instantiation<my-message> <span class="subject">Hello</span> <p>How are you?</p></my-message>
<div id="frame"> <b>Subject: </b><content select=".subject"></content> <content select="p"></content></div>
|
Custom Element Instantiation
<style> #frame { border: 1px solid black; }</style>
<div id="frame"> <b>Subject: </b><content select=".subject"></content> <content select="p"></content></div>
|
Custom Element Instantiation
<style> #frame { border: 1px solid black; }</style>
<div id="frame"> <b>Subject: </b><content select=".subject"></content> <content select="p"></content></div>
|
Custom Element Instantiation
<style> #frame { border: 1px solid black; }</style>
<div id="frame"> <b>Subject: </b><content select=".subject"></content> <content select="p"></content></div>
<div id="frame">This won't be framed</div>
|
Custom Element Instantiation
<style> #frame { border: 1px solid black; }</style>
<div id="frame"> <b>Subject: </b><content select=".subject"></content> <content select="p"></content></div>
<div id="frame">This won't be framed</div>
|
Behavior
@CustomTag('my-message')class MyMessage extends PolymerElement { enteredView() {
… this.children …
}}
|
Behavior
@CustomTag('my-message')class MyMessage extends PolymerElement { enteredView() {
… this.children …
}}
|
Behavior
@CustomTag('my-message')class MyMessage extends PolymerElement { enteredView() {
… this.children …
}}
|
Behavior
@CustomTag('my-message')class MyMessage extends PolymerElement { enteredView() {
… this.children …
}}
|
Behavior
@CustomTag('my-message')class MyMessage extends PolymerElement { enteredView() {
… this.children …
}}
Which ones?
|
Shadow DOM
shadow root
b content content
my-message
span p
"Hello" "How are you?" "Subject:"
div
|
Behavior
@CustomTag('my-message')class MyMessage extends PolymerElement { enteredView() { }}
|
Behavior
@CustomTag('my-message')class MyMessage extends PolymerElement { enteredView() { SpanElement subject = host.query('.subject'); subject.text = subject.text.toUpperCase(); }}
DOM
|
Behavior
@CustomTag('my-message')class MyMessage extends PolymerElement { enteredView() { SpanElement subject = host.query('.subject'); subject.text = subject.text.toUpperCase(); DivElement frame = shadowRoot.query('#frame'); frame.style.borderWidth = '3px'; }}
Shadow DOM
DOM
|
Behavior
Uppercase3px
• Declarative Model-View-*
• Supports two-way bindings out of the box
|
Data Binding
|
Data Binding<polymer-element name="click-counter"> <template> <button on-click="increment">Click Me</button> <p>You clicked the button {{count}} times.</p> </template> </polymer-element>
|
Data Binding<polymer-element name="click-counter"> <template> <button on-click="increment">Click Me</button> <p>You clicked the button {{count}} times.</p> </template> </polymer-element>
|
Data Binding<polymer-element name="click-counter"> <template> <button on-click="increment">Click Me</button> <p>You clicked the button {{count}} times.</p> </template> </polymer-element>
|
Data Binding
@CustomTag('click-counter')class ClickCounterElement extends PolymerElement { @observable int count = 0; void increment(Event e, var detail, Node target) { count += 1; }}
<polymer-element name="click-counter"> <template> <button on-click="increment">Click Me</button> <p>You clicked the button {{count}} times.</p> </template> <script src="click_counter.dart" type="…" ></script></polymer-element>
|
Data Binding
@CustomTag('click-counter')class ClickCounterElement extends PolymerElement { @observable int count = 0; void increment(Event e, var detail, Node target) { count += 1; }}
<polymer-element name="click-counter"> <template> <button on-click="increment">Click Me</button> <p>You clicked the button {{count}} times.</p> </template> <script src="click_counter.dart" type="…" ></script></polymer-element>
|
Real World Example
data List<A> = Nil | Cons(A x, List<A> xs)
class List<A> { … }class Nil<A> extends List<A> { … }class Cons<A> extends List<A> { … }
|
Real World Example
|
Real World Example
<h2>Define</h2><textarea value='{{input}}'></textarea>
|
Real World Example
<label> <input type='checkbox' checked='{{finalFields}}'> final fields</label>
|
Real World Example
<h2>Profit</h2><code> <pre id='generated'> {{generated}} </pre></code>
|
Real World Example
<h2>Profit</h2><code> <pre id='generated'> {{generated}} </pre></code>
String get generated { final config = new Config(finalFields, … ); return generate(input, config);}
|
Can I have my Reader Now?
|
Can I have my Reader Now?
YES!
• Haskell backend
• Polymer.dart* frontend
|
Bringing Reader Back to Life
* actually its ancestor
|
Bringing Reader Back to Life
|
http://dartlang.org