mean stack wenode barcelona workshop

124
Guided MEAN Stack Hackathon Valeri Karpov Software Engineer, MongoDB www.thecodebarbarian.com www.slideshare.net/vkarpov15 github.com/vkarpov15 @code_barbarian Building (and Testing) a Single Page App in 2 Hours

Upload: valeri-karpov

Post on 01-Jul-2015

472 views

Category:

Technology


3 download

TRANSCRIPT

Page 1: MEAN Stack WeNode Barcelona Workshop

Guided MEAN Stack Hackathon

Valeri KarpovSoftware Engineer, MongoDBwww.thecodebarbarian.com

www.slideshare.net/vkarpov15github.com/vkarpov15

@code_barbarian

Building (and Testing) a Single Page App in 2 Hours

Page 2: MEAN Stack WeNode Barcelona Workshop

*

Who is this guy?

•Coined the MEAN stack in April ‘13

•CI/Tools/NodeJS/Go Engineer at MongoDB

•Maintains mongoose, omni-di

•AngularJS since 0.9.4 in 2010

•Hackmaster General at Bookalokal

•Former CTO, LevelUp

Page 3: MEAN Stack WeNode Barcelona Workshop

*

General Outline

•MEAN = MongoDB, ExpressJS, AngularJS, NodeJS

•Beginner talk: high-level concepts of MEAN

•Emphasis on testing and workflow

•Building a single page app - Axl

•NPM-inspired Package Manager for Golang

•Browser interface only

•No Go knowledge required

Page 4: MEAN Stack WeNode Barcelona Workshop

*

What You’re Building

Page 5: MEAN Stack WeNode Barcelona Workshop

*

What You’re Building

•Server for semver-aware package manager

Page 6: MEAN Stack WeNode Barcelona Workshop

*

Concepts You’ll Be Learning About

•Streams

•API testing

•DOM integration tests with Sauce

•Build systems and architecture

•Configuration + workflow

•General principles for writing NPM packages

Page 7: MEAN Stack WeNode Barcelona Workshop

*

NPM Packages You’ll Be Using

•mocha: unit tests and API integration tests

•browserify: compile Node JS into browser JS

•mongoose: schema validation for Node + MongoDB

•karma: browser automation for testing

•gulp: general-purpose build workflow

•And several more

Page 8: MEAN Stack WeNode Barcelona Workshop

*

Step By Step, the Server Side

•Step 1: Define the problem + brief overview of Go

•Step 2: Define schema and models (mongoose)

•Step 3: Build an API (express)

•Step 4: API-level testing (mocha)

•Step 5: Extending the API to support search

Page 9: MEAN Stack WeNode Barcelona Workshop

*

Step By Step, the HTML Client Side

•Step 6: Create AngularJS SPA client (browserify)

•Step 7: Testing the Single Page App (karma)

•Step 8: CDN for templates and JS (gulp)

Page 10: MEAN Stack WeNode Barcelona Workshop

*

Step 1: A Brief Overview of Go

•Language developed by Google

•Cute toy language with some niche use cases:• Fast-compiling small native binaries

• Tight integration with C

• “Agent” programs like MongoDB MMS agents

•Has some bad limitations• Generics

• Package management

Page 11: MEAN Stack WeNode Barcelona Workshop

*

Hello, World in Go

Page 12: MEAN Stack WeNode Barcelona Workshop

*

Why Build a Go Package Manager

•npm gets package management mostly right

•Go doesn’t and could use some help

Page 13: MEAN Stack WeNode Barcelona Workshop

*

What npm Does Right

•Mostly semantic versioning (no v20130722)• Will my code break if I upgrade from v2.1.3 to v2.1.4?

•2 commands to install and test• npm install

• npm test

• And you’re ready to hack

•No need to change PATH or env variables

•Result: a package for every use case

•Go doesn’t have any of this

Page 14: MEAN Stack WeNode Barcelona Workshop

*

Goals for Axl Server

•Upload/download releases of projects

•Projects hosted on Amazon Cloudfront (streams!)

•Query for projects using semver syntax:• version 1.2.0 matches “~1.2”, “>=1.2.0”, “<=1.3.0”, etc.

• Thankfully, there’s an npm module for that

•Ability to search projects by keyword

