Router-First Architecture in Angular Apps

DOGUHAN ULUCA

Ways We Develop Apps

Personal

Enterprise

  1. On your own time
  2. Passion-driven
  3. Likely under engineered
  4. No routing
  1. On company time
  2. Requirement-driven
  3. Likely over engineered
  4. ngrx

Line-of-Business Apps

Personal

Enterprise

Apps We Develop

Line-of-Business Apps

"set of critical computer applications perceived as vital to running an enterprise"

Source: Wikipedia

Personal

Enterprise

The Enterprise Niche

really complicated or large LOB apps, tools or products 

Line-of-Business Apps

  1. When we start coding, we really never know how much or how little our app will be used

  2. Our apps can quickly become a LOB app

  3. LOB apps are really important to businesses

So

Fundamental architecture is really important

Thus

What is Router-First Architecture?

  • enforce high-level thinking
  • ensuring consensus on features
  • before you start coding
  • plan on your codebase/team to grow
  • little engineering overhead

A way to

High-Level Architecture

Lemon

Mart

Lemon

Mart

Stakeholders

😎

😄

😄

😄

Stakeholders

😄

😟

😄

😄

Stakeholders

🤔

😟

😟

😎

/manager/dashboard

/inventory/dashboard

/manager/dashboard

Stakeholders

😞

😟

😟

😠

more dev teams

Major UX redesign

"I quit",
"Haha, not before I do"

BUGS

😰

🤬

😱

🤮

  1. Develop a roadmap and scope
  2. Design with lazy loading in mind
  3. Implement a walking-skeleton navigation experience
  4. Achieve a stateless, data-driven design
  5. Enforce a decoupled component architecture
  6. Differentiate between user controls and components
  7. Maximize code reuse with ES6/TypeScript

How to implement Router-First?

  1. Develop a roadmap and scope
  2. Design with lazy loading in mind
  3. Implement a walking-skeleton navigation experience
  4. Achieve a stateless, data-driven design
  5. Enforce a decoupled component architecture
  6. Differentiate between user controls and components
  7. Maximize code reuse with ES6/TypeScript

How to implement Router-First?

Site Map

Site Map

Site Map

1. Develop a Roadmap and Scope

  • Get high-level architecture right
  • Define the map before getting on the road
  • Capture the vision concretely
  • Bring tools in only when necessary
  • Implement iteratively
  • Drive for perfection only after the fundamentals are in place and agreed upon
  • Document every artifact you create
  1. Develop a roadmap and scope
  2. Design with lazy loading in mind
  3. Implement a walking-skeleton navigation experience
  4. Achieve a stateless, data-driven design
  5. Enforce a decoupled component architecture
  6. Differentiate between user controls and components
  7. Maximize code reuse with ES6/TypeScript

How to implement Router-First?

First-Paint Matters, A Lot

  • 53% of mobile users* abandon if load times > 3 secs
  • Content is consumed mostly on mobile*
  • 70% in the US
  • 90% in China
  • Angular Universal is hard

*Source: Angular Team, Google Analytics, 2018

Define User Roles

  • manager
  • inventory
  • pos
  • unauthorized

Lazy Loading Tips

2. Design with Lazy-Loading in Mind

  • First-paint matters a lot
  • Lazy loading is low hanging fruit
  • Requires user roles to be defined early on
  • Very difficult implement lazy-loading after the fact
  1. Develop a roadmap and scope
  2. Design with lazy loading in mind
  3. Implement a walking-skeleton navigation experience
  4. Achieve a stateless, data-driven design
  5. Enforce a decoupled component architecture
  6. Differentiate between user controls and components
  7. Maximize code reuse with ES6/TypeScript

How to implement Router-First?

  • Gather feedback from users
  • Workout fundamental workflow and integration issues quickly
  • Concrete representation of scope
  • Sets the stage for multiple teams to work in tandem

