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

PDF
Towards an Agile Authoring methodology: Learning from Lean
PDF
M is for modernization
PPTX
Writing code samples for API/SDK documentation
PPTX
06 integrating extra features and looking forward
PPTX
API Workshop: Deep dive into code samples
PPTX
API workshop: Introduction to APIs (TC Camp)
PPTX
AI and Python: Developing a Conversational Interface using Python
PPTX
API Workshop: Deep dive into REST APIs
Towards an Agile Authoring methodology: Learning from Lean
M is for modernization
Writing code samples for API/SDK documentation
06 integrating extra features and looking forward
API Workshop: Deep dive into code samples
API workshop: Introduction to APIs (TC Camp)
AI and Python: Developing a Conversational Interface using Python
API Workshop: Deep dive into REST APIs

What's hot (20)

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

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

PDF
FFS The Browser and Everything In It Is Wrong - We've Ruined Software Enginee...
PDF
Quick introduction to Angular 4 for AngularJS 1.5 developers
PDF
Learn With Angular 4 Bootstrap And Nodejs 2nd Edition Jeffry Houser
PDF
Where and Why Use Angular for Web Development?
PDF
Evolution and History of Angular as Web Development Platform.pdf
PDF
Test-Driven Development with TypeScript+Jasmine+AngularJS
PPTX
Detailed Guide of Angular Development 2022.pptx
PDF
Building Enterprise Grade Front-End Applications with JavaScript Frameworks
PDF
Why Angular It's Still a Top Choice for Developers in 2025.pdf
PPTX
PDF
The Pros and Cons of Angular Development: All You Need to Know
PDF
AngularJS vs NodeJS vs ReactJS Which One Would You Choose.pdf
ODP
Angular 6 - The Complete Guide
PDF
AngularJS vs NodeJS vs ReactJS Which One Would You Choose.pdf
PDF
How Angular Development services can help you in expanding your business?.pdf
PPTX
AngularJS2 / TypeScript / CLI
DOCX
Best Angular JS training in Hyderabad, India
PPTX
2018-09 - F# and Fable
PDF
How Angular Streamlines Complex Mobile App Development Projects.pdf
PDF
FFS The Browser and Everything In It Is Wrong - We've Ruined Software Enginee...
Quick introduction to Angular 4 for AngularJS 1.5 developers
Learn With Angular 4 Bootstrap And Nodejs 2nd Edition Jeffry Houser
Where and Why Use Angular for Web Development?
Evolution and History of Angular as Web Development Platform.pdf
Test-Driven Development with TypeScript+Jasmine+AngularJS
Detailed Guide of Angular Development 2022.pptx
Building Enterprise Grade Front-End Applications with JavaScript Frameworks
Why Angular It's Still a Top Choice for Developers in 2025.pdf
The Pros and Cons of Angular Development: All You Need to Know
AngularJS vs NodeJS vs ReactJS Which One Would You Choose.pdf
Angular 6 - The Complete Guide
AngularJS vs NodeJS vs ReactJS Which One Would You Choose.pdf
How Angular Development services can help you in expanding your business?.pdf
AngularJS2 / TypeScript / CLI
Best Angular JS training in Hyderabad, India
2018-09 - F# and Fable
How Angular Streamlines Complex Mobile App Development Projects.pdf
Ad

More from Matt Eland (6)

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

Recently uploaded (20)

PPTX
Internet of Things (IOT) - A guide to understanding
PPTX
Infosys Presentation by1.Riyan Bagwan 2.Samadhan Naiknavare 3.Gaurav Shinde 4...
PDF
PRIZ Academy - 9 Windows Thinking Where to Invest Today to Win Tomorrow.pdf
PPTX
Current and future trends in Computer Vision.pptx
PDF
Evaluating the Democratization of the Turkish Armed Forces from a Normative P...
PPTX
MET 305 2019 SCHEME MODULE 2 COMPLETE.pptx
PDF
keyrequirementskkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
PPTX
Safety Seminar civil to be ensured for safe working.
PDF
Enhancing Cyber Defense Against Zero-Day Attacks using Ensemble Neural Networks
PDF
Mitigating Risks through Effective Management for Enhancing Organizational Pe...
PDF
Unit I ESSENTIAL OF DIGITAL MARKETING.pdf
PDF
Operating System & Kernel Study Guide-1 - converted.pdf
DOCX
ASol_English-Language-Literature-Set-1-27-02-2023-converted.docx
PPTX
FINAL REVIEW FOR COPD DIANOSIS FOR PULMONARY DISEASE.pptx
PPTX
CH1 Production IntroductoryConcepts.pptx
PPTX
additive manufacturing of ss316l using mig welding
PDF
composite construction of structures.pdf
PPT
Project quality management in manufacturing
PDF
Mohammad Mahdi Farshadian CV - Prospective PhD Student 2026
PDF
BMEC211 - INTRODUCTION TO MECHATRONICS-1.pdf
Internet of Things (IOT) - A guide to understanding
Infosys Presentation by1.Riyan Bagwan 2.Samadhan Naiknavare 3.Gaurav Shinde 4...
PRIZ Academy - 9 Windows Thinking Where to Invest Today to Win Tomorrow.pdf
Current and future trends in Computer Vision.pptx
Evaluating the Democratization of the Turkish Armed Forces from a Normative P...
MET 305 2019 SCHEME MODULE 2 COMPLETE.pptx
keyrequirementskkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
Safety Seminar civil to be ensured for safe working.
Enhancing Cyber Defense Against Zero-Day Attacks using Ensemble Neural Networks
Mitigating Risks through Effective Management for Enhancing Organizational Pe...
Unit I ESSENTIAL OF DIGITAL MARKETING.pdf
Operating System & Kernel Study Guide-1 - converted.pdf
ASol_English-Language-Literature-Set-1-27-02-2023-converted.docx
FINAL REVIEW FOR COPD DIANOSIS FOR PULMONARY DISEASE.pptx
CH1 Production IntroductoryConcepts.pptx
additive manufacturing of ss316l using mig welding
composite construction of structures.pdf
Project quality management in manufacturing
Mohammad Mahdi Farshadian CV - Prospective PhD Student 2026
BMEC211 - INTRODUCTION TO MECHATRONICS-1.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