front matter

preface

I’ve been coding in one form or another since I was 11 years old, so by the time I landed my first job as a software engineer, I’d written quite a lot of code. Despite this, I quickly discovered that coding and software engineering are not the same thing. Coding as a software engineer meant that my code had to make sense to other people and not break when they changed things. It also meant that there were real people (sometimes lots of them) using and relying on my code, so the consequences of things going wrong were a lot more serious.

As a software engineer gets more experienced, they learn how the decisions they make in their everyday coding can have big consequences on whether software will work properly, keep working properly, and be maintainable by others. Learning how to write good code (from a software engineering point of view) can take many years. These skills are often picked up slowly and in an ad hoc way as engineers learn from their own mistakes or get piecemeal advice from more senior engineers that they work with.

This book aims to give new software engineers a jump-start in acquiring these skills. It teaches some of the most important lessons and theoretical underpinnings of writing code that will be reliable, maintainable, and adaptable to changing requirements. I hope that you find it useful.

acknowledgments

Writing a book is not a lone effort, and I’d like to thank everyone who had a hand in bringing this book into reality. In particular, I’d like to thank my development editor, Toni Arritola, for patiently guiding me through the process of authoring a book, and for her constant focus on the reader and high-quality teaching. I’d also like to thank my acquisition editor, Andrew Waldron, for believing in the idea for the book in the first place and for the many invaluable insights provided along the way. I’d also like to thank my technical development editor, Michael Jensen, for his deep technical insights and suggestions throughout the book. And thank you to my technical proofreader, Chris Villanueva, for carefully reviewing the code and technical content of the book, and for all the great suggestions.

I’d also like to thank all of the reviewers—Amrah Umudlu, Chris Villanueva, David Racey, George Thomas, Giri Swaminathan, Harrison Maseko, Hawley Waldman, Heather Ward, Henry Lin, Jason Taylor, Jeff Neumann, Joe Ivans, Joshua Sandeman, Koushik Vikram, Marcel van den Brink, Sebastian Larsson, Sebastián Palma, Sruti S, Charlie Reams, Eugenio Marchiori, Jing Tang, Andrei Molchanov, and Satyaki Upadhyay—who took the time to read the book at multiple stages throughout its development and provide precise and actionable feedback. It’s hard to overstate just how important and useful this feedback has been.

Nearly all the concepts in this book are well-established ideas and techniques within the software engineering community, so as a final acknowledgement I’d like to say thank you to all those who have contributed to, and shared, this body of knowledge over the years.

about this book

Good Code, Bad Code introduces key concepts and techniques that professional software engineers regularly use to produce reliable and maintainable code. Rather than just enumerating do’s and don’ts, the book aims to explain the core reasoning behind each concept and technique, as well as any trade-offs. This should help readers develop a fundamental understanding of how to think and code like a seasoned software engineer.

Who should read this book

This book is aimed at people who can already code but who want to improve their skills at coding as a software engineer in a professional environment. This book will be most useful to anyone with zero to three years’ experience as a software engineer. More experienced engineers will probably find that they already know many of the things in the book, but I hope that they will still find it a useful resource for mentoring others.

How this book is organized: A roadmap

The book is organized into 11 chapters, spread across three parts. The first part introduces some more theoretical, high-level concepts that shape the way we think about code. The second part moves onto more practical lessons. Each chapter in part 2 is split into a series of topics that cover a particular consideration or technique. The third and final part of the book covers principles and practices that go into creating effective and maintainable unit tests.

The general pattern in individual sections of the book is to demonstrate a scenario (and some code) that can be problematic and to then show an alternative approach that eliminates some or all of the problems. In this sense, sections tend to progress from showing “bad” code to showing “good” code, with the caveat that the terms bad and good are subjective and context dependent. And as the book aims to emphasize, there are often nuances and trade-offs to consider, meaning this distinction is not always clear-cut.

Part 1, “In theory,” sets the foundations for some overarching and slightly more theoretical considerations that shape our approach to writing code as software engineers.

  • Chapter 1 introduces the concept of code quality, and in particular a practical set of goals for what we aim to achieve with high-quality code. It then expands these into six “pillars of code quality,” which provide high-level strategies that can be employed in our everyday coding.

  • Chapter 2 discusses layers of abstraction, a fundamental consideration that guides how we structure and split code into distinct parts.

  • Chapter 3 highlights the importance of thinking about other engineers who will have to work with our code. It goes on to discuss code contracts and how thinking carefully about these can prevent bugs.

  • Chapter 4 discusses errors and why thinking carefully about how to signal and handle them is a vital part of writing good code.

Part 2, “In practice,” covers the first five pillars of code quality (established in chapter 1) in a more practical way with specific techniques and examples.

  • Chapter 5 covers making code readable, which ensures that other engineers will be able to make sense of it.

  • Chapter 6 covers avoiding surprises, which minimizes the chance of bugs by ensuring that other engineers will not misinterpret what a piece of code does.

  • Chapter 7 covers making code hard to misuse, which minimizes the chance of bugs by making it difficult for engineers to accidentally produce code that is logically wrong or that violates assumptions.

  • Chapter 8 covers making code modular, a key technique that helps ensure code exhibits clean layers of abstraction, and that it will be adaptable to changing requirements.

  • Chapter 9 covers making code reusable and generalization. This makes adding new functionality or building new features easier and safer by preventing the need to reinvent the wheel.

Part 3, “Unit testing,” introduces key principles and practices that go into writing effective unit tests.

  • Chapter 10 introduces a number of principles and higher level considerations that influence how we unit test code.

  • Chapter 11 builds on the principles in chapter 10 to provide a number of specific and practical suggestions for writing unit tests.

