43

patterns TypeScript size interface IModelChangeAccessor { insertText(position:IPosition, text:string): IEditorPosition; deleteText(range:IRange):

Embed Size (px)

Citation preview

Page 1: patterns TypeScript size interface IModelChangeAccessor { insertText(position:IPosition, text:string): IEditorPosition; deleteText(range:IRange):
Page 2: patterns TypeScript size interface IModelChangeAccessor { insertText(position:IPosition, text:string): IEditorPosition; deleteText(range:IRange):

Erich GammaDistinguished EngineerVSPlatform Tools/Monaco

Surviving Application Scale JavaScript - TypeScript in the Trenches

3-583

Page 3: patterns TypeScript size interface IModelChangeAccessor { insertText(position:IPosition, text:string): IEditorPosition; deleteText(range:IRange):

Web based development tools, platform, and cloud services

What do we do?

Page 4: patterns TypeScript size interface IModelChangeAccessor { insertText(position:IPosition, text:string): IEditorPosition; deleteText(range:IRange):

Team Foundation Server

Page 5: patterns TypeScript size interface IModelChangeAccessor { insertText(position:IPosition, text:string): IEditorPosition; deleteText(range:IRange):

IE F12 Source Code Viewer

Page 6: patterns TypeScript size interface IModelChangeAccessor { insertText(position:IPosition, text:string): IEditorPosition; deleteText(range:IRange):

TypeScript Playground

Page 7: patterns TypeScript size interface IModelChangeAccessor { insertText(position:IPosition, text:string): IEditorPosition; deleteText(range:IRange):

WinJS Playground

Page 8: patterns TypeScript size interface IModelChangeAccessor { insertText(position:IPosition, text:string): IEditorPosition; deleteText(range:IRange):

OneDrive

Page 9: patterns TypeScript size interface IModelChangeAccessor { insertText(position:IPosition, text:string): IEditorPosition; deleteText(range:IRange):

Visual Studio Online Monaco

Page 10: patterns TypeScript size interface IModelChangeAccessor { insertText(position:IPosition, text:string): IEditorPosition; deleteText(range:IRange):

The Road to Monaco

Small 50 kLOC

ModulesClasses

Promises

10% Typescript

Medium100 kLOC

“AMD”Lazy Loaded Contributions

50% Typescript

Larger200 kLOC

ComponentsAPI

Dependency Injection

100% Typescript

patterns

TypeScript

2011

2013

2012

size

Page 11: patterns TypeScript size interface IModelChangeAccessor { insertText(position:IPosition, text:string): IEditorPosition; deleteText(range:IRange):

We enjoy programming in JavaScript, but…

Page 12: patterns TypeScript size interface IModelChangeAccessor { insertText(position:IPosition, text:string): IEditorPosition; deleteText(range:IRange):

Organizing a large and growing code base Need to come up with “compensating” patterns for classes and

modules/namespaces

Refactoring JavaScript code is difficult “JavaScript code ‘rots’ over time” “Writing JavaScript code in a large project is like carving code in stone”

Describing APIs Keep the description in synch with the implementation

Concerns with JavaScript

Page 13: patterns TypeScript size interface IModelChangeAccessor { insertText(position:IPosition, text:string): IEditorPosition; deleteText(range:IRange):

Optional and structural typing Fewer type annotations are necessary than you think

Classes, modules Formalization of common JavaScript patterns

Interfaces Interfaces named object types for describing the shape of JavaScript

objects

TypeScript to the Rescue…

Page 14: patterns TypeScript size interface IModelChangeAccessor { insertText(position:IPosition, text:string): IEditorPosition; deleteText(range:IRange):

TypeScript at Work: Interfaces

interface IModelChangeAccessor {insertText(position:IPosition, text:string): IEditorPosition;deleteText(range:IRange): IDeleteTextResult;

}

interface IEditableTextModel {change(callback:

(changeAccessor:IModelChangeAccessor)=>any): …}

Interfaces to be implemented

Page 15: patterns TypeScript size interface IModelChangeAccessor { insertText(position:IPosition, text:string): IEditorPosition; deleteText(range:IRange):

TypeScript at Work: Interfaces

export interface IValidationFilter {(resource:IEventEmitter): boolean;

}

public constructor(filter:IValidationFilter) {}

new Validator((resource)=>this.includeModel(resource));

Callbacks

Page 16: patterns TypeScript size interface IModelChangeAccessor { insertText(position:IPosition, text:string): IEditorPosition; deleteText(range:IRange):

TypeScript at Work: Interfaces

interface ICommonEditorOptions {selectOnLineNumbers?:boolean;glyphMargin?:boolean;roundedSelection?:boolean;theme?:string;readOnly?:boolean;//…

}

Option bags

Page 17: patterns TypeScript size interface IModelChangeAccessor { insertText(position:IPosition, text:string): IEditorPosition; deleteText(range:IRange):

TypeScript at Work: Interfaces

var options:IBuildData = JSON.parse(req.responseText);

export interface IBuildData {requestId:string;logOutput?:string;buildOutput?:BuildOutput;killOutput?:KillOutput;

}

JSON structures

Page 18: patterns TypeScript size interface IModelChangeAccessor { insertText(position:IPosition, text:string): IEditorPosition; deleteText(range:IRange):

TypeScript at Work: Interfaces

declare module WinJS { module Binding {

//... } } class Promise<T> { //... }}

External types from other libraries

Page 19: patterns TypeScript size interface IModelChangeAccessor { insertText(position:IPosition, text:string): IEditorPosition; deleteText(range:IRange):

Promises Pattern

promise.then(onFulfilled, onRejected);An object representing a value which may not yet have been computed onFulFilled

called after a promise is fulfilled, with the promise’s value as its first argument

onRejected called after a promise is rejected, with the promise’s reason as its first argument

http://promises-aplus.github.io/promises-spec/https://github.com/promises-aplus/promises-spec/blob/master/implementations.md

promise.then((result) => {...}, (err) => {...});

Page 20: patterns TypeScript size interface IModelChangeAccessor { insertText(position:IPosition, text:string): IEditorPosition; deleteText(range:IRange):

class Promise<T> { then<U>(success?: (value: T) => Promise<U>, error?: (error: any) => Promise<U>, progress?: (progress: any) => void): Promise<U>; //…}

export interface ITypeDeclarationSupport { findTypeDeclaration(position:Editor.IPosition):Promise<IReference>;}

TypeScript at Work: Generics

Page 21: patterns TypeScript size interface IModelChangeAccessor { insertText(position:IPosition, text:string): IEditorPosition; deleteText(range:IRange):

https://github.com/borisyankov/DefinitelyTyped

TypeScript Type Definitions

TSD: a package manager to search and install TypeScript definition files directly from the DefinitelyTyped repository.

Page 22: patterns TypeScript size interface IModelChangeAccessor { insertText(position:IPosition, text:string): IEditorPosition; deleteText(range:IRange):

TypeScript at Work: Modules

We started with internal modules

Page 23: patterns TypeScript size interface IModelChangeAccessor { insertText(position:IPosition, text:string): IEditorPosition; deleteText(range:IRange):

The Road to Monaco

Small 50 kLOC

ModulesClasses

InterfacesPromises

10% Typescript

Medium100 kLOC

“AMD”Lazy Loaded Contributions

50% Typescript

Larger200 kLOC

ComponentsAPI

Dependency Injection

100% Typescript

patterns

TypeScript

2011

2013

2012

size

Page 24: patterns TypeScript size interface IModelChangeAccessor { insertText(position:IPosition, text:string): IEditorPosition; deleteText(range:IRange):

Modules are open undisciplined name space contributions…

You can have cyclic dependencies without noticing…

Name spaces have no relationship to the code organization on disk Renaming files/name spaces is no fun…

Code organization started to rot

Code Organization Pains

Page 25: patterns TypeScript size interface IModelChangeAccessor { insertText(position:IPosition, text:string): IEditorPosition; deleteText(range:IRange):

Growing Pains: Order Matters…

Page 26: patterns TypeScript size interface IModelChangeAccessor { insertText(position:IPosition, text:string): IEditorPosition; deleteText(range:IRange):

Growing Pains: Dependencies…

“… our dependency graph was such a mess that each area had a dependency on just about every other area.”

Page 27: patterns TypeScript size interface IModelChangeAccessor { insertText(position:IPosition, text:string): IEditorPosition; deleteText(range:IRange):

Growing Pains: Eager loading

Page 28: patterns TypeScript size interface IModelChangeAccessor { insertText(position:IPosition, text:string): IEditorPosition; deleteText(range:IRange):

Separately loaded code referenced using external module names

Implemented in separate source files Entities are private unless exported

TypeScript: External Modules

File main.ts:import adder= require("./adder"); adder.add(3,4);

File adder.ts: export function add(op1: number, op2: number):number {

return op1+op2;}

Page 29: patterns TypeScript size interface IModelChangeAccessor { insertText(position:IPosition, text:string): IEditorPosition; deleteText(range:IRange):

CommonJS used by node.js

Asynchronous Module Definition (AMD) requires an AMD compliant module loader, e.g. requireJS

TypeScript: Module Patterns

define(‘main’, [‘adder'], function(adder) { // code goes here adder.add()});

var adder = require(“adder”);adder.add()

tsc --module amd main.ts

tsc --module commonjs main.ts

Page 30: patterns TypeScript size interface IModelChangeAccessor { insertText(position:IPosition, text:string): IEditorPosition; deleteText(range:IRange):

AMD in TypeScript vs. JavaScript

AMD in JavaScript

define([‘…./winjs.base‘, ‘…./zoneWidget’], function(WinJS, ZoneWidget) { … });

AMD in TypeScriptimport WinJS= require('vs/base/lib/winjs');import ZoneWidget = require('vs/editor/zoneWidget');

Page 31: patterns TypeScript size interface IModelChangeAccessor { insertText(position:IPosition, text:string): IEditorPosition; deleteText(range:IRange):

Server uses node.js Migrated server to TypeScript once a node.d.ts file became available

Client migrated to AMD and converted to TypeScript

Common module syntax enables code sharing between client and server

Monaco

Page 32: patterns TypeScript size interface IModelChangeAccessor { insertText(position:IPosition, text:string): IEditorPosition; deleteText(range:IRange):

“It feels like fresh showered. Self contained modules, no more cycles, no more globals, clean file system structure”

After the AMD Migration Impressions

Page 33: patterns TypeScript size interface IModelChangeAccessor { insertText(position:IPosition, text:string): IEditorPosition; deleteText(range:IRange):

AMD Applied – Lazy Loadingcsharp.ts

export class CSMode extends AbstractMode { constructor() { super('vs.languages.csharp'); } // lots of code …. }

csharp.contribution.ts

modeRegistry.registerMode( [‘text/x-csharp'], new Platform.Descriptor( 'vs/languages/csharp/csharp', ‘CSMode'));

Registered on start-up Loaded on demand

Page 34: patterns TypeScript size interface IModelChangeAccessor { insertText(position:IPosition, text:string): IEditorPosition; deleteText(range:IRange):

Pain: “global” CSS files Want to package CSS files with the JS files into modules Want to express CSS file dependencies in code

AMD loader plugins Required module path can refer to a plugin “plugin!/” We implemented a css loader plugin, that allows to define:

define(["require", "vs/css!./actionbar", ...], …) CSS dependencies expressed in a pragma

AMD Applied – CSS Dependencies

Page 35: patterns TypeScript size interface IModelChangeAccessor { insertText(position:IPosition, text:string): IEditorPosition; deleteText(range:IRange):

The Road to Monaco

Small 50 kLOC

ModulesClasses

InterfacesPromises

10% Typescript

Medium100 kLOC

“AMD”Lazy Loaded Contributions

50% Typescript

Larger200 kLOC

ComponentsAPI

Dependency Injection

100% Typescript

patterns

TypeScript

2011

2013

2012

size

Page 36: patterns TypeScript size interface IModelChangeAccessor { insertText(position:IPosition, text:string): IEditorPosition; deleteText(range:IRange):

Migration is code clean-up but real work… Velocity around 300 LOCs per hour No implicit ‘anys’ No missing return types

Towards 100% TypeScript

“As I did conversions, I began typing various object literals I was passing around as interfaces. Soon enough, I realized how inconsistent I was, the same data was flowing around in at least 3 different formats. This is because of the easiness through which you can create literals in JavaScript …. Need some placeholder for data?... Just create a new literal object.”

Page 37: patterns TypeScript size interface IModelChangeAccessor { insertText(position:IPosition, text:string): IEditorPosition; deleteText(range:IRange):

Reuse TypeScript code as ‘binary’ JS components with a declarations file

Example using TypeScript language services as a component Compiler and language services > 30kLOC of TypeScript

Generates a typescriptservices.d.ts

Componentization

tsc –declarations –out typescriptservices.js typescript.ts

Page 38: patterns TypeScript size interface IModelChangeAccessor { insertText(position:IPosition, text:string): IEditorPosition; deleteText(range:IRange):

We were on the bleeding edge… …but we expected it and had plenty of band aid

We would do it again, the benefits outweigh the pains Confidence, refactoring agility, tooling, fun

We would start with TypeScript (and CommonJS/AMD) from the beginning

TS Retrospective

Page 39: patterns TypeScript size interface IModelChangeAccessor { insertText(position:IPosition, text:string): IEditorPosition; deleteText(range:IRange):

Friday 2:00-3:00pm Building Websites using VSOnline Monaco Chris Dias

Related Talks

Page 41: patterns TypeScript size interface IModelChangeAccessor { insertText(position:IPosition, text:string): IEditorPosition; deleteText(range:IRange):

for MSDN Ultimate subscribers

Go to http://msdn.Microsoft.com/specialoffers

SPECIAL OFFERSPartner Program

Page 42: patterns TypeScript size interface IModelChangeAccessor { insertText(position:IPosition, text:string): IEditorPosition; deleteText(range:IRange):

Your Feedback is Important

Fill out an evaluation of this session and help shape future events.

Scan the QR code to evaluate this session on your mobile device.

You’ll also be entered into a daily prize drawing!

Page 43: patterns TypeScript size interface IModelChangeAccessor { insertText(position:IPosition, text:string): IEditorPosition; deleteText(range:IRange):

© 2014 Microsoft Corporation. All rights reserved. Microsoft, Windows, Windows Vista and other product names are or may be registered trademarks and/or trademarks in the U.S. and/or other countries.The information herein is for informational purposes only and represents the current view of Microsoft Corporation as of the date of this presentation. Because Microsoft must respond to changing market conditions, it should not be interpreted to be a commitment on the part of Microsoft, and Microsoft cannot guarantee the accuracy of any information provided after the date of this presentation. MICROSOFT MAKES NO WARRANTIES, EXPRESS, IMPLIED OR STATUTORY, AS TO THE INFORMATION IN THIS PRESENTATION.