SlideShare a Scribd company logo
Accelerating Angular Application
Development
Using Third Party Code
Matt Eland
Website
http://www.MattEland.com
Twitter
@IntegerMan
LinkedIn
https://www.linkedin.com/in/matteland/
Currently:
 Lead Software Engineer @ MoveHQ
Previously:
 Senior Software Engineer @ TeamDynamix
 Software Developer @ Exceptional Innovation
 Software Engineer @ Verizon Business
This presentation is
like a mullet
Business in the front; party in the back
Talk Overview
Angular Plan Manager Gantt Chart / Task Management App
Backlog Manager / Card Wall Agile Project Management Tools
Angular IF Interactive Fiction Game Engine Prototype
Emergence Roguelike Game
Overall Lessons Learned Okay, so maybe note exactly like a mullet...
Talk Overview
Angular Plan Manager Gantt Chart / Task Management App
Backlog Manager / Card Wall Agile Project Management Tools
Angular IF Interactive Fiction Game Engine Prototype
Emergence Roguelike Game
Overall Lessons Learned Okay, so maybe note exactly like a mullet...
Talk Overview
Angular Plan Manager Gantt Chart / Task Management App
Backlog Manager / Card Wall Agile Project Management Tools
Angular IF Interactive Fiction Game Engine Prototype
Emergence Roguelike Game
Overall Lessons Learned Okay, so maybe note exactly like a mullet...
Some
Disclaimers
This talk IS about
When should third party
code be considered
How to reduce risk when
using external code
Some examples from
various projects
This talk is NOT
Focused on code
An in-depth discussion of
Angular
An Angular tutorial
What is Angular?
 Angular vs AngularJS
 Created by Google in 2016
 Single Page Application (SPA) framework
 Built around TypeScript
 Quick start with Angular CLI and npm
 Consists of common types of entities (Services, Components, Pipes, etc.)
 A “M-V-Whatever” application framework
Angular Plan Manager
Angular adaptation of a Silverlight project planning application
Angular Plan Manager
Built in 2015-2016 on
Angular 2.0 RC2
Angular 2 was not officially released
until after the project initially shipped
Intended as a web-based
alternative to Project
Gantt Chart
DataGrid with inline editing
Complex Clipboard Support
Replaced an existing
Silverlight application
If you don’t know this pain, I envy
you a little.
Mirrored the capabilities of a
complex WPF app
Iteratively developed over around 3
years.
Grew from WPF to WPF / Silverlight
Angular Plan Manager – Key Problems
User Experience
Grid-based editing capabilities, including copy / paste
Product needed a Gantt Chart to resemble other products
Technology Limitations
Potentially large and hierarchical data sets
Domain logic is complex and written in .NET
Heavily Client / Server Oriented
Project Constraints
Fixed deadline (Chrome’s removal of Silverlight)
Angular 2 not formally released until after the deadline
HandsOnTable to the Rescue?
 Best capabilities of all alternatives viewed
 Square Peg / Round Hole
 Product still rapidly evolving
 No Angular support at time of adoption
 API was extremely cumbersome and later replaced
 We had to fork and modify
 Got the job done
 Performance was an issue
 Long-term, the UI layer was likely throwaway
Lessons Learned – Angular Plan Manager
DO
 Spike into options early on in a project
 Identify core use cases for a component
 Go with the “best worst” option
 Whatever it takes when the project impact is
important enough
 Your best to sleep at night after horrible
hacks are made
DON’T
 Fork 3rd Party Libraries
 Forget to plan to upgrading beta
components once they mature
 Invest development in a technology that can
be globally killed like Silverlight
“TD Agile”
Internal name for the Backlog Manager and Card
Wall Angular applications.
“TD Agile” (Think Jira Agile)
Built in 2017–2018
using Angular 4
Compete against
bigger fish
Primarily Jira
Backlog Manager
Product Backlog
Management tool
Card Wall
Agile Scrum Board
Replaced an Angular JS
Implementation
Shared logic between
apps
Card Details
Backlog Manager
Multi-sprint backlog planning tool with drag and drop task and resource management
Card Wall
Angular-based drag and drop agile card wall
“TD Agile” - Key Problems
User Experience
Required real-time updates from concurrent users
Needed a slick drag-drop UI with multiple classes of draggable items
Needed to work with a variety of users with different permissions levels
Project Constraints
Could not drop existing features
Needed to be ready for release before the annual user conference
So very Sortable
 Wound up relying on a customized version of Sortable.JS
 Only minor customization was needed
 Needed more detail on the context of the drag operation
 Resulting library capable of:
 Drag / Drop items in lists
 Lists of items
 Lists of lists of items
 Preventing Drag or Drop Conditionally
 Feeding us enough information to grab the model object out of the list
Lessons Learned – “TD Agile”
DO
 Dedicate time to evaluating libraries
 Share components and services between
major app areas where it makes sense
 Rapidly prototype and iterate when making a
UI heavy project
 Define standard patterns and helpers to
consolidate client-server interaction logic
 Consider using the Redux pattern in Angular
when the application is complex
DON’T
 Evaluate third party libraries without
understanding all major requirements
 Expect third party libraries to fix bugs or
accept pull requests
 Neglect Server-Side Logging
Angular IF
Simultaneously Beating a Dead Horse and Reinventing the Wheel
http://matteland.com/ngApps/angularIF/
“Angular IF”
 Built for fun in Angular 4 in 2017
 Later converted to Angular 5
 IF = Interactive Fiction
 i.e. Zork, Enchanter, The Lurking Horror, Wishbringer
 A modern web development take on a childhood
and early adult hobby of mine
 Intended to practice larger application
development using TypeScript
Angular IF – Key Problems
Architecture Problems
Needed to be data-driven
Needed to be highly testable
Should not need to talk to a server once loaded
Needed an integrated editor
IF-Oriented Problems
Potentially a large amount of possible (valid) things to try
Lots of different ways to state the same command
Generic responses can be frustrating
Limited system vocabularies can be frustrating
How an Input Becomes a Response
Tokenizer
Sentence is broken
down into words
Some Substitution occurs:
“Pick Up” becomes “Get”, “W”
becomes “West”, etc.
Lexer
Individual tokens
are augmented
with tags
Parser
Token relationships
are extrapolated
based on parts of
speech
Interpreting
Match nouns to
items inside the
game world
Execution
Sentence
command is
handed off to the
verb handler.
nlp-compromise
http://compromise.cool/
Tokenizer
User Input
> “Open the door using the rusty key.”
Tokens
 Open
 The
 Door
 Using
 The
 Rusty
 Key
nlp-compromise
http://compromise.cool/
Lexer
Tokens
 Open
 The
 Door
 Using
 The
 Rusty
 Key
CommandTokens (Tokens with Compromise information)
 Open [Verb, VerbPhrase]
 The [Determiner]
 Door [Noun, Singular]
 Using [Gerund, PresentTense, Verb, VerbPhrase]
 The [Determiner]
 Rusty [Adjective]
 Key [Noun, Singular]
nlp-compromise
With some custom definitions & tweaks
http://compromise.cool/
Tokenizing input with nlp-compromise
public getTerms(sentence: string): LanguageTerm[] {
// Commas are death.
sentence = StringHelper.replaceAll(sentence, ',', '');
const lexicon = LexiconService.instance.lexicon;
const data: LanguageTerm[] = this.nlp(sentence, lexicon).terms().data();
// Compromise casing workaround omitted for clarity
return data;
}
http://compromise.cool/
Enhancing Compromise’s Intelligence
Compromise Term CommandToken Abstraction Object
export class CommandToken {
name: string;
term: LanguageTerm;
classification: TokenClassification;
isInferred: boolean = false;
previousToken: CommandToken;
nextToken: CommandToken;
modifies: CommandToken[];
modifiedBy: CommandToken[];
entity: EntityBase;
// Supporting methods and properties
}
http://compromise.cool/
export class LanguageTerm {
text: string;
bestTag: string;
tags: string[];
normal: string;
implicit: string;
spaceBefore: string;
spaceAfter: string;
}
Parsing & Interpreting
Considerations
 Identify the first verb
 See if other verbs can act as other parts of speech
 Infer a subject if no noun is before the verb
 Link nouns to local entities
 Associate adjectives & determiners with next noun
 Associate adverbs with the verbs
 Split along prepositional phrases (e.g. using)
Command Object
Execution
Input
 VerbHandler (if one is implemented)
 Command (parsed sentence structure)
 CommandContext
 Room
 Player
 Misc. world data
 Methods to manipulate the game world
Output
One or more Story Responses:
 “I don’t see a door here”
Or...
 “You unlock the door using the rusty key”
 “The door opens with a noisy creak”
 Your score has gone up by one point