3. Walking-Skeleton Navigation UX

  1. Develop a roadmap and scope
  2. Design with lazy loading in mind
  3. Implement a walking-skeleton navigation experience
  4. Achieve a stateless, data-driven design
  5. Enforce a decoupled component architecture
  6. Differentiate between user controls and components
  7. Maximize code reuse with ES6/TypeScript

How to implement Router-First?

RxJS/BehaviorSubject as Data Anchors

Using RxJS/BehaviorSubject

4. Be Stateless & Data-Driven

  • Define "data anchors"
  • Leverage RxJS features
  • Write "functional" code
  • Don't store data in components
  • Data across components are kept in sync
  1. Develop a roadmap and scope
  2. Design with lazy loading in mind
  3. Implement a walking-skeleton navigation experience
  4. Achieve a stateless, data-driven design
  5. Enforce a decoupled component architecture
  6. Differentiate between user controls and components
  7. Maximize code reuse with ES6/TypeScript

How to implement Router-First?

Loading Data

Router Doesn't Always Make Sense

*Use reactive forms

i.e. Forms*

@Input and @Output Bindings

Simple Hierarchy of Components

Refrain from dynamic templates

Router Outlets and Auxiliary Paths to Compose Screens

Router Links

Resolvers

Auth Guards

5. Be Decoupled

  • Every component should be responsible of loading their own data
  • Allows for composition of components
  • Router enables URL driven composition
  • Don't abuse the router
  • Ok to design for a parent component to contain multiple hard-coded components
  1. Develop a roadmap and scope
  2. Design with lazy loading in mind
  3. Implement a walking-skeleton navigation experience
  4. Achieve a stateless, data-driven design
  5. Enforce a decoupled component architecture
  6. Differentiate between user controls and components
  7. Maximize code reuse with ES6/TypeScript

How to implement Router-First?

i.e. Custom Date Input

Highly coupled, convoluted, complicated code

Using Angular features no one has ever heard of before

What's a User Control?

i.e. Form with date inputs

Code must be easy to read and understand

Stick to Angular basics

What is a component?

So code is stable  and easy to maintain

User controls encapsulate complicated code

Reusability

User controls can be shipped in libraries

User controls can be open sourced

Save time and resources

Composable components

6. User Controls vs Components

  • Wire-framing allows to identify reusable elements early on
  • Keep user interaction code separate from business logic
  • Encapsulate domain specific behavior and share it
  1. Develop a roadmap and scope
  2. Design with lazy loading in mind
  3. Implement a walking-skeleton navigation experience
  4. Achieve a stateless, data-driven design
  5. Enforce a decoupled component architecture
  6. Differentiate between user controls and components
  7. Maximize code reuse with ES6/TypeScript

How to implement Router-First?

DRY

Don't Repeat Yourself

Object-Oriented Design

Move behavior to classes

i.e. Hydration, ToJSON, Calculated Properties

Remain stateless and functional

Documents shape of data

Separate internal data shape from external shape

Aim for flat data hierarchy

Interfaces

Pass abstractions, not concretions

Arrays and simple shapes for common objects are okay

i.e. name object, domain-specific object

No string literals in code

Enum

No string literals in code

No string literals in code

Validators and Pipes

7. Use ES6 & TypeScript Features

  • Design around abstractions
  • Use classes to reuse context specific behavior
  • Use interfaces to communicate the shape of internal and external data
  • Use enums instead of string literals
  • Leverage Angular Validators and Pipes to reuse logic

Router-First Metrics

  • 6 months of development
  • Increasing team size
  • Increasing velocity
  • Increasing quality
  • First-paint 2-3 seconds
  • Module loads vary 25-30 seconds
  • Unoptimized, uncompressed
  • Slow 3G first-paint

(3 to about a dozen)

(811 KB)

(2.4 MB)

30 seconds

, module loads 1.6 mins

Think Router-First

Keep it simple

Master the fundamentals

AngularForEnterprise.com

@duluca

github.com/duluca