•Sane build system and workflow

•Take advantage of a single page app

Page 15: MEAN Stack WeNode Barcelona Workshop

*

Step 2: Design Schemas

“Smart data structures and dumb code works a lot better than the other way around.”

- Eric S. Raymond

“Bad programmers worry about the code. Good programmers worry about data structures and their relationships.”

- Linus Torvalds

Page 16: MEAN Stack WeNode Barcelona Workshop

*

A Brief Overview of Mongoose

•MongoDB is schema-less

•But your schema design still matters!

•Mongoose = NodeJS schemas for MongoDB• Validation

• Casting for objects and queries

• Promises and other syntactic sugar

• Object document mapper (ODM)

•Users include Tinder and McDonalds

Page 17: MEAN Stack WeNode Barcelona Workshop

*

Simple Example: A User Schema

Page 18: MEAN Stack WeNode Barcelona Workshop

*

Model = Schema + DB Connection

Page 19: MEAN Stack WeNode Barcelona Workshop

*

About the User Model

•_id and username will be pulled from Twitter oauth

•Most real data will be tracked in other models

Page 20: MEAN Stack WeNode Barcelona Workshop

*

The Project Schema

•In Go, project names are strings like “github.com/vkarpov15/mgo”

•Releases a list of semver strings

Page 21: MEAN Stack WeNode Barcelona Workshop

*

Why the data Field?

•Simple and intuitive access control

•data contains fields user can edit

Page 22: MEAN Stack WeNode Barcelona Workshop

*

Project Schema Indexes

•MongoDB has indexes for speeding up queries

•Tradeoffs: may make writes slower

•Project schema indexes on:• Project name

• Maintainers usernames (multi-key!)

• Name and keywords text index (more in search section)

Page 23: MEAN Stack WeNode Barcelona Workshop

*

The Release Schema

•Semver release of a project (with download info)

Page 24: MEAN Stack WeNode Barcelona Workshop

*

Validators in Mongoose

•validate ensures name exists and version is valid semver

Page 25: MEAN Stack WeNode Barcelona Workshop

*

Virtuals in Mongoose

•stringify can be accessed as a property

Page 26: MEAN Stack WeNode Barcelona Workshop

*

Indexes for Release Schema

•Indexes can be ordered to help with sorting

•The -1 means higher releaseNumbers come first

•Indexes define how you’ll query your data

Page 27: MEAN Stack WeNode Barcelona Workshop

*

Last Schema: DownloadHistory

•Because you want to highlight popular packages

Page 28: MEAN Stack WeNode Barcelona Workshop

*

DownloadHistory Indexes

•For the two common use cases of DownloadHistory• How many downloads did a package have this month?

• What are the most popular packages this month?

Page 29: MEAN Stack WeNode Barcelona Workshop

*

Schema Design Takeaways

•Design schemas carefully

•Use indexes that fit your use cases

•Don’t go overboard on indexing everything!

•Use Mongoose for seamless validation + casting

Page 30: MEAN Stack WeNode Barcelona Workshop

*

Step 3: REST-ish API with Express

•Express: powerful lightweight web framework

•Highly customizable (> 6900 packages on npm)

•Rapidly growing user base:• NBC

• SegmentIO

• MySpace

Page 31: MEAN Stack WeNode Barcelona Workshop

*

Whats in an API?

•API = actions on top of objects

•REST principles: use HTTP error codes and verbs

•Key concerns for API scalability:• Load search results piece-by-piece from DB

• Hit indexes

• Don’t preclude horizontal scalability (multiple servers)

•MEAN stack allows you to be very lazy

Page 32: MEAN Stack WeNode Barcelona Workshop

*

API Basics: Load a Project By Name

•GET /api/project?project=gopkg.in/mgo

Page 33: MEAN Stack WeNode Barcelona Workshop

*

A Slide Dedicated to a Bad Pun

•Only place where Axl can tolerate a Slash :)•(Slash was the guitarist for GNR. He and Axl don’t like each other)

Page 34: MEAN Stack WeNode Barcelona Workshop

*

Brief Aside on Dependency Injection

•Using my lightweight DI helper, omni-di

•Tool for managing and constructing dependencies

•Create objects once, pass them in to functions