Sample Verb Handler
export class WinHandler extends VerbHandler {
get isHidden(): boolean {
return true;
}
get verbType(): VerbType {
return VerbType.system;
}
handleCommand(command: Command, context: CommandContext): CommandResult {
if (!environment.showDebugAids) {
// Win is not a valid verb in production
context.output.addSystem('Cheaters never prosper.');
} else {
// But in dev it is!
context.engine.endGame(context, true, 'Well, that was easy.');
}
return CommandResult.BuildActionSuccessResult();
}
}
DEMO: Angular IF
Hello Cloak of Darkness
http://matteland.com/ngApps/angularIF/index.html
Testing Strategy
Manual Tests Can I still type in text and see a response?
Unit Tests Phrase / Word Substitution
Component Tests Angular CLI Smoke Tests for Services / Components
Integration Tests Room / Story / Scenario-based Tests
Sample Story-Based Tests
it('should be winnable with max score in 5 moves', () => {
game.input('w');
game.input('put the cloak on the small hook');
game.input('e');
game.input('s');
game.input('x message');
expect(game.gameState).toBe(GameState.won);
expect(game.currentScore).toBe(2);
});
it('should be loseable', () => {
game.input('s');
game.input('drop cloak');
game.input('x self');
game.input('x room');
game.input('n');
game.input('w');
game.input('put the cloak on the small hook');
game.input('e');
game.input('s');
game.input('x message');
expect(game.gameState).toBe(GameState.lost);
expect(game.currentScore).toBe(1);
});
Sample Room-based Test
it('should contain a front yard room that passes spec validation', () => {
const spec = game.buildRoomSpec(room)
.shouldResolveFrom(`frontyard`)
.shouldResolveFrom(`front yard`)
.shouldNavigateTo('w', 'nearplayground')
.shouldNavigateTo('e', 'cornerwp')
.shouldNavigateTo('s', 'hall')
.shouldNavigateTo('se', 'sideyard')
.shouldNavigateTo('go in', 'hall')
.shouldNavigateTo('go inside', 'hall')
.shouldNavigateTo('go to the sideyard', 'sideyard')
.shouldFailNavigationTo('sw', `poop`)
.shouldFailNavigationTo('nw', `house`)
.shouldFailNavigationTo('n', `house`)
.shouldFailNavigationTo('ne', `house`)
.shouldRespondToCommandWith(`look`, `front`, `yard`, `car`, `fog`, `house`, `door`, `west`, `east`, `southeast`)
.shouldRespondToCommandWith(`look s`, `door`)
.shouldRespondToCommandWith(`look n`, `neighbor`)
.shouldRespondToCommandWith(`look w`, `street`)
.shouldRespondToCommandWith(`look e`, `corner`)
.shouldNotBeGettable('serious');
expect(spec.validate()).toBeFalsy();
});
Helper Object for Fluent Tests
export class RoomSpec extends EntitySpec {
public shouldNavigateTo(command: string, newRoomKey: string): RoomSpec {
this.addCheck( () => {
this.game.input(command);
const actualKey = this.game.currentRoom.key;
if (actualKey !== newRoomKey) {
return `Expected '${command}' to result in a current room of ${newRoomKey} but current room is ${actualKey}.`;
}
return null;
});
return this;
}
public shouldFailNavigationTo(command: string, ...expectedResponses: string[]): RoomSpec {
this.addCheck( () => {
this.game.input(command);
const actualKey = this.game.currentRoom.key;
if (actualKey !== this.key) {
return `Expected navigation to ${command} to result in remaining in ${this.key} but current room is ${actualKey}.`;
}
return this.checkForExpectedReply(...expectedResponses);
});
return this;
}
}
Troubleshooting Complex User Input
Debugging Displays
Sentence Structure
Object State
Token Analysis
Specialized Verbs
Debug Verb
ReportBug Verb
Reporting
Rollbar
Google Analytics
Lessons Learned – Angular IF
DO
 Test integrations, especially when they have a
broad surface area
 Outsource complex aspects of your app that
you don’t need to heavily customize
 Wrap external code in facades and
abstraction objects
DON’T
 Only evaluate one library
 Try to force something into a client-side only
box that should really be client-server
 Build an editor when command line would
work instead
Emergence
Because building a Roguelike in JavaScript sounds like fun!
Emergence
 A Roguelike inspired by Dungeons of Dredmor
 Set in a computer network
 Player is a newly “awakened” AI entity
 Objective is to escape to the Internet
 Levels are machines in the network
 In active development under Angular 5 / .NET Core 2.0
 Initial version was entirely client-side logic in Angular 4 / TypeScript
 In a transitory Client / Server state
 Will ultimately wind up in Unity
Emergence – Key Problems
Rendering
Mixing Angular content and the main game surface
Animation
Performance
Art Assets
Roguelike Challenges
Procedural Generation
Random Number Generation
Artificial Intelligence
Line of Sight Algorithm
Gamedev Issues
Continuous Deployment
Production / Preview / Nightly Branches
Busy Seasons of Life
Holy Scope Creep, Batman
Web API
 .NET Core 2.0 Web API Project
 Called by multiple Angular app deployments
 Maturity Level 2 REST Service
 Resources & Verbs
 No HATEOAS
 No backing data store
 Uses Swashbuckle
 Generates Swagger file and Swagger UI
 Decreases development time
 Encourages documentation
 Increases discoverability
 Hosted as an Azure Web App
