This is one the best books for programmers and I think every programmer should read it. The only problem this book has is some parts of it is written specifically for senior developers and architects; so, you may want to skip them, if you're not a SENIOR developer yet, like myself.
Most of the reviews here seem to praise this book. Engineers I work with, themselves skeptical of the agile movement, found the book an outdated artifact of the long-deprecated waterfall model of software development. I found the truth somewhere in between: the book is full of important nuggets of wisdom, many of which are under-appreciated in the broader software engineering culture, but these bits are mixed with tons of more dubious advice that's often as bureaucratic as the book itself. That said, this book is quite thoughtful, and nearly all of the topics are important issues to consider, even if I found many of the specific suggestions less useful.
Random examples of ideas that resonated strongly with me:
* Ch5: Design is "wicked", and you're best off iterating with both top-down and bottom-up approaches and using loose heuristics rather than rigid algorithms. * Ch9: "One of the biggest differences between hobbyists and professional programmers is the difference that grows out of moving from superstition into understanding." Amen. Similarly, in the debugging chapter, I strongly agreed with the emphasis on truly understanding the root cause of an issue and all of the observed behavior before fixing the problem. * Ch10: All of the comments on scoping and the reasons to minimize scopes. * Ch23: Totally agree with the general attitude towards debugging, and the notion that programmers learn a lot from debugging. I've probably learned 2/3 of what I know from my experiences debugging, and those experiences inform every line of code that I write. That said, the notion that one should seriously consider giving up on a bug after less than an hour of debugging is ridiculous. * Ch24: Parts of this chapter on refactoring and "design-ahead code" are remarkably concise and forceful. I can't tell you how many times I've written code for a feature I was sure we were going to want, but didn't quite flesh out because we weren't sure exactly how it should work, and that code turned out to be poorly exercised, buggy, and ultimately ripped out -- not because of the poor quality, but because we simply didn't need the feature, or the feature needed to work very differently than we initially anticipated. Of course, like all things, there's a balance, and one has to consider each case individually. * Ch32: Bad idea to refer to bugids and other historical artifacts in code. The source should represent the current state of the system, and the bug tracker and source control document what changes were made when, by whom, and why.
By contrast, there's lots I took issue with:
* Ch5: Many of the examples, particularly in the design section and with respect to OOP, are highly simplistic. * Ch6: Encapsulation as typically lauded in OOP texts is often a sham, in my experience. Realistic problems rarely lend themselves to simple, clean abstractions. Even traditionally successful abstractions, like Unix file descriptors and POSIX open/read/write/close, reveal a lot about the underlying implementation, and one cannot use them successfully in complex programs without understanding details about the implementation. * Ch7: The Bjarne Stroustrup quote about macros (that each macro demonstrate a flaw in the programming language) is exactly the kind of dogmatic lunacy that gave us C++[11]. * Ch8: The discussion of error handling misses what I consider the most important question in determining what a component should do in handling an error, which is: can the current layer be *sure* it knows what the caller wants to do? If not, it should either propagate the error to the caller so that it can decide what to do with it, or else provide options so that the caller can indicate ahead of time what it wants to do (e.g., ignore, retry N times, or fail). If there's more than one consumer, err on the side of providing rich information to the caller so it can decide what it wants to do. There's nothing more infuriating than library functions that retry operatons after errors that you know aren't transient or which try to deal with a fatal error by papering over it. It's much worse than having to retry something the library should have known should be retried. * Ch9: The pseudocode-writing technique suggests thinking both implementation-agnostic and low-level enough that code generation is automatic. These two are always competing, and (in my experience) usually exclusive. * Ch13: There's an over-emphasis on a superficial notion of "safety", and the suggestion that things like void pointers in C lead to serious runtime bugs. Despite the arguments for "proper" generics in higher-level languages, in my experience, improper use of void*'s in data structures is not even remotely an important category of runtime bugs. One of the "C" examples in this chapter isn't even valid C. * Ch16 is full of small errors and some braindead code (e.g., "if (...) { assert(false); }").
The book is divided into several sections:
* The first few chapters on metaphors and the notion of construction are thoughtful and unusually self-aware for this kind of "advice" book. * The next several chapters on requirements and design are a microcosm of much of the rest of the book, containing a smattering of useful ideas in a sea of more dubious, often bureaucratic advice. * The middle chapters on actual writing and structuring of code are probably the best. * Some of the later chapters on debugging, refactoring, style, and so on, are pretty thoughtful. Some of the others (like collaborative construction and tools) feel like useless catalogs of techniques and software packages: they're not immediately useful to the reader, nor are they a particularly good reference, but they seem to be there to flesh out an exhaustive description of software construction.
One nice thing about the book is that the text itself is organized with useful headings and bolded main ideas, and each major section ends with main idea bullet points and a complete checklist, making it relatively easy to skim. This could help an experienced engineer pick out good parts that are worth reading more about. Unfortunately, the kinds of things that are most useful to learn are typically the things you wouldn't necessarily realize are important from a bullet point.
As I mentioned, the book is very thoughtful, and the issues raised are all important and relevant for practicing engineers. I found about 30% of the advice strongly resonated with me, at least 50% was highly suspect, and the rest was pretty thought-provoking. For less experienced engineers who are good at picking things up from books like this, it might be a useful text. For experienced engineers, or the majority of us who learn subtle lessons much better by making the mistakes (or at least seeing real-life, personally meaningful examples), you may be better off learning by doing.
Steve McConnell's Code Complete 2 is a classic piece of literature in Software Development. I joined a book club for reading this book, and the discussions along the way were some of the most valuable I've had. It was very rewarding to me to see many of the pieces of advice given reaffirming my own coding practices and the way things are done here at SEP, but I certainly took some new information away. One of the main lessons taught throughout the book is that code should be easy to understand. Levels of abstraction, clear class and variable names, information hiding, coding standards - they all leave one less detail you have to juggle in your mind when trying to understand the code you're reading. If you write code that is as close to possible to self-documenting, you'll make your life and everyone else's life that much easier. Mostly this book was just the tip of the iceburg, a good overview of several key topics in the industry. It was very well-researched and cited, though quite a bit of the research was as old or older than I am! There was a recommended reading list at the end of the book which seems very valuable, and I intend to go through it. This book left me with a feeling of 'just getting started' and seems like it would be a good thing for new-hires to read.
It is a nice book but too MS-centric. Some of the things are going to confuse you if you come from a different environment. For example, it took me a while to realize that the term "magic number" was used for hard-coded constants; in Unix, the magic number is used to identify file type as described in /etc/magic. Similarly, the author did not like the indentation standard use by Gnu. There was something he did not like about Kernighan and Ritchie either Overall, I still think it was a decent book..
The focus of Code Complete is software construction, i.e. the coding part of software development. As Steve McConnell notes in the preface, "construction is the only activity that is guaranteed to be done". You can skip almost any step (requirements, testing etc), but if you don't write any code there is not going to be any software.
I bought my copy of the first edition of Code Complete in 1997, and I was immediately fascinated. I had never read anything like it before - a book that concentrated on the actual writing of the code. For example, it had a whole chapter on if- and case-statements, and another chapter on the naming of variables. I had no idea there was so much to learn about these seemingly straight forward activities. It was immediately useful to me, and I started to apply as much as I could of what I learnt from it.
Although it concentrated on coding, it covered a broad spectrum of activities around coding, from requirements and design to testing, debugging and optimization. It also had a great reference section with suggestions of further reading in the area of software engineering. This became my starting point for finding lots of other good books to read, like Peopleware: Productive Projects and Teams and Programming Pearls.
So this summer I decided to re-read this seminal book, partly to see what's new in the second edition, and partly to see if still think it is such a great book.
To answer my own question - yes, it is still the number one book on writing code. It is near encyclopaedic in its coverage of the nuts and bolts of programming. There are chapters on the naming of variables, on organizing straight-line code, on conditionals, on loops, on lay-out, on good commenting and on how to write good methods.
In it, there are frequent references to scientific studies that support the advice given in the book. For example, how long should variable names be? Instead of just giving us his opinion, McConnell summarized the findings of several scientific studies on the subject.
Each time there is reference to a study, there is a little "hard data" symbol in the margin. There are other symbols in the margin as well, "Coding Horror" for code examples of what not to do, and "Key Point" for, well, key points. The margin is also used for cross references to other chapters, and for quotes related to the subject discussed. For me, this works really well. It is both useful and makes the text easier to read. In general, the book is very well laid out.
Some of my favourite advice from the book (all of which I remember from reading the first edition) are:
Chapter 7.1 Valid Reasons to Create a Routine - for example: Reduce complexity, Introduce an intermediate understandable abstraction, and Avoid duplicate code (there are 6 more valid reasons in this chapter). The second part of the chapter is called Operations That Seem Too Simple to Put Into Routines and contains a great example of why it can be good to put even a one-line calculation in a routine - the code becomes more readable, and small operations tend to turn into larger operations.
Page 172 (and 264 for variables) Use opposites precisely. When naming "opposite" methods and variables, be careful to use the correct pairs, like add/remove, begin/end, create/destroy etc. This makes the relationship between them clear and obvious.
Page 433 Break complicated tests into partial tests with new boolean variables. This is such a simple thing, but it makes the code a lot more readable.
Page 754 "Make the incompleteness of a statement obvi". For example, when breaking up a logical and over two lines, end the first line with && - that way, it is clear that the statement continues on the next line.
Even though the book truly is great, there are a few things to complain about. In the first edition, the chapters on layout and comments came right after the chapters on the different control structures. But in the second edition, these two chapters have been moved further back. To me, that doesn't make sense, since they too are related to how you actually write your code. Now there are chapters on testing, debugging, optimization and refactoring in between.
And talking about refactoring: while this is an important subject, I don't feel the chapter on refactoring is particularly good. This chapter is new in the second edition. The summary of refactoring is OK, but a good part of the chapter consists of just listing different kinds of refactorings.
Overall though, the second edition is a nice face lift. The code examples are now mostly in Java, C++ or Visual Basic (in the first edition they were in Pascal, C or Ada). But since all the major themes of the book were already present in the first edition, it does not make a big difference if you happen to read the first edition instead of the second edition.
Code Complete is thick - 862 pages (not counting the bibliography and index). If that feels like a lot to read, then I suggest you start by just reading one or two chapters, for example "Using Conditionals" or "Layout and Style". They (and pretty much any chapter in the book) can easily be read without first reading the preceding chapters, and these will give you a sense of what you can expect from the other chapters. Even if these are all you read, you will still get a lot of value from the book.
However, if you are a programmer and care about how you write code, you owe it to yourself to read the whole book. It is considered by many (including me) to be the best book available on programming, and it will almost certainly make you a better programmer. Highly recommended.
This book was a pretty good read. Most of what is discussed is extremely valuable information. Although with only 5 years of experience I felt like many of the points that Steve brought up were fairly obvious once you've been working as a Software Developer. If you are new to programming, want to move to a more professional level of programming or just plain have plenty of time on your hands this is a great book. However, if you already have a fair amount of experience developing software professionally, I would suggest you look elsewhere for good reading.
Terribly bloated. Long-winded and trivial. I do not get the high score for this book; in a related area, but much more crisp is Programming Pearls (it even engages your brain, imagine that).
Not terrible, but not great, this book has a much higher stature among Microsofties than is strictly deserved, and little visibility beyond that group. Says nothing in 960 pages that The Practice of Programming doesn't manage to convey more clearly and succinctly in 267. Ok as a supplement to the latter for those looking for longer justifications for the same recommendations, or those deathly allergic to Unixisms. Pointless otherwise.