JavaScript Magic

[ Work-in-progress, Includes Future JavaScript Article Ideas ]

This post is geared to modern browsers and Node.JS/iojs.

Imperative vs. Recursive vs. Functional


// Imperative: The Fastest ( + very simple, no new pointers or excess allocs ):
function fib(n) {
  var a = 1, b = 1, c = 0;
  for(var i = 1; i < n-1; ++i) {
    c = a + b;
    a = b;
    b = c;
  }
  return b;
}

// Recursive: (FIREFOX or BABELJS Only) ES6 function definition with
//  parameter defaults used to set initial (internal/recursive) values
function fib(n, current=0, a=1, b=1, c=0) {
  current++;
  c = a + b;
  a = b;
  b = c;
  return current >= n ? b : fib(n, current, a, b, c);
}

// Text-book-Bad Example - poor function scope w/ multiple mutable external values
function fib(n) {
  if (!arr) { var arr = [1,1]; n=n-2; };// Bad
  if (n===-1) {return [arr[0]];}
  if (n===0) {return arr;}
  var proc = function() {
    --n;
    arr.push(arr[arr.length-1] + arr[arr.length-2]);
    return (n===0 ? arr : proc());
    // Bad: inner recursive function not needed, hint: variables used are from parent function scope
  };
  var ans = proc();
  return ans[ans.length-1];
}

Promises: Awesome!

![fuck this][fuck_this]


// Example Using bluebird Promises and it's
var Promise = require('bluebird'),
    fs = Promise.promisifyAll(require('fs')),
    less = Promise.promisifyAll(require('less'));

function writeFileData(data) {
  return fs.writeFileAsync('/tmp/output.css', data);
}
// Bluebird makes something like this perhaps uncomfortably simple and succinct:
fs.readFileAsync('./style.less') // Call promisified readFile()
  .then(less.renderAsync)         // Hand off to less.render
  .then(writeFileData);      // Function to recieve the css contents (1st parameter)
  1. While, native ES6 Promises are great, I prefer the robust Bluebird Promise Library.
  2. Library or not, modern browsers have supported Promise for years.
  3. Promises can be utilized without crazy patterns - implicit deferred is preferable.
  4. $q just sucks just use bluebird, see above.
  5. Worth mentioning: Bluebirds Benchmarks are best-case tests, so take note if doing crazy fancy promise chains

Java vs JavaScript

Rate Limiting / Debouncing / Throttling

  1. In JavaScript David Walsh implemented debounce in less than 20 lines!
  2. In Java, JDebounce, an library which is a lot more complicated, at ~500+ lines.
  3. _ Comparing the two: _
  4. The JavaScript is fast & uses first-class functions to achieve brilliant simplicity.
  5. Whereas the Java has many more moving parts, annotations are used to apply behaviour at compile-time, and there’s a ton of XML, just for funsies!

Inversion of Control Techniques

Work-in-progress

Docker Firewall Setup

Setup Docker Host Firewall

  1. Debian/Ubuntu Server is assumed
  2. Designed to run on Docker Host Server

Install Requirements

# Ultimate Firewall Needed
apt-get update && apt-get install -y ufw nmap curl

Get your Internal & External IP Addresses

# Get your IP Addresses, simple output:
hostname --all-ip-addresses

# OR use ip tool, example:
ip addr

Firtewall (UFW) Setup - Example Cmds

ufw logging on # on=low - medium might be better for diagnostics
ufw logging medium
# First, block all the things
ufw default deny incoming

# REQUIRED: CHOOSE *ONE* OF THE FOLLOWING DEFAULT OUTBOUND RULES:
ufw default deny outgoing
ufw default allow outgoing


# Allow and log all new ssh connections,
ufw allow log proto tcp from any to any port 22
## Allow http traffic (w/o explicit logging)
ufw allow out on docker0 53/udp to 172.17.0.1/16
ufw allow out on eth0 to any port 53
ufw allow out on eth0 from 0.0.0.0/0 to any port 80 proto tcp
ufw allow out on eth0 from 0.0.0.0/0 to any port 443 proto tcp

# Verbose: ufw allow proto tcp from any to any port 80
ufw allow 80/tcp
ufw allow 443/tcp
ufw allow log 22/tcp
ufw limit ssh # Basic Rate limit 4 SSH brute force mitigation

# Set your ext IP
export EXTERNAL_IP=123.123.123.123
# Update docker IP if needed
export DOCKER_IP=172.17.42.1
# Forward tcp 8080 traffic to  Dockerized App
ufw allow proto tcp from $EXTERNAL_IP port 8080 to $DOCKER_IP port 3000

