What is legacy code? I’m a fan of Michael Feathers’s definition in his excellent book, Working Effectively with Legacy Code (Prentice Hall): legacy code is code without tests. This code either will not survive or will never be touched by anyone. When the time comes to touch legacy code, it gets rewritten. Take a look at your current project; any code that does not have tests will likely be rewritten. Probably not by the author of the code, but by whoever is now tasked with dealing with it—either enhancing or bug-fixing it. Unless tests are written, this is dead code that will have to be rewritten. The code may be spectacular, but the only way it will survive is if it never causes bugs and if no one ever requests enhancements or new features for it. Even then, how happy are you to ship production code with no tests? Even if the code “worked” before, are you content to keep rolling the dice? Is your company, which owns the code, content to keep rolling the dice? Typically the piper must be paid, and this code will just get rewritten. It’s too bad the company had to pay to have this possibly spectacular code written twice, but such is the case with legacy code.
As you can see in the matrix shown in Figure P-1, it is very easy for any legacy code you’ve written to fall into someone else’s hands and be rewritten. That path is typically less painful than bringing someone else’s legacy code up to speed with tests. It is very easy to move from side to side in this matrix, as code changes hands constantly, moving into and out of your purview with great agility. Moving “down” is the hardest path for code to take; writing tests for existing code is a job no one wants to do, and most people will go to impressively great lengths to avoid it—typically resulting in a complete rewrite.
Unfortunately, moving up in this matrix happens with some regularity. Code that starts out with tests can lapse into legacy code if it falls into the wrong hands. Vigilance is required to keep tests up to date as more enhancements and features are bolted on, but this is a much simpler process than writing tests for code without any (or with very few) tests.
Starting with the good habits of structuring your code syntactically and semantically for testability, writing the right tests at the right times, running them regularly, and monitoring their results will keep you in that lower-left sweet spot in the matrix.
I am currently a Software Engineer in Test at Google, putting all of those hard-earned lessons to good use, and I hope you can too.
There are two things to learn from this book: the right way and the wrong way! There is, of course, a continuum between “right” and “wrong.” After you have finished reading this book, I would like you to be coding or looking at someone else’s code and know why you feel good or feel bad about it. If you can already tell what is wrong with code, good for you. When I look at code for the first time, either what I wrote or what someone else wrote, I get a good or bad feeling pretty quickly: either I understand the code almost immediately (a good feeling), or my eyes glaze over (a bad feeling). It is nice to be able to articulate to the author issues with his code; hopefully Chapter 2 will give you not only a more concrete sense of good versus bad, but also a shared vocabulary to communicate back to the author.
The overrriding theme of this book is writing and maintaining “testable” code. But what is testable code? Why should we strive to write it? And how do we do so? We will begin by exploring all of these questions, and taking a look at some popular development methodologies and how they relate to testable code. Ultimately, whatever practice you may choose to follow, the key to writing testable code lies in keeping it small, clear, uncomplicated, and loosely coupled.”
After our discussion on complexity, we will dive deeper into event-based architecture. This application-level architecture can greatly reduce complexity and coupling while providing easy ways to break down your application into smaller, more self-sufficient pieces. Regardless of whether your application is server-side, client-side, or (most likely) both, an event-based architecture solves many of the problems enumerated in Chapter 2. Even if it is not suitable as the overall architecture for every application, there certainly is a place within the overall structure to leverage event-based architecture concepts and practices.
Code Coverage typically goes hand in hand with unit testing. Code coverage can be a good measure of unit-test efficacy; however, we will see that this is not always the case. Yet code coverage is not just for unit testing anymore! All kinds of testing can benefit from code coverage measurements, including integration, manual, and performance testing. We will investigate the good and the bad of code coverage metrics and how to generate, view, and make sense of them.
The code we write is not perfect, no matter how perfect it seems when we first write it. Our code will have bugs. Lots of bugs. Stuff you thought about and stuff you did not even conceive of will bedevil your code. Your tests, someone else’s tests, or a user using your application will find the bugs. Bugs found by tests are by far the easiest to fix, which is another great reason to maximize your tests. Bugs found by users running production code are far more difficult to track down. The upshot is that you will have to debug not only your code but also someone else’s. I’ll share some tips and tricks for debugging both Node.js and browser code. Get a good debugging environment set up, because you will be doing a lot of it.
Finally, doing things manually over and over again is not only not sustainable but also not very fun. Writing software is one of the most manual processes in the world, but testing and maintaining software does not have to be. Running tests, generating code coverage reports, performing static analysis, minifying and compressing code, and deploying and rolling back code to and from production and other environments should all be part of an automated process. Automation ensures that whatever happens, success or failure, it will happen quickly and, more importantly, in a way that can be repeated. You will fail. Tests will fail, a production launch will fail, and things will go wrong that will have absolutely nothing to do with your code. That is life. It is critical that you can recover from those failures (along with the failures you have caused) as quickly and seamlessly as possible.
If you like—or don’t like—this book, by all means, please let people know. Amazon reviews are one popular way to share your happiness (or lack of happiness), or you can leave reviews at the book’s website.
That website also provides a link to errata, giving you a way to let us know about typos, errors, and other problems with the book. These errata will be visible on the page immediately, and we’ll confirm them after checking them out. O’Reilly can also fix errata in future printings of the book and on Safari, making for a better reader experience pretty quickly.
We have tested and verified the information in this book to the best of our ability, but you may find that features have changed (or even that we have made a few mistakes!). Please let us know about any errors you find, as well as your suggestions for future editions, by writing to:
|O’Reilly Media, Inc.|
|1005 Gravenstein Highway North|
|Sebastopol, CA 95472|
|800-998-9938 (in the U.S. or Canada)|
To comment or ask technical questions about this book, send email to email@example.com.
For more information about our books, courses, conferences, and news, see our website at http://www.oreilly.com.
Find us on Facebook: http://facebook.com/oreilly
Follow us on Twitter: http://twitter.com/oreillymedia
Watch us on YouTube: http://www.youtube.com/oreillymedia
The following typographical conventions are used in this book:
Indicates new terms, URLs, email addresses, filenames, and file extensions.
Used for program listings, as well as within paragraphs to refer to program elements such as variable or function names, databases, data types, environment variables, statements, and keywords.
Constant width bold
Shows commands or other text that should be typed literally by the user.
Constant width italic
Shows text that should be replaced with user-supplied values or by values determined by context.
This icon signifies a tip, suggestion, or general note.
This icon indicates a warning or caution.
This book is here to help you get your job done. In general, if this book includes code examples, you may use the code in your programs and documentation. You do not need to contact us for permission unless you’re reproducing a significant portion of the code. For example, writing a program that uses several chunks of code from this book does not require permission. Selling or distributing a CD-ROM of examples from O’Reilly books does require permission. Answering a question by citing this book and quoting example code does not require permission. Incorporating a significant amount of example code from this book into your product’s documentation does require permission.
If you feel your use of code examples falls outside fair use or the permission given above, feel free to contact us at firstname.lastname@example.org.
Technology professionals, software developers, web designers, and business and creative professionals use Safari Books Online as their primary resource for research, problem solving, learning, and certification training.
Members have access to thousands of books, training videos, and prepublication manuscripts in one fully searchable database from publishers like O’Reilly Media, Prentice Hall Professional, Addison-Wesley Professional, Microsoft Press, Sams, Que, Peachpit Press, Focal Press, Cisco Press, John Wiley & Sons, Syngress, Morgan Kaufmann, IBM Redbooks, Packt, Adobe Press, FT Press, Apress, Manning, New Riders, McGraw-Hill, Jones & Bartlett, Course Technology, and hundreds more. For more information about Safari Books Online, please visit us online.
A Big Thank You to everyone who helped me cobble together this book, starting with my former employer, Yahoo!, which green-lighted the time I needed to spend writing during “business hours”; thanks Julia and Randy! Also a Big Shout-Out to the amazing frontend team working on Yahoo! Mail, especially those based in Rancho Bernardo—I’m looking at you, Brian, Jeff, Hung, Dan, Mily, Steve, and Scott. Thanks to my manager here at Google, Matt Evans, and the rest of our team for letting me continue to pursue my goal of developing sane software.
A special thank you to everyone who contributes to open source technology. It is amazing that there continue to be fewer reasons to use commercial software, which is quite ironic for someone in the commercial software business. It is clear that money is not the be-all and end-all motivator, and it warms the cockles of my heart that passion trumps money every time. Hey employers, the intersection of your employees’ passion and your product is how quality work actually gets done!
Finally, much love to my family—Walter, Inslee, and especially Michelle, who has had to live with the gestation process of this book for too long. Now, on to the next one?