JavaScript Application Design
A Build First approach
Nicolas G. Bevacqua
Foreword by Addy Osmani
  • January 2015
  • ISBN 9781617291951
  • 344 pages
  • printed in black & white

Enjoy the ride through the process of improving your development workflow.

FROM THE FOREWORD by Addy Osmani, Google

The fate of most applications is often sealed before a single line of code has been written. How is that possible? Simply, bad design assures bad results. Good design and effective processes are the foundation on which maintainable applications are built, scaled, and improved. For JavaScript developers, this means discovering the tooling, modern libraries, and architectural patterns that enable those improvements.

JavaScript Application Design: A Build First Approach introduces techniques to improve software quality and development workflow. You'll begin by learning how to establish processes designed to optimize the quality of your work. You'll execute tasks whenever your code changes, run tests on every commit, and deploy in an automated fashion. Then you'll focus on designing modular components and composing them together to build robust applications.

Table of Contents show full

foreword

preface

acknowledgments

about this book

about the author

about the cover illustration

Part 1 Build processes

1. Introduction to Build First

1.1. When things go wrong

1.1.1. How to lose $172,222 a second for 45 minutes

1.1.2. Build First

1.1.3. Rites of initiation

1.2. Planning ahead with Build First

1.2.1. Core principles in Build First

1.3. Build processes

1.4. Handling application complexity and design

1.5. Diving into Build First

1.5.1. Keeping code quality in check

1.5.2. Lint in the command line

1.6. Summary

2. Composing build tasks and flows

2.1. Introducing Grunt

2.1.1. Installing Grunt

2.1.2. Setting up your first Grunt task

2.1.3. Using Grunt to manage the build process

2.2. Preprocessing and static asset optimization

2.2.1. Discussing preprocessing

2.2.2. Doing LESS

2.2.3. Bundling static assets

2.2.4. Static asset minification

2.2.5. Implementing image sprites

2.3. Setting up code integrity

2.3.1. Cleaning up your working directory

2.3.2. Lint, lint, lint!

2.3.3. Automating unit testing

2.4. Writing your first build task

2.5. Case study: database tasks

2.6. Summary

3. Mastering environments and the development workflow

3.1. Application environments

3.1.1. Configuring build distributions

3.1.2. Environment-level configuration

3.1.3. What’s so special about development?

3.2. Configuring environments

3.2.1. Storing configuration in a waterfall

3.2.2. Using encryption to harden environment configuration security

3.2.3. Setting environment-level configuration at the OS level

3.2.4. Merging configuration as a waterfall in code

3.3. Automating tedious first-time setup tasks

3.4. Working in continuous development

3.4.1. Waste no time, use a watch!

3.4.2. Monitoring for changes to the Node app

3.4.3. A text editor that cares

3.4.4. Browser refresh is so Y2K

3.5. Summary

4. Release, deployment, and monitoring

4.1. Releasing your application

4.1.1. Image optimization

4.1.2. Static asset caching

4.1.3. Inlining critical above-the-fold CSS

4.1.4. Testing before a deployment

4.2. Predeployment operations

4.2.1. Semantic versioning

4.2.2. Using changelogs

4.2.3. Bumping changelogs

4.3. Deploying to Heroku

4.3.1. Deploying builds

4.3.2. Managing environments

4.4. Continuous integration

4.4.1. Hosted CI using Travis

4.4.2. Continuous deployments

4.5. Monitoring and diagnostics

4.5.1. Logging and notifications

4.5.2. Debugging Node applications

4.5.3. Adding performance analytics

4.5.4. Uptime and process management

4.6. Summary

Part 2 Managing complexity

5. Embracing modularity and dependency management

5.1. Working with code encapsulation

5.1.1. Understanding the Single Responsibility Principle

5.1.2. Information hiding and interfaces

5.1.3. Scoping and this keyword

5.1.4. Strict mode

5.1.5. Variable hoisting

5.2. JavaScript modules

5.2.1. Closures and the module pattern

5.2.2. Prototypal modularity

5.2.3. CommonJS modules

5.3. Using dependency management

5.3.1. Dependency graphs

5.3.2. Introducing RequireJS

5.3.3. Browserify: CJS in the browser

5.3.4. The Angular way

5.4. Understanding package management

5.4.1. Introducing Bower

5.4.2. Big libraries, small components

5.4.3. Choosing the right module system

5.4.4. Learning about circular dependencies

5.5. Harmony: a glimpse of ECMAScript 6

5.5.1. Traceur as a Grunt task

5.5.2. Modules in Harmony

5.5.3. Let there be block scope

5.6. Summary

6. Understanding asynchronous flow control methods in JavaScript

6.1. Using callbacks

6.1.1. Avoiding callback hell

6.1.2. Untangling the callback jumble

6.1.3. Requests upon requests

6.1.4. Asynchronous error handling

6.2. Using the async library

6.2.1. Waterfall, series, or parallel?

6.2.2. Asynchronous functional tasks

6.2.3. Asynchronous task queues

6.2.4. Flow composition and dynamic flows

6.3. Making Promises

6.3.1. Promise fundamentals

6.3.2. Chaining Promises

6.3.3. Controlling the flow

6.3.4. Handling rejected Promises

6.4. Understanding events

6.4.1. Events and the DOM