Enable / Start Firewall

Be Careful, Don’t Lock out your SSH port (sshd defaults to 22)

ufw --force enable

ufw reset

Test Your Firewall

Important: USE A REMOTE IP ADDR/LOCATION

# Verify dependency
apt-get update && apt-get install -y nmap

# Set scan target
export TARGET_HOST=123.123.123.123

# Example Scan Commands:
# Fast open port check
nmap -p 1-10240,27017 -T5 $TARGET_HOST
# Thorough scan
nmap -p 1-10240,27017 --open -v -APN $TARGET_HOST
# Svc Inspection
nmap -p 1-10240,27017 -O --osscan-guess $TARGET_HOST

DONE! Now you should see ONLY the ports you configured!

Docker server Setup

Docker Host Server Setup

Basic Monitoring Tools

# Debian/BSD Requirements / Updates + monitoring tools: atop & htop
apt-get update && apt-get install -y vim-nox git-core curl atop htop build-essential libssl-dev linux-image-amd64 linux-headers-amd64

# OSX, Debian & RHEL: Host OS Tuning
sysctl -w vm.max_map_count=262144

# Updates Profile init scripts before appending new scripts below
mkdir ~/backups
cp ~/.bash* ~/backups/

# Debian/BSD:  Append Shell Environment Shortcuts + XTERM Colors
curl -o- https://raw.githubusercontent.com/justsml/system-setup-tools/master/modules/vim-update.sh | bash

curl -sSL https://gist.githubusercontent.com/justsml/882f6c7cee46aa71625f/raw/a4f0d1ed006080d5fe7f40b6e07b8eb9d6838a5f/.bashrc >> ~/.bashrc
curl -sSL https://gist.githubusercontent.com/justsml/b667f158731fd054cd38/raw/5778dbb5d3d138ccf99ae1bf973457ce89661362/.bash_aliases >> ~/.bash_aliases
# Read into current shell (login steps already missed the aliases file)
source ~/.bashrc

# Install Docker, straight from the horses mouth
curl -sSL https://get.docker.com/ | sh

Only for SELinux Enabled Systems

# SELinux fixes (optional)
# chcon -Rt svirt_sandbox_file_t /mongodb
# chcon -Rt svirt_sandbox_file_t /elastic

Simple Database Setup/Startup

MongoDB v3 Server

mkdir /mongodb
docker run --name mongo -p 27017:27017 -v /mongodb:/data -d mongo:latest bash -c 'mongod --logpath /data/mongodb.log --logappend --dbpath /data/data --storageEngine=wiredTiger'

Elastic Search

mkdir /elastic
docker run --name elastic -d -p 9200:9200 -p 9300:9300 -v /elastic:/data elasticsearch bash -c 'elasticsearch --cluster.name elastic_cluster --node.name elastic01 --path.data /data/elastic-data --path.logs /data/elastic-logs '

You just lit up 2 database docker instances!!! If it were any easier, I’m pretty sure you couldn’t invoice for it.

Package up your NodeJS/Ruby/Python/Web App

  1. Add a blank file named Dockerfile in your project root.
  2. (Optional, Recommended) Add a .dockerignore using .gitignore rules to exclude large non-essential paths. By default all project files are included.

Create a Dockerfile

# Example for NodeJS
FROM node:0.12
EXPOSE [3000]
COPY . /app/
WORKDIR /app
RUN apt-get update \
    && apt-get dist-upgrade -y
RUN ["npm", "install"]
# Overridable Command
CMD ["npm", "start"]

It’s easier to show how to start using the Dockerfile and demonstrate the results via console (see commands below).

In terminal, cd to your project folder and run the following build command everytime you deploy changes - or want to change/upgrade OS or Env config)

docker build -t app-name-here .

Docker Commands to Learn

Build Docker Image Every Deploy/Change

docker build -t app-name-here .

Create/Run Web App w/ Links to DB Servers

docker run -d --name webapp01 -p 3000:3000 --link mongo:mongo --link elastic:elastic app-name-here

Run Interactively (non-daemon, in terminal)

docker run -it --name webapp01 -p 3000:3000 --link mongo:mongo --link elastic:elastic app-name-here bash

Delete Container Instance or Image

Important: Any data not stored on the mounted volume path will be lost!!

# Delete Image
docker rmi -f app-name-here
docker rm -f webapp01
# now re-run your `docker run...` from ^^^
# So for example, let's kill your db instances above, run: ( start with something like `docker stop {mongo,elastic}` )
docker rm -f mongo elastic
Winning Design Resource

Solve 2 UI challenges

Your Prototype Apps Suck: So sprinkle some awesome in there

Beautiful Sliding Menus

Side-Menu Demo

Note: Not my code, however I’ve evaluated it and I have to say I rarely find code at this level. Like, never, folks. The author, Mary Lou is just incredibly talented.

Impressive Tooltips

View demo

Wow! … Am I Right?

Misc

I know I said it, but let me emphasize: All the code is extraordinarily well doneI never say that, most devs rarely bother to be this meticulous

Btw, I say ‘prototype apps’ merely because the examples need a few accessability/usability tweaks (which are described in Mary’s articles).

Here’s where I found this stuff: follow codrops at https://twitter.com/codrops

AngularJS Tricks

AngularJS CAN BE Fast!

  1. AngularJS Developers quickly discover that their med-large apps are buckling under the weight of scattered $watch's and the often bloated crutch known as $scope.
  2. Keep your $scope free of excess UI state, try limit the size & depth of your overall hierarchy.

2-way data binding: 2-way Sword

2-way binding alone makes coming from other frameworks like Backbone, well, frickin amazeballs.

The problem is: many sites chronically overuse Angular’s design patterns. This leads to directive sprawl and a $scope/rootScope which easily has 1000’s of instances, and can cling to huge objects preventing any hope of effective garbage collection.

You know where this is going: an exhausted browser! Forever doomed to work at a frantic pace executing endless and redundant UI/DOM re-compiles.

Stop OVER-Angular.JSification

“If your only tool is a hammer, then every problem looks like a nail.” - old adage

Does your app have a problem with directives?

current-user-status-label
  div(ng-if='loggedIn')
    view-user-surplusage(ng-if='!editMode')
      .head: contact-details(user='user')
      .tool: contact-buttons(loggedIn='loggedIn')
      a.edit-icon(ng-click='editMode = true')
    edit-user-surplusage(ng-if='editMode')
      .head: avatar-edit(user='user')
      .body: edit-contact-details(user='user')
      a.save-icon(ng-click='editMode = false')

Let’s design a flexible user-widget which helps:

  1. Versatile componentization w/ DRY Angular code
  2. Understandable directives, with minimal directive size/depth (mind your ng-repeats)
  3. Simple Service Layer
  4. Little actual coding to implement - just HTML/View Code
// jade
user-widget
  div(ng-if='loggedIn')
    div.edit(ng-if='editMode')
      h4.email-icon: input(type='email', ng-model='user.email')
      h4.phone-icon: input(type='email', ng-model='user.phone')
      a.save-icon(ng-click='editMode = false')
    div.show(ng-if='!editMode')
      h1.users-icon 
      h4.email-icon 
      h4.phone-icon 
      a.edit-icon(ng-click='editMode = true')
  div(ng-if='!loggedIn')
    h5: i Welcome User
    a.btn(href='/login') Login

Solutions

Angular Tips

  1. Use 1-way binding ( e.g. { :: title } )
  2. Limit recursive nesting of directives
  3. And if you must nest directives, NEVER do so inside an ng-repeat - Performance will start to inversely mirror something like O(n^2)^3 ;)
  4. Use native JS/DOM code in a factory pattern to create basic DOM/UI fragments, examples: Modal msg box, status bar. Call UI factories from either directives or controllers.
  5. Bonus: Understand cost and triggers of browser render lifecycle: animation, composite rendering, reflows

Use Browserify to Organize Project

Not specifically for Angular per-se, but essential for simple dependency resolution.

Browserify makes JS projects managable with virtually no added code overhead (ok, a few 100 chars).

Just read this section of the Browserify Handbook.

Alternatives

ReactJS from Facebook

For views which need minimal description: If you have tons of small reusable UI components - ReactJS might be a better choice:

  • If your project…?:
    • Has a different philosophy to UI/DOM implementation than Angular
    • Already has some kind of ‘framework’ - You can use ReactJS alongside AngularJS, Ember, Backbone.
    • Handles frequent data model changes in it’s own code, you’ll benefit by avoiding the ADHD digest/loop pattern of Angular

Polymer Project from Google

Pure-er JS Approach

  • By the way, here’s where I try create framework agnostic code (+1 testability, +1 reuse)
    1. Use plain javascript class to load data (AJAX/JSONP/Embedded in page, et al.)
    2. Use mustache templating to create HTML strings (or DOM directly)
    3. Cache rendered content in localStorage if you can
    4. (Optional) Now add an event listener to re-render the content. I have standardized on the event name refresh.<class-name>