The ideal way to read this book is cover to cover, because the ideas in earlier parts of the book lay the foundations for subsequent parts. But despite this, the topics in part 2 (and chapter 11) are typically quite self-contained, and each span only a few pages, so most will be useful even if read in isolation. This is deliberate, with the aim of providing an effective way to quickly explain an established best practice to another engineer. This is intended to be useful for any engineers wishing to explain a specific concept in a code review or while mentoring another engineer.

About the code

The book is aimed at engineers who code in a statically typed, object-oriented programming language, such as one of the following: Java, C#, TypeScript, JavaScript (ECMAScript 2015 or later with a static type checker), C++, Swift, Kotlin, Dart 2, or similar. The concepts covered in this book are widely applicable whenever coding in a language like one of these.

Different programming languages have different syntaxes and paradigms for expressing logic and code structure. But in order to provide code examples in this book, it’s necessary to standardize on some kind of syntax and set of paradigms. For this, the book uses a pseudocode that borrows ideas from a number of different languages. The aim with the pseudocode is to be explicit, clear, and easily recognizable to the greatest number of engineers. Please bear this utilitarian intent in mind; the book does not aim to suggest that any one language is better or worse than any other.

Similarly, where there is a trade-off between being unambiguous and being succinct, the pseudocode examples tend to err on the side of being unambiguous. One example of this is the use of explicit variable types, as opposed to inferred types with a keyword like var. Another example is the use of if-statements to handle nulls, rather than the more succinct (but perhaps less familiar) null coalescing and null conditional operators (see appendix B). In real codebases (and outside of the context of a book) engineers may wish to place a greater emphasis on succinctness.

liveBook discussion forum

Purchase of Good Code, Bad Code: Think Like a Software Engineer includes free access to a private web forum run by Manning Publications where you can make comments about the book, ask technical questions, and receive help from the author and from other users. To access the forum, go to https://livebook.manning.com/#!/book/good-code-bad-code/discussion. You can also learn more about Manning's forums and the rules of conduct at https://livebook.manning.com/#!/discussion.

Manning’s commitment to our readers is to provide a venue where a meaningful dialogue between individual readers and between readers and the author can take place. It is not a commitment to any specific amount of participation on the part of the author, whose contribution to the forum remains voluntary (and unpaid). We suggest you try asking the author some challenging questions lest his interest stray! The forum and the archives of previous discussions will be accessible from the publisher’s website as long as the book is in print.

How to use the advice in this book

While reading any book or article about software engineering, it’s always worth remembering that it’s a subjective topic and that the solutions to real-world problems are rarely clear-cut. In my experience, the best engineers approach everything they read with a healthy amount of skepticism and a desire to understand the fundamental thinking behind it. Opinions differ and evolve, and the tools and programming languages available are constantly improving. Understanding the reasons behind a particular piece of advice, its context, and its limits are essential for knowing when to apply it and when to ignore it.

This book aims to collect a number of useful topics and techniques to help guide engineers toward writing better code. Even though it’s probably wise to consider these things, nothing in this book should be considered infallible or applied as a hard-and-fast rule that can never be broken. Good judgment is an essential ingredient of good engineering.

Further reading

This book aims to be a stepping stone into the world of coding as a software engineer. It should give the reader a broad idea of ways to think about code, things that can be problematic, and techniques for avoiding these problems. But the journey shouldn’t end here; software engineering is a huge and ever evolving subject area, and it’s highly advisable to read broadly and to keep up-to date with things. In addition to reading articles and blogs, some books on the subject that readers may find useful are as follows:

  • Refactoring: Improving the Design of Existing Code, second edition, Martin Fowler (Addison-Wesley, 2019)

  • Clean Code: A Handbook of Agile Software Craftsmanship, Robert C. Martin (Prentice Hall, 2008)

  • Code Complete: A Practical Handbook of Software Construction, second edition, Steve McConnell (Microsoft Press, 2004)

  • The Pragmatic Programmer: Your Journey to Mastery, 20th anniversary, second edition, David Thomas and Andrew Hunt (Addison-Wesley 2019)

  • Design Patterns: Elements of Reusable Object-Oriented Software, Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides (Addison-Wesley, 1994)

  • Effective Java, third edition, Joshua Bloch (Addison-Wesley, 2017)

  • Unit Testing: Principles, Practices and Patterns, Vladimir Khorikov (Manning Publications, 2020)

about the author

Tom Long is a software engineer at Google. He works as a tech lead, and among other tasks, regularly mentors new software engineers in professional coding best practices.

about the cover illustration

The figure on the cover of Good Code, Bad Code is captioned “Homme Zantiote,” or a man from the island of Zakynthos in Greece. The illustration is taken from a collection of dress costumes from various countries by Jacques Grasset de Saint-Sauveur (1757-1810), titled Costumes de Différents Pays, published in France in 1797. Each illustration is finely drawn and colored by hand. The rich variety of Grasset de Saint-Sauveur’s collection reminds us vividly of how culturally apart the world’s towns and regions were just 200 years ago. Isolated from each other, people spoke different dialects and languages. In the streets or in the countryside, it was easy to identify where they lived and what their trade or station in life was just by their dress.

The way we dress has changed since then and the diversity by region, so rich at the time, has faded away. It is now hard to tell apart the inhabitants of different continents, let alone different towns, regions, or countries. Perhaps we have traded cultural diversity for a more varied personal life—certainly for a more varied and fast-paced technological life.

At a time when it is hard to tell one computer book from another, Manning celebrates the inventiveness and initiative of the computer business with book covers based on the rich diversity of regional life of two centuries ago, brought back to life by Grasset de Saint-Sauveur’s pictures.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.115.195