Friday, August 28, 2015

Book Review: JavaScript at Scale

JavaScript at Scale (Packt Publishing, July 2015) is written by Adam Boduch and has the subtitle "Build enduring JavaScript applications with scaling insights from the front-line of JavaScript development." JavaScript at Scale features ten chapters spanning approximately 240 substantive pages.

Preface

JavaScript at Scale's Preface includes a sentence or two describing each of its ten chapters. Readers of the book who want to work with the examples are encouraged to have Node.js, a code editor or IDE, and a "modern web browser" available while using this book.

The Preface states that the book is intended for "a senior JavaScript developer who is curious about architectural issues in the frontend." The Preface adds that "no prerequisite framework knowledge [is] required," but states that "strong JavaScript language skills are required." The Preface also points out more details on the nature of this book: "the concepts presented throughout the book are adaptations of components found in frameworks such as Backbone, Angular, or Ember."

These statements are important for developers considering purchasing and/or reading JavaScript at Scale as they provide an appropriate glimpse at what the author is aiming for with this book. The emphasis of JavaScript at Scale is definitely on higher-level design and architectural principles than on low-level implementation details (including use of specific frameworks and libraries in the category of low-level implementation details).

Chapter 1: Scale from a JavaScript Perspective

The initial chapter of JavaScript at Scale describes common scalability concerns and how they pertain to JavaScript. The chapter uses a hypothetical new generic JavaScript application as an example and talks about different scaling concerns that arise as more users use the application, as more features are added to the application, and as more developers are added to the development team.

Chapter 1 discusses architecture of components and communication between components for a browser-hosted application. The chapter discusses responsiveness, addressability, and configurability. There are several other discussion items in this chapter such as trade-offs that can be made in designing a JavaScript application's architecture, using frameworks and libraries, and taking advantage of communities.

Chapter 2: Influencers of Scale

The second chapter of JavaScript at Scale delves into a concept introduced in the first chapter: the influencers of scale. In looking specifically at scaling users, the chapter discusses business models for attracting customers, license fees, subscription fees, consumption fees, including advertisements in the product, using and being open source, communication between users, support mechanisms, allowing feedback and notifying users, and collecting user metrics.

Chapter 2 provides more discussion on subjects such as collecting metrics to determine which features to add to the application, dealing with too few to too many developers for the application development, and managing users.

JavaScript at Scale's second chapter concludes with presentation of scale influencer checklists. Several checklists are presented with several questions on each. These checklists tend to ask questions related to the topics discussed in the chapter and provide a way for development teams to start conversation on these potential influencers of scale.

Chapter 3: Component Composition