•Injector inspects parameter names to find correct dependencies

Page 35: MEAN Stack WeNode Barcelona Workshop

*

Brief Aside on Dependency Injection

Page 36: MEAN Stack WeNode Barcelona Workshop

*

Routes With Dependency Injection

Page 37: MEAN Stack WeNode Barcelona Workshop

*

Using the Express Router

Page 38: MEAN Stack WeNode Barcelona Workshop

*

Filling out the Project API

Page 39: MEAN Stack WeNode Barcelona Workshop

*

Brief Aside: Authentication

•Twitter Oauth with redirect

•Passport: Express-compatible login middleware

Page 40: MEAN Stack WeNode Barcelona Workshop

*

Brief Aside: Authentication

Page 41: MEAN Stack WeNode Barcelona Workshop

*

POST = Create a Project

•POST /api/project - Mongoose is magical

Page 42: MEAN Stack WeNode Barcelona Workshop

*

PUT = Modify an Existing Project

Page 43: MEAN Stack WeNode Barcelona Workshop

*

More Sophisticated: Semver Query

•Find me a Release that matches “~1.2”

•GET /api/release?project=gopkg.in/mgo&version=~1.2

•Perfect application of streams

•Hard to index semver queries

Page 44: MEAN Stack WeNode Barcelona Workshop

*

More Sophisticated: Semver Query

Page 45: MEAN Stack WeNode Barcelona Workshop

*

Streaming Document by Document

•Like a for loop, but don’t load whole array in RAM

Page 46: MEAN Stack WeNode Barcelona Workshop

*

And If You Don’t Find a Document...

•Return a nice, handy 404

Page 47: MEAN Stack WeNode Barcelona Workshop

*

POST /api/release

•The most important and most sophisticated

•Subtleties:• Race conditions between multiple servers

• Error handling

• CDN (or, why the “scale npm” campaign happened)

• Authorization

Page 48: MEAN Stack WeNode Barcelona Workshop

*

Pushing a new Release

•POST /api/release?project=gopkg.in/mgo&version=1.2.0

Page 49: MEAN Stack WeNode Barcelona Workshop

*

MongoDB for Multi-server Concurrency

•MongoDB operations are ACID per document

•ACID stands for• Atomic

• Consistent

• Isolated

• Durable

•FindAndModify underlies Mongoose findOneAndUpdate()

Page 50: MEAN Stack WeNode Barcelona Workshop

*

Multi-Server POST /api/release

•findOneAndUpdate is ACID means a version gets added to a project only once

•Multiple servers => only one wins

Page 51: MEAN Stack WeNode Barcelona Workshop

*

The isNew Flag

•isNew = false means “return document before update”

Page 52: MEAN Stack WeNode Barcelona Workshop

*

POST /api/release Checks, Part 1

Page 53: MEAN Stack WeNode Barcelona Workshop

*

POST /api/release Checks, Part 2

•Check if release existed before findOneAndUpdate

•If so, return handy conflict error

Page 54: MEAN Stack WeNode Barcelona Workshop

*

Pushing To Amazon S3

•Easy to set up Cloudfront on top of Amazon S3

•Node lets you stream files to S3

•No more worrying about server HD space

Page 55: MEAN Stack WeNode Barcelona Workshop

*

Pushing To Amazon S3

Page 56: MEAN Stack WeNode Barcelona Workshop

*

Using PipeToS3

Page 57: MEAN Stack WeNode Barcelona Workshop

*

Step 3: Testing the API

•Writing API is easy, testing can be hard

•But easy with Express + Mocha + Node!

•Stub out authentication

•Event-driven nature of JS: no interrupts

•Single process responsible for:• Running Express server

• Sending HTTP requests to Express server

• Using Mocha to test the results of HTTP requests

Page 58: MEAN Stack WeNode Barcelona Workshop

*

Step 4: Testing the API

•Writing API is easy, testing can be hard

•But easy with Express + Mocha + Node!

•Stub out authentication

•Event-driven nature of JS: no interrupts

•Single process responsible for:• Running Express server

• Sending HTTP requests to Express server

• Using Mocha to test the results of HTTP requests

Page 59: MEAN Stack WeNode Barcelona Workshop

*

Why One Process?

•Minimal setup