Emergence – Major Components
External Code
 Rendering / Animation
 Pixi .JS
 Chromatism
 UI Styling
 Customized Materialize CSS and Angular Material
 Uses ng-drag-drop to make the UI interactive
 Calculations
 Visibility with The Field (will need a C# alternative)
 Random number generation with Chance
 TODO, but likely will use external code
 Artificial Intelligence
 Pathfinding
Custom Built
 Core Game Engine
 Character Management
 World Generation
 Menu System
 Help System
 Could have been relegated to a CMS
Color tweaks with Chromatism
 Benefits of Chromatism:
 Flexible color models
 Simple color adjustments
 Drawbacks of Chromatism:
 So CPU intensive it required caching
 Typing Colour can be distracting
export class ColorHelper {
private static shadeValues: string[];
/**
* Gets a faded variant of the requested shade.
* This method is performance intensive, so values are cached.
*/
public static getFadedColor(bgColor: string): string {
// Initialize the cache as needed
if (!this.shadeValues) {
this.shadeValues = [];
}
// Check to see if we have it in the cache
if (this.shadeValues[bgColor]) {
return this.shadeValues[bgColor];
}
// We don't have it in the cache, do the computation
let c: ColourObject = chromatism.convert(bgColor);
c = chromatism.contrast(0.25, c.rgb);
c = chromatism.shade(-5, c.rgb);
// Store the value for next time
this.shadeValues[bgColor] = c.hex;
return c.hex;
}
// More goodness...
}
https://github.com/toish/chromatism
Line of Sight with “The Field”
export class FovCalculator {
public static calculateVisibleCellsFromPoint(pos: Point, visionRadius: number, level: GameLevel): Cell[] {
const offset: Point = new Point(pos.x - Math.floor(visionRadius), pos.y - Math.floor(visionRadius));
const candidates: Cell[] = level.getCellGrid(pos, true, Math.floor(visionRadius));
const fov: MaskRect = FovCalculator.getFieldOfView(pos, visionRadius, candidates, offset);
const cells: Cell[] = [];
for (const cell of candidates) {
const distance: number = pos.calculateDistanceFrom(cell.pos);
if (distance <= visionRadius) {
if (cell && fov.get(cell.pos.x - offset.x, cell.pos.y - offset.y)) {
cells.push(cell);
}
}
}
return cells;
}
private static getFieldOfView(pos: Point, visionRadius: number, candidates: Cell[], offset: Point): MaskRect {
const fovRange: number = Math.floor(visionRadius * 2 + 1);
const map: FieldOfViewMap = new TheField.FieldOfViewMap(fovRange, fovRange);
for (const cell of candidates) {
if (cell && !cell.pos.equals(pos) && cell.generatesSightBlocker) {
map.addBody(cell.pos.x - offset.x, cell.pos.y - offset.y);
}
}
return map.getFieldOfView(pos.x - offset.x, pos.y - offset.y, Math.floor(visionRadius));
}
}
 Benefits of The Field
 Don’t need to worry about visibility
 Low footprint
 Integration is easily testable
 Developer was very responsive
https://github.com/sbj42/the-field
Dragon Drop with ng-drag-drop
 Benefits of ng-drag-drop
 Simple to use
 Built for Angular
 (though some issues with Angular 6)
 Meets my basic needs in a concise way
// command-management-screen.component.html
<mat-grid-list [cols]="10“ #listAvailable id="listAvailable">
<mat-grid-tile *ngFor="let slot of actor.storedCommandSlots">
<em-command-slot
class="command-slot"
draggable
droppable
[dragScope]="'command’”
[dropScope]="'command’”
[dragData]="slot"
(onDrop)="onCommandDropped(slot, $event)"
(click)="selectSlot(slot)"
[slot]="slot"
[isSortable]="true"
[selected]="slot === selectedSlot">
</em-command-slot>
</mat-grid-tile>
</mat-grid-list>
// command-management-screen.component.ts
public onCommandDropped(target: CommandSlot, e: DropEvent): void {
Logger.debug(`Command drop detected`, target, e);
// Have a centralized helper carry out the swap
const source: CommandSlot = <CommandSlot>e.dragData;
DragonDropHelper.handleCommandDragDrop(target, source);
// Ensure the selection moves to the new slot
if (this.selectedSlot === source) {
this.selectedSlot = target;
}
}
https://www.npmjs.com/package/ng-drag-drop
Better Random Numbers with Chance
import * as Chance from 'chance';
import {isNullOrUndefined} from 'util';
export class Randomizer {
private static _chance: Chance = null;
private static get rng(): Chance {
// Lazy instantiate the Chance library
if (isNullOrUndefined(Randomizer._chance)) {
Randomizer._chance = new Chance();
}
return Randomizer._chance;
}
public static getWeightedEntry(entries: any[], weights: number[]): any {
return Randomizer.rng.weighted(entries, weights);
}
public static getRandomNumber(min: number, max: number): number {
// Don't do anything expensive if this isn't really a choice
if (max <= min) {
return min;
}
return Randomizer.rng.integer({ min, max });
}
}
 Benefits of using Chance:
 Convenience methods for data types
 Includes complex formats like
 Names
 Device IDs
 URLs
 Weighted probability supported
 Repeatably Random
 Minimalist Profile
https://chancejs.com
DEMO: Emergence
I will die. It will be hilarious.
Patreon.com/IntegerMan
Lessons Learned – Emergence
DO
 Thank people for their libraries
 Update dependencies on feature branches
 Find others using libraries and share what
you’re doing with them
DON’T
 Assume third party libraries will be
performant
 Forget that dependencies can cause
dependency versioning headaches
 Forget that keeping your options open has a
price
 In terms of schedule time
 In terms of inertia and energy
Overall Lessons Learned
General wisdom around integrating third party controls and libraries
Benefits of Third
Party Code
 Lets you focus on what you need for your
app to be successful
 Can drastically improve schedule
 Letting others specialize on their code can
lead to high degrees of polish
 Allows you to do things you wouldn’t be
able to do otherwise
Use a tool or
process if...
 It allows you to be more effective
 Do more in less time
 Produce a higher quality output
 Do the right work
 It eliminates a key pain
 TSLint
 Prettier
 Rollbar / Raygun
 Google Analytics / App Insights
 TeamCity / Jenkins
Potential Traps
 Can get you only 90% of the way there
 Customization can eat up time
 Workarounds can lead to chaos
 Issues sometimes only appear at scale
 Others don’t fix things on your timeline
 (or at all)
 Forking leads to issues updating later
Evaluating Libraries
1. Itemize must-haves and nice-to-haves
2. Identify potential libraries that match your
needs
1. Note any unexpected opportunities
2. Rate update frequency
3. Rate support responsiveness
3. Spike into core / complex use cases
4. Pick a library
5. Provide feedback to the author early
Reducing Risk
 Tackle tasks most likely to fail ASAP
 Highlights missing customization options
 Allows time for vendor fixes / workarounds
 Resist widespread propagation of third party types
 Wrap into a custom wrapper object
 Or use a façade to manage interactions
 Include third party code in automated tests
 Don’t test their core functionality
 Unless it has failed previously
 Test integration scenarios
Your Turn
Go and build all of the things (with some strategic help)
Questions & Links
My Stuff
 MattEland.com/ngApps/angularIF
 MattEland.com/Projects/Emergence
 Patreon.com/IntegerMan
 @IntegerMan
 LinkedIn.com/in/matteland
Libraries Mentioned
 handsontable.com
 rubaxa.github.io/Sortable
 compromise.cool
 github.com/toish/chromatism
 github.com/sbj42/the-field
 npmjs.com/package/ng-drag-drop
 chancejs.com
 pixijs.com
This talk available at: https://gitlab.com/IntegerMan/accelerating-angular-app-dev-talk

More Related Content

What's hot

Survival Strategies for API Documentation: Presentation to Southwestern Ontar...
Survival Strategies for API Documentation: Presentation to Southwestern Ontar...Survival Strategies for API Documentation: Presentation to Southwestern Ontar...
Survival Strategies for API Documentation: Presentation to Southwestern Ontar...
Tom Johnson
 
Bridging the virtual and the physical space : Kornelia - a chatbot for public...
Bridging the virtual and the physical space : Kornelia - a chatbot for public...Bridging the virtual and the physical space : Kornelia - a chatbot for public...
Bridging the virtual and the physical space : Kornelia - a chatbot for public...
Jasmin Hügi
 
Publishing API documentation -- Presentation
Publishing API documentation -- PresentationPublishing API documentation -- Presentation
Publishing API documentation -- Presentation
Tom Johnson
 
STC Summit 2015: API Documentation, an Example-Based Approach
STC Summit 2015: API Documentation, an Example-Based ApproachSTC Summit 2015: API Documentation, an Example-Based Approach
STC Summit 2015: API Documentation, an Example-Based ApproachLois Patterson
 
API Documentation Workshop tcworld India 2015
API Documentation Workshop tcworld India 2015API Documentation Workshop tcworld India 2015
API Documentation Workshop tcworld India 2015
Tom Johnson
 
API workshop: Deep dive into Java
API workshop: Deep dive into JavaAPI workshop: Deep dive into Java
API workshop: Deep dive into Java
Tom Johnson
 
One Engine Two Tools
One Engine Two ToolsOne Engine Two Tools
One Engine Two Tools
Chris Eargle
 
Build chatbots with api.ai and Google cloud functions
Build chatbots with api.ai and Google cloud functionsBuild chatbots with api.ai and Google cloud functions
Build chatbots with api.ai and Google cloud functions
The Incredible Automation Day
 
Hack in the Box GSEC 2016 - Reverse Engineering Swift Applications
Hack in the Box GSEC 2016 - Reverse Engineering Swift ApplicationsHack in the Box GSEC 2016 - Reverse Engineering Swift Applications
Hack in the Box GSEC 2016 - Reverse Engineering Swift Applications
eightbit
 
Monorepo: React + React Native. React Alicante
Monorepo:  React + React Native. React Alicante Monorepo:  React + React Native. React Alicante
Monorepo: React + React Native. React Alicante
Eugene Zharkov
 
Clean Software Design: The Practices to Make The Design Simple
Clean Software Design: The Practices to Make The Design SimpleClean Software Design: The Practices to Make The Design Simple
Clean Software Design: The Practices to Make The Design Simple
Lemi Orhan Ergin
 
Writing Your First Plugin
Writing Your First PluginWriting Your First Plugin
Writing Your First Plugin
George Ornbo
 
Monorepo: React Web & React Native
Monorepo: React Web & React NativeMonorepo: React Web & React Native
Monorepo: React Web & React Native
Eugene Zharkov
 
Publishing API documentation -- Workshop
Publishing API documentation -- WorkshopPublishing API documentation -- Workshop
Publishing API documentation -- Workshop
Tom Johnson
 
Build software like a bag of marbles, not a castle of LEGO®
Build software like a bag of marbles, not a castle of LEGO®Build software like a bag of marbles, not a castle of LEGO®
Build software like a bag of marbles, not a castle of LEGO®
Hannes Lowette
 
Software development fundamentals
Software development fundamentalsSoftware development fundamentals
Software development fundamentals
Alfred Jett Grandeza
 
Playgrounds: A Swift Introduction
Playgrounds: A Swift IntroductionPlaygrounds: A Swift Introduction
Playgrounds: A Swift Introduction
Jeremy Curcio
 
Building mobile apps with PhoneGap and Backbone
Building mobile apps with PhoneGap and BackboneBuilding mobile apps with PhoneGap and Backbone
Building mobile apps with PhoneGap and Backbone
Troy Miles
 
How to contribute to Apache Flink @ Seattle Flink meetup
How to contribute to Apache Flink @ Seattle Flink meetupHow to contribute to Apache Flink @ Seattle Flink meetup
How to contribute to Apache Flink @ Seattle Flink meetup
Bowen Li
 
DSL, Page Object and WebDriver – the path to reliable functional tests.pptx
DSL, Page Object and WebDriver – the path to reliable functional tests.pptxDSL, Page Object and WebDriver – the path to reliable functional tests.pptx
DSL, Page Object and WebDriver – the path to reliable functional tests.pptx
Mikalai Alimenkou
 

What's hot (20)

Survival Strategies for API Documentation: Presentation to Southwestern Ontar...
Survival Strategies for API Documentation: Presentation to Southwestern Ontar...Survival Strategies for API Documentation: Presentation to Southwestern Ontar...
Survival Strategies for API Documentation: Presentation to Southwestern Ontar...
 
Bridging the virtual and the physical space : Kornelia - a chatbot for public...
Bridging the virtual and the physical space : Kornelia - a chatbot for public...Bridging the virtual and the physical space : Kornelia - a chatbot for public...
Bridging the virtual and the physical space : Kornelia - a chatbot for public...
 
Publishing API documentation -- Presentation
Publishing API documentation -- PresentationPublishing API documentation -- Presentation
Publishing API documentation -- Presentation
 
STC Summit 2015: API Documentation, an Example-Based Approach
STC Summit 2015: API Documentation, an Example-Based ApproachSTC Summit 2015: API Documentation, an Example-Based Approach
STC Summit 2015: API Documentation, an Example-Based Approach
 
API Documentation Workshop tcworld India 2015
API Documentation Workshop tcworld India 2015API Documentation Workshop tcworld India 2015
API Documentation Workshop tcworld India 2015
 
API workshop: Deep dive into Java
API workshop: Deep dive into JavaAPI workshop: Deep dive into Java
API workshop: Deep dive into Java
 
One Engine Two Tools
One Engine Two ToolsOne Engine Two Tools
One Engine Two Tools
 
Build chatbots with api.ai and Google cloud functions
Build chatbots with api.ai and Google cloud functionsBuild chatbots with api.ai and Google cloud functions
Build chatbots with api.ai and Google cloud functions
 
Hack in the Box GSEC 2016 - Reverse Engineering Swift Applications
Hack in the Box GSEC 2016 - Reverse Engineering Swift ApplicationsHack in the Box GSEC 2016 - Reverse Engineering Swift Applications
Hack in the Box GSEC 2016 - Reverse Engineering Swift Applications
 
Monorepo: React + React Native. React Alicante
Monorepo:  React + React Native. React Alicante Monorepo:  React + React Native. React Alicante
Monorepo: React + React Native. React Alicante
 
Clean Software Design: The Practices to Make The Design Simple
Clean Software Design: The Practices to Make The Design SimpleClean Software Design: The Practices to Make The Design Simple
Clean Software Design: The Practices to Make The Design Simple
 
Writing Your First Plugin
Writing Your First PluginWriting Your First Plugin
Writing Your First Plugin
 
Monorepo: React Web & React Native
Monorepo: React Web & React NativeMonorepo: React Web & React Native
Monorepo: React Web & React Native
 
Publishing API documentation -- Workshop
Publishing API documentation -- WorkshopPublishing API documentation -- Workshop
Publishing API documentation -- Workshop
 
Build software like a bag of marbles, not a castle of LEGO®
Build software like a bag of marbles, not a castle of LEGO®Build software like a bag of marbles, not a castle of LEGO®
Build software like a bag of marbles, not a castle of LEGO®
 
Software development fundamentals
Software development fundamentalsSoftware development fundamentals
Software development fundamentals
 
Playgrounds: A Swift Introduction
Playgrounds: A Swift IntroductionPlaygrounds: A Swift Introduction
Playgrounds: A Swift Introduction
 
Building mobile apps with PhoneGap and Backbone
Building mobile apps with PhoneGap and BackboneBuilding mobile apps with PhoneGap and Backbone
Building mobile apps with PhoneGap and Backbone
 
How to contribute to Apache Flink @ Seattle Flink meetup
How to contribute to Apache Flink @ Seattle Flink meetupHow to contribute to Apache Flink @ Seattle Flink meetup
How to contribute to Apache Flink @ Seattle Flink meetup
 
DSL, Page Object and WebDriver – the path to reliable functional tests.pptx
DSL, Page Object and WebDriver – the path to reliable functional tests.pptxDSL, Page Object and WebDriver – the path to reliable functional tests.pptx
DSL, Page Object and WebDriver – the path to reliable functional tests.pptx
 

Similar to Accelerating Angular Application Development with Third Party Code

Buzzword, How'd They Build That?
Buzzword, How'd They Build That?Buzzword, How'd They Build That?
Buzzword, How'd They Build That?
dcoletta
 
Importance Of Being Driven
Importance Of Being DrivenImportance Of Being Driven
Importance Of Being Driven
Antonio Terreno
 
HTML5 Technical Executive Summary
HTML5 Technical Executive SummaryHTML5 Technical Executive Summary
HTML5 Technical Executive Summary
Gilad Khen
 
Domain Modeling & Full-Stack Web Development F#
Domain Modeling & Full-Stack Web Development F#Domain Modeling & Full-Stack Web Development F#
Domain Modeling & Full-Stack Web Development F#
Kevin Avignon
 
Markdown - friend or foe?
Markdown - friend or foe?Markdown - friend or foe?
Markdown - friend or foe?
Ellis Pratt
 
Designing Powerful Web Applications - Monterey
Designing Powerful Web Applications - MontereyDesigning Powerful Web Applications - Monterey
Designing Powerful Web Applications - Monterey
Dave Malouf
 
Whats New in Android
Whats New in AndroidWhats New in Android
Whats New in Android
donnfelker
 
JQuery Mobile vs Appcelerator Titanium vs Sencha Touch
JQuery Mobile vs Appcelerator Titanium vs Sencha TouchJQuery Mobile vs Appcelerator Titanium vs Sencha Touch
JQuery Mobile vs Appcelerator Titanium vs Sencha Touch
Steve Drucker
 
Envisioning the Future of Language Workbenches
Envisioning the Future of Language WorkbenchesEnvisioning the Future of Language Workbenches
Envisioning the Future of Language Workbenches
Markus Voelter
 
Bp308 Ibm Lotus Domino Web Facelift Using Ajax And Dxl
Bp308 Ibm Lotus Domino Web Facelift Using Ajax And DxlBp308 Ibm Lotus Domino Web Facelift Using Ajax And Dxl
Bp308 Ibm Lotus Domino Web Facelift Using Ajax And Dxldominion
 
Build your own Language - Why and How?
Build your own Language - Why and How?Build your own Language - Why and How?
Build your own Language - Why and How?
Markus Voelter
 
System design for Web Application
System design for Web ApplicationSystem design for Web Application
System design for Web Application
Michael Choi
 
UCD Android Workshop
UCD Android WorkshopUCD Android Workshop
UCD Android Workshop
Sean Murphy
 
How to build and publish a google home app with dialogflow
How to build and publish a google home app with dialogflowHow to build and publish a google home app with dialogflow
How to build and publish a google home app with dialogflow
Moses Sam Paul Johnraj
 
Untangling6
Untangling6Untangling6
Untangling6
Derek Jacoby
 
Write Better JavaScript
Write Better JavaScriptWrite Better JavaScript
Write Better JavaScriptKevin Whinnery
 

Similar to Accelerating Angular Application Development with Third Party Code (20)

Buzzword, How'd They Build That?
Buzzword, How'd They Build That?Buzzword, How'd They Build That?
Buzzword, How'd They Build That?
 
Importance Of Being Driven
Importance Of Being DrivenImportance Of Being Driven
Importance Of Being Driven
 
HTML5 Technical Executive Summary
HTML5 Technical Executive SummaryHTML5 Technical Executive Summary
HTML5 Technical Executive Summary
 
Domain Modeling & Full-Stack Web Development F#
Domain Modeling & Full-Stack Web Development F#Domain Modeling & Full-Stack Web Development F#
Domain Modeling & Full-Stack Web Development F#
 
Markdown - friend or foe?
Markdown - friend or foe?Markdown - friend or foe?
Markdown - friend or foe?
 
Spsmi13 charts
Spsmi13 chartsSpsmi13 charts
Spsmi13 charts
 
Designing Powerful Web Applications - Monterey
Designing Powerful Web Applications - MontereyDesigning Powerful Web Applications - Monterey
Designing Powerful Web Applications - Monterey
 
Whats New in Android
Whats New in AndroidWhats New in Android
Whats New in Android
 
Dean4j@Njug5
Dean4j@Njug5Dean4j@Njug5
Dean4j@Njug5
 
JQuery Mobile vs Appcelerator Titanium vs Sencha Touch
JQuery Mobile vs Appcelerator Titanium vs Sencha TouchJQuery Mobile vs Appcelerator Titanium vs Sencha Touch
JQuery Mobile vs Appcelerator Titanium vs Sencha Touch
 
Chhatarsha Singh
Chhatarsha SinghChhatarsha Singh
Chhatarsha Singh
 
Envisioning the Future of Language Workbenches
Envisioning the Future of Language WorkbenchesEnvisioning the Future of Language Workbenches
Envisioning the Future of Language Workbenches
 
Bp308 Ibm Lotus Domino Web Facelift Using Ajax And Dxl
Bp308 Ibm Lotus Domino Web Facelift Using Ajax And DxlBp308 Ibm Lotus Domino Web Facelift Using Ajax And Dxl
Bp308 Ibm Lotus Domino Web Facelift Using Ajax And Dxl
 
Build your own Language - Why and How?
Build your own Language - Why and How?Build your own Language - Why and How?
Build your own Language - Why and How?
 
Jmp108
Jmp108Jmp108
Jmp108
 
System design for Web Application
System design for Web ApplicationSystem design for Web Application
System design for Web Application
 
UCD Android Workshop
UCD Android WorkshopUCD Android Workshop
UCD Android Workshop
 
How to build and publish a google home app with dialogflow
How to build and publish a google home app with dialogflowHow to build and publish a google home app with dialogflow
How to build and publish a google home app with dialogflow
 
Untangling6
Untangling6Untangling6
Untangling6
 
Write Better JavaScript
Write Better JavaScriptWrite Better JavaScript
Write Better JavaScript
 

More from Matt Eland

Empowering Data Science Experiments with Azure Machine Learning.pptx
Empowering Data Science Experiments with Azure Machine Learning.pptxEmpowering Data Science Experiments with Azure Machine Learning.pptx
Empowering Data Science Experiments with Azure Machine Learning.pptx
Matt Eland
 
Expanding Your .NET Testing Toolbox - GLUG NET
Expanding Your .NET Testing Toolbox - GLUG NETExpanding Your .NET Testing Toolbox - GLUG NET
Expanding Your .NET Testing Toolbox - GLUG NET
Matt Eland
 
Building a Text Based Game in Modern JavaScript
Building a Text Based Game in Modern JavaScriptBuilding a Text Based Game in Modern JavaScript
Building a Text Based Game in Modern JavaScript
Matt Eland
 
Stand back; I'm going to try Scientist!
Stand back; I'm going to try Scientist!Stand back; I'm going to try Scientist!
Stand back; I'm going to try Scientist!
Matt Eland
 
Technical Debt Must Die: Communicating Code to Business Stakeholders
Technical Debt Must Die: Communicating Code to Business StakeholdersTechnical Debt Must Die: Communicating Code to Business Stakeholders
Technical Debt Must Die: Communicating Code to Business Stakeholders
Matt Eland
 
How do you tame a big ball of mud? One test at a time.
How do you tame a big ball of mud? One test at a time.How do you tame a big ball of mud? One test at a time.
How do you tame a big ball of mud? One test at a time.
Matt Eland
 

More from Matt Eland (6)

Empowering Data Science Experiments with Azure Machine Learning.pptx
Empowering Data Science Experiments with Azure Machine Learning.pptxEmpowering Data Science Experiments with Azure Machine Learning.pptx
Empowering Data Science Experiments with Azure Machine Learning.pptx
 
Expanding Your .NET Testing Toolbox - GLUG NET
Expanding Your .NET Testing Toolbox - GLUG NETExpanding Your .NET Testing Toolbox - GLUG NET
Expanding Your .NET Testing Toolbox - GLUG NET
 
Building a Text Based Game in Modern JavaScript
Building a Text Based Game in Modern JavaScriptBuilding a Text Based Game in Modern JavaScript
Building a Text Based Game in Modern JavaScript
 
Stand back; I'm going to try Scientist!
Stand back; I'm going to try Scientist!Stand back; I'm going to try Scientist!
Stand back; I'm going to try Scientist!
 
Technical Debt Must Die: Communicating Code to Business Stakeholders
Technical Debt Must Die: Communicating Code to Business StakeholdersTechnical Debt Must Die: Communicating Code to Business Stakeholders
Technical Debt Must Die: Communicating Code to Business Stakeholders
 
How do you tame a big ball of mud? One test at a time.
How do you tame a big ball of mud? One test at a time.How do you tame a big ball of mud? One test at a time.
How do you tame a big ball of mud? One test at a time.
 

Recently uploaded

一比一原版(UofT毕业证)多伦多大学毕业证成绩单如何办理
一比一原版(UofT毕业证)多伦多大学毕业证成绩单如何办理一比一原版(UofT毕业证)多伦多大学毕业证成绩单如何办理
一比一原版(UofT毕业证)多伦多大学毕业证成绩单如何办理
ydteq
 
Planning Of Procurement o different goods and services
Planning Of Procurement o different goods and servicesPlanning Of Procurement o different goods and services
Planning Of Procurement o different goods and services
JoytuBarua2
 
Hierarchical Digital Twin of a Naval Power System
Hierarchical Digital Twin of a Naval Power SystemHierarchical Digital Twin of a Naval Power System
Hierarchical Digital Twin of a Naval Power System
Kerry Sado
 
DESIGN A COTTON SEED SEPARATION MACHINE.docx
DESIGN A COTTON SEED SEPARATION MACHINE.docxDESIGN A COTTON SEED SEPARATION MACHINE.docx
DESIGN A COTTON SEED SEPARATION MACHINE.docx
FluxPrime1
 
power quality voltage fluctuation UNIT - I.pptx
power quality voltage fluctuation UNIT - I.pptxpower quality voltage fluctuation UNIT - I.pptx
power quality voltage fluctuation UNIT - I.pptx
ViniHema
 
MCQ Soil mechanics questions (Soil shear strength).pdf
MCQ Soil mechanics questions (Soil shear strength).pdfMCQ Soil mechanics questions (Soil shear strength).pdf
MCQ Soil mechanics questions (Soil shear strength).pdf
Osamah Alsalih
 
ML for identifying fraud using open blockchain data.pptx
ML for identifying fraud using open blockchain data.pptxML for identifying fraud using open blockchain data.pptx
ML for identifying fraud using open blockchain data.pptx
Vijay Dialani, PhD
 
Architectural Portfolio Sean Lockwood
Architectural Portfolio Sean LockwoodArchitectural Portfolio Sean Lockwood
Architectural Portfolio Sean Lockwood
seandesed
 
Water Industry Process Automation and Control Monthly - May 2024.pdf
Water Industry Process Automation and Control Monthly - May 2024.pdfWater Industry Process Automation and Control Monthly - May 2024.pdf
Water Industry Process Automation and Control Monthly - May 2024.pdf
Water Industry Process Automation & Control
 
Fundamentals of Electric Drives and its applications.pptx
Fundamentals of Electric Drives and its applications.pptxFundamentals of Electric Drives and its applications.pptx
Fundamentals of Electric Drives and its applications.pptx
manasideore6
 
一比一原版(IIT毕业证)伊利诺伊理工大学毕业证成绩单专业办理
一比一原版(IIT毕业证)伊利诺伊理工大学毕业证成绩单专业办理一比一原版(IIT毕业证)伊利诺伊理工大学毕业证成绩单专业办理
一比一原版(IIT毕业证)伊利诺伊理工大学毕业证成绩单专业办理
zwunae
 
Runway Orientation Based on the Wind Rose Diagram.pptx
Runway Orientation Based on the Wind Rose Diagram.pptxRunway Orientation Based on the Wind Rose Diagram.pptx
Runway Orientation Based on the Wind Rose Diagram.pptx
SupreethSP4
 
weather web application report.pdf
weather web application report.pdfweather web application report.pdf
weather web application report.pdf
Pratik Pawar
 
The Benefits and Techniques of Trenchless Pipe Repair.pdf
The Benefits and Techniques of Trenchless Pipe Repair.pdfThe Benefits and Techniques of Trenchless Pipe Repair.pdf
The Benefits and Techniques of Trenchless Pipe Repair.pdf
Pipe Restoration Solutions
 
The role of big data in decision making.
The role of big data in decision making.The role of big data in decision making.
The role of big data in decision making.
ankuprajapati0525
 
Sachpazis:Terzaghi Bearing Capacity Estimation in simple terms with Calculati...
Sachpazis:Terzaghi Bearing Capacity Estimation in simple terms with Calculati...Sachpazis:Terzaghi Bearing Capacity Estimation in simple terms with Calculati...
Sachpazis:Terzaghi Bearing Capacity Estimation in simple terms with Calculati...
Dr.Costas Sachpazis
 
J.Yang, ICLR 2024, MLILAB, KAIST AI.pdf
J.Yang,  ICLR 2024, MLILAB, KAIST AI.pdfJ.Yang,  ICLR 2024, MLILAB, KAIST AI.pdf
J.Yang, ICLR 2024, MLILAB, KAIST AI.pdf
MLILAB
 
space technology lecture notes on satellite
space technology lecture notes on satellitespace technology lecture notes on satellite
space technology lecture notes on satellite
ongomchris
 
RAT: Retrieval Augmented Thoughts Elicit Context-Aware Reasoning in Long-Hori...
RAT: Retrieval Augmented Thoughts Elicit Context-Aware Reasoning in Long-Hori...RAT: Retrieval Augmented Thoughts Elicit Context-Aware Reasoning in Long-Hori...
RAT: Retrieval Augmented Thoughts Elicit Context-Aware Reasoning in Long-Hori...
thanhdowork
 
Gen AI Study Jams _ For the GDSC Leads in India.pdf
Gen AI Study Jams _ For the GDSC Leads in India.pdfGen AI Study Jams _ For the GDSC Leads in India.pdf
Gen AI Study Jams _ For the GDSC Leads in India.pdf
gdsczhcet
 

Recently uploaded (20)

一比一原版(UofT毕业证)多伦多大学毕业证成绩单如何办理
一比一原版(UofT毕业证)多伦多大学毕业证成绩单如何办理一比一原版(UofT毕业证)多伦多大学毕业证成绩单如何办理
一比一原版(UofT毕业证)多伦多大学毕业证成绩单如何办理
 
Planning Of Procurement o different goods and services
Planning Of Procurement o different goods and servicesPlanning Of Procurement o different goods and services
Planning Of Procurement o different goods and services
 
Hierarchical Digital Twin of a Naval Power System
Hierarchical Digital Twin of a Naval Power SystemHierarchical Digital Twin of a Naval Power System
Hierarchical Digital Twin of a Naval Power System
 
DESIGN A COTTON SEED SEPARATION MACHINE.docx
DESIGN A COTTON SEED SEPARATION MACHINE.docxDESIGN A COTTON SEED SEPARATION MACHINE.docx
DESIGN A COTTON SEED SEPARATION MACHINE.docx
 
power quality voltage fluctuation UNIT - I.pptx
power quality voltage fluctuation UNIT - I.pptxpower quality voltage fluctuation UNIT - I.pptx
power quality voltage fluctuation UNIT - I.pptx
 
MCQ Soil mechanics questions (Soil shear strength).pdf
MCQ Soil mechanics questions (Soil shear strength).pdfMCQ Soil mechanics questions (Soil shear strength).pdf
MCQ Soil mechanics questions (Soil shear strength).pdf
 
ML for identifying fraud using open blockchain data.pptx
ML for identifying fraud using open blockchain data.pptxML for identifying fraud using open blockchain data.pptx
ML for identifying fraud using open blockchain data.pptx
 
Architectural Portfolio Sean Lockwood
Architectural Portfolio Sean LockwoodArchitectural Portfolio Sean Lockwood
Architectural Portfolio Sean Lockwood
 
Water Industry Process Automation and Control Monthly - May 2024.pdf
Water Industry Process Automation and Control Monthly - May 2024.pdfWater Industry Process Automation and Control Monthly - May 2024.pdf
Water Industry Process Automation and Control Monthly - May 2024.pdf
 
Fundamentals of Electric Drives and its applications.pptx
Fundamentals of Electric Drives and its applications.pptxFundamentals of Electric Drives and its applications.pptx
Fundamentals of Electric Drives and its applications.pptx
 
一比一原版(IIT毕业证)伊利诺伊理工大学毕业证成绩单专业办理
一比一原版(IIT毕业证)伊利诺伊理工大学毕业证成绩单专业办理一比一原版(IIT毕业证)伊利诺伊理工大学毕业证成绩单专业办理
一比一原版(IIT毕业证)伊利诺伊理工大学毕业证成绩单专业办理
 
Runway Orientation Based on the Wind Rose Diagram.pptx
Runway Orientation Based on the Wind Rose Diagram.pptxRunway Orientation Based on the Wind Rose Diagram.pptx
Runway Orientation Based on the Wind Rose Diagram.pptx
 
weather web application report.pdf
weather web application report.pdfweather web application report.pdf
weather web application report.pdf
 
The Benefits and Techniques of Trenchless Pipe Repair.pdf
The Benefits and Techniques of Trenchless Pipe Repair.pdfThe Benefits and Techniques of Trenchless Pipe Repair.pdf
The Benefits and Techniques of Trenchless Pipe Repair.pdf
 
The role of big data in decision making.
The role of big data in decision making.The role of big data in decision making.
The role of big data in decision making.
 
Sachpazis:Terzaghi Bearing Capacity Estimation in simple terms with Calculati...
Sachpazis:Terzaghi Bearing Capacity Estimation in simple terms with Calculati...Sachpazis:Terzaghi Bearing Capacity Estimation in simple terms with Calculati...
Sachpazis:Terzaghi Bearing Capacity Estimation in simple terms with Calculati...
 
J.Yang, ICLR 2024, MLILAB, KAIST AI.pdf
J.Yang,  ICLR 2024, MLILAB, KAIST AI.pdfJ.Yang,  ICLR 2024, MLILAB, KAIST AI.pdf
J.Yang, ICLR 2024, MLILAB, KAIST AI.pdf
 
space technology lecture notes on satellite
space technology lecture notes on satellitespace technology lecture notes on satellite
space technology lecture notes on satellite
 
RAT: Retrieval Augmented Thoughts Elicit Context-Aware Reasoning in Long-Hori...
RAT: Retrieval Augmented Thoughts Elicit Context-Aware Reasoning in Long-Hori...RAT: Retrieval Augmented Thoughts Elicit Context-Aware Reasoning in Long-Hori...
RAT: Retrieval Augmented Thoughts Elicit Context-Aware Reasoning in Long-Hori...
 
Gen AI Study Jams _ For the GDSC Leads in India.pdf
Gen AI Study Jams _ For the GDSC Leads in India.pdfGen AI Study Jams _ For the GDSC Leads in India.pdf
Gen AI Study Jams _ For the GDSC Leads in India.pdf
 

Accelerating Angular Application Development with Third Party Code

  • 2. Matt Eland Website http://www.MattEland.com Twitter @IntegerMan LinkedIn https://www.linkedin.com/in/matteland/ Currently:  Lead Software Engineer @ MoveHQ Previously:  Senior Software Engineer @ TeamDynamix  Software Developer @ Exceptional Innovation  Software Engineer @ Verizon Business
  • 3. This presentation is like a mullet Business in the front; party in the back
  • 4. Talk Overview Angular Plan Manager Gantt Chart / Task Management App Backlog Manager / Card Wall Agile Project Management Tools Angular IF Interactive Fiction Game Engine Prototype Emergence Roguelike Game Overall Lessons Learned Okay, so maybe note exactly like a mullet...
  • 5. Talk Overview Angular Plan Manager Gantt Chart / Task Management App Backlog Manager / Card Wall Agile Project Management Tools Angular IF Interactive Fiction Game Engine Prototype Emergence Roguelike Game Overall Lessons Learned Okay, so maybe note exactly like a mullet...
  • 6. Talk Overview Angular Plan Manager Gantt Chart / Task Management App Backlog Manager / Card Wall Agile Project Management Tools Angular IF Interactive Fiction Game Engine Prototype Emergence Roguelike Game Overall Lessons Learned Okay, so maybe note exactly like a mullet...
  • 7. Some Disclaimers This talk IS about When should third party code be considered How to reduce risk when using external code Some examples from various projects This talk is NOT Focused on code An in-depth discussion of Angular An Angular tutorial
  • 8. What is Angular?  Angular vs AngularJS  Created by Google in 2016  Single Page Application (SPA) framework  Built around TypeScript  Quick start with Angular CLI and npm  Consists of common types of entities (Services, Components, Pipes, etc.)  A “M-V-Whatever” application framework
  • 9. Angular Plan Manager Angular adaptation of a Silverlight project planning application
  • 10. Angular Plan Manager Built in 2015-2016 on Angular 2.0 RC2 Angular 2 was not officially released until after the project initially shipped Intended as a web-based alternative to Project Gantt Chart DataGrid with inline editing Complex Clipboard Support Replaced an existing Silverlight application If you don’t know this pain, I envy you a little. Mirrored the capabilities of a complex WPF app Iteratively developed over around 3 years. Grew from WPF to WPF / Silverlight
  • 11. Angular Plan Manager – Key Problems User Experience Grid-based editing capabilities, including copy / paste Product needed a Gantt Chart to resemble other products Technology Limitations Potentially large and hierarchical data sets Domain logic is complex and written in .NET Heavily Client / Server Oriented Project Constraints Fixed deadline (Chrome’s removal of Silverlight) Angular 2 not formally released until after the deadline
  • 12. HandsOnTable to the Rescue?  Best capabilities of all alternatives viewed  Square Peg / Round Hole  Product still rapidly evolving  No Angular support at time of adoption  API was extremely cumbersome and later replaced  We had to fork and modify  Got the job done  Performance was an issue  Long-term, the UI layer was likely throwaway
  • 13. Lessons Learned – Angular Plan Manager DO  Spike into options early on in a project  Identify core use cases for a component  Go with the “best worst” option  Whatever it takes when the project impact is important enough  Your best to sleep at night after horrible hacks are made DON’T  Fork 3rd Party Libraries  Forget to plan to upgrading beta components once they mature  Invest development in a technology that can be globally killed like Silverlight
  • 14. “TD Agile” Internal name for the Backlog Manager and Card Wall Angular applications.
  • 15. “TD Agile” (Think Jira Agile) Built in 2017–2018 using Angular 4 Compete against bigger fish Primarily Jira Backlog Manager Product Backlog Management tool Card Wall Agile Scrum Board Replaced an Angular JS Implementation Shared logic between apps Card Details
  • 16. Backlog Manager Multi-sprint backlog planning tool with drag and drop task and resource management
  • 17. Card Wall Angular-based drag and drop agile card wall
  • 18. “TD Agile” - Key Problems User Experience Required real-time updates from concurrent users Needed a slick drag-drop UI with multiple classes of draggable items Needed to work with a variety of users with different permissions levels Project Constraints Could not drop existing features Needed to be ready for release before the annual user conference
  • 19. So very Sortable  Wound up relying on a customized version of Sortable.JS  Only minor customization was needed  Needed more detail on the context of the drag operation  Resulting library capable of:  Drag / Drop items in lists  Lists of items  Lists of lists of items  Preventing Drag or Drop Conditionally  Feeding us enough information to grab the model object out of the list
  • 20. Lessons Learned – “TD Agile” DO  Dedicate time to evaluating libraries  Share components and services between major app areas where it makes sense  Rapidly prototype and iterate when making a UI heavy project  Define standard patterns and helpers to consolidate client-server interaction logic  Consider using the Redux pattern in Angular when the application is complex DON’T  Evaluate third party libraries without understanding all major requirements  Expect third party libraries to fix bugs or accept pull requests  Neglect Server-Side Logging
  • 21. Angular IF Simultaneously Beating a Dead Horse and Reinventing the Wheel http://matteland.com/ngApps/angularIF/
  • 22. “Angular IF”  Built for fun in Angular 4 in 2017  Later converted to Angular 5  IF = Interactive Fiction  i.e. Zork, Enchanter, The Lurking Horror, Wishbringer  A modern web development take on a childhood and early adult hobby of mine  Intended to practice larger application development using TypeScript
  • 23. Angular IF – Key Problems Architecture Problems Needed to be data-driven Needed to be highly testable Should not need to talk to a server once loaded Needed an integrated editor IF-Oriented Problems Potentially a large amount of possible (valid) things to try Lots of different ways to state the same command Generic responses can be frustrating Limited system vocabularies can be frustrating
  • 24. How an Input Becomes a Response Tokenizer Sentence is broken down into words Some Substitution occurs: “Pick Up” becomes “Get”, “W” becomes “West”, etc. Lexer Individual tokens are augmented with tags Parser Token relationships are extrapolated based on parts of speech Interpreting Match nouns to items inside the game world Execution Sentence command is handed off to the verb handler. nlp-compromise http://compromise.cool/
  • 25. Tokenizer User Input > “Open the door using the rusty key.” Tokens  Open  The  Door  Using  The  Rusty  Key nlp-compromise http://compromise.cool/
  • 26. Lexer Tokens  Open  The  Door  Using  The  Rusty  Key CommandTokens (Tokens with Compromise information)  Open [Verb, VerbPhrase]  The [Determiner]  Door [Noun, Singular]  Using [Gerund, PresentTense, Verb, VerbPhrase]  The [Determiner]  Rusty [Adjective]  Key [Noun, Singular] nlp-compromise With some custom definitions & tweaks http://compromise.cool/
  • 27. Tokenizing input with nlp-compromise public getTerms(sentence: string): LanguageTerm[] { // Commas are death. sentence = StringHelper.replaceAll(sentence, ',', ''); const lexicon = LexiconService.instance.lexicon; const data: LanguageTerm[] = this.nlp(sentence, lexicon).terms().data(); // Compromise casing workaround omitted for clarity return data; } http://compromise.cool/
  • 28. Enhancing Compromise’s Intelligence Compromise Term CommandToken Abstraction Object export class CommandToken { name: string; term: LanguageTerm; classification: TokenClassification; isInferred: boolean = false; previousToken: CommandToken; nextToken: CommandToken; modifies: CommandToken[]; modifiedBy: CommandToken[]; entity: EntityBase; // Supporting methods and properties } http://compromise.cool/ export class LanguageTerm { text: string; bestTag: string; tags: string[]; normal: string; implicit: string; spaceBefore: string; spaceAfter: string; }
  • 29. Parsing & Interpreting Considerations  Identify the first verb  See if other verbs can act as other parts of speech  Infer a subject if no noun is before the verb  Link nouns to local entities  Associate adjectives & determiners with next noun  Associate adverbs with the verbs  Split along prepositional phrases (e.g. using) Command Object
  • 30. Execution Input  VerbHandler (if one is implemented)  Command (parsed sentence structure)  CommandContext  Room  Player  Misc. world data  Methods to manipulate the game world Output One or more Story Responses:  “I don’t see a door here” Or...  “You unlock the door using the rusty key”  “The door opens with a noisy creak”  Your score has gone up by one point
  • 31. Sample Verb Handler export class WinHandler extends VerbHandler { get isHidden(): boolean { return true; } get verbType(): VerbType { return VerbType.system; } handleCommand(command: Command, context: CommandContext): CommandResult { if (!environment.showDebugAids) { // Win is not a valid verb in production context.output.addSystem('Cheaters never prosper.'); } else { // But in dev it is! context.engine.endGame(context, true, 'Well, that was easy.'); } return CommandResult.BuildActionSuccessResult(); } }
  • 32. DEMO: Angular IF Hello Cloak of Darkness http://matteland.com/ngApps/angularIF/index.html
  • 33. Testing Strategy Manual Tests Can I still type in text and see a response? Unit Tests Phrase / Word Substitution Component Tests Angular CLI Smoke Tests for Services / Components Integration Tests Room / Story / Scenario-based Tests
  • 34. Sample Story-Based Tests it('should be winnable with max score in 5 moves', () => { game.input('w'); game.input('put the cloak on the small hook'); game.input('e'); game.input('s'); game.input('x message'); expect(game.gameState).toBe(GameState.won); expect(game.currentScore).toBe(2); }); it('should be loseable', () => { game.input('s'); game.input('drop cloak'); game.input('x self'); game.input('x room'); game.input('n'); game.input('w'); game.input('put the cloak on the small hook'); game.input('e'); game.input('s'); game.input('x message'); expect(game.gameState).toBe(GameState.lost); expect(game.currentScore).toBe(1); });
  • 35. Sample Room-based Test it('should contain a front yard room that passes spec validation', () => { const spec = game.buildRoomSpec(room) .shouldResolveFrom(`frontyard`) .shouldResolveFrom(`front yard`) .shouldNavigateTo('w', 'nearplayground') .shouldNavigateTo('e', 'cornerwp') .shouldNavigateTo('s', 'hall') .shouldNavigateTo('se', 'sideyard') .shouldNavigateTo('go in', 'hall') .shouldNavigateTo('go inside', 'hall') .shouldNavigateTo('go to the sideyard', 'sideyard') .shouldFailNavigationTo('sw', `poop`) .shouldFailNavigationTo('nw', `house`) .shouldFailNavigationTo('n', `house`) .shouldFailNavigationTo('ne', `house`) .shouldRespondToCommandWith(`look`, `front`, `yard`, `car`, `fog`, `house`, `door`, `west`, `east`, `southeast`) .shouldRespondToCommandWith(`look s`, `door`) .shouldRespondToCommandWith(`look n`, `neighbor`) .shouldRespondToCommandWith(`look w`, `street`) .shouldRespondToCommandWith(`look e`, `corner`) .shouldNotBeGettable('serious'); expect(spec.validate()).toBeFalsy(); });
  • 36. Helper Object for Fluent Tests export class RoomSpec extends EntitySpec { public shouldNavigateTo(command: string, newRoomKey: string): RoomSpec { this.addCheck( () => { this.game.input(command); const actualKey = this.game.currentRoom.key; if (actualKey !== newRoomKey) { return `Expected '${command}' to result in a current room of ${newRoomKey} but current room is ${actualKey}.`; } return null; }); return this; } public shouldFailNavigationTo(command: string, ...expectedResponses: string[]): RoomSpec { this.addCheck( () => { this.game.input(command); const actualKey = this.game.currentRoom.key; if (actualKey !== this.key) { return `Expected navigation to ${command} to result in remaining in ${this.key} but current room is ${actualKey}.`; } return this.checkForExpectedReply(...expectedResponses); }); return this; } }
  • 37. Troubleshooting Complex User Input Debugging Displays Sentence Structure Object State Token Analysis Specialized Verbs Debug Verb ReportBug Verb Reporting Rollbar Google Analytics
  • 38. Lessons Learned – Angular IF DO  Test integrations, especially when they have a broad surface area  Outsource complex aspects of your app that you don’t need to heavily customize  Wrap external code in facades and abstraction objects DON’T  Only evaluate one library  Try to force something into a client-side only box that should really be client-server  Build an editor when command line would work instead
  • 39. Emergence Because building a Roguelike in JavaScript sounds like fun!
  • 40. Emergence  A Roguelike inspired by Dungeons of Dredmor  Set in a computer network  Player is a newly “awakened” AI entity  Objective is to escape to the Internet  Levels are machines in the network  In active development under Angular 5 / .NET Core 2.0  Initial version was entirely client-side logic in Angular 4 / TypeScript  In a transitory Client / Server state  Will ultimately wind up in Unity
  • 41. Emergence – Key Problems Rendering Mixing Angular content and the main game surface Animation Performance Art Assets Roguelike Challenges Procedural Generation Random Number Generation Artificial Intelligence Line of Sight Algorithm Gamedev Issues Continuous Deployment Production / Preview / Nightly Branches Busy Seasons of Life Holy Scope Creep, Batman
  • 42. Web API  .NET Core 2.0 Web API Project  Called by multiple Angular app deployments  Maturity Level 2 REST Service  Resources & Verbs  No HATEOAS  No backing data store  Uses Swashbuckle  Generates Swagger file and Swagger UI  Decreases development time  Encourages documentation  Increases discoverability  Hosted as an Azure Web App
  • 43. Emergence – Major Components External Code  Rendering / Animation  Pixi .JS  Chromatism  UI Styling  Customized Materialize CSS and Angular Material  Uses ng-drag-drop to make the UI interactive  Calculations  Visibility with The Field (will need a C# alternative)  Random number generation with Chance  TODO, but likely will use external code  Artificial Intelligence  Pathfinding Custom Built  Core Game Engine  Character Management  World Generation  Menu System  Help System  Could have been relegated to a CMS
  • 44. Color tweaks with Chromatism  Benefits of Chromatism:  Flexible color models  Simple color adjustments  Drawbacks of Chromatism:  So CPU intensive it required caching  Typing Colour can be distracting export class ColorHelper { private static shadeValues: string[]; /** * Gets a faded variant of the requested shade. * This method is performance intensive, so values are cached. */ public static getFadedColor(bgColor: string): string { // Initialize the cache as needed if (!this.shadeValues) { this.shadeValues = []; } // Check to see if we have it in the cache if (this.shadeValues[bgColor]) { return this.shadeValues[bgColor]; } // We don't have it in the cache, do the computation let c: ColourObject = chromatism.convert(bgColor); c = chromatism.contrast(0.25, c.rgb); c = chromatism.shade(-5, c.rgb); // Store the value for next time this.shadeValues[bgColor] = c.hex; return c.hex; } // More goodness... } https://github.com/toish/chromatism
  • 45. Line of Sight with “The Field” export class FovCalculator { public static calculateVisibleCellsFromPoint(pos: Point, visionRadius: number, level: GameLevel): Cell[] { const offset: Point = new Point(pos.x - Math.floor(visionRadius), pos.y - Math.floor(visionRadius)); const candidates: Cell[] = level.getCellGrid(pos, true, Math.floor(visionRadius)); const fov: MaskRect = FovCalculator.getFieldOfView(pos, visionRadius, candidates, offset); const cells: Cell[] = []; for (const cell of candidates) { const distance: number = pos.calculateDistanceFrom(cell.pos); if (distance <= visionRadius) { if (cell && fov.get(cell.pos.x - offset.x, cell.pos.y - offset.y)) { cells.push(cell); } } } return cells; } private static getFieldOfView(pos: Point, visionRadius: number, candidates: Cell[], offset: Point): MaskRect { const fovRange: number = Math.floor(visionRadius * 2 + 1); const map: FieldOfViewMap = new TheField.FieldOfViewMap(fovRange, fovRange); for (const cell of candidates) { if (cell && !cell.pos.equals(pos) && cell.generatesSightBlocker) { map.addBody(cell.pos.x - offset.x, cell.pos.y - offset.y); } } return map.getFieldOfView(pos.x - offset.x, pos.y - offset.y, Math.floor(visionRadius)); } }  Benefits of The Field  Don’t need to worry about visibility  Low footprint  Integration is easily testable  Developer was very responsive https://github.com/sbj42/the-field
  • 46. Dragon Drop with ng-drag-drop  Benefits of ng-drag-drop  Simple to use  Built for Angular  (though some issues with Angular 6)  Meets my basic needs in a concise way // command-management-screen.component.html <mat-grid-list [cols]="10“ #listAvailable id="listAvailable"> <mat-grid-tile *ngFor="let slot of actor.storedCommandSlots"> <em-command-slot class="command-slot" draggable droppable [dragScope]="'command’” [dropScope]="'command’” [dragData]="slot" (onDrop)="onCommandDropped(slot, $event)" (click)="selectSlot(slot)" [slot]="slot" [isSortable]="true" [selected]="slot === selectedSlot"> </em-command-slot> </mat-grid-tile> </mat-grid-list> // command-management-screen.component.ts public onCommandDropped(target: CommandSlot, e: DropEvent): void { Logger.debug(`Command drop detected`, target, e); // Have a centralized helper carry out the swap const source: CommandSlot = <CommandSlot>e.dragData; DragonDropHelper.handleCommandDragDrop(target, source); // Ensure the selection moves to the new slot if (this.selectedSlot === source) { this.selectedSlot = target; } } https://www.npmjs.com/package/ng-drag-drop
  • 47. Better Random Numbers with Chance import * as Chance from 'chance'; import {isNullOrUndefined} from 'util'; export class Randomizer { private static _chance: Chance = null; private static get rng(): Chance { // Lazy instantiate the Chance library if (isNullOrUndefined(Randomizer._chance)) { Randomizer._chance = new Chance(); } return Randomizer._chance; } public static getWeightedEntry(entries: any[], weights: number[]): any { return Randomizer.rng.weighted(entries, weights); } public static getRandomNumber(min: number, max: number): number { // Don't do anything expensive if this isn't really a choice if (max <= min) { return min; } return Randomizer.rng.integer({ min, max }); } }  Benefits of using Chance:  Convenience methods for data types  Includes complex formats like  Names  Device IDs  URLs  Weighted probability supported  Repeatably Random  Minimalist Profile https://chancejs.com
  • 48. DEMO: Emergence I will die. It will be hilarious. Patreon.com/IntegerMan
  • 49. Lessons Learned – Emergence DO  Thank people for their libraries  Update dependencies on feature branches  Find others using libraries and share what you’re doing with them DON’T  Assume third party libraries will be performant  Forget that dependencies can cause dependency versioning headaches  Forget that keeping your options open has a price  In terms of schedule time  In terms of inertia and energy
  • 50. Overall Lessons Learned General wisdom around integrating third party controls and libraries
  • 51. Benefits of Third Party Code  Lets you focus on what you need for your app to be successful  Can drastically improve schedule  Letting others specialize on their code can lead to high degrees of polish  Allows you to do things you wouldn’t be able to do otherwise
  • 52. Use a tool or process if...  It allows you to be more effective  Do more in less time  Produce a higher quality output  Do the right work  It eliminates a key pain  TSLint  Prettier  Rollbar / Raygun  Google Analytics / App Insights  TeamCity / Jenkins
  • 53. Potential Traps  Can get you only 90% of the way there  Customization can eat up time  Workarounds can lead to chaos  Issues sometimes only appear at scale  Others don’t fix things on your timeline  (or at all)  Forking leads to issues updating later
  • 54. Evaluating Libraries 1. Itemize must-haves and nice-to-haves 2. Identify potential libraries that match your needs 1. Note any unexpected opportunities 2. Rate update frequency 3. Rate support responsiveness 3. Spike into core / complex use cases 4. Pick a library 5. Provide feedback to the author early
  • 55. Reducing Risk  Tackle tasks most likely to fail ASAP  Highlights missing customization options  Allows time for vendor fixes / workarounds  Resist widespread propagation of third party types  Wrap into a custom wrapper object  Or use a façade to manage interactions  Include third party code in automated tests  Don’t test their core functionality  Unless it has failed previously  Test integration scenarios
  • 56. Your Turn Go and build all of the things (with some strategic help)
  • 57. Questions & Links My Stuff  MattEland.com/ngApps/angularIF  MattEland.com/Projects/Emergence  Patreon.com/IntegerMan  @IntegerMan  LinkedIn.com/in/matteland Libraries Mentioned  handsontable.com  rubaxa.github.io/Sortable  compromise.cool  github.com/toish/chromatism  github.com/sbj42/the-field  npmjs.com/package/ng-drag-drop  chancejs.com  pixijs.com This talk available at: https://gitlab.com/IntegerMan/accelerating-angular-app-dev-talk