Preface

Writing large applications in C++ is a complex and tricky business. However, designing reusable C++ interfaces that are robust, stable, easy to use, and durable is even more difficult. The best way to succeed in this endeavor is to adhere to the tenets of good Application Programming Interface (API) design.

An API presents a logical interface to a software component and hides the internal details required to implement that component. It offers a high-level abstraction for a module and promotes code reuse by allowing multiple applications to share the same functionality.

Modern software development has become highly dependent on APIs, from low-level application frameworks to data format APIs and graphical user interface (GUI) frameworks. In fact, common software engineering terms such as modular development, code reuse, componentization, dynamic link library or DLL, software frameworks, distributed computing, and service-oriented architecture all imply the need for strong API design skills.

Some popular C and C++ APIs that you may already be aware of include the Standard Template Library (STL), Boost, the Microsoft Windows API (Win32), Microsoft Foundation Classes (MFC), libtiff, libpng, zlib, libxml++, OpenGL, MySQL++, Nokia’s Qt, wxWidgets, GTK++, KDE, SkypeKit, POSIX pthreads, Intel’s Threading Building Blocks, the Netscape Plugin API, and the Apache module API. In addition, many of Google’s open-source projects are C++, as is much of the code on the sourceforge.net, bitbucket.org, and freshmeat.net Web sites.

APIs such as these are used in all facets of software development, from desktop applications, to mobile computing and embedded systems, to Web development. For example, the Mozilla Firefox Web browser is built on top of more than 80 dynamic libraries, each of which provides the implementation for one or more APIs.

Elegant and robust API design is therefore a critical aspect of contemporary software development. One important way in which this differs from standard application development is the far greater need for change management. As we all know, change is an inevitable factor in software development; new requirements, feature requests, and bug fixes cause software to evolve in ways that were never anticipated when it was first devised. However, changes to an API that’s shared by hundreds of end-user applications can cause major upheaval and ultimately may cause clients to abandon an API. The primary goal of good API design is therefore to provide your clients with the functionality they need while also causing minimal impact to their code—ideally zero impact—when you release a new version.

Why you should read this book

If you write C++ code that another engineer relies upon, you’re an API designer and this book has been written for you.

Interfaces are the most important code that you write because a problem with your interface is far more costly to fix than a bug in your implementation. For instance, an interface change may require all of the applications based on your code to be updated, whereas an implementation-only change can be integrated transparently and effortlessly into client applications when they adopt the new API version. Put in more economic terms, a poorly designed interface can seriously reduce the long-term survival of your code. Learning how to create high-quality interfaces is therefore an essential engineering skill, and the central focus of this book.

As Michi Henning noted, API design is more important today than it was 20 years ago. This is because many more APIs have been designed in recent years. These also provide richer and more complex functionality and are shared by more end-user applications (Henning, 2009). Despite this fact, no other books currently on the market concentrate on the topic of API design for C++.

It’s worth noting that this book is not meant to be a general C++ programming guide—there are already many good examples of these on the market. I will certainly cover lots of object-oriented design material and present many handy C++ tips and tricks. However, I will focus on techniques for representing clean modular interfaces in C++. By corollary, I will not dive as deeply into the question of how to implement the code behind these interfaces, such as specific algorithm choices or best practices limited to the code within the curly braces of your function bodies.

However, this book will cover the full breadth of API development, from initial design through implementation, testing, documentation, release, versioning, maintenance, and deprecation. I will even cover specialized API topics such as creating scripting and plugin APIs. While many of these topics are also relevant to software development in general, the focus here will be on the particular implications for API design. For example, when discussing testing strategies I will concentrate on automated API testing techniques rather than attempting to include end-user application testing techniques such as GUI testing, system testing, or manual testing.

In terms of my own credentials to write this book, I have led the development of APIs for research code shared by several collaborating institutions, in-house animation system APIs that have been used to make Academy Award-winning movies, and open-source client/server APIs that have been used by millions of people worldwide. Throughout all of these disparate experiences, I have consistently witnessed the need for high-quality API design. This book therefore presents a practical distillation of the techniques and strategies of industrial-strength API design that have been drawn from a range of real-world experiences.

Who is the target audience

While this book is not a beginner’s guide to C++, I have made every effort to make the text easy to read and to explain all terminology and jargon clearly. The book should therefore be valuable to new programmers who have grasped the fundamentals of C++ and want to advance their design skills, as well as senior engineers and software architects who are seeking to gain new expertise to complement their existing talents.

There are three specific groups of readers that I have borne in mind while writing this book.

1. Practicing software engineers and architects. Junior and senior developers who are working on a specific API project and need pragmatic advice on how to produce the most elegant and enduring design.

2. Technical managers. Program and product managers who are responsible for producing an API product and who want to gain greater insight into the technical issues and development processes of API design.

3. Students and educators. Computer science and software engineering students who are learning how to program and are seeking a thorough resource on software design that is informed by practical experience on large-scale projects.

Focusing on C++

While there are many generic API design methodologies that can be taught—skills that apply equally well to any programming language or environment—ultimately an API has to be expressed in a particular programming language. It is therefore important to understand the language-specific features that contribute to exemplary API design. This book is therefore focused on the issues of designing APIs for a single language (C++) rather than diluting the content to make it applicable for all languages. While readers who wish to develop APIs for other languages, such as Java or C#, may still gain much general insight from this text, the book is directly targeted at C++ engineers who must write and maintain APIs for other engineers to consume.

C++ is still one of the most widely used programming languages for large software projects and tends to be the most popular choice for performance-critical code. As a result, there are many diverse C and C++ APIs available for you to use in your own applications (some of which I listed earlier). I will therefore concentrate on aspects of producing good APIs in C++ and include copious source code examples to illustrate these concepts better. This means that I will deal with C++-specific topics such as templates, encapsulation, inheritance, namespaces, operators, const correctness, memory management, use of STL, the pimpl idiom, and so on.

Additionally, this book has been published during an exciting time in the evolution of C++. A new version of the C++ specification has been approved by ISO/IEC. Most C++ compilers currently aim to conform to the standard that was first published in 1998, known as C++98. A later revision of this standard was published in 2003 to correct several defects. Since that time, the standards committee has been working on a major new version of the specification. This version is now ratified and is referred to as C++11, because it was approved in 2011 (when this book was first printed, C++11 was not officially approved and was referred to as C++0x at that time).

Many of the major C++ compilers have already started to implement the new features of C++11. In terms of API design, several of these new language features can be used to produce more elegant and sturdy interfaces. As such, I have endeavored to highlight and explain those areas of C++11 throughout the book. This book should therefore remain a relevant resource for several years to come.

Conventions

While it is more traditional to employ the term “user” to mean a person who uses a software application, such as a user of Microsoft Word or Mozilla Firefox, in the context of API design I will apply the term to mean a software developer who is creating an application and is using an API to achieve this. In other words, I will generally be talking about API users and not application users. The term “client” will be used synonymously in this regard. Note that the term “client,” in addition to referring to a human user of your API, can also refer impersonally to other pieces of software that must call functions in your API.

While there are many file format extensions used to identify C++ source and header files, such as .cpp, .cc, .cxx, .h, .hh, and .hpp, I will standardize on the use of .cpp and .h throughout this book. I will also use the terms module and component interchangeably to mean a single .cpp and .h file pair. These are notably not equivalent to a class because a component or module may contain multiple classes. I will use the term library to refer to a physical collection, or package, of components, that is, library > module/component > class.

The term method, while generally understood in the object-oriented programming community, is not strictly a C++ term; it originally evolved from the Smalltalk language. The equivalent C++ term is member function, although some engineers prefer the more specific definition of virtual member function. Because I am not particularly concerned with the subtleties of these terms in this book, I will use method and member function interchangeably. Similarly, although the term data member is the more correct C++ expression, I will treat the term member variable as a synonym.

In terms of typographical conventions, I will use a fixed-width font to typeset all source code examples, as well as any filenames or language keywords that may appear in the text. Also, I will prefer upper camel case for all class and function names in the examples that I present, that is, CamelCase instead of camelCase or snake_case, although obviously I will preserve the case for any external code that I reference, such as std::for_each(). I follow the convention of using an “m” prefix in front of data members, for example, mMemberVar, and “s” in front of static variables, for example, sStaticVar.

It should be pointed out that the source examples within the book are often only code snippets and are not meant to show fully functional samples. I will also often strip comments from the example code in the book. This is done for reasons of brevity and clarity. In particular, I will often omit any preprocessor guard statements around a header file. I will assume that the reader is aware that every C/C++ header should enclose all of its content within guard statements and that it’s good practice to contain all of your API declarations within a consistent namespace (as covered in Chapters 3 and 6). In other words, it should be assumed that each header file that I present is implicitly surrounded by code, such as the following.

 #ifndef MY_MODULE_H

 #define MY_MODULE_H

 // required #include files…

 namespace apibook {

 // API declarations …

 }

 #endif

Tip

I will also highlight various API design tips and key concepts throughout the book. These callouts are provided to let you search quickly for a concept you wish to reread. If you are particularly pressed for time, you could simply scan the book for these tips and then read the surrounding text to gain greater insight for those topics that interest you the most.

Book web site

This book also has a supporting Web site, http://APIBook.com/. On this site you can find general information about the book, as well as supporting material, such as the complete set of source code examples contained within the text. Feel free to download and play with these samples yourself—they were designed to be as simple as possible, while still being useful and illustrative. I have used the cross-platform CMake build system to facilitate compiling and linking the examples so they should work on Windows, Mac OS X, and UNIX operating systems.

I will also publish any information about new revisions of this book and any errata on this Web site, as well as useful links to other related API resources on the Internet, such as interesting toolkits, articles, and utilities.

The book Web site also provides access to a utility that I wrote called API Diff. This program lets you compare two versions of an API and review differences to code or comments in a visual side-by-side format. You can also generate a report of everything that changed in a particular release so that your clients know exactly what to look out for. This utility is available for Windows, Mac OS X, and Linux.