•Run tests with one command

•Use real configuration

•Can assert on state of DB as well as result

Page 60: MEAN Stack WeNode Barcelona Workshop

*

High Level Mocha Structure

Page 61: MEAN Stack WeNode Barcelona Workshop

*

General Idea for Release API Tests

Page 62: MEAN Stack WeNode Barcelona Workshop

*

First Case: Load Exact Version

Page 63: MEAN Stack WeNode Barcelona Workshop

*

Test Loading Version with Semver

Page 64: MEAN Stack WeNode Barcelona Workshop

*

Test Uploading a Release

Page 65: MEAN Stack WeNode Barcelona Workshop

*

Testing Workflow

•Systems like Gulp are sometimes overkill

•Don’t ask people to “npm install mocha -g”!• Version management

• Incompatibilities with different projects versions

• Breaks the npm install promise

Page 66: MEAN Stack WeNode Barcelona Workshop

*

Using Makefile for Testing

•Makefile surprisingly common in NodeJS

•Usually as a command shortener

•Use “make api-test” to run tests

Page 67: MEAN Stack WeNode Barcelona Workshop

*

Brief Demo of Tests

Page 68: MEAN Stack WeNode Barcelona Workshop

*

Step 5: Search API

•Use testing framework to do some TDD

•Test-driven Development: tests first, then code

•Usually done with unit tests

•Faster and more fun with API integration tests

Page 69: MEAN Stack WeNode Barcelona Workshop

*

TDD First Step

Page 70: MEAN Stack WeNode Barcelona Workshop

*

Assumptions from Test

•GET /api/search?q=test

•Search project name and keywords

•Return list of projects in JSON

Page 71: MEAN Stack WeNode Barcelona Workshop

*

MongoDB Text Search

•Introduced in MongoDB 2.6 (beta feature in 2.4)

•Does exactly what this search API needs

•First need to create a text index

Page 72: MEAN Stack WeNode Barcelona Workshop

*

Filling Out The Search API

Page 73: MEAN Stack WeNode Barcelona Workshop

*

Notes on Text Search

•Requires mongoose >= 3.8.9

•The $meta keyword used to get “text score”

•Higher text score => more relevant

•Usually want to sort by text result

•Supports stemming in 15 languages

Page 74: MEAN Stack WeNode Barcelona Workshop

*

What is Stemming?

Page 75: MEAN Stack WeNode Barcelona Workshop

*

What is Stemming?

•“Test” matches both “test” and “testing”

Page 76: MEAN Stack WeNode Barcelona Workshop

*

Step 6: AngularJS SPA Client

•REST API is only the beginning

•What about building a client?

•AngularJS is the best tool for the job (IMO)• MVC-ish client-side templating framework

• Two-way data binding

• Dependency injection, elegant structure

•Writing client-side JS is painful - use Browserify

•Won’t need very sophisticated AngularJS for Axl

Page 77: MEAN Stack WeNode Barcelona Workshop

*

Book Announcement

•My book on AngularJS is coming out Dec 22

•Pre-order on Amazon for a more detailed dive into AngularJS

Page 78: MEAN Stack WeNode Barcelona Workshop

*

Overview of AngularJS

•Client-side templates (Two-way data binding)

•Client-side routing (Single Page Apps)

Page 79: MEAN Stack WeNode Barcelona Workshop

*

Why a Single Page App?

•Clean separation of data and views

•Ship HTML separately from data

•Enables you to store HTML as static asset (Cloudfront)

•Leaves your server free to serve up JSON

•Cleaner separation of concerns

Page 80: MEAN Stack WeNode Barcelona Workshop

*

Overview of Browserify

•Compiles NodeJS JS into one browser-friendly file

•Use same dependencies on client and server:• moment

• underscore

• mongoose (schemas + validation only)

• other isomorphic JS

•Easy to upload JS to Cloudfront as static asset

Page 81: MEAN Stack WeNode Barcelona Workshop

*

Using AngularJS and Browserify

•npm has an angular package

•Only includes “core angular”

•You may still need other packages

Page 82: MEAN Stack WeNode Barcelona Workshop

*

Word of Warning

•npm angular package depends on contextify

•Contextify is notoriously picky about install reqs

•You need right version of python and a C++ compiler

•Possible, but tricky, to install on Windows

•I prefer to list angular as a devDependency in package.json

Page 83: MEAN Stack WeNode Barcelona Workshop

*

Writing AngularJS in NodeJS

•Create an AngularJS “module”

•Axl also needs the angular client-side routing module

Page 84: MEAN Stack WeNode Barcelona Workshop

*

Setting up Client Side Routing

Page 85: MEAN Stack WeNode Barcelona Workshop

*

How Client-Side Routing Works

•Only modify hash portion of the URL

Page 86: MEAN Stack WeNode Barcelona Workshop

*

What Does a Template Look Like?

•Written in Jade:

•“ng-” and “{{ }}” are tie-ins to AngularJS

Page 87: MEAN Stack WeNode Barcelona Workshop

*

Ok, So What’s a Controller?

•Defines an in-HTML API for the template to use

•Responsible for loading and organizing data

•Attaches properties to template “scope”

Page 88: MEAN Stack WeNode Barcelona Workshop

*

And What’s $projects?

•A service

•Typically a convenience wrapper around a resource loaded from the server

Page 89: MEAN Stack WeNode Barcelona Workshop

*

How Do Controllers and Services Get Added to AngularJS?

Page 90: MEAN Stack WeNode Barcelona Workshop

*

Compiling with Browserify

•Output ./bin/javascript/ui.js with all JavaScript

Page 91: MEAN Stack WeNode Barcelona Workshop

*

Using Compiled JS

•In base jade file, layout.jade, include ui.js:

•Browserify downside: need to compile before use

Page 92: MEAN Stack WeNode Barcelona Workshop

*

Compiling Templates

•Jade downside: need to compile to HTML

•Jade has significant upsides over static HTML:• Readability

• Can include conditionals on server configuration

• Handy for testing - next section

•So we also need to compile Jade!

Page 93: MEAN Stack WeNode Barcelona Workshop

*

Why Compile Templates

•Jade downside: need to compile to HTML

•Jade has significant upsides over static HTML:• Readability

• Can include conditionals on server configuration

• Handy for testing - next section

•So we also need to compile Jade!

Page 94: MEAN Stack WeNode Barcelona Workshop

*

Idea For Compiling Jade

Page 95: MEAN Stack WeNode Barcelona Workshop

*

Compiling Templates Wrapup

•AngularJS templates need to be HTML

•Very easy to compile Jade

•Take advantage of server configuration

Page 96: MEAN Stack WeNode Barcelona Workshop

*

Step 7: Testing the AngularJS Client

•Trickiest part of any project: users will run your code in different OS, browser, machine, etc.

•My job at MongoDB = this for the mongodb server

•Great tools for this in web-dev world:• Sauce: think Amazon EC2 for browsers

• Karma: Popular browser automation tool

• ngScenario: AngularJS E2E testing framework

Page 97: MEAN Stack WeNode Barcelona Workshop

*

DOM Integration Tests

•Test the whole browser side of your code

•That is, test AngularJS’ integration with the DOM

•Stub out REST API calls (speed and ease of setup)

•Setting up data for E2E tests is often complex

•Sometimes known as a “midway test”

Page 98: MEAN Stack WeNode Barcelona Workshop

*

Karma Overview

•Interface for launching a browser and running tests

•Rich set of plugins

•Handles tunneling for remote browsers

•Plugins for launching• local browsers (chrome, firefox, IE, etc.)

• browsers in the Sauce cloud

•My answer to “if I were stuck on a desert island with only one npm module”

Page 99: MEAN Stack WeNode Barcelona Workshop

*

Tradeoffs, Local vs Sauce

•I recommend doing both

•Sauce allows you to spawn any browser:• Chrome on Linux

• IE6 on WinXP

• Android 4.3 (yes, mobile included)

•But is slow and flakey

•Local is difficult to set up, but:• Easier to debug: you can actually see the tests run

• Fast and reliable

Page 100: MEAN Stack WeNode Barcelona Workshop

*

Workflow and Local vs Sauce

•Make sure tests run with local config on Chrome

•Then use Sauce to run tests on different browsers

•Karma makes this easy: different configs

Page 101: MEAN Stack WeNode Barcelona Workshop

*

Karma Plugin Ecosystem

•Karma itself is a lightweight core

•Need plugins to make it do anything useful

•Yet another npm package with its own npm package ecosystem (~170 plugins)

Page 102: MEAN Stack WeNode Barcelona Workshop

*

Generating a Karma Config

•Karma configs are pretty straightforward

•Karma has some handy tools:

• “node_modules/karma/bin/karma init” creates a new config after asking you a few questions

•Or just copy/paste examples

Page 103: MEAN Stack WeNode Barcelona Workshop

*

Local Karma Config for Axl

Page 104: MEAN Stack WeNode Barcelona Workshop

*

Sauce Karma Config - Browser List

Page 105: MEAN Stack WeNode Barcelona Workshop

*

Sauce Karma Config - The Rest

Page 106: MEAN Stack WeNode Barcelona Workshop

*

Karma Sauce Environment Vars

•karma-sauce-launcher relies on 2 env variables:• SAUCE_USERNAME: your Sauce username

• SAUCE_ACCESS_KEY: Sauce API key

•Make sure these are set or your tests will fail

Page 107: MEAN Stack WeNode Barcelona Workshop

*

Writing the Actual DOM Tests

Page 108: MEAN Stack WeNode Barcelona Workshop

*

Couple Words of Warning

•The api() function is home-baked

•The AngularJS equivalent, $httpBackend, is weird

•More about $httpBackend in Chapter 9 of Professional AngularJS :)

•ngScenario is quirky and technically deprecated

•Its replacement, Protractor, is more quirky and doesn’t support DOM integration tests

Page 109: MEAN Stack WeNode Barcelona Workshop

*

How Does the API Function Work?

•ngScenario DSL: domain specific language

Page 110: MEAN Stack WeNode Barcelona Workshop

*

window.AxlAPI

•Use a different layout.jade for running tests:• Don’t load bootstrap

• Expose methods to stub out API requests

•ngScenario runs your tests in an iframe, so it can actually interact with the code under test

Page 111: MEAN Stack WeNode Barcelona Workshop

*

window.AxlAPI

Page 112: MEAN Stack WeNode Barcelona Workshop

*

Makefile Rules for Running Tests

•Remember, need env vars for Sauce tests

Page 113: MEAN Stack WeNode Barcelona Workshop

*

Demo of Running DOM Tests

Page 114: MEAN Stack WeNode Barcelona Workshop

*

Step 8: Deploying to S3 with Gulp

•With SPA, your HTML is static

•Might as well push it out to a CDN

•Last step, stay focused!

Page 115: MEAN Stack WeNode Barcelona Workshop

*

Overview of Gulp

•Simple build tool for web apps

•Another core package with a lot of plugins

•Grunt is its more well-known competitor

•Advantage of Gulp: its plain NodeJS

•List tasks in gulpfile.js

•Re-use your existing code and use streams!

Page 116: MEAN Stack WeNode Barcelona Workshop

*

Including Gulp in package.json

Page 117: MEAN Stack WeNode Barcelona Workshop

*

Minifying JS with Gulp

Page 118: MEAN Stack WeNode Barcelona Workshop

*

Uploading to S3 with Gulp Overview

Page 119: MEAN Stack WeNode Barcelona Workshop

*

Uploading Templates to S3 with Gulp

Page 120: MEAN Stack WeNode Barcelona Workshop

*

Configuring AngularJS to Load Templates Remotely

Page 121: MEAN Stack WeNode Barcelona Workshop

*

Configuring Jade to Load Templates Remotely

Page 122: MEAN Stack WeNode Barcelona Workshop

*

And the End Result

Page 123: MEAN Stack WeNode Barcelona Workshop

*

And that’s a wrap! Time to Review

•Single page app with MEAN stack

•Mongoose Schema

•Express API

•AngularJS routing

•Browserify for building client code

•Karma for testing

•Gulp for pushing HTML+JS to S3+Cloudfront

Page 124: MEAN Stack WeNode Barcelona Workshop

*

Thanks for Listening!

•Slides on:• Twitter: @code_barbarian

• Slideshare: slideshare.net/vkarpov15

•Repo on github: https://github.com/vkarpov15/axl-server

•Professional AngularJS on Amazon