Reading is very important for anyone who wants to be a good software developer. The key, however, is to not just read language manuals, “cookbooks”, and other hands-on texts; but to gain an actual understanding of software development, what makes a good program/function/design/whatnot, what common conceptual errors are, and so on. Regrettably, this is something that most developers, including senior and chief developers, have neglected: It is not uncommon that someone with ten years of experience lacks insights that I had gained in my first year in the work-force because I made sure to read the right kind of literature from the go. (Note that this kind of prolonged ignorance is not in anyway unique to software development: I have come to consider it the norm, m.m., in executives, managers, PM’s, product managers, and business analysts. I strongly suspect that it is prevalent in other groups too.)
The below contains a (highly incomplete) list of books that I know from personal experience to be very helpful. Beware that my last reading of some was close to ten years ago: I may be a little vague on details.
On the off chance that the reader is the author/publisher/proponent of a particular book that is not included: I will be happy to receive a complimentary issue of the work in question. If it also turns out to be of both high quality and high relevance, I will include it. A large cheque is also welcome, but will not affect the chances of inclusion.
The below has its main focus on what I consider the “core curriculum”: What all software developers should have an understanding of, and where a beginner might do well to put in intense efforts. Once this material is reasonably covered, further educational efforts can be noticeably less intense; however, they must not stop! Later worthy areas of study include, but are not limited to, software architecture and high level design, algorithms, how hardware works, how databases works, details of various tools and languages, ... (Obviously, some minimum of knowledge in these areas should be present earlier too: Not knowing, e.g., what basic collections are available and what their rough algorithmic implications are, can be a severe deficit.)
My first master thesis, a long time ago, provides two excellent examples of the wrong kind of thinking—fortunately, I was the bad guy only in the first.
I needed to write a
semi-complex C program. At one point, I found
myself in a convoluted situation where a goto
statement would be a quick
solution—and in youthful naivete I considered this an opportunity to use a
feature of C that I had previously never needed. Shee-eesh! Today, knowing much
better, I would have concluded that if goto
seemed the best option
(something exceedingly unlikely to be true), then my code was in severe need of
a re-structuring—and would have proceeded to clean it up.
Note that this refers to C: In other languages and contexts, goto
may be
the best solution; however, typically because conditionals, loops, and/or
functions are not provided or incomplete—I recall, e.g., my first programming
experiences with C64-Basic, where I not only had to constantly resort to
goto
s and gosub
s, but even had to keep track of actual line
numbers myself...
In earlier years, a professor had expounded on the benefits of e.g. automatic checks for memory leaks—and I had actually been saved from several bugs by applying, as a matter of course and without having yet noticed any leaks, a checker on previous programs. Writing my thesis as an exchange student at another university, I inquired about a corresponding leak checker. One was provided with a comment of (roughly) “Hope you find your leak! Those buggers can be nasty.”—indicating that the sender only used such tools when he actually had problems with a leak.
This is entirely the wrong attitude: A professional uses any automatic tools to his disposal in a pre-emptive manner. As the saying goes: An ounce of prevention is worth a pound of cure.
Other signs of similar naivete (that I have seen in many others) include
premature optimization, lack of interest in readability, duplicating code
instead of writing methods, neglecting to use constructs (e.g. this
in
Java) that can give the compiler valuable hints, ... I once had a colleague
who positively took pride in doing multiplications/divisions by two with
bit-shift operators—in a web-centric and database-heavy Java application in
2002.
Code Completew by Steve McConnell is one of the few good things to come from Microsoft. It is a very thorough introduction to good coding, in particular, and software development, in general—the best single book in the area that I know of. Even in those areas where I do not agree with this work, it still has the benefit of bringing the right kind of thinking to the attention of the reader.
This was not only one of the very first (and best) books I read on the subject, but also my first pointer to some of the below books.
The Art of Unix Programmingw by Eric S. Raymond gives very valuable insights into the Unix philosophy, what makes Unix great, how to make good software, etc. Even reading just the few first chapters on philosophy can provide very valuable insights into the right kind of thinking. An absolute must read, even for those who do not intend to do Unix programming, per se. (Although these can obviously skip over some of the more detailed parts.)
Not to be forgotten are its additional benefits for those interested in developing operating systems or in the history of operating systems.
Note that there are several free-of-charge online-editions of this book, including http://www.faqs.org/docs/artu/e and http://www.catb.org/~esr/writings/index.htmle. The latter also contains a number of other works by the same author, some very worthwhile, and links to some interesting texts by other authors.
Programming Pearlsw by John Bentley originated, IIRC, as a series of columns on programming. Correspondingly, it covers a variety of topics in reasonably stand-alone chapters. Here a wealth on insights and anecdotes can be found, in particular relating to practical issues and how to think.
The Mythical Man-Monthw by Fred Brooks is one the true classics, with a first edition in 1975—the same year I was born. However, because the book focuses on higher level issue this is usually of little consequence (some caution should be taken while reading, however). It can give a very good understanding of how software projects work, what typical misconceptions and errors tend to accompany software projects, and so on. A central theme is that a man-month is not the same as a man-month—but that other factors, such as individual competence, timing, overall head-count, the need for mentoring, and similar, plays in. In an extreme example, one proficient developer can do more in one month than sixty beginners can do in one day—something that, unfortunately, many managers and PM’s seem to be unaware of. (Arguably, the sixty beginners can do more harm in the allotted time, but ...)
This is in particular a book that should be read not just by developers, but by anyone who makes decisions regarding or administrates a software project. (Notably, many of the principles hold for work in other disciplines too.)
The Psychology of Computer Programming by Gerald M. Weinberg is another still relevant seventies book: It has little to do with actual programming, but deals with issues of psychology, sociology, human behaviour in and around computer programming. Computer programming has changed tremendously since then—the people have not.
Design Patternsw by Gamma et al. is a thorough catalog of the basic design patterns commonly used in software development (and arguably the beginning of the design pattern craze). This book will not only serve as a good reference and provide some interesting ideas on how to solve problems, but can also provide a good guide on how to think up new solutions/patterns.
The point were many go astray with this book, is seeing it as a Bible with the solutions, measuring a developer’s ability by his knowledge of what patterns are available, etc. The better use is to read it, think about the patterns, draw lessons, and as a consequence learn to build/find appropriate solutions in more generic contexts. The difference in meaning between “facade” and “adapter” is of comparatively little interest: the ability to recognize situations where some kind of wrapper could be beneficial, to consider pro’s and con’s, choose an appropriate variation, ..., is much more important—the details, including exemplary implementations of standard cases, can always be looked up when needed.
Refactoring: Improving the Design of Existing Code by Fowler et al deals (unsurprisingly) with the important topic of refactoring. A variety of techniques are given, as are a number of “bad smells”—heuristic signs that the current code is or will later be problematic. It is in particular useful to try to understand the principles of bad smells, and possibly even learn to avoid the corresponding problems in the first place.
Disclaimer: I have only read about a third of the book (during unproductive waiting times in the poorly organized E4). That third was very pleasing, and I will likely buy a private copy sooner or later; however, because almost all of the contents had been things I already knew, or related to errors I had no history of making, it has not been an urgent priority.
In his 1972 ACM Turing Lecture, The Humble Programmere, Edsger W. Dijkstra makes some very interesting points, including the problems that increasing complexity had brought on already by that time.
Of course, one of my central claims is that complexity is the greatest single problem in modern software development—the situation is far, far worse today.
Try to read as much as possible on advocacy for this and that, best practices, various design and architecture decisions, etc. The Internet is a good source for such information. In addition, it makes great sense to read up on the tools and language you currently use or expect to use—at least to the point where you know what features are available, what can and can not be done, etc. (The exact details of the “how” can always be looked up later.)
Knuth’s multi-volume magnum opus is a very valuable work in its own right (at least the one volume that I have read), but deals more with algorithms, mathematics, assembler programming, etc., than with what is relevant for a typical modern software developer. If the former is something that interests you privately, if you develop or research algorithms, do a lot of assembler, look to go from very good to extremely good, ..., then by all means study it.
However, for the average developer, this adventure does not provide anywhere near the right cost/benefit ratio to justify a work-related study over the books mentioned above. It is not a help to go from poor to decent, nor decent to good; but, as stated above, very good to extremely good (and even here, like all works, it only covers a limited range of abilities.)
Make no mistake: We are not talking “Java in 24 Hours”, but a very long academic work requiring much thinking and problem solving.
But is not every program an algorithm? It is (or at least an implementation or representation of an algorithm); however, there is difference in what skills and knowledge needs to be developed to write a run-of-the-mill (sub-)program, on the one hand, and e.g. a highly optimized sorting algorithm, on the other.
In particular, for the latter, developers in most languages will have a number of ready made alternatives, which have been very thoroughly tested and tweaked, and which he only very rarely has a valid reason to compete with. What he needs is a very basic understanding of complexities (e.g. the behaviour of an O(Nlog(N)) algorithm vs. an O(N^2) algorithm) and trade-offs , a reference with pro’s and con’s of various algorithms, and a few common-sensical tidbits (file access is slower than memory access, caching can save time, not caching can save memory, swapping is slow/thrashing is snail-pace, ...)—first semester computer science.
The priority of a good software developer should be in writing high quality, easy to read, easy to maintain code, creating sensible designs, and so on. Writing sorting algorithms in assembler can actually be detrimental to this purpose—shot-put and high-jump is another combination that can be problematic, even if both are perfectly valid occupations on their own.
Works intended for the masses tend to be very low in understanding, highly over-focused on doing a small range of specific tasks, and generally useless for anything but a superficial overview of whatever the topic. Typical warning signs include names with “... in 24 hours”, “... in 7 days” (or similar; “... for beginners” is obviously not a good sign either), too flashy covers, authors who are journalists, language that over-uses the full stop and the word “you”, and a back-cover that makes promises of ease or speed.
The rubbish taught in these books can typically be learned over the Internet—free of charge. Often noticeably deeper skills can be learned too; in particular, where open-source technologies are concerned.
Should a book be needed, the publisher O’Reilly is usually a safe bet. The quality varies, but a certain minimum level should be guaranteed; the coverage is typically good; and the pricing is reasonable.
A common recommendation is that a developer should read as much code as possible. This is something that I personally disagree with: The vast majority of all code written is so third-rate that it is likely to have a negative effect on the reader’s own habits. Further, reading code is often boring, which makes it a more “expensive” investment than reading other kinds of information.
Reading code does have a place, however. My suggestion is to only rarely read code (except, obviously, when it is needed in the daily work), but, when is is read, to read it very actively, with a focus on understanding intentions, finding errors, pondering what could be done better, etc. This goes in particular when a problem is detected: Why was this code too slow? Why did this bug happen? Why is this particular function hard to understand? How could it have been done better? Etc. Similarly, if you find something someone else has done that is unexpected, goes down another road than you would have chosen, is particular elegant, ..., particular attention may be beneficial.
In short: Quality reading over quantity reading.
The above presumes that the developer has already reached a state where he can read the code of a particular language fluently and effortlessly—if not, he should very obviously prioritize that basic skill.
However, code differs from e.g. an entertainment novel in that, once fluency has been reached, further improvements in reading speed will only be of marginal use: In the former case, it so much more important to understand what happens on a deeper level, to think about the code, etc. A similar case can be made when comparing a text-book on math with an entertainment novel; to varying degrees also when comparing other non-fiction or “high literature” with cheaper literature.
Todo: Write something about how to read code, blocking, and similar.
The following is an automatically generated list of other pages linking to this one. These may or may not contain further content relevant to this topic.
Home
Job application paradoxes
Theoretical and practical knowledge in skill-sheets
Sitemap