Chapter 3 of JavaScript at Scale is the first chapter that gets detailed enough to include code listings. The author `states, "Large-scale JavaScript code is still a relatively new thing." The chapter explains that JavaScript doesn't have module support and so popular approaches for dealing with JavaScript modules include RequireJS and Browserify (CommonJS). There is extensive discussion regarding routing logic as well as discussion on controllers and views, models and collections, templates, and extending generic components in creating application-specific components.

The third chapter also looks at how to map features to components and how to most appropriately deviate from desired generic component features when creating application-specific features. The chapter includes discussion regarding maintaining, debugging, and refactoring complex components. Other discussion covers organizing component code, implementing stateless functions, and extending versus configuring components.

Chapter 4: Component Composition and Responsibilities

The fourth chapter of JavaScript at Scale "focuses on the glue in between our JavaScript components." The chapter begins by looking at the two predominant communication mechanisms for communication between JavaScript components: message passing and event triggering. The chapter describes messaging considerations such as data size, naming conventions, and common data.

A particularly useful section of Chapter 4 describes implementing "traceable component communication" and describes three approaches for doing this. The chapter covers other considerations and approaches for communication overhead, areas of communication responsibility, loosely coupled communication, handling unexpected events, and component layers.

Chapter 5: Addressability and Navigation

JavaScript at Scale's fifth chapter opens by stating that URI processing "has shifted mostly to the frontend" in "large-scale JavaScript applications," but points out that the "benefits of frontend routing do come at a cost." The chapter then introduces "two approaches to routing in JavaScript": hash URIs and browser history API.

The fifth chapter spends some time looking at JavaScript routers, describing what they are, describing router responsibilities, describing router events, examining what should be in and not be in URIs, and describing manually and automatically associating URIs with resources. The router-heavy chapter continues with coverage of topics such as triggering routes, configuring routes, deactivating routes, troubleshooting routes, logging routes, and handling invalid resource states. Although most of this fifth chapter is discussion text like the earlier chapters of the book, there are a couple lengthy code listings in this chapter.

Chapter 6: User Preferences and Defaults

Chapter 6 of JavaScript at Scale opens with discussion of "three main types of preferences we're concerned with when designing large-scale JavaScript architectures": locales, behavior, and appearance. The chapter provides a brief overview of each of these three types of preferences before revisiting each of the three in significantly greater detail. The sixth chapter closes with a section on performance considerations related to preferences that includes a lengthy code listing.

Chapter 7: Load Time and Responsiveness

The seventh chapter of JavaScript at Scale points out that "Performance is the prominent indicator of quality in the eyes of a user." The chapter looks at JavaScript scale and performance in terms of load time and responsiveness. The chapter discusses use of different sizes of components to deal with network request overhead and developer overhead. The chapter also provides discussion on lazy loading modules and on advantages of using ECMAScript 6 modules over third-party module frameworks.

Chapter 7 also discusses scaling related to communication between components. There is discussion and a code listing explaining use of event brokers and indirection can be useful at first but then present a communication bottleneck with larger JavaScript applications. The chapter briefly describes a small number of JavaScript profiling approaches (such as using the browsers' console.profile() and console.profileEnd() and benchmark.js) that can be used to determine communication bottlenecks to be addressed.

Chapter 7's discussion on addressing issues with state includes an interesting discussion on use of purely functional code with no side effects to improve performance by reducing mutable state. There is also discussion on other topics such as improving performance related to DOM updates and increasing amounts of data to render.

Chapter 8: Portability and Testing

Chapter 8 of JavaScript at Scale begins with a discussion of advantages of loosening the coupling between front-end JavaScript and back-end JavaScript components. This discussion also outlines the advantages and costs associated with mocking data. The discussion looks at the traits desired in a mocking layer and looks at two approaches to mocking the backend. This mocking discussion is fairly extensive.

The eighth chapter also discusses unit testing and discusses how unit test tools built-in to popular JavaScript frameworks are related to framework-agnostic testing tools. The chapter then discusses advantages of "standalone unit testing tools" and emphasizes Jasmine. The chapter concludes with discussion on toolchains, integration testing, and end-to-end testing.

Chapter 9: Scaling Down

The ninth chapter of JavaScript at Scale discusses "scaling down from bloated design" and states, "The composition of our application as a whole determines how easy or how difficult it'll be to scale down by turning features off." The section on "JavaScript artifact size" states, "The biggest contributor to growing JavaScript artifact sizes are the new features we constantly add to our product." The section on "Network bandwidth" states, "The challenge is that any new feature is going to add new network bandwidth consumption." There is also discussion in this chapter on topics such as memory usage and garbage collection, CPU consumption, and backend scalability.

Chapter 9's discussion regarding scaling down also provides discussion on irrelevant features and overlapping features that often exist in older and larger JavaScript baselines. The chapter also discusses how customer demand and design failures relate to the need to scale down. The section on "unnecessary components" makes an interesting assertion: "The most common pattern flaw is unnecessary indirection." This section talks about issues that can arise when originally selected patterns no longer apply well and when the generic nature of frameworks' patterns do not fit well with the architecture.

"Inefficient data processing" is also described in this ninth chapter and the author describes how moving and transforming data between multiple components can lead to inefficiencies. The chapter finishes with discussions regarding "excessively creative markup" and "application composition." Chapter 9 is a discussion-rich chapter, but it also provides several code listings demonstrating how the conditions described in the chapter can occur that need to be scaled down.

Chapter 10: Coping with Failure

The final chapter of JavaScript at Scale provides the assertion, "As we scale our application, the approaches of how we deal with failures need to scale too." The chapter compares and contrasts failing fast and attempting to recover. The importance of quality constraints, meaningful feedback, fault tolerance, and disabling or even removing faulty components.

Chapter 10's coverage of fault recovery includes discussion regarding retrying failed operations, restarting components, requiring manual user intervention, and what to do when the application cannot be recovered. The chapter also looks at how addition of exception handling, state checking, intra-component notification, logging, and debugging can help deal with errors but also can lead to more scaling issues to consider. Like Chapter 9, Chapter 10 includes several code listings to illustrate its concepts.

The final paragraph of Chapter 10 also serves as the final summary paragraph for JavaScript at Scale. This paragraph articulates well in two sentences what the author hopes readers of this book get from the book: "To get the right answers, we first need to ask the right questions. I hope this book has equipped you with the requisite knowledge to formulate questions around scaling your JavaScript application."

General Observations

  • JavaScript at Scale emphasizes architectural and high-level design discussion related to scaling JavaScript applications rather than focusing on low-level implementation details (code, frameworks, libraries) that can be used to make JavaScript applications more scalable.
    • See my review of The Preface above for some of the author's comments that advertise this architectural emphasis in JavaScript at Scale.
    • See bullet below with details regarding author's blog post in which he further describes the architectural emphasis of JavaScript at Scale.
    • A prospective reader looking for a detailed account of exactly how to implement a one-size-fits-all scalable architecture will not find that elusive target here. A reader looking for general architectural principles to be considered when designing a JavaScript application so that it can scale in multiple directions and in response to multiple scalability "influencers" will be happier with this book.
    • See the last paragraph of my review of Chapter 10 above for more information on what the author advertised as the intention of this book. I believe that this book's strength is what he suggests: it can help JavaScript architects and developers come up with the questions they need to ask themselves to understand how to best implement and refactor a JavaScript application to be scalable.
  • The author of JavaScript at Scale has written a blog post that describes this book. The post articulates the focus of the book and includes this statement, "Architectural considerations get lost in all this choice [of JavaScript libraries and frameworks]." He adds that the information presented in JavaScript at Scale "is important information to have at our disposal when making architectural decisions, or when selecting a piece of technology to use in our application. With it, we can make informed choices about the scalability of our code, because code for one application is going to have different scaling characteristics than another application."
  • Although much of JavaScript at Scale is more discussion oriented than code-oriented, there are code listings in some of the chapters These listings feature black text on a white background even in the electronic edition (PDF) that I reviewed. There are no line numbers and no color syntax highlighting in the code listings. Most of the listings are small, but the longer ones can be more difficult to humanly parse without color coded syntax highlighting.
  • JavaScript at Scale is discussion-heavy and most of the writing is easy to follow. There are some typos (such as the use of "manor" when "manner" was intended), but these generally did not detract from the readability of the text.
  • The tone of JavaScript at Scale is generally like having a leisurely chat with a fellow architect about general JavaScript architectural questions and issues. At times, this was more verbose than I needed and I had to be careful not to skim too much because some really useful insights could be buried in the verbose prose. At other times, in areas in which I'm less familiar, the verbosity of text was helpful.

Conclusion

It is a common phrase in software development that there are no silver bullets and JavaScript at Scale doesn't try to sell that there is one when it comes to building scalable JavaScript applications. Instead, JavaScript at Scale identifies a myriad of issues for JavaScript architects and designers to consider in implementing and maintaining large-scale JavaScript applications. Although the readers of JavaScript at Scale are likely to be introduced to (or reminded of) some ideas to consider when making their applications more scalable, the author points out that there is really no way to summarize the approaches that work for all applications in all contexts. Instead, the author emphasizes the considerations that should be made in terms of several aspects of JavaScript application development and the possible approaches to deal with these different considerations as best fits each situation. Readers of JavaScript at Scale should be prepared to tailor what they're reading to their own applications' needs.

No comments: