Foreword |
|
xv | |
Preface |
|
xvii | |
Acknowledgments |
|
xxiii | |
Author Biography |
|
xxv | |
|
|
1 | (20) |
|
1.1 What Are Application Programming Interfaces? |
|
|
1 | (3) |
|
1.1.1 Contracts and Contractors |
|
|
1 | (2) |
|
|
3 | (1) |
|
1.2 What's Different About API Design? |
|
|
4 | (2) |
|
1.3 Why Should You Use APIs? |
|
|
6 | (4) |
|
|
6 | (1) |
|
|
7 | (2) |
|
1.3.3 Parallel Development |
|
|
9 | (1) |
|
1.4 When Should You Avoid APIs? |
|
|
10 | (1) |
|
|
11 | (5) |
|
|
11 | (3) |
|
1.5.2 A Real-Life Example |
|
|
14 | (2) |
|
1.6 File Formats and Network Protocols |
|
|
16 | (1) |
|
|
17 | (4) |
|
|
21 | (44) |
|
2.1 Model the Problem Domain |
|
|
21 | (4) |
|
2.1.1 Provide a Good Abstraction |
|
|
21 | (2) |
|
2.1.2 Model the Key Objects |
|
|
23 | (2) |
|
2.2 Hide Implementation Details |
|
|
25 | (9) |
|
2.2.1 Physical Hiding: Declaration versus Definition |
|
|
25 | (1) |
|
2.2.2 Logical Hiding: Encapsulation |
|
|
26 | (2) |
|
2.2.3 Hide Member Variables |
|
|
28 | (3) |
|
2.2.4 Hide Implementation Methods |
|
|
31 | (2) |
|
2.2.5 Hide Implementation Classes |
|
|
33 | (1) |
|
|
34 | (5) |
|
|
35 | (1) |
|
2.3.2 Add Virtual Functions Judiciously |
|
|
36 | (1) |
|
|
37 | (2) |
|
|
39 | (13) |
|
|
40 | (1) |
|
2.4.2 Difficult to Misuse |
|
|
40 | (3) |
|
|
43 | (2) |
|
|
45 | (2) |
|
2.4.5 Robust Resource Allocation |
|
|
47 | (4) |
|
2.4.6 Platform Independent |
|
|
51 | (1) |
|
|
52 | (10) |
|
2.5.1 Coupling by Name Only |
|
|
53 | (1) |
|
2.5.2 Reducing Class Coupling |
|
|
54 | (2) |
|
2.5.3 Intentional Redundancy |
|
|
56 | (2) |
|
|
58 | (1) |
|
2.5.5 Callbacks, Observers, and Notifications |
|
|
59 | (3) |
|
2.6 Stable, Documented, and Tested |
|
|
62 | (3) |
|
|
65 | (40) |
|
|
67 | (9) |
|
|
67 | (4) |
|
|
71 | (1) |
|
3.1.3 Pimpl and Smart Pointers |
|
|
72 | (1) |
|
3.1.4 Advantages of Pimpl |
|
|
73 | (1) |
|
3.1.5 Disadvantages of Pimpl |
|
|
74 | (1) |
|
3.1.6 Opaque Pointers in C |
|
|
75 | (1) |
|
|
76 | (9) |
|
3.2.1 Implementing Singletons in C++ |
|
|
77 | (2) |
|
3.2.2 Making Singletons Thread Safe |
|
|
79 | (2) |
|
3.2.3 Singleton versus Dependency Injection |
|
|
81 | (1) |
|
3.2.4 Singleton versus Monostate |
|
|
82 | (2) |
|
3.2.5 Singleton versus Session State |
|
|
84 | (1) |
|
|
85 | (6) |
|
3.3.1 Abstract Base Classes |
|
|
86 | (1) |
|
3.3.2 Simple Factory Example |
|
|
87 | (1) |
|
3.3.3 Extensible Factory Example |
|
|
88 | (3) |
|
3.4 API Wrapping Patterns |
|
|
91 | (8) |
|
|
91 | (3) |
|
3.4.2 The Adapter Pattern |
|
|
94 | (2) |
|
|
96 | (3) |
|
|
99 | (6) |
|
3.5.1 Model-View-Controller |
|
|
99 | (2) |
|
3.5.2 Implementing the Observer Pattern |
|
|
101 | (2) |
|
3.5.3 Push versus Pull Observers |
|
|
103 | (2) |
|
|
105 | (46) |
|
4.1 A Case for Good Design |
|
|
105 | (6) |
|
4.1.1 Accruing Technical Debt |
|
|
106 | (1) |
|
4.1.2 Paying Back the Debt |
|
|
107 | (2) |
|
4.1.3 Design for the Long Term |
|
|
109 | (2) |
|
4.2 Gathering Functional Requirements |
|
|
111 | (2) |
|
4.2.1 What Are Functional Requirements? |
|
|
111 | (1) |
|
4.2.2 Example Functional Requirements |
|
|
112 | (1) |
|
4.2.3 Maintaining the Requirements |
|
|
113 | (1) |
|
|
113 | (5) |
|
4.3.1 Developing Use Cases |
|
|
114 | (1) |
|
|
114 | (1) |
|
4.3.3 Writing Good Use Cases |
|
|
115 | (2) |
|
4.3.4 Requirements and Agile Development |
|
|
117 | (1) |
|
4.4 Elements of API Design |
|
|
118 | (1) |
|
|
119 | (13) |
|
4.5.1 Developing an Architecture |
|
|
121 | (2) |
|
4.5.2 Architecture Constraints |
|
|
123 | (1) |
|
4.5.3 Identifying Major Abstractions |
|
|
124 | (2) |
|
4.5.4 Inventing Key Objects |
|
|
126 | (3) |
|
4.5.5 Architectural Patterns |
|
|
129 | (1) |
|
4.5.6 Communicating the Architecture |
|
|
130 | (2) |
|
|
132 | (10) |
|
4.6.1 Object-Oriented Concepts |
|
|
132 | (1) |
|
4.6.2 Class Design Options |
|
|
133 | (1) |
|
|
134 | (1) |
|
4.6.4 Liskov Substitution Principle |
|
|
135 | (4) |
|
4.6.5 The Open/Closed Principle |
|
|
139 | (1) |
|
|
140 | (1) |
|
|
141 | (1) |
|
|
142 | (9) |
|
4.7.1 Function Design Options |
|
|
142 | (1) |
|
|
143 | (1) |
|
4.7.3 Function Parameters |
|
|
144 | (2) |
|
|
146 | (5) |
|
|
151 | (22) |
|
|
152 | (6) |
|
|
153 | (1) |
|
5.1.2 Benefits of an ANSI C API |
|
|
154 | (1) |
|
5.1.3 Writing an API in ANSI C |
|
|
155 | (1) |
|
5.1.4 Calling C Functions from C++ |
|
|
156 | (1) |
|
5.1.5 Case Study: FMOD C API |
|
|
157 | (1) |
|
5.2 Object-Oriented C++ APIs |
|
|
158 | (2) |
|
5.2.1 Advantages of Object-Oriented APIs |
|
|
158 | (1) |
|
5.2.2 Disadvantages of Object-Oriented APIs |
|
|
159 | (1) |
|
5.2.3 Case Study: FMOD C++ API |
|
|
159 | (1) |
|
|
160 | (4) |
|
5.3.1 An Example Template-Based API |
|
|
161 | (1) |
|
5.3.2 Templates versus Macros |
|
|
162 | (1) |
|
5.3.3 Advantages of Template-Based APIs |
|
|
163 | (1) |
|
5.3.4 Disadvantages of Template-Based APIs |
|
|
164 | (1) |
|
|
164 | (9) |
|
5.4.1 Data-Driven Web Services |
|
|
165 | (1) |
|
5.4.2 Advantages of Data-Driven APIs |
|
|
166 | (1) |
|
5.4.3 Disadvantages of Data-Driven APIs |
|
|
167 | (1) |
|
5.4.4 Supporting Variant Argument Lists |
|
|
168 | (2) |
|
5.4.5 Case Study: FMOD Data-Driven API |
|
|
170 | (3) |
|
|
173 | (36) |
|
|
173 | (2) |
|
6.2 Constructors and Assignment |
|
|
175 | (5) |
|
6.2.1 Controlling Compiler-Generated Functions |
|
|
176 | (1) |
|
6.2.2 Defining Constructors and Assignment |
|
|
177 | (2) |
|
6.2.3 The Explicit Keyword |
|
|
179 | (1) |
|
|
180 | (3) |
|
6.3.1 Method Const Correctness |
|
|
180 | (2) |
|
6.3.2 Parameter Const Correctness |
|
|
182 | (1) |
|
6.3.3 Return Value Const Correctness |
|
|
182 | (1) |
|
|
183 | (7) |
|
6.4.1 Template Terminology |
|
|
184 | (1) |
|
6.4.2 Implicit Instantiation API Design |
|
|
185 | (2) |
|
6.4.3 Explicit Instantiation API Design |
|
|
187 | (3) |
|
|
190 | (8) |
|
6.5.1 Overloadable Operators |
|
|
190 | (1) |
|
6.5.2 Free Operators versus Member Operators |
|
|
191 | (2) |
|
6.5.3 Adding Operators to a Class |
|
|
193 | (2) |
|
|
195 | (2) |
|
6.5.5 Conversion Operators |
|
|
197 | (1) |
|
|
198 | (2) |
|
6.6.1 Pointer versus Reference Parameters |
|
|
198 | (1) |
|
|
199 | (1) |
|
6.7 Avoid #define for Constants |
|
|
200 | (2) |
|
|
202 | (2) |
|
|
204 | (3) |
|
|
207 | (2) |
|
|
209 | (32) |
|
7.1 Pass Input Arguments by Const Reference |
|
|
210 | (2) |
|
7.2 Minimize #include Dependencies |
|
|
212 | (5) |
|
7.2.1 Avoid "Winnebago" Headers |
|
|
212 | (1) |
|
7.2.2 Forward Declarations |
|
|
213 | (2) |
|
7.2.3 Redundant #include Guards |
|
|
215 | (2) |
|
|
217 | (2) |
|
7.3.1 The New constexpr Keyword |
|
|
218 | (1) |
|
|
219 | (2) |
|
|
221 | (4) |
|
7.6 Don't Inline Until You Need To |
|
|
225 | (4) |
|
|
229 | (4) |
|
7.8 Iterating Over Elements |
|
|
233 | (2) |
|
|
233 | (1) |
|
|
234 | (1) |
|
|
235 | (1) |
|
|
235 | (6) |
|
7.9.1 Time-Based Analysis |
|
|
236 | (2) |
|
7.9.2 Memory-Based Analysis |
|
|
238 | (1) |
|
7.9.3 Multithreading Analysis |
|
|
239 | (2) |
|
|
241 | (26) |
|
|
241 | (4) |
|
8.1.1 Version Number Significance |
|
|
241 | (2) |
|
8.1.2 Esoteric Numbering Schemes |
|
|
243 | (1) |
|
8.1.3 Creating a Version API |
|
|
244 | (1) |
|
8.2 Software Branching Strategies |
|
|
245 | (4) |
|
8.2.1 Branching Strategies |
|
|
246 | (1) |
|
|
246 | (1) |
|
8.2.3 APIs and Parallel Branches |
|
|
247 | (1) |
|
8.2.4 File Formats and Parallel Products |
|
|
248 | (1) |
|
|
249 | (1) |
|
8.4 Levels of Compatibility |
|
|
250 | (6) |
|
8.4.1 Backward Compatibility |
|
|
251 | (1) |
|
8.4.2 Functional Compatibility |
|
|
251 | (1) |
|
8.4.3 Source Compatibility |
|
|
252 | (1) |
|
8.4.4 Binary Compatibility |
|
|
253 | (2) |
|
8.4.5 Forward Compatibility |
|
|
255 | (1) |
|
8.5 How to Maintain Backward Compatibility |
|
|
256 | (5) |
|
8.5.1 Adding Functionality |
|
|
256 | (1) |
|
8.5.2 Changing Functionality |
|
|
257 | (2) |
|
8.5.3 Deprecating Functionality |
|
|
259 | (2) |
|
8.5.4 Removing Functionality |
|
|
261 | (1) |
|
|
261 | (6) |
|
8.6.1 The Purpose of API Reviews |
|
|
262 | (1) |
|
8.6.2 Prerelease API Reviews |
|
|
263 | (2) |
|
8.6.3 Precommit API Reviews |
|
|
265 | (2) |
|
|
267 | (24) |
|
9.1 Reasons to Write Documentation |
|
|
267 | (6) |
|
|
268 | (1) |
|
9.1.2 Documenting the Interface's Contract |
|
|
269 | (2) |
|
9.1.3 Communicating Behavioral Changes |
|
|
271 | (1) |
|
|
272 | (1) |
|
9.2 Types of Documentation |
|
|
273 | (7) |
|
9.2.1 Automated API Documentation |
|
|
274 | (2) |
|
9.2.2 Overview Documentation |
|
|
276 | (1) |
|
9.2.3 Examples and Tutorials |
|
|
276 | (1) |
|
|
277 | (1) |
|
9.2.5 License Information |
|
|
277 | (3) |
|
9.3 Documentation Usability |
|
|
280 | (1) |
|
|
281 | (10) |
|
9.4.1 The Configuration File |
|
|
281 | (1) |
|
9.4.2 Comment Style and Commands |
|
|
282 | (1) |
|
|
283 | (1) |
|
|
284 | (1) |
|
|
285 | (1) |
|
|
286 | (1) |
|
|
287 | (1) |
|
9.4.8 Sample Header with Documentation |
|
|
287 | (4) |
|
|
291 | (38) |
|
10.1 Reasons to Write Tests |
|
|
291 | (2) |
|
10.2 Types of API Testing |
|
|
293 | (8) |
|
|
295 | (2) |
|
10.2.2 Integration Testing |
|
|
297 | (1) |
|
10.2.3 Performance Testing |
|
|
298 | (3) |
|
|
301 | (4) |
|
10.3.1 Qualities of a Good Test |
|
|
301 | (1) |
|
|
302 | (2) |
|
10.3.3 Focusing the Testing Effort |
|
|
304 | (1) |
|
|
304 | (1) |
|
10.4 Writing Testable Code |
|
|
305 | (13) |
|
10.4.1 Test-Driven Development |
|
|
305 | (3) |
|
10.4.2 Stub and Mock Objects |
|
|
308 | (3) |
|
10.4.3 Testing Private Code |
|
|
311 | (2) |
|
|
313 | (1) |
|
10.4.5 Contract Programming |
|
|
314 | (3) |
|
10.4.6 Record and Playback Functionality |
|
|
317 | (1) |
|
10.4.7 Supporting Internationalization |
|
|
318 | (1) |
|
10.5 Automated Testing Tools |
|
|
318 | (11) |
|
|
319 | (3) |
|
|
322 | (3) |
|
|
325 | (1) |
|
10.5.4 Continuous Build System |
|
|
326 | (3) |
|
|
329 | (32) |
|
11.1 Adding Script Bindings |
|
|
329 | (4) |
|
11.1.1 Extending versus Embedding |
|
|
329 | (1) |
|
11.1.2 Advantages of Scripting |
|
|
330 | (1) |
|
11.1.3 Language Compatibility Issues |
|
|
331 | (2) |
|
11.1.4 Crossing the Language Barrier |
|
|
333 | (1) |
|
11.2 Script-Binding Technologies |
|
|
333 | (4) |
|
|
334 | (1) |
|
|
334 | (1) |
|
|
334 | (1) |
|
|
335 | (1) |
|
|
336 | (1) |
|
11.3 Adding Python Bindings with Boost Python |
|
|
337 | (12) |
|
11.3.1 Building Boost Python |
|
|
338 | (1) |
|
11.3.2 Wrapping a C++ API with Boost Python |
|
|
338 | (3) |
|
|
341 | (1) |
|
11.3.4 Extending the Python API |
|
|
341 | (3) |
|
11.3.5 Inheritance in C++ |
|
|
344 | (1) |
|
11.3.6 Cross-Language Polymorphism |
|
|
345 | (1) |
|
11.3.7 Supporting Iterators |
|
|
346 | (1) |
|
11.3.8 Putting It All Together |
|
|
347 | (2) |
|
11.4 Adding Ruby Bindings with SWIG |
|
|
349 | (12) |
|
11.4.1 Wrapping a C++ API with SWIG |
|
|
350 | (2) |
|
11.4.2 Tuning the Ruby API |
|
|
352 | (1) |
|
|
353 | (1) |
|
11.4.4 Extending the Ruby API |
|
|
353 | (1) |
|
11.4.5 Inheritance in C++ |
|
|
354 | (2) |
|
11.4.6 Cross-Language Polymorphism |
|
|
356 | (1) |
|
11.4.7 Putting It All Together |
|
|
357 | (4) |
|
|
361 | (30) |
|
12.1 Extending via Plugins |
|
|
361 | (13) |
|
12.1.1 Plugin Model Overview |
|
|
362 | (2) |
|
12.1.2 Plugin System Design Issues |
|
|
364 | (2) |
|
12.1.3 Implementing Plugins in C++ |
|
|
366 | (1) |
|
|
367 | (2) |
|
|
369 | (1) |
|
12.1.6 The Plugin Manager |
|
|
370 | (2) |
|
|
372 | (2) |
|
12.2 Extending via Inheritance |
|
|
374 | (11) |
|
12.2.1 Adding Functionality |
|
|
374 | (1) |
|
12.2.2 Modifying Functionality |
|
|
375 | (1) |
|
12.2.3 Inheritance and the STL |
|
|
376 | (1) |
|
12.2.4 Inheritance and Enums |
|
|
377 | (1) |
|
12.2.5 The Visitor Pattern |
|
|
378 | (6) |
|
12.2.6 Prohibiting Subclassing |
|
|
384 | (1) |
|
12.3 Extending via Templates |
|
|
385 | (6) |
|
12.3.1 Policy-Based Templates |
|
|
386 | (1) |
|
12.3.2 The Curiously Recurring Template Pattern |
|
|
387 | (4) |
|
|
391 | (18) |
|
A.1 Static versus Dynamic Libraries |
|
|
391 | (3) |
|
|
391 | (1) |
|
|
392 | (2) |
|
A.1.3 Dynamic Libraries as Plugins |
|
|
394 | (1) |
|
|
394 | (5) |
|
A.2.1 Importing and Exporting Functions |
|
|
395 | (1) |
|
A.2.2 The DLL Entry Point |
|
|
396 | (1) |
|
A.2.3 Creating Libraries on Windows |
|
|
397 | (1) |
|
A.2.4 Useful Windows Utilities |
|
|
398 | (1) |
|
A.2.5 Loading Plugins on Windows |
|
|
398 | (1) |
|
|
399 | (6) |
|
A.3.1 Creating Static Libraries on Linux |
|
|
399 | (1) |
|
A.3.2 Creating Dynamic Libraries on Linux |
|
|
400 | (1) |
|
A.3.3 Shared Library Entry Points |
|
|
401 | (1) |
|
A.3.4 Useful Linux Utilities |
|
|
402 | (1) |
|
A.3.5 Loading Plugins on Linux |
|
|
403 | (1) |
|
A.3.6 Finding Dynamic Libraries at Run Time |
|
|
404 | (1) |
|
A.4 Libraries on Mac OS X |
|
|
405 | (4) |
|
A.4.1 Creating Static Libraries on Mac OS X |
|
|
405 | (1) |
|
A.4.2 Creating Dynamic Libraries on Mac OS X |
|
|
405 | (1) |
|
A.4.3 Frameworks on Mac OS X |
|
|
406 | (1) |
|
A.4.4 Finding Dynamic Libraries at Run Time |
|
|
407 | (2) |
Bibliography |
|
409 | (4) |
Index |
|
413 | |