CONTENTS
INTRODUCTION xxi
PART I: LAYING A SOLID FOUNDATION
CHAPTER 1: PRACTICING SKILLFUL SOFTWARE 3
Writing Code That Starts Correct 4 Mastering the Features of JavaScript 4 Case Study: D3.js 5 JavaScript Is Single-Threaded 15 Avoiding JavaScript’s Pitfalls in Larger Systems 16 Scripts Are Not Modules 16 Nested Functions Control Scope 16 Coding by Contract 17 Applying the Principles of Software Engineering 18 The SOLID Principles 18 The DRY Principle 21 Writing Code That Stays Correct 22 Investing for the Future with Unit Tests 22 Practicing Test-Driven Development 23 Engineering Your Code to Be Easy to Test 24 Summary 27
CHAPTER 2: TOOLING UP 29
Using a Testing Framework 29 Identifying Incorrect Code 33 Designing for Testability 35 Writing the MinimumCOPYRIGHTED Required Code MATERIAL 36 Safe Maintenance and Refactoring 36 Runnable Specifi cation 37 Current Open-Source and Commercial Frameworks 37 QUnit 37 D.O.H. 38 Introducing Jasmine 39 Suites and Specs 39 Expectations and Matchers 41 Spies 41
ftoc.indd xi 15/06/2015 3:27 PM CONTENTS
Using a Dependency-Injection Framework 45 What Is Dependency Injection? 45 Making Your Code More Reliable with Dependency Injection 46 Mastering Dependency Injection 47 Case Study: Writing a Lightweight Dependency-Injection Framework 47 Using a Dependency-Injection Framework 55 Current Dependency-Injection Frameworks 56 RequireJS 56 AngularJS 57 Using an Aspect Toolkit 58 Case Study: Caching with and without AOP 58 Implementing Caching without AOP 58 Making Your Code More Reliable with AOP 60 Case Study: Building the Aop.js Module 60 Other AOP Libraries 72 AspectJS 72 AopJS jQuery Plugin 73 YUI’s Do Class 73 Conclusion 73 Using a Code-Checking Tool 73 Making Your Code More Reliable with Linting Tools 74 Introducing JSHint 76 Using JSHint 76 If You Don’t Run It, Bugs Will Come 79 Alternatives to JSHint 79 JSLint 79 ESLint 79 Strict Mode 80 Summary 80
CHAPTER 3: CONSTRUCTING RELIABLE OBJECTS 81
Using Primitives 81 Using Object Literals 83 Using the Module Pattern 84 Creating Modules‐at‐Will 84 Creating Immediate‐Execution Modules 85 Creating Reliable Modules 86 Using Object Prototypes and Prototypal Inheritance 87 The Default Object Prototype 87 Prototypal Inheritance 88 Prototype Chains 88
xii
ftoc.indd xii 15/06/2015 3:27 PM f CONTENTS
Creating Objects with New 89 The new Object Creation Pattern 89 Potential for Bad Things to Happen 90 Enforcing the Use of new 90 Using Classical Inheritance 95 Emulating Classical Inheritance 95 Repetition Killed the Kangaroo 96 Using Functional Inheritance 98 Monkey‐Patching 100 Summary 102
PART II: TESTING PATTERN-BASED CODE
CHAPTER 4: REVIEWING THE BENEFITS OF PATTERNS 107
Case Study 107 Producing More Elegant Code by Using a Broader Vocabulary 108 Producing Reliable Code with Well-Engineered, Well-Tested Building Blocks 109 Summary 110 CHAPTER 5: ENSURING CORRECT USE OF THE CALLBACK PATTERN 111
Understanding the Pattern Through Unit Tests 112 Writing and Testing Code That Uses Callback Functions 112 Writing and Testing Callback Functions 117 Avoiding Problems 121 Flattening the Callback Arrow 121 Minding this 123 Summary 128 CHAPTER 6: ENSURING CORRECT USE OF THE PROMISE PATTERN 129
Understanding Promises Through Unit Tests 130 Using a Promise 130 Constructing and Returning a Promise 135 Testing an XMLHttpRequest 138 Chaining Promises 141 Using a Promise Wrapper 142 Understanding States and Fates 143 Distinguishing Standard Promises from jQuery Promises 143 Summary 143
xiii
M ftoc.indd xiii 15/06/2015 3:27 PM CONTENTS
CHAPTER 7: ENSURING CORRECT USE OF PARTIAL FUNCTION APPLICATION 145
Unit-Testing a Partial Function Application 145 Creating an Aspect for Partial Function Application 147 Distinguishing Between Partial Function Application and Currying 149 Currying 149 Partial Function Application 149 Summary 150 CHAPTER 8: ENSURING CORRECT USE OF THE MEMOIZATION PATTERN 151
Understanding the Pattern Through Unit Tests 152 Adding Memoization with AOP 155 Creating the Memoization Aspect 155 Applying the returnValueCache Aspect to restaurantApi 159 Summary 160 CHAPTER 9: ENSURING CORRECT IMPLEMENTATION OF THE SINGLETON PATTERN 161
Understanding the Pattern Through Unit Tests 162 Implementing a Singleton Shared Cache with an Object Literal 162 Implementing a Singleton Shared Cache with a Module 166 Summary 170 CHAPTER 10: ENSURING CORRECT IMPLEMENTATION OF THE FACTORY PATTERN 173
Writing Unit Tests for a Factory 173 Implementing the Factory Pattern 179 Considering Other Factory Types 181 Summary 181 CHAPTER 11: ENSURING CORRECT IMPLEMENTATION AND USE OF THE SANDBOX PATTERN 183
Understanding the Pattern Through Unit Tests 184 Creating a Widget Sandbox 185 Instantiating a Widget Sandbox 185 Providing Tools to the Widget via the Sandbox 187 Creating and Testing Sandbox Tools 197 Creating Functions for Use with a Sandbox 201 Summary 203
xiv
ftoc.indd xiv 15/06/2015 3:27 PM f CONTENTS
CHAPTER 12: ENSURING CORRECT IMPLEMENTATION OF THE DECORATOR PATTERN 205
Developing a Decorator the Test‐Driven Way 207 Writing a Fake for the Decorated Object 207 Writing Tests for Pass‐Through of Errors 208 Writing a Do‐Nothing Decorator 209 Adding Pass‐Through Functionality to the Decorator 210 Verifying Pass‐Through of Successes 213 Adding the Decorator’s Features 215 Generalizing the Decorator 222 Summary 222
CHAPTER 13: ENSURING CORRECT IMPLEMENTATION OF THE STRATEGY PATTERN 223
Understanding the Pattern Through Unit Tests 223 Implementing the transportScheduler Without the Strategy Pattern 224 Implementing the transportScheduler Using the Strategy Pattern 226 Creating transportScheduler Using Test‐Driven Development 227 Creating a Strategy for Use with transportScheduler 235 Summary 237
CHAPTER 14: ENSURING CORRECT IMPLEMENTATION OF THE PROXY PATTERN 239
Developing a Proxy the Test‐Driven Way 240 Summary 256
CHAPTER 15: ENSURING CORRECT IMPLEMENTATION OF CHAINABLE METHODS 257
Understanding the Pattern Through Unit Tests 259 Chaining then 266 Summary 267
PART III: TESTING AND WRITING WITH ADVANCED JAVASCRIPT FEATURES
CHAPTER 16: CONFORMING TO INTERFACES IN AN INTERFACE-FREE LANGUAGE 271
Understanding the Benefi ts of Interfaces 272 Understanding the Interface Segregation Principle 273
xv
M ftoc.indd xv 15/06/2015 3:27 PM CONTENTS
Using Test-Driven Development to Create a Contract Registry 275 Defi ning a Contract 275 Determining Whether a Contract Is Fulfi lled 278 Asserting That a Contract Is Fulfi lled 282 Bypassing Contract Enforcement 283 Creating an Aspect to Enforce a Contract on a Returned (Created) Object 283 Summary 288
CHAPTER 17: ENSURING CORRECT ARGUMENT TYPES 289
Introduction 289 Understanding the Opportunities and Risks Posed by JavaScript’s Type-Free Parameters 290 Extending the ContractRegistry to Check Arguments 290 Scoping Out the Task 291 Determining Whether Every Variable in a Set Fulfi lls Its Contract 291 Asserting That Every Variable in a Set Fulfi lls Its Contract 300 Packaging Argument-Checking in an Aspect 301 Supporting Contract Libraries 303 Putting It All Together 303 Creating the Contracts Modules 304 Creating the Application’s ContractRegistry 307 Bypassing Contracts for Production 307 Comparing the Aspect-Oriented Solution to a Static Solution 307 Considering the Advantages of TypeScript 308 Considering the Advantages of Aspects 308 Summary 308
CHAPTER 18: ENSURING CORRECT USE OF CALL, APPLY, AND BIND 311
Exploring How this Is Bound 312 Default Binding 312 Default Binding and strict Mode 313 Implicit Binding 314 new Binding 316 Explicit Binding 317 Creating and Testing Code That Uses call, apply, and bind 317 Using call and apply 318 Creating an Array.prototype.forEach Polyfi ll Using Test-Driven Development 320
xvi
ftoc.indd xvi 15/06/2015 3:27 PM f CONTENTS
Using bind 329 Summary 334
CHAPTER 19: ENSURING THE CORRECT USE OF METHOD‐ BORROWING 335
Ensuring the Borrowing Object Is Suitable 336 Making the Borrowed Function Qualify the Borrower 336 Attaching an Aspect to the Borrowed Object 338 Using a borrow() Method 342 Adding an Object‐Validator to the ContractRegistry 342 Anticipating Side Effects on the Borrower 343 Considering Side Effects from an Isolated Function 343 Considering Side Effects from a Function That Calls Other Functions 345 Anticipating Side Effects on the Donor Object 351 Summary 351
CHAPTER 20: ENSURING CORRECT USE OF MIXINS 353
Creating and Using Mixins 355 Creating and Using a Traditional Mixin 356 Creating the extend Function Using Test‐driven Development 356 Creating a Traditional Mixin Using Test‐driven Development 367 Creating and Using a Functional Mixin 373 Summary 380
CHAPTER 21: TESTING ADVANCED PROGRAM ARCHITECTURES 383
Ensuring Reliable Use of the Observer Pattern 384 Examining the Observer Pattern 384 Enhancing the Reliability of the Observer Pattern 391 Ensuring Reliable Use of the Mediator Pattern 395 Examining the Mediator Pattern 396 Enhancing the Reliability of Mediator-Based Code 397 Developing a Colleague 398 Testing a Colleague 399 Segregating the Mediator’s Interfaces 402 Deciding Where to Put the Contracts 403 Ensuring the Colleague Gets a Mediator with the Expected Interface 404 Developing a Mediator 406 Testing the Mediator 408 Summary 410
xvii
M ftoc.indd xvii 15/06/2015 3:27 PM CONTENTS
PART IV: SPECIAL SUBJECTS IN TESTING
CHAPTER 22: TESTING ADVANCED PROGRAM ARCHITECTURES 383
Ensuring Reliable Use of the Observer Pattern 384 Examining the Observer Pattern 384 Enhancing the Reliability of the Observer Pattern 391 Ensuring Reliable Use of the Mediator Pattern 395 Examining the Mediator Pattern 396 Enhancing the Reliability of Mediator-Based Code 397 Developing a Colleague 398 Testing a Colleague 399 Segregating the Mediator’s Interfaces 402 Deciding Where to Put the Contracts 403 Ensuring the Colleague Gets a Mediator with the Expected Interface 404 Developing a Mediator 406 Testing the Mediator 408 Summary 410
CHAPTER 23: ENSURING CONFORMANCE TO STANDARDS 435
Using ESLint 436 Installing ESLint 436 Installing Node and npm 436 Installing ESLint Using npm 439 Running ESLint 439 Executing ESLint on a Single File 442 Executing ESLint on All the JavaScript Files in a Directory 443 Enforcing Coding Standards with ESLint 444 Creating a Custom ESLint Rule 445 Running ESLint with Custom Rules 448 Enforcing Architectural Divisions 449 The Family-Secret Technique 450 The Imprinting Technique 452 The Mission Impossible Technique 454 The Magic Wand Technique 459 Do Not Use the Call Stack Technique 460 Other Techniques 460 Other Architectures 460 Summary 460
xviii
ftoc.indd xviii 15/06/2015 3:27 PM f CONTENTS
PART V: SUMMARY
CHAPTER 24: SUMMARY OF THE PRINCIPLES OF TEST-DRIVEN DEVELOPMENT 465
Recalling Why Test-Driven Developmentp Is Worthwhile 465 Practicing Test-Driven Development 466 Writing Unit-Testable Code 466 Mastering the Mechanics of Test-Driven Development 466 Writing the Test Before the Code 467 Keeping Your Tests DRY 467 Testing Error Conditions First 467 Testing the Simple before the Complex 467 Being Specifi c 467 Testing Just One Thing 468 Your Test Data Are Just As Important As the Test 468 Using Jasmine Effectively 468 Testing the Patterns in This Book 468 Testing Aspect-Oriented Programming 468 Testing Object Construction 469 Testing Callbacks 469 Testing Promise-Based Code 469 Testing a Partial Function Application 470 Testing Memoization 470 Testing a Singleton 470 Testing a Factory Method 470 Testing a Sandbox 470 Testing the Decorator Pattern 471 Testing the Strategy Pattern 471 Testing the Proxy Pattern 471 Testing Chainable Methods 471 Testing Conformance to an Interface 472 Testing the Use of call and apply 472 Testing the Method-Borrowing Pattern 472 Testing Mixins 472 Testing Mediators and Observers 473 Testing DOM Access 473 Tests to Enforce Architectural Divisions 473 Summary 473
xix
M ftoc.indd xix 15/06/2015 3:27 PM CONTENTS
CHAPTER 25: SUMMARY OF JAVASCRIPT IDIOMS IN THIS BOOK 475
Reviewing Objects 475 Object Properties May Be Added and Removed 476 Objects May Be Used as a Dictionary 476 Reviewing Variables 477 Variable Declarations Are Hoisted 477 Variables Have Function Scope 478 Reviewing Functions 481 Functions Are Objects 481 Functions Declarations Are Hoisted 481 Functions Don’t Have Return Types 482 Functions May Be Anonymous 482 Functions May Be Nested 483 Functions May Be Invoked with Any Number of Arguments 484 Functions May Be Invoked Immediately 485 Reviewing Boolean Operations 486 Types May Be Coerced When Testing Equality 486 Values May Be Truthy or Falsy 487 Summary 487
INDEX 489
xx
ftoc.indd xx 15/06/2015 3:27 PM