A Supreme Approach To UI Architecture

Michael K. Snead

msnead@paylocity.com

"A" Supreme Approach

As part of an agile culture, we change, adapt and evolve and this is just a snapshot.

As told by one member of Team Supreme.

High Level Architecture

App Component

Child

Component

Child

Component

Child

Component

Manager

store.dispatch(action)

Redux

Store/

Dispatcher

 

Reducer(s)

store.subscribe(...);

state

  • Redux "store" has initial state (ie: from server)
  • App component subscribes to store
  • Children of App receive state from parent via binding
  • Child components / Manager dispatch actions
  • Redux asks reducers to compute next app state and broadcasts to listener(s) (App)

High Level Architecture

App Component

Child

Component

Child

Component

Child

Component

Manager

store.dispatch(action)

Redux

Store/

Dispatcher

 

Reducer(s)

store.subscribe(...);

state

UI components only reflect the state passed to them and either dispatch actions directly or ask the Manager to do it.

Logic lives in the Reducers. AJAX API lives in Service(s).

High Level Architecture

Application File Structure

/foo-bar/

/src/

app

manager.es6

reducers.es6

store.es6

actions.es6

validators.es6

/components/

FooList

This serves as the entrypoint for the "foobar" application at runtime, and for the sake of bundling.

This orchestrates asynchronous actions, or actions that must be executed in order.

This contains the reducers for the app. In larger, very complex apps, it might be broken up.

This is the redux store. It depends on the reducers.

This is effectively an enum of all possible actions for this A2 app.

These validators are bundles of validation rules that compute a validation context.

UI Components and their templates for the app live here.

High Level Architecture

Application File Structure

/foo-bar/

/src/

app

manager.es6

reducers.es6

store.es6

actions.es6

validators.es6

/components/

FooList

Action "flow", if needed, lives here.

For AJAX, call out to services that are pass-through to MVC controllers.

Simple apps may not be concerned about action flow or might even exclude the singleton 'Manager'.

Logic for calculating the next state lives here, but no side effects, no asynchronicity. You cannot dispatch from a reducer.

Reducers must be "pure" in a functional sense.

Redux

A functional approach

What are the advertised benefits to a functional approach?

  • Taming side effects
  • Reducing state changes
  • Greater predictability
  • Easier extensibility
  • Improved testability
  • Minimizing moving parts

PluralSight - Functional Programming with C# (less than 1.5 hours for entire course)

Redux

Flux is a pattern of unidirectional data flow, Redux is an implementation.

  • Really small (2KB), simple API
  • Established
  • Framework agnostic

Egghead.io - Getting Started with Redux

After the first 1/2 hour of content you should pretty much know Redux.

Rangle.IO - "Redux is the future of React/A2"

Redux Pros & Cons

  • Flux is an established pattern in industry
  • Easier to test and maintain long term
  • Scales with complexity
  • Low risk to buy into / can adopt gradually

Pros

  • More boilerplate / planning up front
  • New to Paylocity

Cons

Immutable.JS

To get the benefits of FP and maximum speed in React, you want immutability. ImmutableJS by Facebook makes immutability easy.

  • Everything in JS is by reference
  • Object.assign() is a shallow copy
  • ImmutableJS is already proven
  • ImmutableJS makes it easier to stay performant

ImmutableJS

Why do we need this?

Egghead.io - Learn How To Use ImmutableJS (subscription required)

ImmutableJS - Roadmap for 2016 with some statistics on its popularity and rating

Building and Testing in CI

  • Webpack
  • gulp
  • node.js 4.2.2 (LTS)
  • babel
  • karma
  • mocha
  • phantomjs

Webpack

  • Best practices for JavaScript module systems advise bundling all of your packages into one file for production.
    In Webpack, this is the case by default.
  • Filesystem pathing + compile time bundle (vs. URL route pathing) ensures that things like virtual directories can't disrupt your pathing
  • Filesystem pathing + compile time bundle makes it simple to use npm/bower modules or files that aren't available offline
  • Webpack has optimizations you can enable to make it crazy fast (ie: cache modules). We use compile-on-save and while working with Angular 2 I've seen 800ms-1.6sec without putting much effort into optimization.
  • Problems with packaging and dependencies can be caught at compile time (IE: in CI) versus at runtime

Webpack

Most module systems have a similar set of features. Webpack is no exception.

 

There are plugins to load all sorts of resources, including CSS, images, JSON files, markup, etc.

 

Webpack also has no problem handling mixed modules (ie: ES7 + TypeScript + CoffeeScript) in the same project.

 

Webpack provides sourcemaps out of the box.

 

Webpack also has an API that makes it trivial to use from gulp.

gulp

It's pretty much established that gulp is superior to grunt.js, but why use gulp at all when we have options like npm or webpack?

Since Visual Studio's Task Runner Explorer options are still very limited, even if we use it for nothing else, we can use gulp to make it easy to plug in task-based processes to Visual Studio. gulp acts as the bridge between the two.

 

This enables us to start/run tasks on solution open, or on build/rebuild.

node.js 4.2.2 (LTS)

node.js recently had their first LTS (Long Term Support) release. This means a stable API and longer-term bug/security fix support.

 

We bundle all of our binaries in source control and execute them by overriding the PATH variable for the process/session in TeamCity. We also configure VS to use the installed node.js, versus the old one it comes packaged with.
 

We also package the node modules needed to build/test and unpack them using 7zip to avoid network-related errors/slowness.

npm 3.5.2

HTTP

Among the great contenders for AJAX there are...

  • Axios
    Axios is popular/battle tested, used by Team Awesome, resembles future fetch APIs.
  • jQuery AJAX
    It's likely jQuery will always be on our pages as it's a requirement for Kendo. We already know jQuery.
  • fetch
    The standard of tomorrow through polyfill. Chrome + Firefox have already implemented fetch API.
    This is what we've chosen to use in new pages.

We specify application/json in headers and add a new attribute to validate anti-forgery token in one of those headers.

ES2015 / ES7

We use WebStorm (or possibly VSCode) for an "IDE feel" environment.

We have Babel configured such that stage-0 ES7 options are turned on.

Questions?

Thanks for your time.

Supreme Approach to UI Architecture

By Michael Snead

Supreme Approach to UI Architecture

Illustrate Supreme's current approach to UI Architecture, as told by Snead.

  • 2,294