2004年美国Jolt大奖入围作品。\r\n 如果你是个程序员的话,那么你就需要本书。可能导致我们阅读代码的原因是:我们不得不去修复它其中所包含的错误;或是对它进行遍查(inspect);或者是改善它。我们阅读代码的方式可能和工程师检查机械的方式一样——找出它的工作原理。或者我们阅读代码的目的是对代码进行清理——找出其中可以被重用的部分。阅读代码有着它自身的技巧,并需要我们能够在重要场合对采用何种技术有着判断能力。在这本不可或缺的书中,Diomidis Spinellis使用了超过600个来自现实世界中的例子来向我们展示如何鉴别好的(或坏的)代码:如何去阅读它,从中去找寻什么,以及如何利用这种技巧来提升我们自身编写的代码的品质。记住这个事实:如果我们养成了阅读好代码的习惯,我们就能写出更高品质的代码。
Figures xiii\r\nTables xix\r\nForeword xxi\r\nPreface xxv\r\n1 Introduction \r\n 1.1 Why and How to Read Code\r\n 1.2 How to Read This Book \r\n2 Basic Programming Elements \r\n 2.1 A Complete Program \r\n 2.2 Functions and Global Variables \r\n 2.3 while Loops, Conditions, and Blocks \r\n 2.4 switch Statements \r\n 2.5 for Loops \r\n 2.6 break and continue Statements \r\n 2.7 Character and Boolean Expressions \r\n 2.8 goto Statements \r\n 2.9 Refactoring in the Small \r\n 2.10 do Loops and Integer Expressions\r\n 2.11 Control Structures Revisited \r\n Further Reading\r\n3 Advanced C Data Types\r\n 3.1 Pointers \r\n 3.2 Structures\r\n 3.3 Unions \r\n 3.4 Dynamic Memory Allocation \r\n 3.5 typedef Declarations\r\n4 C Data Structures\r\n 4.1 Vectors \r\n 4.2 Matrices and Tables \r\n 4.3 Stacks \r\n 4.4 Queues \r\n 4.5 Maps \r\n 4.6 Sets \r\n 4.7 Linked Lists \r\n 4.8 Trees \r\n 4.9 Graphs \r\nFurther Reading \r\n5 Advanced Control Flow \r\n 5.1 Recursion \r\n 5.2 Exceptions \r\n 5.3 Parallelism \r\n 5.3.1 Hardware and Software Parallelism \r\n 5.3.2 Control Models \r\n 5.3.3 Thread Implementations \r\n 5.4 Signals \r\n 5.5 Nonlocal Jumps \r\n 5.6 Macro Substitution\r\n Further Reading \r\n6 Tackling Large Projects \r\n 6.1 Design and Implementation Techniques \r\n 6.2 Project Organization \r\n 6.3 The Build Process and Makefiles \r\n 6.4 Configuration \r\n 6.5 Revision Control \r\n 6.6 Project-Specific Tools \r\n 6.7 Testing \r\n Further Reading \r\n7 Coding Standards and Conventions\r\n 7.1 File Names and Organization \r\n 7.2 Indentation \r\n 7.3 Formatting \r\n 7.4 Naming Conventions \r\n 7.5 Programming Practices\r\n 7.6 Process Standards \r\n Further Reading \r\n8 Documentation \r\n 8.1 Documentation Types \r\n 8.2 Reading Documentation \r\n 8.3 Documentation Problems \r\n 8.4 Additional Documentation Sources \r\n 8.5 Common Open-Source Documentation Formats \r\n Further Reading\r\n9 Architecture \r\n 9.1 System Structures\r\n 9.2 Control Models \r\n 9.3 Element Packaging \r\n 9.4 Architecture Reuse\r\n Further Reading\r\n10 Code-Reading Tools \r\n 10.1 Regular Expressions \r\n 10.2 The Editor as a Code Browser\r\n 10.3 Code Searching with grep \r\n 10.4 Locating File Differences\r\n 10.5 Roll Your Own Tool \r\n 10.6 The Compiler as a Code-Reading Tool\r\n 10.7 Code Browsers and Beautifiers \r\n 10.8 Runtime Tools \r\n 10.9 Nonsoftware Tools\r\n Tool Availability and Further Reding\r\n11 A Complete Example\r\n 11.1 Overview \r\n 11.2 Attack Plan \r\n 11.3 Code Reuse \r\n 11.4 Testing and Debugging\r\n 11.5 Documentation\r\n 11.6 Observations \r\nA Outline of the Code Provided \r\nB Source Code Credits \r\nC Referenced Source Files\r\nD Source Code Licenses\r\n D.1 ACE\r\n D.2 Apache \r\n D.3 ArgoUML\r\n D.4 DemoGL \r\n D.5 hsqldb \r\n D.6 NetBSD \r\n D.7 OpenCl \r\n D.8 Perl \r\n D.9 qtchat \r\n D.10 socked \r\n D.11 vcf \r\n D.12 X Window System \r\nE Maxims for Reading Code\r\nBibliography \r\nAuthor Index
Diomidis Spinellis 从1985年起,就为许多具有创造性的并获得广泛赞誉的商业及开源项目编写和维护超过了250000行代码,与此同时他与逐步完善了本书中所介绍的技术。他从伦敦大学帝国学院获得了软件工程学科的工程学硕士学位和计算机科学学科的博士学位。现在他是雅典经贸大学管理科学及技术系的助理教授。
We're programmers. Our job (and in many cases our passion) is to make things happen by writing code. We don't meet our user's requirements with acres of diagrams, with detailed project schedules, with four-foot-high piles of design documentation. These are all wishes—expressions of what we'd like to be true. No, we deliver by writing code: code is reality. So that's what we're taught. Seems reasonable. Our job is to write code, so we need to learn how to write code. College courses teach us to to write programs. Training courses tell us how to code to new libraries and APIs. And that's one of the biggest tragedies in the industry. Because the way to learn to write great code is by reading code. Lots of code. High-quality code, low-quality code. Code in assembler, code in Haskell. Code written by strangers ten thousand miles away, and code written by ourselves last week. Because unless we do that, we're continually reinventing what has already been done, repeating both the successes and mistakes of the past. I wonder how many great novelists have never read someone else's work, how many great painters never studied another's brush strokes, how many skilled surgeons never learned by looking over a colleague's shoulder, how many 767 captains didn't first spend time in the copilot's seat watching how it's really done. And yet that's what we expect programmers to do. "This week's assignment is to write...." We teach developers the rules of syntax and construction, and then we expect them to be able to write the software equivalent of a great novel. The irony is that there's never been a better time to read code. Thanks to the huge contributions of the open-source community, we now have gigabytes of source code floating around the 'net just waiting to be read. Choose any language, and you'll be able to find source code. Select a problem domain, and there'll be source code. Pick a level, from microcode up to high-level business functions, and you'll be able to look at a wide body of source code. Code reading is fun. I love to read others' code. I read it to learn tricks and to study traps. Sometimes I come across small but precious gems. I still remember the pleasure I got when I came across a binary-to-octal conversion routine in PDP-11 assembler that managed to output the six octal digits in a tight loop with no loop counter. I sometimes read code for the narrative, like a book you'd pick up at an airport before a long flight. I expect to be entertained by clever plotting and unexpected symmetries. Jame Clark's gpic program (part of his GNU groff package) is a wonderful example of this kind of code. It implements something that's apparently very complex (a declarative, device-independent picture-drawing language)in a compact and elegant structure. I came away feeling inspired to try to structure my own code as tidily. Sometimes I read code more critically. This is slower going. While I'm reading, I'm asking myself questions such as "Why is this written this way?" or "What in the author's background would lead her to this choice?" Often I'm in this mode because I'm reviewing code for problems. I'm looking for patterns and clues that might give me pointers. If I see that the author failed to take a lock on a shared data structure in one part of the code, I might suspect that the same might hold elsewhere and then wonder if that mistake could account for the problem I'm seeing. I also use the incongruities I find as a double check on my understanding; often I find what I think is a problem, but it on closer examination it turns out to be perfectly good code. Thus I learn something. In fact, code reading is one of the most effective ways to eliminate problems in programs. Robert Glass, one of this book's reviewers, says, "by using (code) inspections properly, more than 90 percent of the errors can be removed from a software product before its first test.[1] In the same article he cites research that shows "Code-focused inspectors were finding 90 percent more errors than process-focused inspectors." Interestingly, while reading the code snippets quoted in this book I came across a couple of bugs and a couple of dubious coding practices. These are problems in code that's running at tens of thousands of sites worldwide. None were critical in nature, but the exercise shows that there's always room to improve the code we write. Code-reading skills clearly have a great practical benefit, something you already know if you've ever been in a code review with folks who clearly don't know how to read code. [1] http://www.stickyminds.com/se/S2587.asp And then there's maintenance, the ugly cousin of software development. There are no accurate statistics, but most researchers agree that more than half of the time we spend on software is used looking at existing code: adding new functionality, fixing bugs, integrating it into new environments, and so on. Code-reading skills are crucial. There's a bug in a 100,000-line program, and you've got an hour to find it. How do you start? How do you know what you're looking at? And how can you assess the impact of a change you're thinking of making? For all these reasons, and many more, I like this book. At its heart it is pragmatic. Rather than taking an abstract, academic approach, it instead focuses on the code itself. It analyzes hundreds of code fragments, pointing out tricks, traps and (as importantly) idioms. It talks about code in its environment and discusses how that environment affects the code. It highlights the important tools of the code reader's trade, from common tools such as grep and find to the more exotic. And it stresses the importance of tool building: write code to help you read code. And, being pragmatic, it comes with all the code it discusses, conveniently cross-referenced on a CD-ROM. This book should be included in every programming course and should be on every developer's bookshelf. If as a community we pay more attention to the art of code reading we'll save ourselves both time and pain. We'll save our industry money. And we'll have more fun while we're doing it. Dave Thomas The Pragmatic Programmers, LLC http://www.pragmaticprogrammer.com Preface What do we ever get nowadays from reading to equal the excitement and the revelation in those first fourteen years? —Graham Greene The reading of code is likely to be one of the most common activities of a computing professional, yet it is seldom taught as a subject or formally used as a method for learning how to design and program. One reason for this sad situation originally may have been the lack of real-world or high-quality code to read. Companies often protect source code as a trade secret and rarely allow others to read, comment on, experiment with, and learn from it. In the few cases where important proprietary code was allowed out of a company's closet, it spurred enormous interest and creative advancements. As an example, a generation of programmers benefited from John Lions's Commentary on the Unix Operating System that listed and annotated the complete source code of the sixth-edition Unix kernel. Although Lions's book was originally written under a grant from AT&T for use in an operating system course and was not available to the general public, copies of it circulated for years as bootleg nth-generation photocopies. In the last few years, however, the popularity of open-source software has provided us with a large body of code we can all freely read. Some of the most popular software systems used today, such as the Apache Web server, the Perl language, the GNU/Linux operating system, the BIND domain name server, and the sendmail mail-transfer agent are in fact available in open-source form. I was thus fortunate to be able to use open-source software such as the above to write this book as a primer and reader for software code. My goal was to provide background knowledge and techniques for reading code written by others. By using real-life examples taken out of working, open-source projects, I tried to cover most concepts related to code that are likely to appear before a software developer's eyes, including programming constructs, data types, data structures, control flow, project organization, coding standards, documentation, and architectures. A companion title to this book will cover interfacing and application-oriented code, including the issues of internationalization and portability, the elements of commonly used libraries and operating systems, low-level code, domain-specific and declarative languages, scripting languages, and mixed language systems. This book is—as far as I know—the first one to exclusively deal with code reading as a distinct activity, one worthy on its own. As such I am sure that there will be inevitable shortcomings, better ways some of its contents could have been treated, and important material I have missed. I firmly believe that the reading of code should be both properly taught and used as a method for improving one's programming abilities. I therefore hope this book will spur interest to include code-reading courses, activities, and exercises into the computing education curriculum so that in a few years our students will learn from existing open-source systems, just as their peers studying a language learn from the great literature.