Clean Code in JavaScript: Develop reliable, maintainable, and robust JavaScript
5/5
()
Javascript
Programming
Software Development
Object-Oriented Programming
Clean Code
Mentor
Star-Crossed Lovers
Power of Knowledge
Importance of Understanding
Love Triangle
Hero's Journey
Chosen One
Mentorship
Quest
Wise Mentor
Abstraction
Control Flow
User Experience
Coercion
Code Quality
About this ebook
Get the most out of JavaScript for building web applications through a series of patterns, techniques, and case studies for clean coding
Key Features- Write maintainable JS code using internal abstraction, well-written tests, and well-documented code
- Understand the agents of clean coding like SOLID principles, OOP, and functional programming
- Explore solutions to tackle common JavaScript challenges in building UIs, managing APIs, and writing states
Building robust apps starts with creating clean code. In this book, you’ll explore techniques for doing this by learning everything from the basics of JavaScript through to the practices of clean code. You’ll write functional, intuitive, and maintainable code while also understanding how your code affects the end user and the wider community.
The book starts with popular clean-coding principles such as SOLID, and the Law of Demeter (LoD), along with highlighting the enemies of writing clean code such as cargo culting and over-management. You’ll then delve into JavaScript, understanding the more complex aspects of the language. Next, you’ll create meaningful abstractions using design patterns, such as the Class Pattern and the Revealing Module Pattern. You’ll explore real-world challenges such as DOM reconciliation, state management, dependency management, and security, both within browser and server environments. Later, you’ll cover tooling and testing methodologies and the importance of documenting code. Finally, the book will focus on advocacy and good communication for improving code cleanliness within teams or workplaces, along with covering a case study for clean coding.
By the end of this book, you’ll be well-versed with JavaScript and have learned how to create clean abstractions, test them, and communicate about them via documentation.
What you will learn- Understand the true purpose of code and the problems it solves for your end-users and colleagues
- Discover the tenets and enemies of clean code considering the effects of cultural and syntactic conventions
- Use modern JavaScript syntax and design patterns to craft intuitive abstractions
- Maintain code quality within your team via wise adoption of tooling and advocating best practices
- Learn the modern ecosystem of JavaScript and its challenges like DOM reconciliation and state management
- Express the behavior of your code both within tests and via various forms of documentation
This book is for anyone who writes JavaScript, professionally or otherwise. As this book does not relate specifically to any particular framework or environment, no prior experience of any JavaScript web framework is required. Some knowledge of programming is assumed to understand the concepts covered in the book more effectively.
Related to Clean Code in JavaScript
Related ebooks
Learning JavaScript Data Structures and Algorithms Rating: 5 out of 5 stars5/5JavaScript Enlightenment Rating: 4 out of 5 stars4/5The Joy of JavaScript Rating: 0 out of 5 stars0 ratingsMastering JavaScript Rating: 4 out of 5 stars4/5React Deep Dive Rating: 5 out of 5 stars5/5JavaScript Unlocked Rating: 5 out of 5 stars5/5JavaScript and JSON Essentials Rating: 5 out of 5 stars5/5React Design Patterns and Best Practices Rating: 0 out of 5 stars0 ratingsNode.js By Example Rating: 2 out of 5 stars2/5Art of Clean Code: How to Write Codes for Human Rating: 3 out of 5 stars3/5JavaScript: Beginner's Guide to Programming Code with JavaScript Rating: 5 out of 5 stars5/5JavaScript: Best Practices to Programming Code with JavaScript Rating: 0 out of 5 stars0 ratingsJavaScript Projects for Kids Rating: 0 out of 5 stars0 ratingsJavaScript All-in-One For Dummies Rating: 5 out of 5 stars5/5JavaScript: Tips and Tricks to Programming Code with Javascript: JavaScript Computer Programming, #2 Rating: 0 out of 5 stars0 ratingsJavaScript: Tips and Tricks to Programming Code with Javascript Rating: 0 out of 5 stars0 ratingsJavaScript: Best Practice Rating: 0 out of 5 stars0 ratingsJavascript For Beginners: Your Guide For Learning Javascript Programming in 24 Hours Rating: 3 out of 5 stars3/5JavaScript: Best Practices to Programming Code with JavaScript: JavaScript Computer Programming, #3 Rating: 0 out of 5 stars0 ratingsWeb Coding & Development All-in-One For Dummies Rating: 1 out of 5 stars1/5Building large scale web apps Rating: 0 out of 5 stars0 ratingsSeriously Good Software: Code that works, survives, and wins Rating: 5 out of 5 stars5/5How JavaScript Works Rating: 0 out of 5 stars0 ratingsJavaScript: Beginner's Guide to Programming Code with JavaScript: JavaScript Computer Programming Rating: 0 out of 5 stars0 ratingsMastering JavaScript Design Patterns Rating: 4 out of 5 stars4/5Professional JavaScript for Web Developers Rating: 0 out of 5 stars0 ratingsMastering JavaScript Design Patterns - Second Edition Rating: 5 out of 5 stars5/550 Recipes for Programming Node.js Rating: 3 out of 5 stars3/5
Internet & Web For You
Coding For Dummies Rating: 5 out of 5 stars5/5Tor and the Dark Art of Anonymity Rating: 5 out of 5 stars5/5Coding All-in-One For Dummies Rating: 4 out of 5 stars4/5How to Be Invisible: Protect Your Home, Your Children, Your Assets, and Your Life Rating: 4 out of 5 stars4/5HTML in 30 Pages Rating: 5 out of 5 stars5/5No Place to Hide: Edward Snowden, the NSA, and the U.S. Surveillance State Rating: 4 out of 5 stars4/5Six Figure Blogging Blueprint Rating: 5 out of 5 stars5/5Python: Learn Python in 24 Hours Rating: 4 out of 5 stars4/5Coding with AI For Dummies Rating: 1 out of 5 stars1/5How to Disappear and Live Off the Grid: A CIA Insider's Guide Rating: 0 out of 5 stars0 ratingsBeginner's Guide To Starting An Etsy Print-On-Demand Shop Rating: 0 out of 5 stars0 ratingsSocial Engineering: The Science of Human Hacking Rating: 3 out of 5 stars3/5Surveillance and Surveillance Detection: A CIA Insider's Guide Rating: 3 out of 5 stars3/5Cybersecurity For Dummies Rating: 5 out of 5 stars5/5The $1,000,000 Web Designer Guide: A Practical Guide for Wealth and Freedom as an Online Freelancer Rating: 4 out of 5 stars4/5More Porn - Faster!: 50 Tips & Tools for Faster and More Efficient Porn Browsing Rating: 3 out of 5 stars3/5Introduction to Internet Scams and Fraud: Credit Card Theft, Work-At-Home Scams and Lottery Scams Rating: 4 out of 5 stars4/5The Hacker Crackdown: Law and Disorder on the Electronic Frontier Rating: 4 out of 5 stars4/5Blogging For Dummies Rating: 0 out of 5 stars0 ratingsAn Ultimate Guide to Kali Linux for Beginners Rating: 3 out of 5 stars3/5The Beginner's Affiliate Marketing Blueprint Rating: 4 out of 5 stars4/5How To Start A Profitable Authority Blog In Under One Hour Rating: 5 out of 5 stars5/5Everybody Lies: Big Data, New Data, and What the Internet Can Tell Us About Who We Really Are Rating: 4 out of 5 stars4/5Ethical Hacking 101 - How to conduct professional pentestings in 21 days or less!: How to hack, #1 Rating: 5 out of 5 stars5/5Content Chemistry: The Illustrated Handbook for Content Marketing Rating: 5 out of 5 stars5/5The Digital Marketing Handbook: A Step-By-Step Guide to Creating Websites That Sell Rating: 5 out of 5 stars5/5Six Figure Blogging In 3 Months Rating: 3 out of 5 stars3/5
Reviews for Clean Code in JavaScript
1 rating0 reviews
Book preview
Clean Code in JavaScript - James Padolsey
Clean Code in JavaScript
Develop reliable, maintainable, and robust JavaScript
James Padolsey
BIRMINGHAM - MUMBAI
Clean Code in JavaScript
Copyright © 2020 Packt Publishing
All rights reserved. No part of this book may be reproduced, stored in a retrieval system, or transmitted in any form or by any means, without the prior written permission of the publisher, except in the case of brief quotations embedded in critical articles or reviews.
Every effort has been made in the preparation of this book to ensure the accuracy of the information presented. However, the information contained in this book is sold without warranty, either express or implied. Neither the author, nor Packt Publishing or its dealers and distributors, will be held liable for any damages caused or alleged to have been caused directly or indirectly by this book.
Packt Publishing has endeavored to provide trademark information about all of the companies and products mentioned in this book by the appropriate use of capitals. However, Packt Publishing cannot guarantee the accuracy of this information.
Commissioning Editor: Pavan Ramchandani
Acquisition Editor: Ashitosh Gupta
Content Development Editor: Akhil Nair
Senior Editor: Martin Whittemore
Technical Editor: Suwarna Patil
Copy Editor: Safis Editing
Project Coordinator: Kinjal Bari
Proofreader: Safis Editing
Indexer: Manju Arasan
Production Designer: Deepika Naik
First published: January 2020
Production reference: 1170120
Published by Packt Publishing Ltd.
Livery Place
35 Livery Street
Birmingham
B3 2PB, UK.
ISBN 978-1-78995-764-8
www.packt.com
Packt.com
Subscribe to our online digital library for full access to over 7,000 books and videos, as well as industry leading tools to help you plan your personal development and advance your career. For more information, please visit our website.
Why subscribe?
Spend less time learning and more time coding with practical eBooks and Videos from over 4,000 industry professionals
Improve your learning with Skill Plans built especially for you
Get a free eBook or video every month
Fully searchable for easy access to vital information
Copy and paste, print, and bookmark content
Did you know that Packt offers eBook versions of every book published, with PDF and ePub files available? You can upgrade to the eBook version at www.packt.com and as a print book customer, you are entitled to a discount on the eBook copy. Get in touch with us at [email protected] for more details.
At www.packt.com, you can also read a collection of free technical articles, sign up for a range of free newsletters, and receive exclusive discounts and offers on Packt books and eBooks.
Contributors
About the author
James Padolsey is a passionate JavaScript and UI engineer with over 12 years' experience. James began his journey into JavaScript as a teenager, teaching himself how to build websites for school and small freelance projects. In the early years, he was a prolific blogger, sharing his unique solutions to common problems in the domains of jQuery, JavaScript, and the DOM. He later contributed to the jQuery library itself and authored a chapter within the jQuery Cookbook published by O'Reilly Media. Over subsequent years, James has been exposed to many unique software projects in his employment at Stripe, Twitter, and Facebook, informing his philosophy on what clean coding truly means in the ever-changing ecosystem of JavaScript.
I'd like to thank the following individuals for their technical insight in the domain of JavaScript: Paul Irish, Alex Sexton, Axel Rauschmayer, John Resig, John Hann, Mathias Bynens, Ana Tudor, Steven Levithan, Juriy Zaytsev, Peter van der Zee, Addy Osmani, Jake Archibald, Dave Methvin, and Lea Verou. I would like to especially thank my family, including Victoria, Henry, George, Alice, and Lucy, and my friends Erik Lundin, Owen Barnes, and Anna Stark.
About the reviewers
Derrek Landauer teaches middle school math and mentors students in an Air Force Research Lab rocketry science program. He earned a bachelor of science in electrical engineering from the University of Texas at El Paso in 2011. His work history spans industry and academia. While attending school, he was involved in defense research projects and was also a lab instructor. He later spent a couple of years managing the network and server infrastructure across four facilities for a subsidiary of a Fortune 100 company. His software development background ranges from programming microprocessors and operating systems to full stack web development.
Dobrin Ganev is a software developer with years of experience working in various development environments, ranging from finance to business process management. In recent years, he has focused on geospatial development and data analytics using JavaScript, Python, Scala, and R. He has extensive knowledge of open source geospatial software and the ESRI platform. He is also skilled in Node.js, React.js, and GraphQL. Dobrin recently authored a video course entitled Hands-On Full Stack Web Development with GraphQL and React, published by Packt.
Packt is searching for authors like you
If you're interested in becoming an author for Packt, please visit authors.packtpub.com and apply today. We have worked with thousands of developers and tech professionals, just like you, to help them share their insight with the global tech community. You can make a general application, apply for a specific hot topic that we are recruiting an author for, or submit your own idea.
Table of Contents
Title Page
Copyright and Credits
Clean Code in JavaScript
About Packt
Why subscribe?
Contributors
About the author
About the reviewers
Packt is searching for authors like you
Preface
Who this book is for
What this book covers
To get the most out of this book
Download the example code files
Download the color images
Conventions used
Get in touch
Reviews
Section 1: What is Clean Code Anyway?
Setting the Scene
Why we write code
Code as intent
Who is the user?
What is the problem?
Truly understanding the problem domain
Writing code for humans
Communicating intent
Readability
Meaningful abstractions
The tower of abstraction
The layers of clean code
Summary
The Tenets of Clean Code
Reliability
Correctness
Stability
Resilience
Efficiency
Time
Space
Efficiency's effects
Maintainability
Adaptability
Familiarity
Usability
User stories
Intuitive design
Accessibility
Summary
The Enemies of Clean Code
Enemy #1 – JavaScript
Enemy #2 – management
Pressure to ship
Bad metrics
Lack of ownership
Enemy #3 – Self
Showing off with syntax
Stubborn opinions
Imposter syndrome
Enemy #4 – The cargo cult
Cargo culting code
Cargo culting tools and libraries
Summary
SOLID and Other Principles
The Law of Demeter
SOLID
Single responsibility principle
Open–closed principle
Liskov substitution principle
Interface segregation principle
Dependency inversion principle
The abstraction principle
Over-abstraction
Under-abstraction
Balanced abstraction
Functional programming principles
Functional purity
Immutability
Summary
Naming Things Is Hard
What's in a name?
Purpose
Concept
Contract
Naming anti-patterns
Needlessly short names
Needlessly exotic names
Needlessly long names
Consistency and hierarchy
Techniques and considerations
Hungarian notation
Naming and abstracting functions
Three bad names
Summary
Section 2: JavaScript and Its Bits
Primitive and Built-In Types
Primitive types
Immutability of primitives
Primitive wrappers
The falsy primitives
Number
String
Boolean
BigInt
Symbol
null
undefined
Objects
Property names
Property descriptors
Map and WeakMap
The prototype
When and how to use objects
Functions
Syntactic context
Function bindings and this
Execution context
super
new.target
arguments
Function names
Function declarations
Function expressions
Arrow functions
Immediately Invoked Function Expressions
Method definitions
Async functions
Generator functions
Arrays and iterables
Array-like objects
Set and WeakSet
Iterable protocol
RegExp
Regular expression 101
RegExp flags
Methods accepting RegExp
RegExp methods and lastIndex
Stickiness
Summary
Dynamic Typing
Detection
The typeof operator
Type-detecting techniques
Detecting Booleans
Detecting numbers
Detecting strings
Detecting undefined
Detecting null
Detecting null or undefined
Detecting arrays
Detecting instances
Detecting plain objects
Conversion, coercion, and casting
Converting into a Boolean
Converting into a String
Converting into a Number
Converting into a primitive
Summary
Operators
What is an operator?
Operator arity
Operator function
Operator precedence and associativity
Arithmetic and numeric operators
The addition operator
Both operands are numbers
Both operands are strings
One operand is a string
One operand is a non-primitive
Conclusion – know your operands!
The subtraction operator
The division operator
The multiplication operator
The remainder operator
The exponentiation operator
The unary plus operator
The unary minus operator
Logical operators
The logical NOT operator
The logical AND operator
The logical OR operator
Comparative operators
Abstract equality and inequality
Strict equality and inequality
Greater than and less than
Lexicographic comparison
Numeric comparison
The instanceof operator
The in operator
Assignment operators
Increment and decrement (prefix and postfix) operators
Prefix increment/decrement
Postfix increment/decrement
Destructuring assignment
Property access operators
Direct property access
Computed property access
Other operators and syntax
The delete operator
The void operator
The new operator
The spread syntax
The comma operator
Grouping
Bitwise operators
Summary
Parts of Syntax and Scope
Expressions, statements, and blocks
Expressions
Statements
Forming statements with semicolons
Blocks
Scopes and declarations
Variable declarations
Let declarations
Const declarations
Function declarations
Closures
Summary
Control Flow
What is control flow?
Imperative versus declarative programming
The movement of control
Invocation
Returning
Yielding
Yielding to a yield
Complexity of yielding
Breaking
Continuing
Throwing
Statements of control flow
The if statement
The for statement
Conventional for
for...in
for...of
The while statement
The do...while statement
The switch statement
Breaking and fallthrough
Returning from a switch directly
Case blocks
Multivariant conditions
Handling cyclomatic complexity
Simplifying conditional spaghetti
Asynchronous control flow
The Event Loop
Native asynchronous APIs
Callbacks
Event subscribing/emitting
Promises
async and await
Summary
Section 3: Crafting Abstractions
Design Patterns
The perspective of a designer
Architectural design patterns
MVC
A working example of MVC
MVVM
MV* and the nature of software
JavaScript modules
Modular design patterns
Constructor patterns
When to use the Constructor pattern
Inheritance with the Constructor pattern
The Class pattern
When to use the Class pattern
Static methods
Public and private fields
Extending classes
Mixing-in classes
Accessing a super-class
The Prototype pattern
When to use the Prototype pattern
The Revealing Module pattern
The Conventional Module pattern
When to use the Conventional Module pattern
The Singleton Class pattern
When to use the Singleton Class pattern
Planning and harmony
Summary
Real-World Challenges
The DOM and single-page applications
DOM binding and reconciliation
DOM reconciliation
React's approach
Messaging and data propagation
Frontend routing
Dependency management
Module definition – then and now
npm and package.json
Bundling and serving
Security
Cross-Site Scripting
Content Security Policy
Subresource Integrity
Cross-Site Request Forgery
Other security vulnerabilities
Summary
Section 4: Testing and Tooling
The Landscape of Testing
What is a test?
The simple assertion
Many moving parts
Types of testing
Unit testing
Integration testing
E2E and functional testing
Test-Driven Development
Summary
Writing Clean Tests
Testing the right thing
Writing intuitive assertions
Creating clear hierarchies
Providing final clarity
Creating clean directory structures
Summary
Tools for Cleaner Code
Linters and formatters
Static typing
E2E testing tools
Automated builds and CI
Summary
Section 5: Collaboration and Making Changes
Documenting Your Code
Aspects of clean documentation
Concept
Specification
Instruction
Usability
Documentation is everywhere
Writing for non-technical audiences
Summary
Other Peoples' Code
Inheriting code
Exploring and understanding
Making a flowchart
Finding structure and observing history
Stepping through the code
Asserting your assumptions
Making changes
Minimally invasive surgery
Encoding changes as tests
Dealing with third-party code
Selection and understanding
Encapsulating and adapting third-party code
Summary
Communication and Advocacy
Planning and setting requirements
Understanding user needs
Quick prototypes and PoCs
Communication strategies
Listen and respond
Explain from the user's perspective
Have small and focused communications
Ask stupid questions and have wild ideas
Pair programming and 1:1s
Identifying issues and driving change
Raising bugs
Driving systemic change
Summary
Case Study
The problem
The design
The implementation
The Plant Selection application
Creating the REST API
Creating the client-side build process
Creating the component
Summary
Other Books You May Enjoy
Leave a review - let other readers know what you think
Preface
JavaScript is a scrappy yet graceful language that has found itself at the center of one of the greatest software shifts in history. It is now the primary programming language used to deliver user experiences on the most ubiquitous platform that exists: the web.
This huge responsibility has meant that the JavaScript language has had to grow up very quickly in a period of shifting demands. For the up-and-coming JavaScript programmer or web developer, these changes have meant that the language and its ecosystem have been increasingly complex to grasp. Nowadays, the sheer number of frameworks and libraries available is overwhelming, even to those who've been in the industry for many years.
The task of this book is to peel back the confusing layers and concepts that the world has placed atop the language to reveal its underlying nature and consider how we can use it to craft reliable and maintainable code with a focus on usability. We will begin by zooming out and considering, in a very fundamental way, why we even write code. We will discover that the code we write does not exist in a vacuum. We will explore the large and small ways in which our code drastically affects our users and fellow programmers, and discuss ways that we can accommodate their various needs.
Beyond a fundamental exploration of clean coding principles, we will deeply delve into JavaScript itself, guiding you through the language, from its most atomic syntax to its more abstract design patterns and conventions. We will also explore how we can go about documenting and testing our code in the cleanest way possible. You should come away with a solid grasp of the JavaScript language and an attuned sense of what clean code is.
Who this book is for
This book is for anyone who has an interest in improving their JavaScript skills. Whether you are an amateur or a professional, there are aspects of this book that you will find valuable. In terms of technical knowledge, the book assumes some previous exposure to programming and at least a small amount of experience of JavaScript itself. The reader who will get the most value from this book is someone who has programmed for a number of months or years in JavaScript but has always felt weighed down by the complexity of it and is unsure of how to craft clean and bug-free JavaScript.
What this book covers
Chapter 1, Setting the Scene, asks you to consider why we write code and explores the many ways in which we communicate our intent via code. This chapter provides a firm foundation upon which you can build and adapt your understanding of clean code.
Chapter 2, The Tenets of Clean Code, uses real-world JavaScript examples to explore the four tenets of clean code: reliability, efficiency, maintainability, and usability. Each of these vital tenets serves as a foundation for the rest of the book.
Chapter 3, The Enemies of Clean Code, uncovers some of the more notorious enemies of clean code. These are the forces and dynamics that lead to the proliferation of unclean code, such as egotistic programming, bad metrics, and cargo cults.
Chapter 4, SOLID and Other Principles, explores the famous SOLID principles and uncovers their deeper meaning by tying them together with functional programming principles, the Law of Demeter, and the abstraction principle.
Chapter 5, Naming Things Is Hard, discusses one of the most challenging aspects of programming: naming things. It poses some of the specific challenges of naming and ties together a foundational naming theory with real-world naming problems and solutions.
Chapter 6, Primitive and Built-In Types, begins a deep exploration into JavaScript. This chapter details the primitive and built-in types available to the JavaScript programmer, warning against common pitfalls and sharing best practices.
Chapter 7, Dynamic Typing, discusses JavaScript's dynamic nature, and goes over some of the challenges related to this. It explains how we can both cleanly detect and convert to various types (via explicit casting or implicit coercion).
Chapter 8, Operators, thoroughly details the operators available within JavaScript, discussing their behaviors and challenges. This includes a detailed account of every operator alongside examples, pitfalls, and best practices.
Chapter 9, Parts of Syntax and Scope, provides a more macro view of the language, highlighting the broader syntaxes and constructs available, such as statements, expressions, blocks, and scope.
Chapter 10, Control Flow, broadly covers the concept of control flow, highlighting the crucial difference between imperative and declarative forms of programming. It then explores how we can cleanly control flow within JavaScript by utilizing control-moving mechanisms such as invoking, returning, yielding, throwing, and more.
Chapter 11, Design Patterns, broadly explores some of the more popular design patterns used in JavaScript. It describes the major architectural design patterns of MVC and MVVM, and the more modular design patterns such as the Constructor pattern, the Class pattern, the Prototype pattern, and the Revealing Module pattern.
Chapter 12, Real-World Challenges, looks at some of the more realistic problem domains within the JavaScript ecosystem and considers how they can be handled cleanly. Topics covered include the DOM and single-page applications, dependency management, and security (XSS, CSRF, and more).
Chapter 13, The Landscape of Testing, describes the broad concepts of testing software, and how these can be applied to JavaScript. It specifically explores unit testing, integration testing, E2E testing, and TDD.
Chapter 14, Writing Clean Tests, delves further into the domain of testing by advising you to author assertions and test suites in a way that is utterly clear, intuitive, representative of the problem domain, and conceptually hierarchical.
Chapter 15, Tools for Cleaner Code, briefly considers several available tools and development flows that can greatly aid us in writing and maintaining clean code. Included are topics such as linting, formatting, source control, and continuous integration.
Chapter 16, Documenting Your Code, uncovers the unique challenges of documentation. This chapter challenges you to consider all the mediums of documentation that are available and asks you to consider how we can understand and accommodate the needs and questions of individuals who may wish to utilize or maintain our code.
Chapter 17, Other Peoples' Code, looks into the challenges of selecting, understanding, and making use of third-party code within our JavaScript projects (such as third-party libraries, frameworks, and utilities). It also discusses methods of encapsulation that allow us to interface with third-party code in a clean and minimally invasive way.
Chapter 18, Communication and Advocacy, explores the wider project-based and interpersonal challenges inherent in the crafting and delivery of clean software. This includes a detailed inquiry into the following: planning and setting requirements, communication strategies, and identifying issues and driving change.
Chapter 19, Case Study, concludes the book with a walk-through of the development of a JavaScript project, including both client-side and server-side pieces. This chapter draws together the principles espoused within the book and affirms them by exposing you to a real-world problem domain and the development of a usable solution.
To get the most out of this book
In order to get the most out of this book, it is useful to have a basic understanding of the JavaScript language and to have some experience of atleast one platform in which JavaScript is utilized. This may include the browser or Node.js, for example.
In order for you to execute the pieces of code shared within the book, you have a few options available:
Create an HTML file with
Directly open the development tools of any modern browser and directly type JavaScript expressions and statements into the JavaScript console. A guide to doing this within the Chrome browser can be found here: https://developers.google.com/web/tools/chrome-devtools/console/javascript.
Create a test.js file and run it via Node.js or use the Node.js REPL to interactively test distinct JavaScript statements and expressions via the command line. A comprehensive guide to getting started with Node.js can be found here: https://nodejs.org/en/docs/guides/getting-started-guide/.
Browser development tools are accessible within all modern browsers. The shortcuts are as follows:
In Chrome: Ctrl + Shift + J on Windows or CMD + Shift + J on macOS
In Firefox: Ctrl + Shift + I or F12 on Windows and Linux, or CMD + OPTION + I on macOS
In IE: F12 on Windows
You are advised to move through the book at your own pace and conduct additional research and exploration online if you are finding a topic hard to grasp. Some especially helpful resources include the following:
Mozilla Developer Network: https://developer.mozilla.org/en-US/docs/Web/JavaScript
ECMAScript Language Specification: https://www.ecma-international.org/publications/standards/Ecma-262.htm
The book gets progressively more detailed as you advance through it, so it is natural to take a slower pace in later chapters. This may be especially true for Chapters 6-12, which cover, in great detail, the characteristics of the JavaScript language itself.
Download the example code files
You can download the example code files for this book from your account at www.packt.com. If you purchased this book elsewhere, you can visit www.packtpub.com/support and register to have the files emailed directly to you.
You can download the code files by following these steps:
Log in or register at www.packt.com.
Select the Support tab.
Click on Code Downloads.
Enter the name of the book in the Search box and follow the onscreen instructions.
Once the file is downloaded, please make sure that you unzip or extract the folder using the latest version of:
WinRAR/7-Zip for Windows
Zipeg/iZip/UnRarX for Mac
7-Zip/PeaZip for Linux
The code bundle for the book is also hosted on GitHub at https://github.com/PacktPublishing/Clean-Code-in-JavaScript. In case there's an update to the code, it will be updated on the existing GitHub repository.
We also have other code bundles from our rich catalog of books and videos available at https://github.com/PacktPublishing/. Check them out!
Download the color images
We also provide a PDF file that has color images of the screenshots/diagrams used in this book. You can download it here: https://static.packt-cdn.com/downloads/9781789957648_ColorImages.pdf.
Conventions used
There are a number of text conventions used throughout this book.
CodeInText: Indicates code words in text, database table names, folder names, filenames, file extensions, pathnames, dummy URLs, user input, and Twitter handles. Here is an example: "We find a publicly available package called shipping_address_validator and decide to use it."
A block of code is set as follows:
function validatePostalCode(code) {
return /^[0-9]{5}(?:-[0-9]{4})?$/.test(code);
}
Any command-line input or output is written as follows:
npm install --save react react-dom
Bold: Indicates a new term, an important word, or words that you see on screen. For example, words in menus or dialog boxes appear in the text like this. Here is an example: For the purposes of our case study, the plant names only exist as their full Latin names, which includes a family (for example, Acanthaceae).
Warnings or important notes appear like this.
Tips and tricks appear like this.
Get in touch
Feedback from our readers is always welcome.
General feedback: If you have questions about any aspect of this book, mention the book title in the subject of your message and email us at [email protected].
Errata: Although we have taken every care to ensure the accuracy of our content, mistakes do happen. If you have found a mistake in this book, we would be grateful if you would report this to us. Please visit www.packtpub.com/support/errata, selecting your book, clicking on the Errata Submission Form link, and entering the details.
Piracy: If you come across any illegal copies of our works in any form on the Internet, we would be grateful if you would provide us with the location address or website name. Please contact us at [email protected] with a link to the material.
If you are interested in becoming an author: If there is a topic that you have expertise in and you are interested in either writing or contributing to a book, please visit authors.packtpub.com.
Reviews
Please leave a review. Once you have read and used this book, why not leave a review on the site that you purchased it from? Potential readers can then see and use your unbiased opinion to make purchase decisions, we at Packt can understand what you think about our products, and our authors can see your feedback on their book. Thank you!
For more information about Packt, please visit packt.com.
Section 1: What is Clean Code Anyway?
In this section, we'll discuss the purpose of code and the tenets of it, such as clarity and maintainability. We'll also cover the very broad challenge of naming things, as well as some of the valuable questions and hazards to watch out for.
This section contains the following chapters:
Chapter 1, Setting the Scene
Chapter 2, The Tenets of Clean Code
Chapter 3, The Enemies of Clean Code
Chapter 4, SOLID and Other Principles
Chapter 5, Naming Things Is Hard
Setting the Scene
JavaScript was created by Brendan Eich in 1995, with the goal of being a glue language. It was intended to help web designers and amateurs easily manipulate and derive behavior from their HTML. JavaScript was able to do this via the DOM API, a set of interfaces provided by the browser that would give access to the parsed representation of HTML. Soon after this, DHTML became the popular term, referring to the more dynamic user interfaces that JavaScript enabled: everything from animated rollover button states to client-side form validation. Eventually came the rise of Ajax, which enabled communication between the client and the server. This opened up a considerable fountain of potential applications. The web, previously purely the domain of documents, was now on the way to becoming a powerhouse of processor- and memory-intensive applications:
In 1995, nobody could have predicted that JavaScript would one day be used to build complex web applications, program robots, query databases, write plugins for photo manipulation software, and be behind one of the most popular server runtimes in existence, Node.js.
In 1997, not long after its creation, JavaScript was standardized by Ecma International under the name ECMAScript, and it is still undergoing frequent changes under the TC39 committee. Most recent versions of the language have been named according to the year of their release, such as ECMAScript 2020 (ES2020).
Due to its burgeoning capabilities, JavaScript has attracted a passionate community that drives its growth and ubiquity. And due to its considerable popularity, there are now countless different ways to do the same thing in JavaScript. There are thousands of popular frameworks, libraries, and utilities. The language too is changing on a near-constant basis in reaction to the increasing demands of its applications. This creates a great challenge: among all of this change, while being pushed and pulled in different directions, how can we know how to write the best possible code? Which frameworks should we use? What conventions should we employ? How should we test our code? How should we craft sensible abstractions?
To answer these questions, we need to briefly go back to basics. And that is the purpose of this chapter. We'll be discussing the following:
What the true purpose of the code is
Who our users are and what problems they have
What it means to write code for humans
Why we write code
At its simplest, we know that programming is about instructing computers, but what are we instructing them to do? And to what end? And what other purposes does code serve?
We can broadly say that code is a way of solving problems. By writing code, we are expressing a complex task or series of actions, distilling them into a singular process that can be easily utilized by a user. So we can say that the code is an expression of a problem domain. We can even say it is a form of communication, a way to relay information and intent. Understanding that code is a complex thing with many complementary purposes, such as problem-solving and communication, will enable us to use it to its fullest potential. Let's delve further into this complexity by exploring what we mean when we speak of code as a method of relaying intent.
Code as intent
We often think of code as simply a series of instructions that are executed by a computer. But in many ways, this misses the true magic of what we're doing when we write code. When we convey instructions, we are expressing our intent to the world; we are saying These are the things that I want to occur.
Humans have been conveying instructions for as long as they've been around. One example of this is a simple cooking recipe:
Cut about three hundred grams of butter (small cubes!)
Take 185 grams dark chocolate
Melt it with butter over a saucepan
Break half dozen eggs, ideally large ones
Mix them together with a few cups of sugar
Instructions like these are quite easy to understand for a human, but you'll notice they follow no strict specification. The measuring units are inconsistent, as is the punctuation and the wording. And some of the instructions are quite ambiguous and therefore open to misinterpretation by someone who hasn't cooked before:
What constitutes a large egg?
When should I consider the butter fully melted?
How dark should the dark chocolate be?
How small is a small cube of butter?
What does over a saucepan mean?
Humans can usually muddle through such ambiguities with their initiative and experience, but machines aren't so adept. A machine must be instructed with enough specificity to carry out every step. What we wish to communicate to a machine is our intent, that is, please do this thing, but due to the nature of machines, we must be utterly specific. Thankfully, how we choose to write these instructions is up to us; there are many programming languages and approaches, and almost all of them were created with the goal of making it easier for humans to communicate their intent in a less burdensome way.
The distance between human capability and computing capability is quickly narrowing. The advent of machine learning, natural language processing, and highly specialized programs means that machines are far more flexible in the types of instructions they can carry out. However, code will continue to be useful for some time, as it allows us to communicate in a highly specific and standardized way. With this high level of specificity and consistency, we can have more faith that our instructions will be executed as intended, every time.
Who is the user?
No meaningful conversation about programming can occur without considering the user. The user, whether they are a fellow programmer or the end user of a UI, is at the core of what we do.
Let's imagine that we are tasked with validating user-inputted shipping addresses on a website. This particular website sells medication to hospitals around the world. We're in a bit of a rush and would prefer to use something that someone else has implemented. We find a publicly available package called shipping_address_validator and decide to use it.
If we had taken the time to check the code within the package, in its postal code validation file, we would have seen this:
function validatePostalCode(code) {
return /^[0-9]{5}(?:-[0-9]{4})?$/.test(code);
}
This validatePostalCode function happens to be using regular expressions (also known as RegExp and regex), delimited by forward slashes, to define a pattern of characters to match a string against. You can read more about these constructs in Chapter 6, Primitive and Built-In Types.
Unfortunately, due to our haste, we didn't question the functionality of the shipping_address_validator package. We assumed it did what it says on the tin. One week after releasing our code to production we get a bug report saying that some users are unable to enter their address information. We look at the code and realize, to our horror, that it only validates US ZIP codes, not all countries' postal codes (for example, it doesn't work on UK postcodes, such as GR82 5JY).
Through this unfortunate series of events, this piece of code is now responsible for blocking the shipment of vital medication to customers all over the world, numbering in the thousands. Fortunately, fixing it doesn't take too long.
Forgetting for a moment who is responsible for this mishap, I'd like to pose the following question: who are the users of this code?
We, the programmers, who decided to use the shipping_address_validator package?
The unwitting customers who are attempting to enter their addresses?
The patients in the hospitals who are left waiting for their medication?
There isn't a clear-cut answer to this question. When bugs appear in the code, we can see how there can be massive unfortunate downstream effects. Should the original programmer of the package be concerned with all these downstream dependencies? When a plumber is hired to fix a tap on a sink, should they only consider the function of the tap itself, or the sink into which it pours?
When we write code, we are defining an implicit specification. This specification is communicated by its name, its configuration options, its inputs, and its outputs. Anyone who uses our code has the right to expect it to work according to its specifications, so the more explicit we can be, the better. If we're writing code that only validates US ZIP codes, then we should name it accordingly. When people create software atop our code, we can't have any control over how they use it. But we can communicate explicitly about it, ensuring that its functionality is clear and expected.
It's important to consider all use cases of our code, to imagine how it might be used and what expectations humans will have about it, programmers and end users alike. What we are responsible or accountable for is up for debate, and is as much a legal question as a technical one. But the question of who our users are is entirely up to us. In my experience, the better programmers consider the full gamut of users, aware that the software they write does not exist in a vacuum.
What is the problem?
We've spoken about the importance of the user in programming, and how we must first understand what it is they wish to do if we are to have any hope of helping them.
Only by understanding the problem can we begin to assemble requirements that our code will have to fulfill. In the exploration of the problem, it's useful to ask yourself the following questions:
What problem is the user encountering?
How do they currently carry out this task?
What existing solutions are there and how do they work?
When we have assembled a complete understanding of the problem, we can then begin ideating, planning, and writing code to solve it. At each step, often without realizing it, we will be modeling the problem in a way that makes sense to us. The way we think about the problem will have a drastic effect on the solution we end up creating. The model of the problem we create will dictate the code we end up writing.
What is the model of a problem?
A model or conceptual model is a schematic or representation that describes how something works. We create and adapt models all the time without realizing it. Over time, as you gain more information about a problem domain, your model will improve to better match reality.
Let's imagine for a moment that we are responsible for a note-taking application for students and are tasked with creating a solution to the following problem that a user has expressed:
I have many notes for my studies and so am finding it hard to organize them. Specifically, when trying to find a note on a given topic, I'll try to use the Search feature but I rarely find what I'm looking for since I can't always recall the specific text I wrote.
We've decided that this warrants changes to the software because we've heard similar things from other users. So, we sit down and try to come up with various ideas for how we could improve the organization of notes. There are a few options we could explore:
Categories: There would be a hierarchical folder structure for categories. A note on Giraffes might exist under studies/zoology. Categories can be easily navigated manually or via search.
Tags: There would be the ability to tag a note with one or more words or phrases. A note on Giraffes might be tagged with mammal and long neck. Tags can then be easily navigated manually or via search.
Links: Introduce a linking feature so notes can link to other notes that are related. A note on Giraffes might be linked to from another note, such as the one on Animals with long necks.
Each solution has its pros and cons, and there is also the possibility of implementing a combination of them. One thing that becomes immediately obvious is that each of these will quite drastically affect how users end up using the application. We can imagine how users exposed to these respective solutions would hold the model of note-taking in their minds:
Categories: Notes I write have their place in my categorical hierarchy
Tags: Notes I write are about many different things
Links: Notes I write are related to other notes I write
In this example, we're developing a UI, so we are sitting very close to the end user of the application. However, the modeling of problems is applicable to all of the work we do. If we were creating a pure REST API for note-keeping, exactly the same considerations would need to be made. Web programmers play a key part in deciding what models other people end up employing. We should not take this responsibility lightly.
Truly understanding the problem domain
The first point of failure is typically misunderstanding the problem. If we don't understand what users are truly trying to accomplish, and we have not received all requirements, then we will inevitably retain a bad model of the problem and thus end up implementing the wrong solutions.
Imagine that this scenario occurs at some point before the invention of the kettle:
Susanne (engineer): Matt, we've been asked to design a vessel that users can boil water with
Matthew (engineer): Understood; I will create a vessel that does exactly that
Matthew asks no questions and immediately gets to work, excited at the prospect of putting his creativity to use. One day later he comes up with the following contraption:
We can see, quite obviously, that Matthew has forgotten one key component. In his haste, he did not stop to ask Susanne for more information about the user, or about their problem, and so did not consider the eventuality that a user would need to pick up the boiling-hot vessel somehow. After receiving feedback, naturally, he designed and introduced a handle to the kettle:
This needn't have occurred at all, though. Imagine this kettle scenario extrapolated to the complexity and length of a large software project spanning multiple months. Imagine the headaches and needless pain involved in such a misunderstanding. The key to designing a good solution to a problem requires, first and foremost, a correct and complete model of the problem. Without this, we'll fail before we even begin. This matters in the design of massive projects but also in the implementation of the smallest JavaScript utilities and components. In every line of code we write, in fact, we are utterly liable to failure if we do not first understand the problem domain.
The problem domain encapsulates not only the problem being encountered by the user but also the problem of meeting their needs via the technologies we have available. And so, the problem domain of writing JavaScript in the browser, for example, includes the complexity of HTTP, the browser object model, the DOM, CSS, and a litany of other details. A good JavaScript programmer has to be adept not only in these technologies but also in understanding new domains of problems encountered by their users.
Writing code for humans
This entire book is concerned with teaching you how to write clean code in JavaScript. In the following chapters, we'll go into a lot of detail, with discussions of almost every construct within the language. Firstly, we need to establish a few key perspectives that'll be important when we think about what it means to write clean code for humans.
Communicating intent
We can say that writing code for humans is broadly about the clarity of intent. And writing code for machines is broadly about functionality. These needs do cross over, of course, but it's vital to discern the difference. We can see the difference if we were writing code only for the machine, focusing purely on function, and forgetting the human audience. Here's an example:
function chb(d,m,y) {
return new Date(y,m-1,d)-new Date / 6e4 * 70;
}
Do you understand what this code is doing? You may be able to decipher what's going on in this code, but it is intent—its true meaning—will be almost impossible to discern.
If we clearly express our intent then the preceding code would look something like this:
const AVG_HEART_RATE_PER_MILLISECOND = 70 / 60000;
function calculateHeartBeatsSinceBirth(birthDay, birthMonth, birthYear) {
const birthMonthIndex = birthMonth - 1;
const birthDate = new Date(birthYear, birthMonthIndex, birthDay);
const currentDate = new Date();
return (currentDate - birthDate) / AVG_HEART_RATE_PER_MILLISECOND;
}
From the preceding code, we can discern that this function is intended to calculate the number of times a heart has beaten since birth. There is no functional difference between these two pieces of code. However, the latter code better communicates the programmer's intentions, and thus is easier to understand and to maintain.
The code we write is primarily for people. You may be building a brochure website, programming a web application, or crafting a complex utility function for a framework. All of these things are for people: people who are the end users of GUIs driven by our code or people who are the programmers making use of our abstractions and interfaces. Programmers are in the business of helping these people.
Even if you're writing code only for yourself, with no possibility of it being used in any way by anyone else, your future self will thank you if you write clear code.
Readability
When we write code, it's essential to consider how human brains will consume it. Fellow programmers will scan over your code, reading the pertinent parts, attempting to gain a running comprehension of its inner workings. Readability is the first hurdle that they must overcome. If they are unable to read and cognitively navigate the code you've written then they'll be less able to use it. This will drastically limit the utility and value of your code.
Programmers, in my experience, don't tend to like thinking of code in terms of aesthetic design, but the best programmers will appreciate that these concepts are intrinsically intertwined. The design of our code in a presentational or visual sense is as vital to its comprehensibility as its architectural design. Design, in the end, is about creating something in a way that optimally delivers a purpose for its users. For our fellow programmers, that purpose is comprehension. And so we must design our code to deliver that purpose.
Machines care purely about specifications and will parse valid code into its parts with little effort. Humans, however, are more complex. We are less capable in areas where machines excel, hence their existence, but we are also skillful in areas where machines may falter. Our highly evolved brains, among their many talents, have become incredibly skilled at spotting patterns and inconsistencies. We rely on difference, or contrast, to focus our attention. If a pattern is not being followed then it creates more work for our brains. For an example of such inconsistency, have a look at this code:
var TheName='James' ;
var City = 'London'
var hobby = 'Photography',job='Programming'
You probably