6.4.2. Creating your own event emitters

6.5. Glimpse of the future: ES6 generators

6.5.1. Creating your first generator

6.5.2. Asynchronicity and generators

6.6. Summary

7. Leveraging the Model-View-Controller

7.1. jQuery isn’t enough

7.2. Model-View-Controller in JavaScript

7.2.1. Why Backbone?

7.2.2. Installing Backbone

7.2.3. Browserifying your Backbone module with Grunt

7.3. Introduction to Backbone

7.3.1. Backbone views

7.3.2. Creating Backbone models

7.3.3. Organizing models with Backbone collections

7.3.4. Adding Backbone routers

7.4. Case study: the shopping list

7.4.1. Starting with a static shopping list

7.4.2. This time with remove buttons

7.4.3. Adding items to your cart

7.4.4. Using inline editing

7.4.5. A service layer and view routing

7.5. Backbone and Rendr: server/client shared rendering

7.5.1. Diving into Rendr

7.5.2. Understanding boilerplate in Rendr

7.5.3. A simple Rendr application

7.6. Summary

8. Testing JavaScript components

8.1. JavaScript testing crash course

8.1.1. Logical units in isolation

8.1.2. Using the Test Anything Protocol (TAP)

8.1.3. Putting together our first unit test

8.1.4. Tape in the browser

8.1.5. Arrange, Act, Assert

8.1.6. Unit testing

8.1.7. Convenience over convention

8.1.8. Case study: unit testing an event emitter

8.1.9. Testing the event emitter

8.1.10. Testing for the .on method

8.1.11. Mocks, spies, and proxies

8.1.12. Mocking

8.1.13. Introducing Sinon.js

8.1.14. Spying on function calls

8.1.15. Proxying require calls

8.2. Testing in the browser

8.2.1. Faking XHR and server communication

8.2.2. Case study: testing DOM interaction

8.3. Case study: unit testing the MVC shopping list

8.3.1. Testing the view router

8.3.2. Testing validation on a view model

8.4. Automating Tape tests

8.4.1. Automating Tape tests for the browser

8.4.2. Continuous testing

8.5. Integration, visual, and performance testing

8.5.1. Integration testing

8.5.2. Visual testing

8.5.3. Performance testing

8.6. Summary

9. REST API design and layered service architectures

9.1. Avoiding API design pitfalls

9.2. Learning REST API design

9.2.1. Endpoints, HTTP verbs, and versioning

9.2.2. Requests, responses, and status codes

9.2.3. Paging, caching, and throttling

9.2.4. Documenting an API

9.3. Implementing layered service architectures

9.3.1. Routing layer

9.3.2. Service layer

9.3.3. Data layer

9.3.4. Routing layer

9.3.5. Service layer

9.3.6. Data layer

9.4. Consuming a REST API on the client side

9.4.1. The request handling layer

9.4.2. Shooting down old requests

9.4.3. Consistent AJAX error management

9.5. Summary

Appendix A: Modules in Node.js

A.1. Installing Node.js

A.2. The module system

A.3. Exporting functionality

A.4. Regarding packages

Appendix B: Introduction to Grunt

B.1. Grunt plugins

B.2. Tasks and targets

B.3. Command-line interface

B.4. Using Grunt in a project

B.5. Configuring Grunt

B.6. Globbing patterns

B.6.1. Brace expressions

B.6.2. Negation expressions

B.7. Setting up a task

B.8. Creating custom tasks

Appendix C: Picking your build tool

C.1. Grunt: the good parts

C.2. Grunt: the bad parts

C.3. npm as a build tool

C.3.1. Installing npm task dependencies

C.3.2. Using shell scripts in npm tasks

C.3.3. npm and Grunt compared: the good and the bad

C.4. Gulp: the streaming build tool

Appendix D: JavaScript code quality guide

D.1. Module organization

D.1.1. Strict mode

D.1.2. Spacing

D.1.3. Semicolons

D.1.4. Linting

D.2. Strings

D.2.1. Variable declaration

D.3. Conditionals

D.3.1. Ternary operators

D.3.2. Functions

D.3.3. Prototypes

D.3.4. Object literals

D.3.5. Array literals

D.4. Regular expressions

D.4.1. Debugging statements

D.4.2. Comments

D.4.3. Variable naming

D.4.4. Polyfills

D.4.5. Everyday tricks

index

What's inside

  • Automated development, testing, and deployment processes
  • JavaScript fundamentals and modularity best practices
  • Modular, maintainable, and well-tested applications
  • Master asynchronous flows, embrace MVC, and design a REST API

About the reader

This book assumes readers understand the basics of JavaScript.

About the author

Nicolas Bevacqua is a freelance developer with a focus on modular JavaScript, build processes, and sharp design. He maintains a blog at ponyfoo.com.


combo $39.99 pBook + eBook
eBook $31.99 pdf + ePub + kindle

FREE domestic shipping on three or more pBooks

For JavaScript developers, a must-read!

Stephen Wakely, Thomson Reuters

An excellent guide through the maze of the modern JavaScript ecosystem.

Jonas Bandi, IvoryCode GmbH

The first-ever design book for developers.

Sandeep Kumar Patel, SAP Labs

A one-stop shop introducing JavaScript developers to modern practices and tools.

Matthew Merkes, MyNeighbor